Permalink
Browse files

created .select method to query specific columns in an adapter indepe…

…ndent manner
  • Loading branch information...
1 parent 6fb6ee5 commit 99de9347384802b5046f0d9b2d37f5a3acd08e11 @jvskelton jvskelton committed Jul 2, 2014
Showing with 173 additions and 8 deletions.
  1. +64 −0 lib/adapters/memory.js
  2. +74 −7 lib/model.js
  3. +35 −1 test/basic-querying.test.js
View
64 lib/adapters/memory.js
@@ -105,6 +105,70 @@ Memory.prototype.fromDb = function(model, data) {
return data;
};
+Memory.prototype.select = function all(model, filter, callback) {
+ var self = this;
+ var table = this.table(model);
+ var nodes;
+ if (filter && filter.attributes) {
+ nodes = filter.attributes;
+ } else {
+ nodes = Object.keys(this.cache[table]).map(function (key) {
+ return this.fromDb(model, this.cache[table][key]);
+ }.bind(this));
+ }
+ if (filter) {
+
+ // do we need some sorting?
+ if (filter.order) {
+ var props = this._models[model].properties;
+ var orders = filter.order;
+ if (typeof filter.order === "string") {
+ orders = [filter.order];
+ }
+ orders.forEach(function (key, i) {
+ var reverse = 1;
+ var m = key.match(/\s+(A|DE)SC$/i);
+ if (m) {
+ key = key.replace(/\s+(A|DE)SC/i, '');
+ if (m[1].toLowerCase() === 'de') reverse = -1;
+ }
+ orders[i] = {"key": key, "reverse": reverse};
+ });
+ nodes = nodes.sort(sorting.bind(orders));
+ }
+
+ // do we need some filtration?
+ if (filter.where) {
+ nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
+ }
+
+ // limit/skip
+ filter.skip = filter.skip || 0;
+ filter.limit = filter.limit || nodes.length;
+ nodes = nodes.slice(filter.skip, filter.skip + filter.limit);
+
+ }
+
+ process.nextTick(function () {
+ if (filter && filter.include) {
+ self._models[model].model.include(nodes, filter.include, callback);
+ } else {
+ callback(null, nodes);
+ }
+ });
+
+ function sorting(a, b) {
+ for (var i=0, l=this.length; i<l; i++) {
+ if (a[this[i].key] > b[this[i].key]) {
+ return 1*this[i].reverse;
+ } else if (a[this[i].key] < b[this[i].key]) {
+ return -1*this[i].reverse;
+ }
+ }
+ return 0;
+ }
+};
+
Memory.prototype.all = function all(model, filter, callback) {
var self = this;
var table = this.table(model);
View
81 lib/model.js
@@ -489,12 +489,13 @@ AbstractClass.all = function all(params, cb) {
if (!params || !params.onlyKeys) {
data.forEach(function (d, i) {
var obj = new constr;
- d = constr._fromDB(d);
- obj._initProperties(d, false);
- if (params && params.include && params.collect) {
- data[i] = obj.__cachedRelations[params.collect];
- } else {
- data[i] = obj;
+ if (params && !params.attributes) {
+ obj._initProperties(d, false);
+ if (params && params.include && params.collect) {
+ data[i] = obj.__cachedRelations[params.collect];
+ } else {
+ data[i] = obj;
+ }
}
});
}
@@ -509,6 +510,72 @@ AbstractClass.all = function all(params, cb) {
};
/**
+ * Find all instances of Model, matched by query, unless specific columns are
+* provided in the attributes param, which will return either an array of objects(if array columns provided)
+* or an array of column data if string literal given.
+ * make sure you have marked as `index: true` fields for filter or sort
+ *
+ * @param {Object} params (optional)
+ *
+ * - where: Object `{ key: val, key2: {gt: 'val2'}}`
+* - attributes: Array '['id, 'name'] or String 'id'
+ * - include: String, Object or Array. See AbstractClass.include documentation.
+ * - order: String
+ * - limit: Number
+ * - skip: Number
+ *
+ * @param {Function} callback (required) called with arguments:
+ *
+ * - err (null or Error)
+ * - Array of instances
+ */
+AbstractClass.select = function select(params, cb) {
+ if (arguments.length === 1) {
+ cb = params;
+ params = null;
+ }
+
+ this.schema.models[this.modelName].all(params, function (err, data) {
+ if (data && data.forEach) {
+ if (params && params.attributes && data.length > 0 && typeof data[0] == 'object') {
+ var model = new this.schema.models[this.modelName]();
+ if (Object.keys(data[0]) && Object.getOwnPropertyNames(model).length <= Object.keys(data[0]).length) {
+ var blackList = Object.keys(data[0]).filter(function (currentKey) {
+ var isBlackListed = true;
+
+ if (Array.isArray(params.attributes)) {
+ params.attributes.forEach(function (key) {
+ if(key === currentKey)
+ isBlackListed = false;
+ });
+ } else if (params.attributes == currentKey) {
+ isBlackListed = false;
+ }
+ return isBlackListed;
+ });
+
+ data.forEach(function (item) {
+ blackList.forEach(function (key) {
+ delete item[key];
+ });
+ });
+
+ if (!Array.isArray(params.attributes)) {
+ data = data.map(function (item) {
+ return item[params.attributes];
+ });
+ }
+ }
+ }
+ cb(err, data);
+ }
+ else
+ cb(err, []);
+
+ }.bind(this));
+}
+
+/**
* Iterate through dataset and perform async method iterator. This method
* designed to work with large datasets loading data by batches.
*
@@ -962,4 +1029,4 @@ function defineReadonlyProp(obj, key, value) {
configurable: true,
value: value
});
-}
+}
View
36 test/basic-querying.test.js
@@ -13,7 +13,7 @@ describe('basic-querying', function() {
role: {type: String, index: true, limit: 100},
order: {type: Number, index: true, sort: true, limit: 100}
});
-
+
db.automigrate(done);
});
@@ -131,7 +131,41 @@ describe('basic-querying', function() {
done();
});
});
+ });
+
+ describe('select', function () {
+
+ it('should query collection and return given attribute as an array of Objects', function(done) {
+ User.select({attributes: ['id']}, function(err, users) {
+ should.exists(users);
+ should.not.exists(err);
+ users.should.be.instanceOf(Array);
+ users.pop().should.be.instanceOf(Object).and.have.property('id');
+ done();
+ });
+ });
+
+ it('should query collection and return given attribute as an array of Numbers', function(done) {
+ User.select({attributes: 'id'}, function(err, users) {
+ should.exists(users);
+ should.not.exists(err);
+ users.should.be.instanceOf(Array);
+ users.pop().should.be.a.Number;
+ done();
+ });
+ });
+ it('should query collection and return given attributes as an array of objects', function(done) {
+ User.select({attributes: ['id', 'name']}, function(err, users) {
+ should.exists(users);
+ should.not.exists(err);
+ should.not.exists(users.pop().mail);
+ should.not.exists(users.pop().order);
+ users.pop().should.be.instanceOf(Object).and.have.property('id');
+ users.pop().should.be.instanceOf(Object).and.have.property('name');
+ done();
+ });
+ });
});
describe('count', function() {

0 comments on commit 99de934

Please sign in to comment.