Comparing version 2.1.0 to 2.1.1
@@ -448,2 +448,3 @@ var util = require(__dirname+'/util.js'); | ||
if (options.init !== false) { | ||
/* | ||
var newIndex = self._createIndex(leftKey) | ||
@@ -455,2 +456,10 @@ .catch(function(error) { | ||
joinedModel._waitFor(newIndex); | ||
*/ | ||
var newIndex = joinedModel._createIndex(rightKey) | ||
.catch(function(error) { | ||
joinedModel._getModel()._setError(error); | ||
self._getModel()._setError(error); | ||
}); | ||
self._waitFor(newIndex); | ||
} | ||
@@ -543,2 +552,11 @@ } | ||
var linkModel; | ||
if (thinky.models[link] === undefined) { | ||
linkModel = thinky.createModel(link, {}); // Create a model, claim the namespace and create the table | ||
} | ||
else { | ||
linkModel = thinky.models[link]; | ||
} | ||
this._getModel()._joins[fieldDoc] = { | ||
@@ -549,3 +567,4 @@ model: joinedModel, | ||
type: 'hasAndBelongsToMany', | ||
link: link | ||
link: link, | ||
linkModel: linkModel | ||
} | ||
@@ -557,12 +576,6 @@ | ||
type: 'hasAndBelongsToMany', | ||
link: link | ||
link: link, | ||
linkModel: linkModel | ||
} | ||
if (thinky.models[link] === undefined) { | ||
var linkModel = thinky.createModel(link, {}); // Create a model, claim the namespace and create the table | ||
} | ||
else { | ||
linkModel = thinky.models[link]; | ||
} | ||
if (options.init !== false) { | ||
@@ -569,0 +582,0 @@ var r = self._getModel()._thinky.r; |
352
lib/query.js
@@ -57,5 +57,13 @@ var Promise = require('bluebird'); | ||
} | ||
this._pointWrite = false; | ||
} | ||
Query.prototype.setPostValidation = function() { | ||
this._postValidation = true; | ||
} | ||
Query.prototype.setPointWrite = function() { | ||
this._pointWrite = true; | ||
} | ||
/** | ||
@@ -185,2 +193,3 @@ * Execute a Query and expect the results to be object(s) that can be converted | ||
if (result.errors > 0) { | ||
console.log(result); | ||
return Promise.reject(new Errors.InvalidWrite("An error occured during the write", result)); | ||
@@ -205,6 +214,9 @@ } | ||
if (self._isPointWrite()) { | ||
if (result.length > 1) { | ||
throw new Error('A point write returned multiple values') | ||
} | ||
return result[0]; | ||
} | ||
return result; | ||
}).error(function(error) { | ||
}).catch(function(error) { | ||
if (error instanceof Errors.DocumentNotFound) { | ||
@@ -421,75 +433,279 @@ // Should we send back null? | ||
/** | ||
* Remove the provided relation | ||
* @param {Object=} relationsToRemove explicit joined documents to retrieve | ||
* @return {Query} | ||
* Add a relation | ||
* @param {string} field The field of the joined document(s) | ||
* @param {Object} joinedDocument An object with the primary key defined or the related key | ||
* @return {Promise} | ||
* | ||
* hasOne, primary key required | ||
* User.get(1).addRelation("account", {id: 2, sold: 2132}) | ||
* The promise resolved the document on which addRelation is called | ||
* | ||
* hasMany, primary key required | ||
* User.get(1).addRelation("accounts", {id: 2, sold: 2132}) | ||
* The promise resolved the updated joined document | ||
* | ||
* belongsTo, right joined key OR primary key required | ||
* User.get(1).addRelation("account", {id: 2, sold: 2132}) | ||
* The promise resolved the document on which addRelation is called | ||
* | ||
* hasAndBelongsToMany, right joined key required | ||
* User.get(1).addRelation("accounts", {id: 2, sold: 2132}) | ||
* The promise resolved with true | ||
*/ | ||
Query.prototype.removeRelations = function(relationsToRemove) { | ||
Query.prototype.addRelation = function(field, joinedDocument) { | ||
var self = this; | ||
var queries = []; | ||
var originalQuery = self._query; | ||
util.loopKeys(relationsToRemove, function(joins, key) { | ||
var join = self._model._getModel()._joins[key]; | ||
if (join === undefined) { | ||
return; | ||
} | ||
switch (join.type) { | ||
case 'hasOne': | ||
case 'hasMany': | ||
queries.push(self._query(join.leftKey).do(function(keys) { | ||
return self._r.branch( | ||
self._r.expr(["ARRAY", "STREAM", "TABLE_SLICE"]).contains(keys.typeOf()).not(), | ||
// keys is a single value | ||
join.model.getAll(keys, {index: join.rightKey}).replace(function(row) { | ||
return row.without(join.rightKey) | ||
})._query, | ||
self._r.branch( // keys.typeOf().eq("ARRAY") | ||
keys.isEmpty(), | ||
{errors: 0}, | ||
join.model.getAll(self._r.args(keys), {index: join.rightKey}).replace(function(row) { | ||
return row.without(join.rightKey) | ||
})._query | ||
) | ||
) | ||
})) | ||
break; | ||
var model = self._model; | ||
var joins = self._model._getModel()._joins; | ||
var joinedModel = joins[field].model; | ||
var r = self._model._thinky.r; | ||
case 'belongsTo': | ||
queries.push(self._query.replace(function(row) { | ||
return row.without(join.leftKey) | ||
})); | ||
break; | ||
switch (joins[field].type) { | ||
case 'hasOne': | ||
case 'hasMany': | ||
if (joinedDocument[joinedModel._pk] === undefined) { | ||
return new Query(model, self, {}, | ||
new Error('Primary key for the joined document not found for a `hasOne/hasMany` relation.') | ||
); | ||
} | ||
var updateValue = {}; | ||
updateValue[joins[field].rightKey] = self._query(joins[field].leftKey); | ||
return joinedModel.get(joinedDocument[joinedModel._pk]).update(updateValue, {nonAtomic: true}).run() | ||
case 'belongsTo': | ||
var updateValue = {}; | ||
if (joinedDocument[joins[field].rightKey] === undefined) { | ||
if (joinedDocument[joinedModel._pk] === undefined) { | ||
return new Query(model, self, {}, | ||
new Error('The primary key or the joined key must be defined in the joined document for a `belongsTo` relation.') | ||
); | ||
} | ||
updateValue[joins[field].leftKey] = joinedModel.get(joinedDocument[joinedModel._pk]).bracket(joins[field].rightKey)._query; | ||
} | ||
else { | ||
updateValue[joins[field].leftKey] = joinedDocument[joins[field].rightKey]; | ||
} | ||
return self.update(updateValue, {nonAtomic: true}).run(); | ||
case 'hasAndBelongsToMany': | ||
var linkModel = joins[field].linkModel; | ||
var linkValue; | ||
var link; | ||
if (joinedDocument[joins[field].rightKey] === undefined) { | ||
if (joinedDocument[joinedModel._pk] === undefined) { | ||
return new Query(model, self, {}, | ||
new Error('The primary key or the joined key must be defined in the joined document for a `hasAndBelongsToMany` relation.') | ||
); | ||
} | ||
link = joinedModel.get(joinedDocument[joinedModel._pk]).bracket(joins[field].rightKey)._query | ||
} | ||
else { | ||
link = r.expr(joinedDocument[joins[field].rightKey]); | ||
} | ||
case 'hasAndBelongsToMany': | ||
queries.push(self._query(join.leftKey).do(function(keys) { | ||
return self._r.branch( | ||
self._r.expr(["ARRAY", "STREAM", "TABLE_SLICE"]).contains(keys.typeOf()).not(), | ||
// keys is a single value | ||
self._r.table(join.link).getAll(keys, {index: self._model.getTableName()+"_"+join.leftKey}).delete(), | ||
self._r.branch( // keys.typeOf().eq("ARRAY") | ||
keys.isEmpty(), | ||
{errors: 0}, | ||
self._r.table(join.link).getAll(self._r.args(keys), {index: self._model.getTableName()+"_"+join.leftKey}).delete() | ||
if ((model.getTableName() === joinedModel.getTableName()) | ||
&& (joins[field].leftKey === joins[field].rightKey)) { | ||
linkValue = self._query(joins[field].leftKey).do(function(leftKey) { | ||
return link.do(function(rightKey) { | ||
return r.branch( | ||
rightKey.lt(leftKey), | ||
r.object( | ||
'id', rightKey.add('_').add(leftKey), | ||
joins[field].leftKey+"_"+joins[field].leftKey, [leftKey, rightKey] | ||
), | ||
r.object( | ||
'id', leftKey.add('_').add(rightKey), | ||
joins[field].leftKey+"_"+joins[field].leftKey, [leftKey, rightKey] | ||
) | ||
) | ||
) | ||
})); | ||
break; | ||
} | ||
}); | ||
if (queries.length > 0) { | ||
self._query = self._r.expr(queries).forEach(function(result) { | ||
return result; | ||
}) | ||
}); | ||
}); | ||
} | ||
else { | ||
linkValue = self._query(joins[field].leftKey).do(function(leftKey) { | ||
return link.do(function(rightKey) { | ||
if (model.getTableName() < joinedModel.getTableName()) { | ||
return r.object( | ||
'id', leftKey.add('_').add(rightKey), | ||
model.getTableName()+"_"+joins[field].leftKey, leftKey, | ||
joinedModel.getTableName()+"_"+joins[field].rightKey,rightKey | ||
) | ||
} | ||
else if (model.getTableName() > joinedModel.getTableName()) { | ||
return r.object( | ||
'id', rightKey.add('_').add(leftKey), | ||
model.getTableName()+"_"+joins[field].leftKey, leftKey, | ||
joinedModel.getTableName()+"_"+joins[field].rightKey,rightKey | ||
) | ||
} | ||
else { | ||
return r.branch( | ||
rightKey.lt(leftKey), | ||
r.object( | ||
'id', leftKey.add('_').add(rightKey), | ||
model.getTableName()+"_"+joins[field].leftKey, leftKey, | ||
joinedModel.getTableName()+"_"+joins[field].rightKey,rightKey | ||
), | ||
r.object( | ||
'id', rightKey.add('_').add(leftKey), | ||
model.getTableName()+"_"+joins[field].leftKey, leftKey, | ||
joinedModel.getTableName()+"_"+joins[field].rightKey,rightKey | ||
) | ||
) | ||
} | ||
}); | ||
}); | ||
} | ||
return linkModel.insert(linkValue, {conflict: "replace", returnChanges: 'always'}).do(function(result) { | ||
return r.branch( | ||
result('errors').eq(0), | ||
true, // not relevant value | ||
r.error(result('errors')) | ||
) | ||
}).execute() | ||
default: | ||
return new Query(model, self, {}, | ||
new Error('The provided field `'+field+'` does not store joined documents.') | ||
); | ||
} | ||
else { | ||
self._query = self._r.expr({errors: 0}); | ||
} | ||
/** | ||
* Remove the provided relation | ||
* @param {string} field The field of the joined document(s) to remove | ||
* @param {Array} joinedDocument The document with who the relation should be removed | ||
* @return {Promise} | ||
*/ | ||
//TODO Support an array of joinedDocuments? | ||
Query.prototype.removeRelation = function(field, joinedDocument) { | ||
var self = this; | ||
var model = self._model; | ||
var joins = self._model._getModel()._joins; | ||
var joinedModel = joins[field].model; | ||
var r = self._model._thinky.r; | ||
var query; | ||
switch (joins[field].type) { | ||
case 'hasOne': | ||
query = joinedModel.getAll(self._query(joins[field].leftKey), {index: joins[field].rightKey}).replace(function(row) { | ||
return row.without(joins[field].rightKey) | ||
}); | ||
query.setPostValidation(); | ||
query.setPointWrite(); | ||
return query; | ||
case 'hasMany': | ||
if (joinedDocument === undefined) { | ||
query = joinedModel.getAll(self._query(joins[field].leftKey), {index: joins[field].rightKey}).replace(function(row) { | ||
return row.without(joins[field].rightKey) | ||
}) | ||
} | ||
else { | ||
query = joinedModel.getAll(r.expr(joinedDocument)(joinedModel._pk)).replace(function(row) { | ||
return row.without(joins[field].rightKey) | ||
}) | ||
} | ||
query.setPostValidation(); | ||
return query; | ||
case 'belongsTo': | ||
query = self.replace(function(row) { | ||
return row.without(joins[field].leftKey) | ||
}) | ||
query.setPostValidation(); | ||
return query; | ||
case 'hasAndBelongsToMany': | ||
var linkModel = joins[field].linkModel; | ||
if (joinedDocument === undefined) { | ||
query = self._query(joins[field].leftKey).do(function(leftKey) { | ||
// range are not supported at the moment, so keys is an object and we don't have to worry about empty sequences | ||
if ((model.getTableName() === joinedModel.getTableName()) | ||
&& (joins[field].leftKey === joins[field].rightKey)) { | ||
return linkModel.getAll(leftKey, {index: joins[field].leftKey+'_'+joins[field].leftKey}).delete()._query | ||
} | ||
else { | ||
return linkModel.getAll(leftKey, {index: model.getTableName()+'_'+joins[field].leftKey}).delete()._query | ||
} | ||
}).do(function(result) { | ||
return r.branch( | ||
result('errors').eq(0), | ||
true, // not relevant value | ||
r.error(result('errors')) | ||
) | ||
}) | ||
} | ||
else { | ||
if (joinedDocument[joins[field].rightKey] === undefined) { | ||
if (joinedDocument[joinedModel._pk] === undefined) { | ||
return new Query(model, self, {}, | ||
new Error('The primary key or the joined key must be defined in the joined document for a `hasAndBelongsToMany` relation.') | ||
); | ||
} | ||
if ((model.getTableName() === joinedModel.getTableName()) | ||
&& (joins[field].leftKey === joins[field].rightKey)) { | ||
query = self._query(joins[field].leftKey).do(function(leftKey) { | ||
return joinedModel.get(joinedDocument[joinedModel._pk]).bracket(joins[field].rightKey).do(function(rightKey) { | ||
if (model.getTableName() < joinedModel.getTableName()) { | ||
return linkModel.getAll(leftKey.add('_').add(rightKey)).delete()._query; | ||
} | ||
else if (model.getTableName() > joinedModel.getTableName()) { | ||
return linkModel.getAll(rightKey.add('_').add(leftKey)).delete()._query; | ||
} | ||
else { | ||
return r.branch( | ||
leftKey.lt(rightKey), | ||
linkModel.getAll(leftKey.add('_').add(rightKey)).delete()._query, | ||
linkModel.getAll(rightKey.add('_').add(leftKey)).delete()._query | ||
) | ||
} | ||
}); | ||
}) | ||
} | ||
else { | ||
query = self._query(joins[field].leftKey).do(function(leftKey) { | ||
return joinedModel.get(joinedDocument[joinedModel._pk]).bracket(joins[field].rightKey).do(function(rightKey) { | ||
if (model.getTableName() < joinedModel.getTableName()) { | ||
return linkModel.getAll(leftKey.add('_').add(rightKey)).delete()._query | ||
} | ||
else if (model.getTableName() > joinedModel.getTableName()) { | ||
return linkModel.getAll(rightKey.add('_').add(leftKey)).delete()._query | ||
} | ||
else { | ||
return r.branch( | ||
leftKey.lt(rightKey), | ||
linkModel.getAll(leftKey.add('_').add(rightKey)).delete()._query, | ||
linkModel.getAll(rightKey.add('_').add(leftKey)).delete()._query | ||
) | ||
} | ||
}); | ||
}) | ||
} | ||
} | ||
else { | ||
query = self._query(joins[field].leftKey).do(function(leftKey) { | ||
var rightKey = r.expr(joinedDocument[joins[field].rightKey]); | ||
if (model.getTableName() < joinedModel.getTableName()) { | ||
return linkModel.getAll(leftKey.add('_').add(rightKey)).delete()._query | ||
} | ||
else if (model.getTableName() > joinedModel.getTableName()) { | ||
return linkModel.getAll(rightKey.add('_').add(leftKey)).delete()._query | ||
} | ||
else { | ||
return r.branch( | ||
leftKey.lt(rightKey), | ||
linkModel.getAll(leftKey.add('_').add(rightKey)).delete()._query, | ||
linkModel.getAll(rightKey.add('_').add(leftKey)).delete()._query | ||
) | ||
} | ||
}) | ||
} | ||
} | ||
return query; | ||
default: | ||
return new Query(model, self, {}, | ||
new Error('The provided field `'+field+'` does not store joined documents.') | ||
); | ||
} | ||
self._query = self._query.do(function(results) { | ||
return self._r.branch( | ||
results('errors').eq(0), | ||
originalQuery, | ||
self._r.error(results('errors')) | ||
) | ||
}); | ||
return self; | ||
}; | ||
@@ -593,3 +809,3 @@ | ||
Query.prototype._isPointWrite = function() { | ||
return Array.isArray(this._query._query) && | ||
return this._pointWrite || (Array.isArray(this._query._query) && | ||
(this._query._query.length > 1) && | ||
@@ -603,3 +819,3 @@ Array.isArray(this._query._query[1]) && | ||
Array.isArray(this._query._query[1][0][1][0]) && | ||
(this._query._query[1][0][1][0][0] === 16) | ||
(this._query._query[1][0][1][0][0] === 16)) | ||
} | ||
@@ -606,0 +822,0 @@ |
@@ -96,3 +96,3 @@ var arrayPrefix = "__array" | ||
} | ||
if (keepGoing && field[path[path.length-1]] === undefined) { | ||
if (keepGoing && util.isPlainObject(field) && field[path[path.length-1]] === undefined) { | ||
if ((typeof value === "function") && !Array.isArray(value._query)) { | ||
@@ -99,0 +99,0 @@ field[path[path.length-1]] = value.call(doc); |
{ | ||
"name": "thinky", | ||
"version": "2.1.0", | ||
"version": "2.1.1", | ||
"description": "RethinkDB ORM for Node.js", | ||
@@ -5,0 +5,0 @@ "main": "lib/thinky.js", |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
216915
5843