Merge branch 'release/1.2.7' into production
This commit is contained in:
commit
76edc79232
83
lib/dao.js
83
lib/dao.js
|
@ -10,7 +10,6 @@ var util = require('util');
|
|||
var jutil = require('./jutil');
|
||||
var validations = require('./validations.js');
|
||||
var ValidationError = validations.ValidationError;
|
||||
var List = require('./list.js');
|
||||
require('./relations.js');
|
||||
var Inclusion = require('./include.js');
|
||||
var Relation = require('./relations.js');
|
||||
|
@ -351,6 +350,83 @@ DataAccessObject.all = function () {
|
|||
DataAccessObject.find.apply(this, arguments);
|
||||
};
|
||||
|
||||
var operators = {
|
||||
gt: '>',
|
||||
gte: '>=',
|
||||
lt: '<',
|
||||
lte: '<=',
|
||||
between: 'BETWEEN',
|
||||
inq: 'IN',
|
||||
nin: 'NOT IN',
|
||||
neq: '!=',
|
||||
like: 'LIKE',
|
||||
nlike: 'NOT LIKE'
|
||||
};
|
||||
|
||||
DataAccessObject._coerce = function (where) {
|
||||
if (!where) {
|
||||
return where;
|
||||
}
|
||||
|
||||
var props = this.getDataSource().getModelDefinition(this.modelName).properties;
|
||||
for (var p in where) {
|
||||
var DataType = props[p] && props[p].type;
|
||||
if (!DataType) {
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(DataType) || DataType === Array) {
|
||||
DataType = DataType[0];
|
||||
}
|
||||
if (DataType === Date) {
|
||||
var OrigDate = Date;
|
||||
DataType = function Date(arg) {
|
||||
return new OrigDate(arg);
|
||||
};
|
||||
} else if (DataType === Boolean) {
|
||||
DataType = function(val) {
|
||||
if(val === 'true') {
|
||||
return true;
|
||||
} else if(val === 'false') {
|
||||
return false;
|
||||
} else {
|
||||
return Boolean(val);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (!DataType) {
|
||||
continue;
|
||||
}
|
||||
var val = where[p];
|
||||
// Check there is an operator
|
||||
var operator = null;
|
||||
if ('object' === typeof val && Object.keys(val).length === 1) {
|
||||
for (var op in operators) {
|
||||
if (op in val) {
|
||||
val = val[op];
|
||||
operator = op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Coerce the array items
|
||||
if (Array.isArray(val)) {
|
||||
for (var i = 0; i < val.length; i++) {
|
||||
val[i] = DataType(val[i]);
|
||||
}
|
||||
} else {
|
||||
val = DataType(val);
|
||||
}
|
||||
// Rebuild {property: {operator: value}}
|
||||
if (operator) {
|
||||
var value = {};
|
||||
value[operator] = val;
|
||||
val = value;
|
||||
}
|
||||
where[p] = val;
|
||||
}
|
||||
return where;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find all instances of Model, matched by query
|
||||
* make sure you have marked as `index: true` fields for filter or sort
|
||||
|
@ -389,6 +465,9 @@ DataAccessObject.find = function find(params, cb) {
|
|||
}
|
||||
|
||||
params = removeUndefined(params);
|
||||
if(params.where) {
|
||||
params.where = this._coerce(params.where);
|
||||
}
|
||||
if(near) {
|
||||
if(supportsGeo) {
|
||||
// convert it
|
||||
|
@ -511,6 +590,7 @@ DataAccessObject.destroyAll = function destroyAll(where, cb) {
|
|||
} else {
|
||||
// Support an optional where object
|
||||
where = removeUndefined(where);
|
||||
where = this._coerce(where);
|
||||
this.getDataSource().connector.destroyAll(this.modelName, where, function (err, data) {
|
||||
cb && cb(err, data);
|
||||
}.bind(this));
|
||||
|
@ -556,6 +636,7 @@ DataAccessObject.count = function (where, cb) {
|
|||
where = null;
|
||||
}
|
||||
where = removeUndefined(where);
|
||||
where = this._coerce(where);
|
||||
this.getDataSource().connector.count(this.modelName, cb, where);
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ var assert = require('assert');
|
|||
var DefaultModelBaseClass = require('./model.js');
|
||||
var List = require('./list.js');
|
||||
var ModelDefinition = require('./model-definition.js');
|
||||
var mergeSettings = require('./utils').mergeSettings;
|
||||
|
||||
// Set up types
|
||||
require('./types')(ModelBuilder);
|
||||
|
@ -283,11 +284,15 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
});
|
||||
|
||||
// Merge the settings
|
||||
subclassSettings = mergeSettings(settings, subclassSettings);
|
||||
|
||||
/*
|
||||
Object.keys(settings).forEach(function (key) {
|
||||
if(subclassSettings[key] === undefined) {
|
||||
subclassSettings[key] = settings[key];
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
// Define the subclass
|
||||
var subClass = modelBuilder.define(className, subclassProperties, subclassSettings, ModelClass);
|
||||
|
|
51
lib/utils.js
51
lib/utils.js
|
@ -3,6 +3,7 @@ exports.fieldsToArray = fieldsToArray;
|
|||
exports.selectFields = selectFields;
|
||||
exports.removeUndefined = removeUndefined;
|
||||
exports.parseSettings = parseSettings;
|
||||
exports.mergeSettings = mergeSettings;
|
||||
|
||||
var traverse = require('traverse');
|
||||
|
||||
|
@ -127,3 +128,53 @@ function parseSettings(urlStr) {
|
|||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge model settings
|
||||
*
|
||||
* Folked from https://github.com/nrf110/deepmerge/blob/master/index.js
|
||||
*
|
||||
* The original function tries to merge array items if they are objects
|
||||
*
|
||||
* @param {Object} target The target settings object
|
||||
* @param {Object} src The source settings object
|
||||
* @returns {Object} The merged settings object
|
||||
*/
|
||||
function mergeSettings(target, src) {
|
||||
var array = Array.isArray(src);
|
||||
var dst = array && [] || {};
|
||||
|
||||
if (array) {
|
||||
target = target || [];
|
||||
dst = dst.concat(target);
|
||||
src.forEach(function (e, i) {
|
||||
if (typeof target[i] === 'undefined') {
|
||||
dst[i] = e;
|
||||
} else {
|
||||
if (target.indexOf(e) === -1) {
|
||||
dst.push(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (target && typeof target === 'object') {
|
||||
Object.keys(target).forEach(function (key) {
|
||||
dst[key] = target[key];
|
||||
});
|
||||
}
|
||||
Object.keys(src).forEach(function (key) {
|
||||
if (typeof src[key] !== 'object' || !src[key]) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
else {
|
||||
if (!target[key]) {
|
||||
dst[key] = src[key]
|
||||
} else {
|
||||
dst[key] = mergeSettings(target[key], src[key])
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "loopback-datasource-juggler",
|
||||
"version": "1.2.6",
|
||||
"version": "1.2.7",
|
||||
"description": "LoopBack DataSoure Juggler",
|
||||
"keywords": [
|
||||
"StrongLoop",
|
||||
|
|
|
@ -572,6 +572,83 @@ describe('Load models with relations', function () {
|
|||
|
||||
});
|
||||
|
||||
describe('DataAccessObject', function () {
|
||||
var ds, model, where;
|
||||
|
||||
before(function () {
|
||||
ds = new DataSource('memory');
|
||||
model = ds.createModel('M1', {
|
||||
id: {type: String, id: true},
|
||||
age: Number,
|
||||
vip: Boolean,
|
||||
date: Date,
|
||||
scores: [Number]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to coerce where clause for string types', function () {
|
||||
where = model._coerce({id: 1});
|
||||
assert.deepEqual(where, {id: '1'});
|
||||
where = model._coerce({id: '1'});
|
||||
assert.deepEqual(where, {id: '1'});
|
||||
});
|
||||
|
||||
it('should be able to coerce where clause for number types', function () {
|
||||
where = model._coerce({age: '10'});
|
||||
assert.deepEqual(where, {age: 10});
|
||||
|
||||
where = model._coerce({age: 10});
|
||||
assert.deepEqual(where, {age: 10});
|
||||
|
||||
where = model._coerce({age: {gt: 10}});
|
||||
assert.deepEqual(where, {age: {gt: 10}});
|
||||
|
||||
where = model._coerce({age: {gt: '10'}});
|
||||
assert.deepEqual(where, {age: {gt: 10}});
|
||||
|
||||
where = model._coerce({age: {between: ['10', '20']}});
|
||||
assert.deepEqual(where, {age: {between: [10, 20]}});
|
||||
});
|
||||
|
||||
it('should be able to coerce where clause for array types', function () {
|
||||
where = model._coerce({scores: ['10', '20']});
|
||||
assert.deepEqual(where, {scores: [10, 20]});
|
||||
});
|
||||
|
||||
it('should be able to coerce where clause for date types', function () {
|
||||
var d = new Date();
|
||||
where = model._coerce({date: d});
|
||||
assert.deepEqual(where, {date: d});
|
||||
|
||||
where = model._coerce({date: d.toISOString()});
|
||||
assert.deepEqual(where, {date: d});
|
||||
});
|
||||
|
||||
it('should be able to coerce where clause for boolean types', function () {
|
||||
where = model._coerce({vip: 'true'});
|
||||
assert.deepEqual(where, {vip: true});
|
||||
|
||||
where = model._coerce({vip: true});
|
||||
assert.deepEqual(where, {vip: true});
|
||||
|
||||
where = model._coerce({vip: 'false'});
|
||||
assert.deepEqual(where, {vip: false});
|
||||
|
||||
where = model._coerce({vip: false});
|
||||
assert.deepEqual(where, {vip: false});
|
||||
|
||||
where = model._coerce({vip: '1'});
|
||||
assert.deepEqual(where, {vip: true});
|
||||
|
||||
where = model._coerce({vip: 0});
|
||||
assert.deepEqual(where, {vip: false});
|
||||
|
||||
where = model._coerce({vip: ''});
|
||||
assert.deepEqual(where, {vip: false});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('Load models from json', function () {
|
||||
it('should be able to define models from json', function () {
|
||||
var path = require('path'),
|
||||
|
@ -649,6 +726,96 @@ describe('Load models from json', function () {
|
|||
|
||||
done(null, customer);
|
||||
});
|
||||
|
||||
it('should be able to extend models with merged settings', function (done) {
|
||||
var modelBuilder = new ModelBuilder();
|
||||
|
||||
var User = modelBuilder.define('User', {
|
||||
name: String
|
||||
}, {
|
||||
defaultPermission: 'ALLOW',
|
||||
acls: [
|
||||
{
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
],
|
||||
relations: {
|
||||
posts: {
|
||||
type: 'hasMany',
|
||||
model:'Post'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var Customer = User.extend('Customer',
|
||||
{customerId: {type: String, id: true}},
|
||||
{
|
||||
defaultPermission: 'DENY',
|
||||
acls: [
|
||||
{
|
||||
principalType: 'ROLE',
|
||||
principalId: '$unauthenticated',
|
||||
permission: 'DENY'
|
||||
}
|
||||
],
|
||||
relations: {
|
||||
orders: {
|
||||
type: 'hasMany',
|
||||
model:'Order'
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
assert.deepEqual(User.settings, {
|
||||
defaultPermission: 'ALLOW',
|
||||
acls: [
|
||||
{
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
],
|
||||
relations: {
|
||||
posts: {
|
||||
type: 'hasMany',
|
||||
model:'Post'
|
||||
}
|
||||
},
|
||||
strict: false
|
||||
});
|
||||
|
||||
assert.deepEqual(Customer.settings, {
|
||||
defaultPermission: 'DENY',
|
||||
acls: [
|
||||
{
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'ALLOW'
|
||||
},
|
||||
{
|
||||
principalType: 'ROLE',
|
||||
principalId: '$unauthenticated',
|
||||
permission: 'DENY'
|
||||
}
|
||||
],
|
||||
relations: {
|
||||
posts: {
|
||||
type: 'hasMany',
|
||||
model:'Post'
|
||||
},
|
||||
orders: {
|
||||
type: 'hasMany',
|
||||
model:'Order'
|
||||
}
|
||||
},
|
||||
strict: false
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('DataSource constructor', function(){
|
||||
|
|
Loading…
Reference in New Issue