Merge pull request #597 from strongloop/feature/enhance-fields-to-array

Enhance fieldsToArray to consider strict mode
This commit is contained in:
Raymond Feng 2015-05-21 09:43:40 -07:00
commit 5af6bf54df
4 changed files with 74 additions and 43 deletions

View File

@ -947,7 +947,7 @@ DataAccessObject._normalize = function (filter) {
// normalize fields as array of included property names // normalize fields as array of included property names
if (filter.fields) { if (filter.fields) {
filter.fields = fieldsToArray(filter.fields, filter.fields = fieldsToArray(filter.fields,
Object.keys(this.definition.properties)); Object.keys(this.definition.properties), this.settings.strict);
} }
filter = removeUndefined(filter); filter = removeUndefined(filter);

View File

@ -181,8 +181,9 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
} else if (ctor.relations[p]) { } else if (ctor.relations[p]) {
var relationType = ctor.relations[p].type; var relationType = ctor.relations[p].type;
var modelTo;
if (!properties[p]) { if (!properties[p]) {
var modelTo = ctor.relations[p].modelTo || ModelBaseClass; modelTo = ctor.relations[p].modelTo || ModelBaseClass;
var multiple = ctor.relations[p].multiple; var multiple = ctor.relations[p].multiple;
var typeName = multiple ? 'Array' : modelTo.modelName; var typeName = multiple ? 'Array' : modelTo.modelName;
var propType = multiple ? [modelTo] : modelTo; var propType = multiple ? [modelTo] : modelTo;
@ -196,7 +197,8 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
self.__data[ctor.relations[p].keyFrom] = propVal[ctor.relations[p].keyTo]; self.__data[ctor.relations[p].keyFrom] = propVal[ctor.relations[p].keyTo];
if (ctor.relations[p].options.embedsProperties) { if (ctor.relations[p].options.embedsProperties) {
var fields = fieldsToArray(ctor.relations[p].properties, modelTo.definition.properties); var fields = fieldsToArray(ctor.relations[p].properties,
modelTo.definition.properties, modelTo.setting.strict);
if (!~fields.indexOf(ctor.relations[p].keyTo)) { if (!~fields.indexOf(ctor.relations[p].keyTo)) {
fields.push(ctor.relations[p].keyTo); fields.push(ctor.relations[p].keyTo);
} }

View File

@ -149,7 +149,7 @@ function mergeQuery(base, update, spec) {
} }
spec = spec || {}; spec = spec || {};
base = base || {}; base = base || {};
if (update.where && Object.keys(update.where).length > 0) { if (update.where && Object.keys(update.where).length > 0) {
if (base.where && Object.keys(base.where).length > 0) { if (base.where && Object.keys(base.where).length > 0) {
base.where = {and: [base.where, update.where]}; base.where = {and: [base.where, update.where]};
@ -178,81 +178,96 @@ function mergeQuery(base, update, spec) {
} }
} }
} }
if (spec.collect !== false && update.collect) { if (spec.collect !== false && update.collect) {
base.collect = update.collect; base.collect = update.collect;
} }
// Overwrite fields // Overwrite fields
if (spec.fields !== false && update.fields !== undefined) { if (spec.fields !== false && update.fields !== undefined) {
base.fields = update.fields; base.fields = update.fields;
} else if (update.fields !== undefined) { } else if (update.fields !== undefined) {
base.fields = [].concat(base.fields).concat(update.fields); base.fields = [].concat(base.fields).concat(update.fields);
} }
// set order // set order
if ((!base.order || spec.order === false) && update.order) { if ((!base.order || spec.order === false) && update.order) {
base.order = update.order; base.order = update.order;
} }
// overwrite pagination // overwrite pagination
if (spec.limit !== false && update.limit !== undefined) { if (spec.limit !== false && update.limit !== undefined) {
base.limit = update.limit; base.limit = update.limit;
} }
var skip = spec.skip !== false && spec.offset !== false; var skip = spec.skip !== false && spec.offset !== false;
if (skip && update.skip !== undefined) { if (skip && update.skip !== undefined) {
base.skip = update.skip; base.skip = update.skip;
} }
if (skip && update.offset !== undefined) { if (skip && update.offset !== undefined) {
base.offset = update.offset; base.offset = update.offset;
} }
return base; return base;
} }
function fieldsToArray(fields, properties) { /**
* Normalize fields to an array of included properties
* @param {String|String[]|Object} fields Fields filter
* @param {String[]} properties Property names
* @param {Boolean} excludeUnknown To exclude fields that are unknown properties
* @returns {String[]} An array of included property names
*/
function fieldsToArray(fields, properties, excludeUnknown) {
if (!fields) return; if (!fields) return;
// include all properties by default // include all properties by default
var result = properties; var result = properties;
var i, n;
if (typeof fields === 'string') { if (typeof fields === 'string') {
return [fields]; result = [fields];
} } else if (Array.isArray(fields) && fields.length > 0) {
if (Array.isArray(fields) && fields.length > 0) {
// No empty array, including all the fields // No empty array, including all the fields
return fields; result = fields;
} } else if ('object' === typeof fields) {
if ('object' === typeof fields) {
// { field1: boolean, field2: boolean ... } // { field1: boolean, field2: boolean ... }
var included = []; var included = [];
var excluded = []; var excluded = [];
var keys = Object.keys(fields); var keys = Object.keys(fields);
if (!keys.length) return; if (!keys.length) return;
keys.forEach(function (k) { for (i = 0, n = keys.length; i < n; i++) {
var k = keys[i];
if (fields[k]) { if (fields[k]) {
included.push(k); included.push(k);
} else if ((k in fields) && !fields[k]) { } else if ((k in fields) && !fields[k]) {
excluded.push(k); excluded.push(k);
} }
}); }
if (included.length > 0) { if (included.length > 0) {
result = included; result = included;
} else if (excluded.length > 0) { } else if (excluded.length > 0) {
excluded.forEach(function (e) { for (i = 0, n = excluded.length; i < n; i++) {
var index = result.indexOf(e); var index = result.indexOf(excluded[i]);
result.splice(index, 1); result.splice(index, 1);
}); }
} }
} }
return result; var fieldArray = [];
if (excludeUnknown) {
for (i = 0, n = result.length; i < n; i++) {
if (properties.indexOf(result[i]) !== -1) {
fieldArray.push(result[i]);
}
}
} else {
fieldArray = result;
}
return fieldArray;
} }
function selectFields(fields) { function selectFields(fields) {
@ -404,16 +419,16 @@ function sortObjectsByIds(idName, ids, objects, strict) {
ids = ids.map(function(id) { ids = ids.map(function(id) {
return (typeof id === 'object') ? String(id) : id; return (typeof id === 'object') ? String(id) : id;
}); });
var indexOf = function(x) { var indexOf = function(x) {
var isObj = (typeof x[idName] === 'object'); // ObjectID var isObj = (typeof x[idName] === 'object'); // ObjectID
var id = isObj ? String(x[idName]) : x[idName]; var id = isObj ? String(x[idName]) : x[idName];
return ids.indexOf(id); return ids.indexOf(id);
}; };
var heading = []; var heading = [];
var tailing = []; var tailing = [];
objects.forEach(function(x) { objects.forEach(function(x) {
if (typeof x === 'object') { if (typeof x === 'object') {
var idx = indexOf(x); var idx = indexOf(x);
@ -421,7 +436,7 @@ function sortObjectsByIds(idName, ids, objects, strict) {
idx === -1 ? tailing.push(x) : heading.push(x); idx === -1 ? tailing.push(x) : heading.push(x);
} }
}); });
heading.sort(function(x, y) { heading.sort(function(x, y) {
var a = indexOf(x); var a = indexOf(x);
var b = indexOf(y); var b = indexOf(y);
@ -430,7 +445,7 @@ function sortObjectsByIds(idName, ids, objects, strict) {
if (a > b) return 1; if (a > b) return 1;
if (a < b) return -1; if (a < b) return -1;
}); });
return heading.concat(tailing); return heading.concat(tailing);
}; };

View File

@ -7,16 +7,17 @@ var mergeIncludes = utils.mergeIncludes;
var sortObjectsByIds = utils.sortObjectsByIds; var sortObjectsByIds = utils.sortObjectsByIds;
describe('util.fieldsToArray', function () { describe('util.fieldsToArray', function () {
it('Turn objects and strings into an array of fields to include when finding models', function () { function sample(fields, excludeUnknown) {
var properties = ['foo', 'bar', 'bat', 'baz'];
function sample(fields) { return {
var properties = ['foo', 'bar', 'bat', 'baz']; expect: function (arr) {
return { should.deepEqual(fieldsToArray(fields, properties, excludeUnknown), arr);
expect: function (arr) {
should.deepEqual(fieldsToArray(fields, properties), arr);
}
} }
} };
}
it('Turn objects and strings into an array of fields' +
' to include when finding models', function () {
sample(false).expect(undefined); sample(false).expect(undefined);
sample(null).expect(undefined); sample(null).expect(undefined);
@ -28,6 +29,19 @@ describe('util.fieldsToArray', function () {
sample({'bat': 0}).expect(['foo', 'bar', 'baz']); sample({'bat': 0}).expect(['foo', 'bar', 'baz']);
sample({'bat': false}).expect(['foo', 'bar', 'baz']); sample({'bat': false}).expect(['foo', 'bar', 'baz']);
}); });
it('should exclude unknown properties', function () {
sample(false, true).expect(undefined);
sample(null, true).expect(undefined);
sample({}, true).expect(undefined);
sample('foo', true).expect(['foo']);
sample(['foo', 'unknown'], true).expect(['foo']);
sample({'foo': 1, unknown: 1}, true).expect(['foo']);
sample({'bat': true, unknown: true}, true).expect(['bat']);
sample({'bat': 0}, true).expect(['foo', 'bar', 'baz']);
sample({'bat': false}, true).expect(['foo', 'bar', 'baz']);
});
}); });
describe('util.removeUndefined', function () { describe('util.removeUndefined', function () {
@ -190,7 +204,7 @@ describe('mergeSettings', function () {
}); });
describe('sortObjectsByIds', function () { describe('sortObjectsByIds', function () {
var items = [ var items = [
{ id: 1, name: 'a' }, { id: 1, name: 'a' },
{ id: 2, name: 'b' }, { id: 2, name: 'b' },
@ -211,7 +225,7 @@ describe('sortObjectsByIds', function () {
var names = sorted.map(function(u) { return u.name; }); var names = sorted.map(function(u) { return u.name; });
should.deepEqual(names, ['e', 'c', 'b', 'a', 'd', 'f']); should.deepEqual(names, ['e', 'c', 'b', 'a', 'd', 'f']);
}); });
it('should sort - strict', function() { it('should sort - strict', function() {
var sorted = sortObjectsByIds('id', [5, 3, 2], items, true); var sorted = sortObjectsByIds('id', [5, 3, 2], items, true);
var names = sorted.map(function(u) { return u.name; }); var names = sorted.map(function(u) { return u.name; });