Merge pull request #47 from strongloop/feature/query-coercing
Coerce query values of where clause based on property types
This commit is contained in:
commit
441596b870
83
lib/dao.js
83
lib/dao.js
|
@ -10,7 +10,6 @@ var util = require('util');
|
||||||
var jutil = require('./jutil');
|
var jutil = require('./jutil');
|
||||||
var validations = require('./validations.js');
|
var validations = require('./validations.js');
|
||||||
var ValidationError = validations.ValidationError;
|
var ValidationError = validations.ValidationError;
|
||||||
var List = require('./list.js');
|
|
||||||
require('./relations.js');
|
require('./relations.js');
|
||||||
var Inclusion = require('./include.js');
|
var Inclusion = require('./include.js');
|
||||||
var Relation = require('./relations.js');
|
var Relation = require('./relations.js');
|
||||||
|
@ -351,6 +350,83 @@ DataAccessObject.all = function () {
|
||||||
DataAccessObject.find.apply(this, arguments);
|
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
|
* Find all instances of Model, matched by query
|
||||||
* make sure you have marked as `index: true` fields for filter or sort
|
* 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);
|
params = removeUndefined(params);
|
||||||
|
if(params.where) {
|
||||||
|
params.where = this._coerce(params.where);
|
||||||
|
}
|
||||||
if(near) {
|
if(near) {
|
||||||
if(supportsGeo) {
|
if(supportsGeo) {
|
||||||
// convert it
|
// convert it
|
||||||
|
@ -511,6 +590,7 @@ DataAccessObject.destroyAll = function destroyAll(where, cb) {
|
||||||
} else {
|
} else {
|
||||||
// Support an optional where object
|
// Support an optional where object
|
||||||
where = removeUndefined(where);
|
where = removeUndefined(where);
|
||||||
|
where = this._coerce(where);
|
||||||
this.getDataSource().connector.destroyAll(this.modelName, where, function (err, data) {
|
this.getDataSource().connector.destroyAll(this.modelName, where, function (err, data) {
|
||||||
cb && cb(err, data);
|
cb && cb(err, data);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -556,6 +636,7 @@ DataAccessObject.count = function (where, cb) {
|
||||||
where = null;
|
where = null;
|
||||||
}
|
}
|
||||||
where = removeUndefined(where);
|
where = removeUndefined(where);
|
||||||
|
where = this._coerce(where);
|
||||||
this.getDataSource().connector.count(this.modelName, cb, where);
|
this.getDataSource().connector.count(this.modelName, cb, where);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 () {
|
describe('Load models from json', function () {
|
||||||
it('should be able to define models from json', function () {
|
it('should be able to define models from json', function () {
|
||||||
var path = require('path'),
|
var path = require('path'),
|
||||||
|
|
Loading…
Reference in New Issue