Add an optional `options` argument to relation methods
This commit is contained in:
parent
9177e07209
commit
93a0342099
|
@ -366,7 +366,7 @@ Memory.prototype.all = function all(model, filter, options, callback) {
|
|||
|
||||
process.nextTick(function () {
|
||||
if (filter && filter.include) {
|
||||
self._models[model].model.include(nodes, filter.include, callback);
|
||||
self._models[model].model.include(nodes, filter.include, options, callback);
|
||||
} else {
|
||||
callback(null, nodes);
|
||||
}
|
||||
|
|
|
@ -2068,10 +2068,10 @@ DataAccessObject.prototype.setAttribute = function setAttribute(name, value) {
|
|||
* @param {Mixed} value Value of property
|
||||
* @param {Function} cb Callback function called with (err, instance)
|
||||
*/
|
||||
DataAccessObject.prototype.updateAttribute = function updateAttribute(name, value, cb) {
|
||||
DataAccessObject.prototype.updateAttribute = function updateAttribute(name, value, options, cb) {
|
||||
var data = {};
|
||||
data[name] = value;
|
||||
return this.updateAttributes(data, cb);
|
||||
return this.updateAttributes(data, options, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,6 @@ var async = require('async');
|
|||
var utils = require('./utils');
|
||||
var isPlainObject = utils.isPlainObject;
|
||||
var defineCachedRelations = utils.defineCachedRelations;
|
||||
var debug = require('debug')('loopback:include');
|
||||
|
||||
/*!
|
||||
* Normalize the include to be an array
|
||||
|
@ -145,11 +144,15 @@ Inclusion.normalizeInclude = normalizeInclude;
|
|||
*
|
||||
* @param {Array} objects Array of instances
|
||||
* @param {String|Object|Array} include Which relations to load.
|
||||
* @param {Object} [options] Options for CRUD
|
||||
* @param {Function} cb Callback called when relations are loaded
|
||||
*
|
||||
*/
|
||||
Inclusion.include = function (objects, include, cb) {
|
||||
debug('include', include);
|
||||
Inclusion.include = function (objects, include, options, cb) {
|
||||
if (typeof options === 'function' && cb === undefined) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
var self = this;
|
||||
|
||||
if (!include || (Array.isArray(include) && include.length === 0) ||
|
||||
|
@ -163,12 +166,12 @@ Inclusion.include = function (objects, include, cb) {
|
|||
include = normalizeInclude(include);
|
||||
|
||||
async.each(include, function(item, callback) {
|
||||
processIncludeItem(objects, item, callback);
|
||||
processIncludeItem(objects, item, options, callback);
|
||||
}, function(err) {
|
||||
cb && cb(err, objects);
|
||||
});
|
||||
|
||||
function processIncludeItem(objs, include, cb) {
|
||||
function processIncludeItem(objs, include, options, cb) {
|
||||
var relations = self.relations;
|
||||
|
||||
var relationName;
|
||||
|
@ -214,8 +217,7 @@ Inclusion.include = function (objects, include, cb) {
|
|||
|
||||
// Just skip if inclusion is disabled
|
||||
if (relation.options.disableInclude) {
|
||||
cb();
|
||||
return;
|
||||
return cb();
|
||||
}
|
||||
//prepare filter and fields for making DB Call
|
||||
var filter = (scope && scope.conditions()) || {};
|
||||
|
@ -372,7 +374,7 @@ Inclusion.include = function (objects, include, cb) {
|
|||
//process.
|
||||
if (subInclude && targets) {
|
||||
tasks.push(function subIncludesTask(next) {
|
||||
relation.modelTo.include(targets, subInclude, next);
|
||||
relation.modelTo.include(targets, subInclude, options, next);
|
||||
});
|
||||
}
|
||||
//process & link each target with object
|
||||
|
@ -450,7 +452,7 @@ Inclusion.include = function (objects, include, cb) {
|
|||
//simultaneously process subIncludes
|
||||
if (subInclude && targets) {
|
||||
tasks.push(function subIncludesTask(next) {
|
||||
relation.modelTo.include(targets, subInclude, next);
|
||||
relation.modelTo.include(targets, subInclude, options, next);
|
||||
});
|
||||
}
|
||||
//process each target object
|
||||
|
@ -511,7 +513,7 @@ Inclusion.include = function (objects, include, cb) {
|
|||
//simultaneously process subIncludes
|
||||
if (subInclude && targets) {
|
||||
tasks.push(function subIncludesTask(next) {
|
||||
relation.modelTo.include(targets, subInclude, next);
|
||||
relation.modelTo.include(targets, subInclude, options, next);
|
||||
});
|
||||
}
|
||||
//process each target object
|
||||
|
@ -597,7 +599,7 @@ Inclusion.include = function (objects, include, cb) {
|
|||
//simultaneously process subIncludes
|
||||
if (subInclude && targets) {
|
||||
tasks.push(function subIncludesTask(next) {
|
||||
Model.include(targets, subInclude, next);
|
||||
Model.include(targets, subInclude, options, next);
|
||||
});
|
||||
}
|
||||
//process each target object
|
||||
|
@ -665,7 +667,7 @@ Inclusion.include = function (objects, include, cb) {
|
|||
//simultaneously process subIncludes
|
||||
if (subInclude && targets) {
|
||||
tasks.push(function subIncludesTask(next) {
|
||||
relation.modelTo.include(targets, subInclude, next);
|
||||
relation.modelTo.include(targets, subInclude, options, next);
|
||||
});
|
||||
}
|
||||
//process each target object
|
||||
|
@ -769,10 +771,10 @@ Inclusion.include = function (objects, include, cb) {
|
|||
|
||||
related = inst[relationName].bind(inst, filter);
|
||||
} else {
|
||||
related = inst[relationName].bind(inst);
|
||||
related = inst[relationName].bind(inst, undefined);
|
||||
}
|
||||
|
||||
related(function (err, result) {
|
||||
related(options, function (err, result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
} else {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
193
lib/scope.js
193
lib/scope.js
|
@ -21,10 +21,11 @@ function ScopeDefinition(definition) {
|
|||
}
|
||||
|
||||
ScopeDefinition.prototype.targetModel = function(receiver) {
|
||||
var modelTo;
|
||||
if (typeof this.options.modelTo === 'function') {
|
||||
var modelTo = this.options.modelTo.call(this, receiver) || this.modelTo;
|
||||
modelTo = this.options.modelTo.call(this, receiver) || this.modelTo;
|
||||
} else {
|
||||
var modelTo = this.modelTo;
|
||||
modelTo = this.modelTo;
|
||||
}
|
||||
if (!(modelTo.prototype instanceof DefaultModelBaseClass)) {
|
||||
var msg = 'Invalid target model for scope `';
|
||||
|
@ -36,16 +37,34 @@ ScopeDefinition.prototype.targetModel = function(receiver) {
|
|||
return modelTo;
|
||||
};
|
||||
|
||||
ScopeDefinition.prototype.related = function(receiver, scopeParams, condOrRefresh, cb) {
|
||||
/*!
|
||||
* Find related model instances
|
||||
* @param {*} receiver The target model class/prototype
|
||||
* @param {Object|Function} scopeParams
|
||||
* @param {Boolean|Object} [condOrRefresh] true for refresh or object as a filter
|
||||
* @param {Object} [options]
|
||||
* @param {Function} cb
|
||||
* @returns {*}
|
||||
*/
|
||||
ScopeDefinition.prototype.related = function(receiver, scopeParams, condOrRefresh, options, cb) {
|
||||
var name = this.name;
|
||||
var self = receiver;
|
||||
|
||||
var actualCond = {};
|
||||
var actualRefresh = false;
|
||||
var saveOnCache = true;
|
||||
if (arguments.length === 3) {
|
||||
if (typeof condOrRefresh === 'function' &&
|
||||
options === undefined && cb === undefined) {
|
||||
// related(receiver, scopeParams, cb)
|
||||
cb = condOrRefresh;
|
||||
} else if (arguments.length === 4) {
|
||||
options = {};
|
||||
condOrRefresh = undefined;
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
if (condOrRefresh !== undefined) {
|
||||
if (typeof condOrRefresh === 'boolean') {
|
||||
actualRefresh = condOrRefresh;
|
||||
} else {
|
||||
|
@ -53,16 +72,15 @@ ScopeDefinition.prototype.related = function(receiver, scopeParams, condOrRefres
|
|||
actualRefresh = true;
|
||||
saveOnCache = false;
|
||||
}
|
||||
} else {
|
||||
throw new Error('Method can be only called with one or two arguments');
|
||||
}
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
|
||||
if (!self.__cachedRelations || self.__cachedRelations[name] === undefined
|
||||
|| actualRefresh) {
|
||||
// It either doesn't hit the cache or refresh is required
|
||||
var params = mergeQuery(actualCond, scopeParams, {nestedInclude: true});
|
||||
var targetModel = this.targetModel(receiver);
|
||||
targetModel.find(params, function (err, data) {
|
||||
targetModel.find(params, options, function (err, data) {
|
||||
if (!err && saveOnCache) {
|
||||
defineCachedRelations(self);
|
||||
self.__cachedRelations[name] = data;
|
||||
|
@ -73,6 +91,7 @@ ScopeDefinition.prototype.related = function(receiver, scopeParams, condOrRefres
|
|||
// Return from cache
|
||||
cb(null, self.__cachedRelations[name]);
|
||||
}
|
||||
return cb.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +168,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
var targetModel = definition.targetModel(this);
|
||||
var self = this;
|
||||
|
||||
var f = function(condOrRefresh, cb) {
|
||||
var f = function(condOrRefresh, options, cb) {
|
||||
if (arguments.length === 0) {
|
||||
if (typeof f.value === 'function') {
|
||||
return f.value(self);
|
||||
|
@ -157,6 +176,18 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
return self.__cachedRelations[name];
|
||||
}
|
||||
} else {
|
||||
if (typeof condOrRefresh === 'function'
|
||||
&& options === undefined && cb === undefined) {
|
||||
// customer.orders(cb)
|
||||
cb = condOrRefresh;
|
||||
options = {};
|
||||
condOrRefresh = undefined;
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
// customer.orders(condOrRefresh, cb);
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {}
|
||||
// Check if there is a through model
|
||||
// see https://github.com/strongloop/loopback/issues/1076
|
||||
if (f._scope.collect &&
|
||||
|
@ -169,11 +200,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
};
|
||||
condOrRefresh = {};
|
||||
}
|
||||
if (arguments.length === 1) {
|
||||
return definition.related(self, f._scope, condOrRefresh);
|
||||
} else {
|
||||
return definition.related(self, f._scope, condOrRefresh, cb);
|
||||
}
|
||||
return definition.related(self, f._scope, condOrRefresh, options, cb);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -186,23 +213,20 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
f._targetClass = i8n.camelize(f._scope.collect);
|
||||
}
|
||||
|
||||
f.getAsync = function (cond, cb) {
|
||||
if (cb === undefined) {
|
||||
if (cond === undefined) {
|
||||
// getAsync()
|
||||
cb = utils.createPromiseCallback();
|
||||
cond = true;
|
||||
} else if (typeof cond !== 'function') {
|
||||
// getAsync({where:{}})
|
||||
cb = utils.createPromiseCallback();
|
||||
} else {
|
||||
// getAsync(function(){})
|
||||
cb = cond;
|
||||
cond = true;
|
||||
}
|
||||
f.getAsync = function(condOrRefresh, options, cb) {
|
||||
if (typeof condOrRefresh === 'function'
|
||||
&& options === undefined && cb === undefined) {
|
||||
// customer.orders.getAsync(cb)
|
||||
cb = condOrRefresh;
|
||||
options = {};
|
||||
condOrRefresh = {};
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
// customer.orders.getAsync(condOrRefresh, cb);
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
definition.related(self, f._scope, cond, cb);
|
||||
return cb.promise;
|
||||
options = options || {}
|
||||
return definition.related(self, f._scope, condOrRefresh, options, cb);
|
||||
}
|
||||
|
||||
f.build = build;
|
||||
|
@ -298,13 +322,19 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
return new targetModel(data);
|
||||
}
|
||||
|
||||
function create(data, cb) {
|
||||
if (typeof data === 'function') {
|
||||
function create(data, options, cb) {
|
||||
if (typeof data === 'function' &&
|
||||
options === undefined && cb === undefined) {
|
||||
// create(cb)
|
||||
cb = data;
|
||||
data = {};
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
// create(data, cb)
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
return this.build(data).save(cb);
|
||||
options = options || {};
|
||||
return this.build(data).save(options, cb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -313,53 +343,108 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
- For every destroy call which results in an error
|
||||
- If fetching the Elements on which destroyAll is called results in an error
|
||||
*/
|
||||
function destroyAll(where, cb) {
|
||||
if (typeof where === 'function') cb = where, where = {};
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
function destroyAll(where, options, cb) {
|
||||
if (typeof where === 'function') {
|
||||
// destroyAll(cb)
|
||||
cb = where;
|
||||
where = {};
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
// destroyAll(where, cb)
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||
return targetModel.destroyAll(filter.where, cb);
|
||||
return targetModel.destroyAll(filter.where, options, cb);
|
||||
}
|
||||
|
||||
function updateAll(where, data, cb) {
|
||||
if (arguments.length === 2) {
|
||||
// Handle updateAll(data, cb)
|
||||
function updateAll(where, data, options, cb) {
|
||||
if (typeof data === 'function' &&
|
||||
options === undefined && cb === undefined) {
|
||||
// updateAll(data, cb)
|
||||
cb = data;
|
||||
data = where;
|
||||
where = {};
|
||||
options = {};
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
// updateAll(where, data, cb)
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||
targetModel.updateAll(filter.where, data, cb);
|
||||
return targetModel.updateAll(filter.where, data, options, cb);
|
||||
}
|
||||
|
||||
function findById(id, cb) {
|
||||
function findById(id, filter, options, cb) {
|
||||
if (options === undefined && cb === undefined) {
|
||||
if (typeof filter === 'function') {
|
||||
// findById(id, cb)
|
||||
cb = filter;
|
||||
filter = {};
|
||||
}
|
||||
} else if (cb === undefined) {
|
||||
if (typeof options === 'function') {
|
||||
// findById(id, query, cb)
|
||||
cb = options;
|
||||
options = {};
|
||||
if (typeof filter === 'object' && !(filter.include || filter.fields)) {
|
||||
// If filter doesn't have include or fields, assuming it's options
|
||||
options = filter;
|
||||
filter = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
filter = filter || {};
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var idName = targetModel.definition.idName();
|
||||
var filter = { where: {} };
|
||||
filter.where[idName] = id;
|
||||
this.findOne(filter, cb);
|
||||
var query = {where: {}};
|
||||
query.where[idName] = id;
|
||||
query = mergeQuery(query, filter);
|
||||
return this.findOne(query, options, cb);
|
||||
}
|
||||
|
||||
function findOne(filter, cb) {
|
||||
if (typeof filter === 'function') cb = filter, filter = {};
|
||||
function findOne(filter, options, cb) {
|
||||
if (typeof filter === 'function') {
|
||||
// findOne(cb)
|
||||
cb = filter;
|
||||
filter = {};
|
||||
options = {};
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
// findOne(filter, cb)
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
var filter = mergeQuery({ where: scoped }, filter || {});
|
||||
targetModel.findOne(filter, cb);
|
||||
filter = mergeQuery({ where: scoped }, filter || {});
|
||||
return targetModel.findOne(filter, options, cb);
|
||||
}
|
||||
|
||||
function count(where, cb) {
|
||||
if (typeof where === 'function') cb = where, where = {};
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
function count(where, options, cb) {
|
||||
if (typeof where === 'function') {
|
||||
// count(cb)
|
||||
cb = where;
|
||||
where = {};
|
||||
} else if (typeof options === 'function' && cb === undefined) {
|
||||
// count(where, cb)
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||
return targetModel.count(filter.where, cb);
|
||||
return targetModel.count(filter.where, options, cb);
|
||||
}
|
||||
|
||||
return definition;
|
||||
|
|
Loading…
Reference in New Issue