attributes = attributeIsString ? [parameter.attribute] : parameter.attribute;
attributes.map(function (attribute) {
- var prop = XT.Orm.getProperty(orm, attribute),
+ var rootAttribute = (attribute.indexOf('.') < 0) ? attribute : attribute.split(".")[0],
+ prop = XT.Orm.getProperty(orm, rootAttribute),
propName = prop.name,
childOrm,
naturalKey,
- index;
+ index,
+ walkPath = function (pathParts, currentOrm, pathIndex) {
+ var currentAttributeIsString = typeof pathParts[pathIndex] === 'string',
+ currentProp = XT.Orm.getProperty(currentOrm, pathParts[pathIndex]),
+ subChildOrm,
+ naturalKey;
+
+ if ((currentProp.toOne || currentProp.toMany)) {
+ if (currentProp.toOne && currentProp.toOne.type) {
+ subChildOrm = that.fetchOrm(nameSpace, currentProp.toOne.type);
+ } else if (currentProp.toMany && currentProp.toMany.type) {
+ subChildOrm = that.fetchOrm(nameSpace, currentProp.toMany.type);
+ } else {
+ plv8.elog(ERROR, "toOne or toMany property is missing it's 'type': " + currentProp.name);
+ }
- if ((prop.toOne || prop.toMany) && attribute.indexOf('.') < 0) {
+ if (pathIndex < pathParts.length - 1) {
+ /* Recurse. */
+ walkPath(pathParts, subChildOrm, pathIndex + 1);
+ } else {
+ /* This is the end of the path. */
+ naturalKey = XT.Orm.naturalKey(subChildOrm);
+ if (currentAttributeIsString) {
+ /* add the natural key to the end of the requested attribute */
+ parameter.attribute = attribute + "." + naturalKey;
+ } else {
+ /* swap out the attribute in the array for the one with the prepended natural key */
+ index = parameter.attribute.indexOf(attribute);
+ parameter.attribute.splice(index, 1);
+ parameter.attribute.splice(index, 0, attribute + "." + naturalKey);
+ }
+ }
+ }
+ }
+
+ if ((prop.toOne || prop.toMany)) {
/* Someone is querying on a toOne without using a path */
- /* TODO: even if there's a path x.y, it's possible that it's still not
- correct because the correct path maybe is x.y.naturalKeyOfY */
if (prop.toOne && prop.toOne.type) {
childOrm = that.fetchOrm(nameSpace, prop.toOne.type);
} else if (prop.toMany && prop.toMany.type) {
} else {
plv8.elog(ERROR, "toOne or toMany property is missing it's 'type': " + prop.name);
}
- naturalKey = XT.Orm.naturalKey(childOrm);
- if (attributeIsString) {
- /* add the natural key to the end of the requested attribute */
- parameter.attribute = attribute + "." + naturalKey;
+
+ if (attribute.indexOf('.') < 0) {
+ naturalKey = XT.Orm.naturalKey(childOrm);
+ if (attributeIsString) {
+ /* add the natural key to the end of the requested attribute */
+ parameter.attribute = attribute + "." + naturalKey;
+ } else {
+ /* swap out the attribute in the array for the one with the prepended natural key */
+ index = parameter.attribute.indexOf(attribute);
+ parameter.attribute.splice(index, 1);
+ parameter.attribute.splice(index, 0, attribute + "." + naturalKey);
+ }
} else {
- /* swap out the attribute in the array for the one with the prepended natural key */
- index = parameter.attribute.indexOf(attribute);
- parameter.attribute.splice(index, 1);
- parameter.attribute.splice(index, 0, attribute + "." + naturalKey);
+ /* Even if there's a path x.y, it's possible that it's still not
+ correct because the correct path maybe is x.y.naturalKeyOfY */
+ walkPath(attribute.split("."), orm, 0);
}
}
});
return ret;
},
+ /**
+ * Get the current database server version.
+ * If the optional precision argument is passed, return the first prec
+ * fields of the full version number.
+ *
+ * @example
+ * var x = getPgVersion(1), // '9'
+ * xy = getPgVersion(2), // '9.1'
+ * xyz = getPgVersion(3), // '9.1.3'
+ * all = getPgVersion(); // '9.1.3'
+ *
+ * @param {Number} proc - optional precision
+ * @returns {String} X[.Y[.Z]]
+ */
+ getPgVersion: function (prec) {
+ var q = plv8.execute("select setting from pg_settings " +
+ "where name='server_version';"),
+ ret;
+ ret = q[0].setting;
+ if (typeof prec === 'number') {
+ ret = ret.split(".").slice(0,prec).join(".");
+ }
+ return ret;
+ },
+
/**
* Get the oid for a given table name.
*
if (printFormat && !prop.toOne && !prop.toMany) {
switch(prop.attr.type) {
case "Date":
+ case "DueDate":
preOffsetDate = item[itemAttr];
offsetDate = preOffsetDate &&
new Date(preOffsetDate.valueOf() + 60000 * preOffsetDate.getTimezoneOffset());
lockExp,
oid,
pcheck,
+ pgver = 0 + XT.Data.getPgVersion(2),
pid = options.pid || null,
- pidSql = "select usename, procpid " +
+ pidcol = (pgver < 9.2) ? "procpid" : "pid",
+ pidSql = "select usename, {pidcol} " +
"from pg_stat_activity " +
"where datname=current_database() " +
" and usename=$1 " +
- " and procpid=$2;",
+ " and {pidcol}=$2;",
query,
selectSql = "select * " +
"from xt.lock " +
" and lock_record_id = $2;",
username = XT.username;
+ pidSql = pidSql.replace(/{pidcol}/g, pidcol);
+
/* If passed a table name, look up the oid. */
oid = typeof table === "string" ? this.getTableOid(table) : table;