Major cleanup all over the helma.objectmodel.db package.

Fixes bug 151.
Some optimization in getElementName().
Removed cases where user prototype was treated as a special case.
This commit is contained in:
hns 2002-11-22 19:26:39 +00:00
parent b052ee89a7
commit 83d997477c
5 changed files with 158 additions and 132 deletions

View file

@ -26,8 +26,6 @@ public final class DbMapping implements Updatable {
// prototype name of this mapping // prototype name of this mapping
String typename; String typename;
// int version;
// properties from where the mapping is read // properties from where the mapping is read
SystemProperties props; SystemProperties props;
@ -42,8 +40,8 @@ public final class DbMapping implements Updatable {
ParentInfo[] parent; ParentInfo[] parent;
// Relations describing subnodes and properties. // Relations describing subnodes and properties.
Relation subnodesRel; Relation subRelation;
Relation propertiesRel; Relation propRelation;
// if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes // if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes
DbMapping groupbyMapping; DbMapping groupbyMapping;
@ -230,17 +228,19 @@ public final class DbMapping implements Updatable {
if (subnodeMapping != null) { if (subnodeMapping != null) {
try { try {
// check if subnode relation already exists. If so, reuse it // check if subnode relation already exists. If so, reuse it
if (subnodesRel == null) if (subRelation == null)
subnodesRel = new Relation (subnodeMapping, "_children", this, props); subRelation = new Relation (subnodeMapping, "_children", this, props);
subnodesRel.update (subnodeMapping, props); subRelation.update (subnodeMapping, props);
if (subnodesRel.accessor != null) // if subnodes are accessed via access name or group name,
propertiesRel = subnodesRel; // the subnode relation is also the property relation.
if (subRelation.accessor != null || subRelation.groupby != null)
propRelation = subRelation;
} catch (Exception x) { } catch (Exception x) {
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ()); app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
// subnodesRel = null; // subRelation = null;
} }
} else { } else {
subnodesRel = propertiesRel = null; subRelation = propRelation = null;
} }
if (groupbyMapping != null) { if (groupbyMapping != null) {
@ -422,8 +422,8 @@ public final class DbMapping implements Updatable {
public DbMapping getSubnodeMapping () { public DbMapping getSubnodeMapping () {
if (subnodesRel != null) if (subRelation != null)
return subnodesRel.otherType; return subRelation.otherType;
if (parentMapping != null) if (parentMapping != null)
return parentMapping.getSubnodeMapping (); return parentMapping.getSubnodeMapping ();
return null; return null;
@ -452,7 +452,7 @@ public final class DbMapping implements Updatable {
* db-mapping with the right relations to create the group-by nodes * db-mapping with the right relations to create the group-by nodes
*/ */
public synchronized DbMapping getGroupbyMapping () { public synchronized DbMapping getGroupbyMapping () {
if (subnodesRel == null || subnodesRel.groupby == null) if (subRelation == null || subRelation.groupby == null)
return null; return null;
if (groupbyMapping == null) { if (groupbyMapping == null) {
initGroupbyMapping (); initGroupbyMapping ();
@ -469,38 +469,31 @@ public final class DbMapping implements Updatable {
groupbyMapping = new DbMapping (app); groupbyMapping = new DbMapping (app);
// If a mapping is defined, make the internal mapping inherit from // If a mapping is defined, make the internal mapping inherit from
// the defined named prototype. // the defined named prototype.
if (subnodesRel.groupbyprototype != null) if (subRelation.groupbyPrototype != null)
groupbyMapping.parentMapping = app.getDbMapping (subnodesRel.groupbyprototype); groupbyMapping.parentMapping = app.getDbMapping (subRelation.groupbyPrototype);
groupbyMapping.subnodesRel = subnodesRel.getGroupbySubnodeRelation (); groupbyMapping.subRelation = subRelation.getGroupbySubnodeRelation ();
if (propertiesRel != null) if (propRelation != null)
groupbyMapping.propertiesRel = propertiesRel.getGroupbyPropertyRelation (); groupbyMapping.propRelation = propRelation.getGroupbyPropertyRelation ();
else else
groupbyMapping.propertiesRel = subnodesRel.getGroupbyPropertyRelation (); groupbyMapping.propRelation = subRelation.getGroupbyPropertyRelation ();
groupbyMapping.typename = subnodesRel.groupbyprototype; groupbyMapping.typename = subRelation.groupbyPrototype;
} }
/* public void setPropertyMapping (DbMapping pm) {
properties = pm;
} */
/* public void setSubnodeRelation (Relation rel) {
subnodesRel = rel;
} */
public void setPropertyRelation (Relation rel) { public void setPropertyRelation (Relation rel) {
propertiesRel = rel; propRelation = rel;
} }
public Relation getSubnodeRelation () { public Relation getSubnodeRelation () {
if (subnodesRel == null && parentMapping != null) if (subRelation == null && parentMapping != null)
return parentMapping.getSubnodeRelation (); return parentMapping.getSubnodeRelation ();
return subnodesRel; return subRelation;
} }
public Relation getPropertyRelation () { public Relation getPropertyRelation () {
if (propertiesRel == null && parentMapping != null) if (propRelation == null && parentMapping != null)
return parentMapping.getPropertyRelation (); return parentMapping.getPropertyRelation ();
return propertiesRel; return propRelation;
} }
public Relation getPropertyRelation (String propname) { public Relation getPropertyRelation (String propname) {
@ -524,9 +517,9 @@ public final class DbMapping implements Updatable {
} }
public String getSubnodeGroupby () { public String getSubnodeGroupby () {
if (subnodesRel == null && parentMapping != null) if (subRelation == null && parentMapping != null)
return parentMapping.getSubnodeGroupby (); return parentMapping.getSubnodeGroupby ();
return subnodesRel == null ? null : subnodesRel.groupby; return subRelation == null ? null : subRelation.groupby;
} }
public String getIDgen () { public String getIDgen () {

View file

@ -17,7 +17,6 @@ import helma.objectmodel.*;
import helma.util.*; import helma.util.*;
import helma.framework.IPathElement; import helma.framework.IPathElement;
import java.math.BigDecimal; import java.math.BigDecimal;
// import com.workingdogs.village.*;
/** /**
@ -154,7 +153,7 @@ public final class Node implements INode, Serializable {
transient String subnodeRelation = null; transient String subnodeRelation = null;
transient long lastSubnodeFetch = 0; transient long lastSubnodeFetch = 0;
transient long lastSubnodeChange = 0; transient long lastSubnodeChange = 0;
transient long lastNameCheck = 0;
transient long lastParentSet = 0; transient long lastParentSet = 0;
transient long lastSubnodeCount = 0; // these two are only used transient long lastSubnodeCount = 0; // these two are only used
@ -261,11 +260,6 @@ public final class Node implements INode, Serializable {
name = nameField == null ? id : rs.getString (nameField); name = nameField == null ? id : rs.getString (nameField);
if (name == null || name.length() == 0) if (name == null || name.length() == 0)
name = dbmap.getTypeName() + " " + id; name = dbmap.getTypeName() + " " + id;
// set parent for user objects to internal userroot node
if ("user".equals (prototype)) {
parentHandle = new NodeHandle (new DbKey (null, "1"));
anonymous = false;
}
created = lastmodified = System.currentTimeMillis (); created = lastmodified = System.currentTimeMillis ();
@ -281,25 +275,25 @@ public final class Node implements INode, Serializable {
switch (rel.getColumnType()) { switch (rel.getColumnType()) {
case Types.BIT: case Types.BIT:
newprop.setBooleanValue (rs.getBoolean(rel.getDbField())); newprop.setBooleanValue (rs.getBoolean(columns[i]));
break; break;
case Types.TINYINT: case Types.TINYINT:
case Types.BIGINT: case Types.BIGINT:
case Types.SMALLINT: case Types.SMALLINT:
case Types.INTEGER: case Types.INTEGER:
newprop.setIntegerValue (rs.getLong(rel.getDbField())); newprop.setIntegerValue (rs.getLong(columns[i]));
break; break;
case Types.REAL: case Types.REAL:
case Types.FLOAT: case Types.FLOAT:
case Types.DOUBLE: case Types.DOUBLE:
newprop.setFloatValue (rs.getDouble(rel.getDbField())); newprop.setFloatValue (rs.getDouble(columns[i]));
break; break;
case Types.DECIMAL: case Types.DECIMAL:
case Types.NUMERIC: case Types.NUMERIC:
BigDecimal num = rs.getBigDecimal (rel.getDbField()); BigDecimal num = rs.getBigDecimal (columns[i]);
if (num == null) if (num == null)
break; break;
if (num.scale() > 0) if (num.scale() > 0)
@ -311,20 +305,20 @@ public final class Node implements INode, Serializable {
case Types.LONGVARBINARY: case Types.LONGVARBINARY:
case Types.VARBINARY: case Types.VARBINARY:
case Types.BINARY: case Types.BINARY:
newprop.setStringValue (rs.getString(rel.getDbField())); newprop.setStringValue (rs.getString(columns[i]));
break; break;
case Types.LONGVARCHAR: case Types.LONGVARCHAR:
case Types.CHAR: case Types.CHAR:
case Types.VARCHAR: case Types.VARCHAR:
case Types.OTHER: case Types.OTHER:
newprop.setStringValue (rs.getString(rel.getDbField())); newprop.setStringValue (rs.getString(columns[i]));
break; break;
case Types.DATE: case Types.DATE:
case Types.TIME: case Types.TIME:
case Types.TIMESTAMP: case Types.TIMESTAMP:
newprop.setDateValue (rs.getTimestamp(rel.getDbField())); newprop.setDateValue (rs.getTimestamp(columns[i]));
break; break;
case Types.NULL: case Types.NULL:
@ -333,7 +327,7 @@ public final class Node implements INode, Serializable {
// continue; // continue;
default: default:
newprop.setStringValue (rs.getString(rel.getDbField())); newprop.setStringValue (rs.getString(columns[i]));
break; break;
} }
@ -478,16 +472,13 @@ public final class Node implements INode, Serializable {
} }
/** /**
* Get something to identify this node within a URL. This is the ID for anonymous nodes * Get something to identify this node within a URL. This is the ID for anonymous nodes
* and a property value for named properties. * and a property value for named properties.
*/ */
public String getElementName () { public String getElementName () {
// if subnodes are also mounted as properties, try to get the "nice" prop value // if subnodes are also mounted as properties, try to get the "nice" prop value
// instead of the id by turning the anonymous flag off. // instead of the id by turning the anonymous flag off.
// Work around this for user objects to alsways return a URL like /users/username if (parentHandle != null && lastNameCheck < Math.max (dbmap.getLastTypeChange(), lastmodified)) {
if ("user".equalsIgnoreCase (prototype)) {
anonymous = false;
} else if (parentHandle != null) {
try { try {
Node p = parentHandle.getNode (nmgr); Node p = parentHandle.getNode (nmgr);
DbMapping parentmap = p.getDbMapping (); DbMapping parentmap = p.getDbMapping ();
@ -508,8 +499,9 @@ public final class Node implements INode, Serializable {
} catch (Exception ignore) { } catch (Exception ignore) {
// just fall back to default method // just fall back to default method
} }
lastNameCheck = System.currentTimeMillis ();
} }
return anonymous || name == null || name.length() == 0 ? id : name; return anonymous || name == null || name.length() == 0 ? id : name;
} }
@ -615,10 +607,13 @@ public final class Node implements INode, Serializable {
* Register a node as parent of the present node. We can't refer to the node directly, so we use * Register a node as parent of the present node. We can't refer to the node directly, so we use
* the ID + DB map combo. * the ID + DB map combo.
*/ */
public void setParent (Node parent) { protected void setParent (Node parent) {
parentHandle = parent == null ? null : parent.getHandle (); parentHandle = parent == null ? null : parent.getHandle ();
} }
/**
* Set the parent handle which can be used to get the actual parent node.
*/
public void setParentHandle (NodeHandle parent) { public void setParentHandle (NodeHandle parent) {
parentHandle = parent; parentHandle = parent;
} }
@ -679,10 +674,11 @@ public final class Node implements INode, Serializable {
// check what's specified in the type.properties for this node. // check what's specified in the type.properties for this node.
ParentInfo[] parentInfo = null; ParentInfo[] parentInfo = null;
if (isRelational () && (lastParentSet < dbmap.getLastTypeChange() || lastParentSet < lastmodified)) if (isRelational () && lastParentSet < Math.max (dbmap.getLastTypeChange(), lastmodified))
parentInfo = dbmap.getParentInfo (); parentInfo = dbmap.getParentInfo ();
// check if current parent candidate matches presciption, if not, try to get it // check if current parent candidate matches presciption,
// if not, try to get one that does.
if (parentInfo != null && state != TRANSIENT) { if (parentInfo != null && state != TRANSIENT) {
for (int i=0; i<parentInfo.length; i++) { for (int i=0; i<parentInfo.length; i++) {
ParentInfo pinfo = parentInfo[i]; ParentInfo pinfo = parentInfo[i];
@ -693,7 +689,7 @@ public final class Node implements INode, Serializable {
if (rel != null && rel.reftype == Relation.REFERENCE) if (rel != null && rel.reftype == Relation.REFERENCE)
pn = getNode (pinfo.propname, false); pn = getNode (pinfo.propname, false);
// the parent of this node is the app's root node... // the parent of this node is the app's root node...
if (pinfo.isroot && pn == null) if (pn == null && pinfo.isroot)
pn = nmgr.getNode ("0", nmgr.getDbMapping ("root")); pn = nmgr.getNode ("0", nmgr.getDbMapping ("root"));
// if we found a parent node, check if we ought to use a virtual or groupby node as parent // if we found a parent node, check if we ought to use a virtual or groupby node as parent
if (pn != null) { if (pn != null) {
@ -1092,11 +1088,6 @@ public final class Node implements INode, Serializable {
// which needs to be unset // which needs to be unset
if (dbmap != null) { if (dbmap != null) {
Relation srel = dbmap.getSubnodeRelation (); Relation srel = dbmap.getSubnodeRelation ();
/*if (srel != null && srel.reftype == Relation.BACKWARD) {
Relation backlink = srel.otherType.columnNameToRelation (srel.getRemoteField ());
if (backlink != null && id.equals (node.getString (backlink.propName, false)))
node.unset (backlink.propName);
} */
} }
// check if subnodes are also accessed as properties. If so, also unset the property // check if subnodes are also accessed as properties. If so, also unset the property
@ -1349,27 +1340,33 @@ public final class Node implements INode, Serializable {
prop.convertToNodeReference (pmap); prop.convertToNodeReference (pmap);
} }
// the property does not exist in our propmap - see if we can create it on the fly, // the property does not exist in our propmap - see if we should create it on the fly,
// either because it is mapped from a relational database or defined as virtual node // either because it is mapped to an object from relational database or defined as
// collection aka virtual node
if (prop == null && dbmap != null) { if (prop == null && dbmap != null) {
Relation prel = dbmap.getPropertyRelation (propname); Relation propRel = dbmap.getPropertyRelation (propname);
Relation srel = dbmap.getSubnodeRelation (); // if no property relation is defined for this specific property name,
if (prel == null && srel != null && srel.groupby != null) // use the generic property relation, if one is defined.
prel = srel; if (propRel == null)
if (prel == null) propRel = dbmap.getPropertyRelation ();
prel = dbmap.getPropertyRelation (); // so if we have a property relation and it does in fact link to another object...
if (prel != null) { if (propRel != null && propRel.isCollection ()) {
// if what we want is a virtual node, fetch anyway. // in some cases we just want to create and set a generic node without consulting
if (state == TRANSIENT && prel.virtual) { // the NodeManager if it exists: When we get a collection (aka virtual node)
INode node = new Node (propname, prel.getPrototype (), nmgr); // from a transient node for the first time, or when we get a collection whose
node.setDbMapping (prel.getVirtualMapping ()); // content objects are stored in the embedded XML data storage.
if (state == TRANSIENT && propRel.virtual) {
INode node = new Node (propname, propRel.getPrototype (), nmgr);
node.setDbMapping (propRel.getVirtualMapping ());
setNode (propname, node); setNode (propname, node);
prop = (Property) propMap.get (propname); prop = (Property) propMap.get (propname);
// if this is from relational database only fetch if this node is itself persistent. }
} else if (state != TRANSIENT && (prel.virtual || prel.accessor != null || prel.groupby != null)) { // if this is from relational database only fetch if this node
// is itself persistent.
else if (state != TRANSIENT && propRel.createPropertyOnDemand ()) {
// this may be a relational node stored by property name // this may be a relational node stored by property name
try { try {
Node pn = nmgr.getNode (this, propname, prel); Node pn = nmgr.getNode (this, propname, propRel);
if (pn != null) { if (pn != null) {
if (pn.parentHandle == null && !"root".equalsIgnoreCase (pn.getPrototype ())) { if (pn.parentHandle == null && !"root".equalsIgnoreCase (pn.getPrototype ())) {
pn.setParent (this); pn.setParent (this);
@ -1391,11 +1388,6 @@ public final class Node implements INode, Serializable {
return prop; return prop;
} }
/* public String getString (String propname, String defaultValue, boolean inherit) {
String propValue = getString (propname, inherit);
return propValue == null ? defaultValue : propValue;
} */
public String getString (String propname, boolean inherit) { public String getString (String propname, boolean inherit) {
// propname = propname.toLowerCase (); // propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit); Property prop = getProperty (propname, inherit);
@ -1493,10 +1485,10 @@ public final class Node implements INode, Serializable {
// check if this node is already registered with the old name; if so, remove it. // check if this node is already registered with the old name; if so, remove it.
// then set parent's property to this node for the new name value // then set parent's property to this node for the new name value
DbMapping parentmap = parent.getDbMapping (); DbMapping parentmap = parent.getDbMapping ();
Relation prel = parentmap.getPropertyRelation (); Relation propRel = parentmap.getPropertyRelation ();
String dbcolumn = dbmap.propertyToColumnName (propname); String dbcolumn = dbmap.propertyToColumnName (propname);
if (prel != null && prel.accessor != null && prel.accessor.equals (dbcolumn)) { if (propRel != null && propRel.accessor != null && propRel.accessor.equals (dbcolumn)) {
INode n = parent.getNode (value, false); INode n = parent.getNode (value, false);
if (n != null && n != this) { if (n != null && n != this) {
parent.unset (value); parent.unset (value);

View file

@ -25,9 +25,6 @@ public final class NodeHandle implements INodeState, Serializable {
// the node's key // the node's key
private Key key; private Key key;
// cached DbMapping
private transient DbMapping dbmap;
static final long serialVersionUID = 3067763116576910931L; static final long serialVersionUID = 3067763116576910931L;
/** /**
@ -64,7 +61,8 @@ public final class NodeHandle implements INodeState, Serializable {
} }
/** /**
* Get the key for the node described by this handle. This may only be called on persistent Nodes. * Get the key for the node described by this handle.
* This may only be called on persistent Nodes.
*/ */
public Key getKey () { public Key getKey () {
if (key == null) if (key == null)
@ -73,7 +71,8 @@ public final class NodeHandle implements INodeState, Serializable {
} }
/** /**
* Get the ID for the node described by this handle. This may only be called on persistent Nodes. * Get the ID for the node described by this handle.
* This may only be called on persistent Nodes.
*/ */
public String getID () { public String getID () {
if (key == null) if (key == null)

View file

@ -1067,10 +1067,11 @@ public final class NodeManager {
private Node getNodeByRelation (ITransaction txn, Node home, String kstr, Relation rel) throws Exception { private Node getNodeByRelation (ITransaction txn, Node home, String kstr, Relation rel) throws Exception {
Node node = null; Node node = null;
if (rel.virtual) { if (rel != null && rel.virtual) {
if (rel.needsPersistence ())
node = new Node (home, kstr, safe, rel.prototype); node = (Node) home.createNode (kstr);
else
node = new Node (home, kstr, safe, rel.prototype);
if (rel.prototype != null) { if (rel.prototype != null) {
node.setPrototype (rel.prototype); node.setPrototype (rel.prototype);
node.setDbMapping (app.getDbMapping (rel.prototype)); node.setDbMapping (app.getDbMapping (rel.prototype));

View file

@ -57,14 +57,13 @@ public final class Relation {
String accessor; // db column used to access objects through this relation String accessor; // db column used to access objects through this relation
String order; String order;
String groupbyorder; String groupbyOrder;
String groupby; String groupby;
String prototype; String prototype;
String groupbyprototype; String groupbyPrototype;
String filter; String filter;
int maxSize = 0; int maxSize = 0;
// Relation subnoderelation = null; // additional relation used to filter subnodes for virtual nodes
/** /**
* This constructor makes a copy of an existing relation. Not all fields are copied, just those * This constructor makes a copy of an existing relation. Not all fields are copied, just those
@ -156,8 +155,8 @@ public final class Relation {
// FIXME: needs to be synchronized? // FIXME: needs to be synchronized?
if (virtualMapping != null) { if (virtualMapping != null) {
virtualMapping.lastTypeChange = ownType.lastTypeChange; virtualMapping.lastTypeChange = ownType.lastTypeChange;
virtualMapping.subnodesRel = getVirtualSubnodeRelation (); virtualMapping.subRelation = getVirtualSubnodeRelation ();
virtualMapping.propertiesRel = getVirtualPropertyRelation (); virtualMapping.propRelation = getVirtualPropertyRelation ();
} }
} }
} }
@ -190,12 +189,12 @@ public final class Relation {
if (groupby != null && groupby.trim().length() == 0) if (groupby != null && groupby.trim().length() == 0)
groupby = null; groupby = null;
if (groupby != null) { if (groupby != null) {
groupbyorder = props.getProperty (propName+".group.order"); groupbyOrder = props.getProperty (propName+".group.order");
if (groupbyorder != null && groupbyorder.trim().length() == 0) if (groupbyOrder != null && groupbyOrder.trim().length() == 0)
groupbyorder = null; groupbyOrder = null;
groupbyprototype = props.getProperty (propName+".group.prototype"); groupbyPrototype = props.getProperty (propName+".group.prototype");
if (groupbyprototype != null && groupbyprototype.trim().length() == 0) if (groupbyPrototype != null && groupbyPrototype.trim().length() == 0)
groupbyprototype = null; groupbyPrototype = null;
// aggressive loading and caching is not supported for groupby-nodes // aggressive loading and caching is not supported for groupby-nodes
aggressiveLoading = aggressiveCaching = false; aggressiveLoading = aggressiveCaching = false;
} }
@ -229,6 +228,55 @@ public final class Relation {
return reftype == PRIMITIVE; return reftype == PRIMITIVE;
} }
/**
* Returns true if this Relation describes an object reference property
*/
public boolean isReference () {
return reftype == REFERENCE;
}
/**
* Returns true if this Relation describes a collection object property
*/
public boolean isCollection () {
return reftype == COLLECTION;
}
/**
* Tell wether the property described by this relation is to be handled as private, i.e.
* a change on it should not result in any changed object/collection relations.
*/
public boolean isPrivate () {
return isPrivate;
}
/**
* Returns true if the object represented by this Relation has to be
* created dynamically by the Helma objectmodel runtime as a virtual
* node. Virtual nodes are objects which are only generated on demand
* and never stored to a persistent storage.
*/
public boolean createPropertyOnDemand () {
return virtual || accessor != null || groupby != null;
}
/**
* Returns true if the object represented by this Relation has to be
* persisted in the internal db in order to be functional. This is true if
* the subnodes contained in this collection are stored in the embedded
* database. In this case, the collection itself must also be an ordinary
* object stored in the db, since a virtual collection would lose its
* its content after restarts.
*/
public boolean needsPersistence () {
if (!virtual)
return false;
if (prototype == null)
return !otherType.isRelational ();
DbMapping sub = otherType.getSubnodeMapping ();
return sub != null && !sub.isRelational ();
}
/** /**
* Return the prototype to be used for object reached by this relation * Return the prototype to be used for object reached by this relation
*/ */
@ -301,8 +349,8 @@ public final class Relation {
return null; return null;
if (virtualMapping == null) { if (virtualMapping == null) {
virtualMapping = new DbMapping (ownType.app); virtualMapping = new DbMapping (ownType.app);
virtualMapping.subnodesRel = getVirtualSubnodeRelation (); virtualMapping.subRelation = getVirtualSubnodeRelation ();
virtualMapping.propertiesRel = getVirtualPropertyRelation (); virtualMapping.propRelation = getVirtualPropertyRelation ();
} }
return virtualMapping; return virtualMapping;
} }
@ -316,8 +364,8 @@ public final class Relation {
throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation"); throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
Relation vr = new Relation (this); Relation vr = new Relation (this);
vr.groupby = groupby; vr.groupby = groupby;
vr.groupbyorder = groupbyorder; vr.groupbyOrder = groupbyOrder;
vr.groupbyprototype = groupbyprototype; vr.groupbyPrototype = groupbyPrototype;
vr.order = order; vr.order = order;
vr.filter = filter; vr.filter = filter;
vr.maxSize = maxSize; vr.maxSize = maxSize;
@ -335,8 +383,8 @@ public final class Relation {
throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation"); throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
Relation vr = new Relation (this); Relation vr = new Relation (this);
vr.groupby = groupby; vr.groupby = groupby;
vr.groupbyorder = groupbyorder; vr.groupbyOrder = groupbyOrder;
vr.groupbyprototype = groupbyprototype; vr.groupbyPrototype = groupbyPrototype;
vr.order = order; vr.order = order;
vr.filter = filter; vr.filter = filter;
vr.maxSize = maxSize; vr.maxSize = maxSize;
@ -352,7 +400,7 @@ public final class Relation {
throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation"); throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation");
Relation vr = new Relation (this); Relation vr = new Relation (this);
vr.order = order; vr.order = order;
vr.prototype = groupbyprototype; vr.prototype = groupbyPrototype;
vr.filter = filter; vr.filter = filter;
vr.constraints = constraints; vr.constraints = constraints;
vr.addConstraint (new Constraint (null, null, groupby, true)); vr.addConstraint (new Constraint (null, null, groupby, true));
@ -369,7 +417,7 @@ public final class Relation {
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation"); throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
Relation vr = new Relation (this); Relation vr = new Relation (this);
vr.order = order; vr.order = order;
vr.prototype = groupbyprototype; vr.prototype = groupbyPrototype;
vr.filter = filter; vr.filter = filter;
vr.constraints = constraints; vr.constraints = constraints;
vr.addConstraint (new Constraint (null, null, groupby, true)); vr.addConstraint (new Constraint (null, null, groupby, true));
@ -410,8 +458,8 @@ public final class Relation {
} }
if (groupby != null) { if (groupby != null) {
q.append (" GROUP BY "+groupby); q.append (" GROUP BY "+groupby);
if (useOrder && groupbyorder != null) if (useOrder && groupbyOrder != null)
q.append (" ORDER BY "+groupbyorder); q.append (" ORDER BY "+groupbyOrder);
} else if (useOrder && order != null) } else if (useOrder && order != null)
q.append (" ORDER BY "+order); q.append (" ORDER BY "+order);
return q.toString (); return q.toString ();
@ -437,26 +485,19 @@ public final class Relation {
*/ */
public String getOrder () { public String getOrder () {
if (groupby != null) if (groupby != null)
return groupbyorder; return groupbyOrder;
else else
return order; return order;
} }
/** /**
* Tell wether the property described by this relation is to be handled as readonly/write protected. * Tell wether the property described by this relation is to be handled
* as readonly/write protected.
*/ */
public boolean isReadonly () { public boolean isReadonly () {
return readonly; return readonly;
} }
/**
* Tell wether the property described by this relation is to be handled as private, i.e.
* a change on it should not result in any changed object/collection relations.
*/
public boolean isPrivate () {
return isPrivate;
}
/** /**
* Check if the child node fullfills the constraints defined by this relation. * Check if the child node fullfills the constraints defined by this relation.