Extract mergeQuery and setScopeValuesFromWhere
Related to #274 - in preparation of default scope
This commit is contained in:
parent
d3b30c3071
commit
610866bd7c
36
lib/dao.js
36
lib/dao.js
|
@ -13,11 +13,12 @@ var Relation = require('./relations.js');
|
||||||
var Inclusion = require('./include.js');
|
var Inclusion = require('./include.js');
|
||||||
var List = require('./list.js');
|
var List = require('./list.js');
|
||||||
var geo = require('./geo');
|
var geo = require('./geo');
|
||||||
var mergeQuery = require('./scope.js').mergeQuery;
|
|
||||||
var Memory = require('./connectors/memory').Memory;
|
var Memory = require('./connectors/memory').Memory;
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var fieldsToArray = utils.fieldsToArray;
|
var fieldsToArray = utils.fieldsToArray;
|
||||||
var removeUndefined = utils.removeUndefined;
|
var removeUndefined = utils.removeUndefined;
|
||||||
|
var setScopeValuesFromWhere = utils.setScopeValuesFromWhere;
|
||||||
|
var mergeQuery = utils.mergeQuery;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
|
||||||
|
@ -69,6 +70,18 @@ DataAccessObject._forDB = function (data) {
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DataAccessObject.applyProperties = function(data) {
|
||||||
|
var scope = this.definition.settings.scope || {};
|
||||||
|
if (typeof scope.where === 'object'
|
||||||
|
&& this.definition.settings.applyProperties !== false) {
|
||||||
|
setScopeValuesFromWhere(data, scope.where, this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DataAccessObject.applyScope = function(cond) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of Model with given data and save to the attached data source. Callback is optional.
|
* Create an instance of Model with given data and save to the attached data source. Callback is optional.
|
||||||
* Example:
|
* Example:
|
||||||
|
@ -136,6 +149,7 @@ DataAccessObject.create = function (data, callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var enforced = {};
|
||||||
var obj;
|
var obj;
|
||||||
var idValue = getIdValue(this, data);
|
var idValue = getIdValue(this, data);
|
||||||
|
|
||||||
|
@ -145,6 +159,10 @@ DataAccessObject.create = function (data, callback) {
|
||||||
} else {
|
} else {
|
||||||
obj = new Model(data);
|
obj = new Model(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.applyProperties(enforced);
|
||||||
|
obj.setAttributes(enforced);
|
||||||
|
|
||||||
data = obj.toObject(true);
|
data = obj.toObject(true);
|
||||||
|
|
||||||
// validation required
|
// validation required
|
||||||
|
@ -220,6 +238,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
|
||||||
inst = new Model(data);
|
inst = new Model(data);
|
||||||
}
|
}
|
||||||
update = inst.toObject(false);
|
update = inst.toObject(false);
|
||||||
|
this.applyProperties(update);
|
||||||
update = removeUndefined(update);
|
update = removeUndefined(update);
|
||||||
this.getDataSource().connector.updateOrCreate(Model.modelName, update, function (err, data) {
|
this.getDataSource().connector.updateOrCreate(Model.modelName, update, function (err, data) {
|
||||||
var obj;
|
var obj;
|
||||||
|
@ -926,13 +945,17 @@ DataAccessObject.prototype.save = function (options, callback) {
|
||||||
if (!('throws' in options)) {
|
if (!('throws' in options)) {
|
||||||
options.throws = false;
|
options.throws = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var inst = this;
|
var inst = this;
|
||||||
var data = inst.toObject(true);
|
var data = inst.toObject(true);
|
||||||
var modelName = Model.modelName;
|
var modelName = Model.modelName;
|
||||||
|
|
||||||
|
Model.applyProperties(data, this);
|
||||||
|
|
||||||
if (this.isNewRecord()) {
|
if (this.isNewRecord()) {
|
||||||
return Model.create(this, callback);
|
return Model.create(this, callback);
|
||||||
|
} else {
|
||||||
|
inst.setAttributes(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate first
|
// validate first
|
||||||
|
@ -1025,6 +1048,9 @@ DataAccessObject.updateAll = function (where, data, cb) {
|
||||||
cb && cb(err);
|
cb && cb(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.applyProperties(data);
|
||||||
|
|
||||||
var connector = this.getDataSource().connector;
|
var connector = this.getDataSource().connector;
|
||||||
connector.update(this.modelName, where, data, cb);
|
connector.update(this.modelName, where, data, cb);
|
||||||
};
|
};
|
||||||
|
@ -1075,7 +1101,7 @@ DataAccessObject.prototype.remove =
|
||||||
* @param {Mixed} value Value of property
|
* @param {Mixed} value Value of property
|
||||||
*/
|
*/
|
||||||
DataAccessObject.prototype.setAttribute = function setAttribute(name, value) {
|
DataAccessObject.prototype.setAttribute = function setAttribute(name, value) {
|
||||||
this[name] = value;
|
this[name] = value; // TODO [fabien] - currently not protected by applyProperties
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1101,6 +1127,8 @@ DataAccessObject.prototype.updateAttribute = function updateAttribute(name, valu
|
||||||
DataAccessObject.prototype.setAttributes = function setAttributes(data) {
|
DataAccessObject.prototype.setAttributes = function setAttributes(data) {
|
||||||
if (typeof data !== 'object') return;
|
if (typeof data !== 'object') return;
|
||||||
|
|
||||||
|
this.constructor.applyProperties(data);
|
||||||
|
|
||||||
var Model = this.constructor;
|
var Model = this.constructor;
|
||||||
var inst = this;
|
var inst = this;
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,10 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
||||||
}
|
}
|
||||||
var properties = _extend({}, ctor.definition.properties);
|
var properties = _extend({}, ctor.definition.properties);
|
||||||
data = data || {};
|
data = data || {};
|
||||||
|
|
||||||
|
if (typeof ctor.applyProperties === 'function') {
|
||||||
|
ctor.applyProperties(data);
|
||||||
|
}
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var applySetters = options.applySetters;
|
var applySetters = options.applySetters;
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
*/
|
*/
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
var utils = require('./utils');
|
||||||
var i8n = require('inflection');
|
var i8n = require('inflection');
|
||||||
var defineScope = require('./scope.js').defineScope;
|
var defineScope = require('./scope.js').defineScope;
|
||||||
var mergeQuery = require('./scope.js').mergeQuery;
|
var mergeQuery = utils.mergeQuery;
|
||||||
var ModelBaseClass = require('./model.js');
|
var ModelBaseClass = require('./model.js');
|
||||||
var applyFilter = require('./connectors/memory').applyFilter;
|
var applyFilter = require('./connectors/memory').applyFilter;
|
||||||
var ValidationError = require('./validations.js').ValidationError;
|
var ValidationError = require('./validations.js').ValidationError;
|
||||||
|
|
89
lib/scope.js
89
lib/scope.js
|
@ -1,13 +1,14 @@
|
||||||
var i8n = require('inflection');
|
var i8n = require('inflection');
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var defineCachedRelations = utils.defineCachedRelations;
|
var defineCachedRelations = utils.defineCachedRelations;
|
||||||
|
var setScopeValuesFromWhere = utils.setScopeValuesFromWhere;
|
||||||
|
var mergeQuery = utils.mergeQuery;
|
||||||
var DefaultModelBaseClass = require('./model.js');
|
var DefaultModelBaseClass = require('./model.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module exports
|
* Module exports
|
||||||
*/
|
*/
|
||||||
exports.defineScope = defineScope;
|
exports.defineScope = defineScope;
|
||||||
exports.mergeQuery = mergeQuery;
|
|
||||||
|
|
||||||
function ScopeDefinition(definition) {
|
function ScopeDefinition(definition) {
|
||||||
this.isStatic = definition.isStatic;
|
this.isStatic = definition.isStatic;
|
||||||
|
@ -229,35 +230,6 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
||||||
|
|
||||||
cls['__count__' + name] = fn_count;
|
cls['__count__' + name] = fn_count;
|
||||||
|
|
||||||
/*
|
|
||||||
* Extracting fixed property values for the scope from the where clause into
|
|
||||||
* the data object
|
|
||||||
*
|
|
||||||
* @param {Object} The data object
|
|
||||||
* @param {Object} The where clause
|
|
||||||
*/
|
|
||||||
function setScopeValuesFromWhere(data, where, targetModel) {
|
|
||||||
for (var i in where) {
|
|
||||||
if (i === 'and') {
|
|
||||||
// Find fixed property values from each subclauses
|
|
||||||
for (var w = 0, n = where[i].length; w < n; w++) {
|
|
||||||
setScopeValuesFromWhere(data, where[i][w], targetModel);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var prop = targetModel.definition.properties[i];
|
|
||||||
if (prop) {
|
|
||||||
var val = where[i];
|
|
||||||
if (typeof val !== 'object' || val instanceof prop.type
|
|
||||||
|| prop.type.name === 'ObjectID') // MongoDB key
|
|
||||||
{
|
|
||||||
// Only pick the {propertyName: propertyValue}
|
|
||||||
data[i] = where[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// and it should have create/build methods with binded thisModelNameId param
|
// and it should have create/build methods with binded thisModelNameId param
|
||||||
function build(data) {
|
function build(data) {
|
||||||
data = data || {};
|
data = data || {};
|
||||||
|
@ -300,60 +272,3 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
||||||
|
|
||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* Merge query parameters
|
|
||||||
* @param {Object} base The base object to contain the merged results
|
|
||||||
* @param {Object} update The object containing updates to be merged
|
|
||||||
* @returns {*|Object} The base object
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function mergeQuery(base, update) {
|
|
||||||
if (!update) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
base = base || {};
|
|
||||||
if (update.where && Object.keys(update.where).length > 0) {
|
|
||||||
if (base.where && Object.keys(base.where).length > 0) {
|
|
||||||
base.where = {and: [base.where, update.where]};
|
|
||||||
} else {
|
|
||||||
base.where = update.where;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge inclusion
|
|
||||||
if (update.include) {
|
|
||||||
if (!base.include) {
|
|
||||||
base.include = update.include;
|
|
||||||
} else {
|
|
||||||
var saved = base.include;
|
|
||||||
base.include = {};
|
|
||||||
base.include[update.include] = saved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (update.collect) {
|
|
||||||
base.collect = update.collect;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set order
|
|
||||||
if (!base.order && update.order) {
|
|
||||||
base.order = update.order;
|
|
||||||
}
|
|
||||||
|
|
||||||
// overwrite pagination
|
|
||||||
if (update.limit !== undefined) {
|
|
||||||
base.limit = update.limit;
|
|
||||||
}
|
|
||||||
if (update.skip !== undefined) {
|
|
||||||
base.skip = update.skip;
|
|
||||||
}
|
|
||||||
if (update.offset !== undefined) {
|
|
||||||
base.offset = update.offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overwrite fields
|
|
||||||
if (update.fields !== undefined) {
|
|
||||||
base.fields = update.fields;
|
|
||||||
}
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
88
lib/utils.js
88
lib/utils.js
|
@ -7,6 +7,8 @@ exports.mergeSettings = mergeSettings;
|
||||||
exports.isPlainObject = isPlainObject;
|
exports.isPlainObject = isPlainObject;
|
||||||
exports.defineCachedRelations = defineCachedRelations;
|
exports.defineCachedRelations = defineCachedRelations;
|
||||||
exports.sortObjectsByIds = sortObjectsByIds;
|
exports.sortObjectsByIds = sortObjectsByIds;
|
||||||
|
exports.setScopeValuesFromWhere = setScopeValuesFromWhere;
|
||||||
|
exports.mergeQuery = mergeQuery;
|
||||||
|
|
||||||
var traverse = require('traverse');
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
@ -21,6 +23,92 @@ function safeRequire(module) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extracting fixed property values for the scope from the where clause into
|
||||||
|
* the data object
|
||||||
|
*
|
||||||
|
* @param {Object} The data object
|
||||||
|
* @param {Object} The where clause
|
||||||
|
*/
|
||||||
|
function setScopeValuesFromWhere(data, where, targetModel) {
|
||||||
|
for (var i in where) {
|
||||||
|
if (i === 'and') {
|
||||||
|
// Find fixed property values from each subclauses
|
||||||
|
for (var w = 0, n = where[i].length; w < n; w++) {
|
||||||
|
setScopeValuesFromWhere(data, where[i][w], targetModel);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var prop = targetModel.definition.properties[i];
|
||||||
|
if (prop) {
|
||||||
|
var val = where[i];
|
||||||
|
if (typeof val !== 'object' || val instanceof prop.type
|
||||||
|
|| prop.type.name === 'ObjectID') // MongoDB key
|
||||||
|
{
|
||||||
|
// Only pick the {propertyName: propertyValue}
|
||||||
|
data[i] = where[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Merge query parameters
|
||||||
|
* @param {Object} base The base object to contain the merged results
|
||||||
|
* @param {Object} update The object containing updates to be merged
|
||||||
|
* @returns {*|Object} The base object
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function mergeQuery(base, update) {
|
||||||
|
if (!update) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
base = base || {};
|
||||||
|
if (update.where && Object.keys(update.where).length > 0) {
|
||||||
|
if (base.where && Object.keys(base.where).length > 0) {
|
||||||
|
base.where = {and: [base.where, update.where]};
|
||||||
|
} else {
|
||||||
|
base.where = update.where;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge inclusion
|
||||||
|
if (update.include) {
|
||||||
|
if (!base.include) {
|
||||||
|
base.include = update.include;
|
||||||
|
} else {
|
||||||
|
var saved = base.include;
|
||||||
|
base.include = {};
|
||||||
|
base.include[update.include] = saved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (update.collect) {
|
||||||
|
base.collect = update.collect;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set order
|
||||||
|
if (!base.order && update.order) {
|
||||||
|
base.order = update.order;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite pagination
|
||||||
|
if (update.limit !== undefined) {
|
||||||
|
base.limit = update.limit;
|
||||||
|
}
|
||||||
|
if (update.skip !== undefined) {
|
||||||
|
base.skip = update.skip;
|
||||||
|
}
|
||||||
|
if (update.offset !== undefined) {
|
||||||
|
base.offset = update.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite fields
|
||||||
|
if (update.fields !== undefined) {
|
||||||
|
base.fields = update.fields;
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
function fieldsToArray(fields, properties) {
|
function fieldsToArray(fields, properties) {
|
||||||
if (!fields) return;
|
if (!fields) return;
|
||||||
|
|
||||||
|
|
|
@ -639,7 +639,7 @@ describe('Load models with base', function () {
|
||||||
assert(Customer.prototype.instanceMethod === User.prototype.instanceMethod);
|
assert(Customer.prototype.instanceMethod === User.prototype.instanceMethod);
|
||||||
assert.equal(Customer.base, User);
|
assert.equal(Customer.base, User);
|
||||||
assert.equal(Customer.base, Customer.super_);
|
assert.equal(Customer.base, Customer.super_);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var Customer1 = ds.define('Customer1', {vip: Boolean}, {base: 'User1'});
|
var Customer1 = ds.define('Customer1', {vip: Boolean}, {base: 'User1'});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
Loading…
Reference in New Issue