Add filter.fields support to dao and memory connector
This commit is contained in:
parent
d51821df3b
commit
d4ca20c01a
|
@ -1,4 +1,5 @@
|
||||||
var geo = require('../geo');
|
var geo = require('../geo');
|
||||||
|
var utils = require('../utils');
|
||||||
|
|
||||||
exports.initialize = function initializeSchema(schema, callback) {
|
exports.initialize = function initializeSchema(schema, callback) {
|
||||||
schema.adapter = new Memory();
|
schema.adapter = new Memory();
|
||||||
|
@ -146,11 +147,15 @@ Memory.prototype.all = function all(model, filter, callback) {
|
||||||
nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
|
nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// field selection
|
||||||
|
if(filter.fields) {
|
||||||
|
nodes = nodes.map(utils.selectFields(filter.fields))
|
||||||
|
}
|
||||||
|
|
||||||
// limit/skip
|
// limit/skip
|
||||||
filter.skip = filter.skip || 0;
|
filter.skip = filter.skip || 0;
|
||||||
filter.limit = filter.limit || nodes.length;
|
filter.limit = filter.limit || nodes.length;
|
||||||
nodes = nodes.slice(filter.skip, filter.skip + filter.limit);
|
nodes = nodes.slice(filter.skip, filter.skip + filter.limit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process.nextTick(function () {
|
process.nextTick(function () {
|
||||||
|
|
12
lib/dao.js
12
lib/dao.js
|
@ -16,6 +16,7 @@ var Inclusion = require('./include.js');
|
||||||
var Relation = require('./relations.js');
|
var Relation = require('./relations.js');
|
||||||
var geo = require('./geo');
|
var geo = require('./geo');
|
||||||
var Memory = require('./adapters/memory').Memory;
|
var Memory = require('./adapters/memory').Memory;
|
||||||
|
var fieldsToArray = require('./utils').fieldsToArray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DAO class - base class for all persist objects
|
* DAO class - base class for all persist objects
|
||||||
|
@ -321,9 +322,16 @@ DataAccessObject.find = function find(params, cb) {
|
||||||
}
|
}
|
||||||
var constr = this;
|
var constr = this;
|
||||||
|
|
||||||
|
|
||||||
|
var fields = params && params.fields;
|
||||||
var near = params && geo.nearFilter(params.where);
|
var near = params && geo.nearFilter(params.where);
|
||||||
var supportsGeo = !!this.schema.adapter.buildNearFilter;
|
var supportsGeo = !!this.schema.adapter.buildNearFilter;
|
||||||
|
|
||||||
|
// normalize fields as array of included property names
|
||||||
|
if(fields) {
|
||||||
|
params.fields = fieldsToArray(fields, Object.keys(this.properties));
|
||||||
|
}
|
||||||
|
|
||||||
if(near) {
|
if(near) {
|
||||||
if(supportsGeo) {
|
if(supportsGeo) {
|
||||||
// convert it
|
// convert it
|
||||||
|
@ -331,10 +339,6 @@ DataAccessObject.find = function find(params, cb) {
|
||||||
} else if(params.where) {
|
} else if(params.where) {
|
||||||
// do in memory query
|
// do in memory query
|
||||||
// using all documents
|
// using all documents
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.schema.adapter.all(this.modelName, {}, function (err, data) {
|
this.schema.adapter.all(this.modelName, {}, function (err, data) {
|
||||||
var memory = new Memory();
|
var memory = new Memory();
|
||||||
var modelName = constr.modelName;
|
var modelName = constr.modelName;
|
||||||
|
|
58
lib/utils.js
58
lib/utils.js
|
@ -1,4 +1,6 @@
|
||||||
exports.safeRequire = safeRequire;
|
exports.safeRequire = safeRequire;
|
||||||
|
exports.fieldsToArray = fieldsToArray;
|
||||||
|
exports.selectFields = selectFields;
|
||||||
|
|
||||||
function safeRequire(module) {
|
function safeRequire(module) {
|
||||||
try {
|
try {
|
||||||
|
@ -9,3 +11,59 @@ function safeRequire(module) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fieldsToArray(fields, properties) {
|
||||||
|
if(!fields) return;
|
||||||
|
|
||||||
|
// include all properties by default
|
||||||
|
var result = properties;
|
||||||
|
|
||||||
|
if(typeof fields === 'string') {
|
||||||
|
return [fields];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(fields) && fields.length > 0) {
|
||||||
|
// No empty array, including all the fields
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('object' === typeof fields) {
|
||||||
|
// { field1: boolean, field2: boolean ... }
|
||||||
|
var included = [];
|
||||||
|
var excluded = [];
|
||||||
|
var keys = Object.keys(fields);
|
||||||
|
if(!keys.length) return;
|
||||||
|
|
||||||
|
keys.forEach(function (k) {
|
||||||
|
if (fields[k]) {
|
||||||
|
included.push(k);
|
||||||
|
} else if ((k in fields) && !fields[k]) {
|
||||||
|
excluded.push(k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (included.length > 0) {
|
||||||
|
result = included;
|
||||||
|
} else if (excluded.length > 0) {
|
||||||
|
excluded.forEach(function (e) {
|
||||||
|
var index = result.indexOf(e);
|
||||||
|
result.splice(index, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectFields(fields) {
|
||||||
|
// map function
|
||||||
|
return function (obj) {
|
||||||
|
var result = {};
|
||||||
|
var key;
|
||||||
|
|
||||||
|
for (var i = 0; i < fields.length; i++) {
|
||||||
|
key = fields[i];
|
||||||
|
|
||||||
|
result[key] = obj[key];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -132,6 +132,53 @@ describe('basic-querying', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should only include fields as specified', function(done) {
|
||||||
|
var remaining = 0;
|
||||||
|
|
||||||
|
function sample(fields) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
expect: function (arr) {
|
||||||
|
remaining++;
|
||||||
|
User.find({fields: fields}, function(err, users) {
|
||||||
|
|
||||||
|
remaining--;
|
||||||
|
if(err) return done(err);
|
||||||
|
|
||||||
|
should.exists(users);
|
||||||
|
|
||||||
|
if(remaining === 0) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
users.forEach(function (user) {
|
||||||
|
var obj = user.toObject();
|
||||||
|
|
||||||
|
Object.keys(obj)
|
||||||
|
.forEach(function (key) {
|
||||||
|
// if the obj has an unexpected value
|
||||||
|
if(obj[key] !== undefined && arr.indexOf(key) === -1) {
|
||||||
|
console.log('Given fields:', fields);
|
||||||
|
console.log('Got:', key, obj[key]);
|
||||||
|
console.log('Expected:', arr);
|
||||||
|
throw new Error('should not include data for key: '+ key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sample({name: true}).expect(['name']);
|
||||||
|
sample({name: false}).expect(['id', 'email', 'role', 'order']);
|
||||||
|
sample({name: false, id: true}).expect(['id']);
|
||||||
|
sample({id: true}).expect(['id']);
|
||||||
|
sample('id').expect(['id']);
|
||||||
|
sample(['id']).expect(['id']);
|
||||||
|
sample(['email']).expect(['email']);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('count', function() {
|
describe('count', function() {
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
var should = require('./init.js');
|
||||||
|
var fieldsToArray = require('../lib/utils').fieldsToArray;
|
||||||
|
|
||||||
|
describe('util.fieldsToArray', function(){
|
||||||
|
it('Turn objects and strings into an array of fields to include when finding models', function() {
|
||||||
|
|
||||||
|
|
||||||
|
function sample(fields) {
|
||||||
|
var properties = ['foo', 'bar', 'bat', 'baz'];
|
||||||
|
return {
|
||||||
|
expect: function (arr) {
|
||||||
|
should.deepEqual(fieldsToArray(fields, properties), arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sample(false).expect(undefined);
|
||||||
|
sample(null).expect(undefined);
|
||||||
|
sample({}).expect(undefined);
|
||||||
|
sample('foo').expect(['foo']);
|
||||||
|
sample(['foo']).expect(['foo']);
|
||||||
|
sample({'foo': 1}).expect(['foo']);
|
||||||
|
sample({'bat': true}).expect(['bat']);
|
||||||
|
sample({'bat': 0}).expect(['foo', 'bar', 'baz']);
|
||||||
|
sample({'bat': false}).expect(['foo', 'bar', 'baz']);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue