Merge pull request #544 from strongloop/feature/nesting-doc-query
Allow nesting properties to be queried for memory connector
This commit is contained in:
commit
16cc870f57
|
@ -295,6 +295,21 @@ Memory.prototype.fromDb = function (model, data) {
|
|||
return data;
|
||||
};
|
||||
|
||||
function getValue(obj, path) {
|
||||
if (obj == null) {
|
||||
return undefined;
|
||||
}
|
||||
var keys = path.split('.');
|
||||
var val = obj;
|
||||
for (var i = 0, n = keys.length; i < n; i++) {
|
||||
val = val[keys[i]];
|
||||
if (val == null) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
Memory.prototype.all = function all(model, filter, callback) {
|
||||
var self = this;
|
||||
var nodes = Object.keys(this.collection(model)).map(function (key) {
|
||||
|
@ -361,12 +376,14 @@ Memory.prototype.all = function all(model, filter, callback) {
|
|||
var undefinedA, undefinedB;
|
||||
|
||||
for (var i = 0, l = this.length; i < l; i++) {
|
||||
undefinedB = b[this[i].key] === undefined && a[this[i].key] !== undefined;
|
||||
undefinedA = a[this[i].key] === undefined && b[this[i].key] !== undefined;
|
||||
var aVal = getValue(a, this[i].key);
|
||||
var bVal = getValue(b, this[i].key);
|
||||
undefinedB = bVal === undefined && aVal !== undefined;
|
||||
undefinedA = aVal === undefined && bVal !== undefined;
|
||||
|
||||
if (undefinedB || a[this[i].key] > b[this[i].key]) {
|
||||
if (undefinedB || aVal > bVal) {
|
||||
return 1 * this[i].reverse;
|
||||
} else if (undefinedA || a[this[i].key] < b[this[i].key]) {
|
||||
} else if (undefinedA || aVal < bVal) {
|
||||
return -1 * this[i].reverse;
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +417,7 @@ function applyFilter(filter) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!test(where[key], obj && obj[key])) {
|
||||
if (!test(where[key], getValue(obj, key))) {
|
||||
pass = false;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -241,12 +241,18 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
ModelClass.getter = {};
|
||||
ModelClass.setter = {};
|
||||
|
||||
// Remove properties that reverted by the subclass
|
||||
for (var p in properties) {
|
||||
// Remove properties that reverted by the subclass
|
||||
if (properties[p] === null || properties[p] === false) {
|
||||
// Hide the base property
|
||||
delete properties[p];
|
||||
}
|
||||
|
||||
// Warn about properties with unsupported names
|
||||
if (/\./.test(p)) {
|
||||
deprecated('Property names containing a dot are not supported. ' +
|
||||
'Model: ' + className + ', property: ' + p);
|
||||
}
|
||||
}
|
||||
|
||||
var modelDefinition = new ModelDefinition(this, className, properties, settings);
|
||||
|
|
|
@ -17,6 +17,7 @@ var _extend = util._extend;
|
|||
var utils = require('./utils');
|
||||
var fieldsToArray = utils.fieldsToArray;
|
||||
var uuid = require('node-uuid');
|
||||
var deprecated = require('depd')('loopback-datasource-juggler');
|
||||
|
||||
// Set up an object for quick lookup
|
||||
var BASE_TYPES = {
|
||||
|
@ -197,6 +198,13 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
if (strict === false || self.__cachedRelations[p]) {
|
||||
self[p] = self.__data[p] =
|
||||
(propVal !== undefined) ? propVal : self.__cachedRelations[p];
|
||||
|
||||
// Warn about properties with unsupported names
|
||||
if (/\./.test(p)) {
|
||||
deprecated('Property names containing a dot are not supported. ' +
|
||||
'Model: ' + this.constructor.modelName +
|
||||
', dynamic property: ' + p);
|
||||
}
|
||||
} else if (strict === 'throw') {
|
||||
throw new Error('Unknown property: ' + p);
|
||||
}
|
||||
|
|
|
@ -146,7 +146,13 @@ describe('Memory connector', function() {
|
|||
birthday: {type: Date, index: true},
|
||||
role: {type: String, index: true},
|
||||
order: {type: Number, index: true, sort: true},
|
||||
vip: {type: Boolean}
|
||||
vip: {type: Boolean},
|
||||
address: {
|
||||
street: String,
|
||||
city: String,
|
||||
state: String,
|
||||
zipCode: String
|
||||
}
|
||||
});
|
||||
|
||||
before(seed);
|
||||
|
@ -317,6 +323,39 @@ describe('Memory connector', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support nested property in query', function(done) {
|
||||
User.find({where: {'address.city': 'San Jose'}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.length.should.be.equal(1);
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
users[i].address.city.should.be.eql('San Jose');
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support nested property with gt in query', function(done) {
|
||||
User.find({where: {'address.city': {gt: 'San'}}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.length.should.be.equal(2);
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
users[i].address.state.should.be.eql('CA');
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support nested property for order in query', function(done) {
|
||||
User.find({where: {'address.state': 'CA'}, order: 'address.city DESC'},
|
||||
function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.length.should.be.equal(2);
|
||||
users[0].address.city.should.be.eql('San Mateo');
|
||||
users[1].address.city.should.be.eql('San Jose');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
function seed(done) {
|
||||
var beatles = [
|
||||
{
|
||||
|
@ -325,7 +364,13 @@ describe('Memory connector', function() {
|
|||
email: 'john@b3atl3s.co.uk',
|
||||
role: 'lead',
|
||||
birthday: new Date('1980-12-08'),
|
||||
vip: true
|
||||
vip: true,
|
||||
address: {
|
||||
street: '123 A St',
|
||||
city: 'San Jose',
|
||||
state: 'CA',
|
||||
zipCode: '95131'
|
||||
}
|
||||
},
|
||||
{
|
||||
seq: 1,
|
||||
|
@ -334,7 +379,13 @@ describe('Memory connector', function() {
|
|||
role: 'lead',
|
||||
birthday: new Date('1942-06-18'),
|
||||
order: 1,
|
||||
vip: true
|
||||
vip: true,
|
||||
address: {
|
||||
street: '456 B St',
|
||||
city: 'San Mateo',
|
||||
state: 'CA',
|
||||
zipCode: '94065'
|
||||
}
|
||||
},
|
||||
{seq: 2, name: 'George Harrison', order: 5, vip: false},
|
||||
{seq: 3, name: 'Ringo Starr', order: 6, vip: false},
|
||||
|
|
|
@ -10,6 +10,10 @@ var Memory = require('../lib/connectors/memory');
|
|||
var ModelDefinition = require('../lib/model-definition');
|
||||
|
||||
describe('ModelDefinition class', function () {
|
||||
var memory;
|
||||
beforeEach(function() {
|
||||
memory = new DataSource({connector: Memory});
|
||||
});
|
||||
|
||||
it('should be able to define plain models', function (done) {
|
||||
var modelBuilder = new ModelBuilder();
|
||||
|
@ -253,7 +257,6 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
|
||||
it('should inherit prototype using option.base', function () {
|
||||
var memory = new DataSource({connector: Memory});
|
||||
var modelBuilder = memory.modelBuilder;
|
||||
var parent = memory.createModel('parent', {}, {
|
||||
relations: {
|
||||
|
@ -273,7 +276,6 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
|
||||
it('should ignore inherited options.base', function() {
|
||||
var memory = new DataSource({connector: Memory});
|
||||
var modelBuilder = memory.modelBuilder;
|
||||
var base = modelBuilder.define('base');
|
||||
var child = base.extend('child', {}, { base: 'base' });
|
||||
|
@ -283,7 +285,6 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
|
||||
it('should ignore inherited options.super', function() {
|
||||
var memory = new DataSource({connector: Memory});
|
||||
var modelBuilder = memory.modelBuilder;
|
||||
var base = modelBuilder.define('base');
|
||||
var child = base.extend('child', {}, { super: 'base' });
|
||||
|
@ -293,7 +294,6 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
|
||||
it('should serialize protected properties into JSON', function() {
|
||||
var memory = new DataSource({connector: Memory});
|
||||
var modelBuilder = memory.modelBuilder;
|
||||
var ProtectedModel = memory.createModel('protected', {}, {
|
||||
protected: ['protectedProperty']
|
||||
|
@ -308,7 +308,6 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
|
||||
it('should not serialize protected properties of nested models into JSON', function(done){
|
||||
var memory = new DataSource({connector: Memory});
|
||||
var modelBuilder = memory.modelBuilder;
|
||||
var Parent = memory.createModel('parent');
|
||||
var Child = memory.createModel('child', {}, {protected: ['protectedProperty']});
|
||||
|
@ -332,7 +331,6 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
|
||||
it('should not serialize hidden properties into JSON', function () {
|
||||
var memory = new DataSource({connector: Memory});
|
||||
var modelBuilder = memory.modelBuilder;
|
||||
var HiddenModel = memory.createModel('hidden', {}, {
|
||||
hidden: ['secret']
|
||||
|
@ -350,7 +348,6 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
|
||||
it('should not serialize hidden properties of nested models into JSON', function (done) {
|
||||
var memory = new DataSource({connector: Memory});
|
||||
var modelBuilder = memory.modelBuilder;
|
||||
var Parent = memory.createModel('parent');
|
||||
var Child = memory.createModel('child', {}, {hidden: ['secret']});
|
||||
|
@ -372,5 +369,26 @@ describe('ModelDefinition class', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should report deprecation warning for property names containing dot', function() {
|
||||
var message = 'deprecation not reported';
|
||||
process.once('deprecation', function(err) { message = err.message; });
|
||||
|
||||
memory.createModel('Dotted', { 'dot.name': String });
|
||||
|
||||
message.should.match(/Dotted.*dot\.name/);
|
||||
});
|
||||
|
||||
it('should report deprecation warning for dynamic property names containing dot', function(done) {
|
||||
var message = 'deprecation not reported';
|
||||
process.once('deprecation', function(err) { message = err.message; });
|
||||
|
||||
var Model = memory.createModel('DynamicDotted');
|
||||
Model.create({ 'dot.name': 'dot.value' }, function(err) {
|
||||
if (err) return done(err);
|
||||
message.should.match(/Dotted.*dot\.name/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue