diff --git a/lib/waterline/adapter/aggregateQueries.js b/lib/waterline/adapter/aggregateQueries.js index 0cc6889e1..2bc94194e 100644 --- a/lib/waterline/adapter/aggregateQueries.js +++ b/lib/waterline/adapter/aggregateQueries.js @@ -10,7 +10,7 @@ var hasOwnProperty = require('../utils/helpers').object.hasOwnProperty; module.exports = { // If an optimized createEach exists, use it, otherwise use an asynchronous loop with create() - createEach: function(valuesList, cb) { + createEach: function(valuesList, cb, metaContainer) { var self = this; var connName, adapter; @@ -27,7 +27,7 @@ module.exports = { adapter = this.connections[connName]._adapter; if (hasOwnProperty(adapter, 'createEach')) { - return adapter.createEach(connName, this.collection, valuesList, cb); + return adapter.createEach(connName, this.collection, valuesList, cb, metaContainer); } } @@ -48,7 +48,7 @@ module.exports = { if (err) return cb(err); results.push(row); cb(); - }); + }, metaContainer); }, function(err) { if (err) return cb(err); cb(null, results); @@ -56,7 +56,7 @@ module.exports = { }, // If an optimized findOrCreateEach exists, use it, otherwise use an asynchronous loop with create() - findOrCreateEach: function(attributesToCheck, valuesList, cb) { + findOrCreateEach: function(attributesToCheck, valuesList, cb, metaContainer) { var self = this; var connName; var adapter; @@ -84,7 +84,7 @@ module.exports = { adapter = this.connections[connName]._adapter; if (hasOwnProperty(adapter, 'findOrCreateEach')) { - return adapter.findOrCreateEach(connName, this.collection, valuesList, cb); + return adapter.findOrCreateEach(connName, this.collection, valuesList, cb, metaContainer); } } @@ -122,7 +122,7 @@ module.exports = { if (model) models.push(model); cb(null, model); - }); + }, metaContainer); }, function(err) { if (err) return cb(err); cb(null, models); diff --git a/lib/waterline/adapter/compoundQueries.js b/lib/waterline/adapter/compoundQueries.js index 629ddc04b..38b5847c0 100644 --- a/lib/waterline/adapter/compoundQueries.js +++ b/lib/waterline/adapter/compoundQueries.js @@ -8,7 +8,7 @@ var hasOwnProperty = require('../utils/helpers').object.hasOwnProperty; module.exports = { - findOrCreate: function(criteria, values, cb) { + findOrCreate: function(criteria, values, cb, metaContainer) { var self = this; var connName, adapter; @@ -29,7 +29,7 @@ module.exports = { adapter = this.connections[connName]._adapter; if (hasOwnProperty(adapter, 'findOrCreate')) { - return adapter.findOrCreate(connName, this.collection, values, cb); + return adapter.findOrCreate(connName, this.collection, values, cb, metaContainer); } } @@ -39,8 +39,8 @@ module.exports = { if (err) return cb(err); if (result) return cb(null, result[0]); - self.create(values, cb); - }); + self.create(values, cb, metaContainer); + }, metaContainer); } }; diff --git a/lib/waterline/adapter/dql.js b/lib/waterline/adapter/dql.js index 7e6d48f58..579d47482 100644 --- a/lib/waterline/adapter/dql.js +++ b/lib/waterline/adapter/dql.js @@ -28,7 +28,7 @@ module.exports = { * @param {[type]} criteria * @param {Function} cb */ - join: function(criteria, cb) { + join: function(criteria, cb, metaContainer) { // Normalize Arguments criteria = normalize.criteria(criteria); @@ -49,7 +49,7 @@ module.exports = { // This is done here so that everywhere else in the codebase can use the collection identity. criteria = schema.serializeJoins(criteria, this.query.waterline.schema); - adapter.join(connName, this.collection, criteria, cb); + adapter.join(connName, this.collection, criteria, cb, metaContainer); }, @@ -62,14 +62,16 @@ module.exports = { * @param {Function} cb [description] * @return {[type]} [description] */ - create: function(values, cb) { + create: function(values, cb, metaContainer) { var globalId = this.query.globalId; // Normalize Arguments cb = normalize.callback(cb); - if (Array.isArray(values)) return this.createEach.call(this, values, cb); + if (Array.isArray(values)) { + return this.createEach.call(this, values, cb, metaContainer); + } // Build Default Error Message var err = 'No create() method defined in adapter!'; @@ -87,7 +89,7 @@ module.exports = { return cb(err); } else return cb(null, createdRecord); - })); + }), metaContainer); }, @@ -100,8 +102,7 @@ module.exports = { * @param {Function} cb [description] * @return {[type]} [description] */ - find: function(criteria, cb) { - + find: function(criteria, cb, metaContainer) { // Normalize Arguments criteria = normalize.criteria(criteria); cb = normalize.callback(cb); @@ -116,7 +117,7 @@ module.exports = { var adapter = this.connections[connName]._adapter; if (!adapter.find) return cb(new Error(err)); - adapter.find(connName, this.collection, criteria, cb); + adapter.find(connName, this.collection, criteria, cb, metaContainer); }, @@ -129,7 +130,7 @@ module.exports = { * @param {Function} cb [description] * @return {[type]} [description] */ - findOne: function(criteria, cb) { + findOne: function(criteria, cb, metaContainer) { // make shallow copy of criteria so original does not get modified criteria = _.clone(criteria); @@ -151,7 +152,7 @@ module.exports = { if (adapter.findOne) { // Normalize Arguments criteria = normalize.criteria(criteria); - return adapter.findOne(connName, this.collection, criteria, cb); + return adapter.findOne(connName, this.collection, criteria, cb, metaContainer); } } @@ -164,7 +165,7 @@ module.exports = { if (models.length < 1) return cb(err); cb(null, models); - }); + }, metaContainer); }, /** @@ -173,7 +174,7 @@ module.exports = { * @param {Function} cb [description] * @return {[type]} [description] */ - count: function(criteria, cb) { + count: function(criteria, cb, metaContainer) { var connName; // Normalize Arguments @@ -196,13 +197,13 @@ module.exports = { if (!connName) connName = this.dictionary.count; var adapter = this.connections[connName]._adapter; - if (hasOwnProperty(adapter, 'count')) return adapter.count(connName, this.collection, criteria, cb); + if (hasOwnProperty(adapter, 'count')) return adapter.count(connName, this.collection, criteria, cb, metaContainer); this.find(criteria, function(err, models) { if (err) return cb(err); var count = models && models.length || 0; cb(err, count); - }); + }, metaContainer); }, @@ -213,7 +214,7 @@ module.exports = { * @param {Function} cb [description] * @return {[type]} [description] */ - update: function(criteria, values, cb) { + update: function(criteria, values, cb, metaContainer) { var globalId = this.query.globalId; @@ -242,7 +243,7 @@ module.exports = { return cb(err); } return cb(null, updatedRecords); - })); + }), metaContainer); }, @@ -252,7 +253,7 @@ module.exports = { * @param {Function} cb [description] * @return {[type]} [description] */ - destroy: function(criteria, cb) { + destroy: function(criteria, cb, metaContainer) { // Normalize Arguments cb = normalize.callback(cb); @@ -267,7 +268,7 @@ module.exports = { var connName = this.dictionary.destroy; var adapter = this.connections[connName]._adapter; - adapter.destroy(connName, this.collection, criteria, cb); + adapter.destroy(connName, this.collection, criteria, cb, metaContainer); } }; diff --git a/lib/waterline/adapter/stream.js b/lib/waterline/adapter/stream.js index 64d39585d..b6ccef169 100644 --- a/lib/waterline/adapter/stream.js +++ b/lib/waterline/adapter/stream.js @@ -13,7 +13,7 @@ module.exports = { // stream.write() is used to send data // Must call stream.end() to complete stream - stream: function(criteria, stream) { + stream: function(criteria, stream, metaContainer) { // Normalize Arguments criteria = normalize.criteria(criteria); @@ -28,7 +28,7 @@ module.exports = { var adapter = this.connections[connName]._adapter; if (!hasOwnProperty(adapter, 'stream')) return stream.end(new Error(err)); - adapter.stream(connName, this.collection, criteria, stream); + adapter.stream(connName, this.collection, criteria, stream, metaContainer); } }; diff --git a/lib/waterline/query/aggregate.js b/lib/waterline/query/aggregate.js index 15be7ab28..f5ba75afa 100644 --- a/lib/waterline/query/aggregate.js +++ b/lib/waterline/query/aggregate.js @@ -21,14 +21,13 @@ module.exports = { * @return Deferred object if no callback */ - createEach: function(valuesList, cb) { + createEach: function(valuesList, cb, metaContainer) { var self = this; // Handle Deferred where it passes criteria first - if (arguments.length === 3) { - var args = Array.prototype.slice.call(arguments); - cb = args.pop(); - valuesList = args.pop(); + if(_.isPlainObject(arguments[0]) && _.isArray(arguments[1])) { + valuesList = arguments[1]; + cb = arguments[2]; } // Return Deferred or pass to adapter @@ -52,7 +51,9 @@ module.exports = { }); // Create will take care of cloning values so original isn't mutated - async.map(filteredValues, self.create.bind(self), cb); + async.map(filteredValues, function(data, next) { + self.create(data, next, metaContainer); + }, cb); }, /** @@ -65,7 +66,7 @@ module.exports = { * @return Deferred object if no callback */ - findOrCreateEach: function(criteria, valuesList, cb) { + findOrCreateEach: function(criteria, valuesList, cb, metaContainer) { var self = this; if (typeof valuesList === 'function') { @@ -160,7 +161,7 @@ module.exports = { cb(null, models); }); - }); + }, metaContainer); }); } }; diff --git a/lib/waterline/query/composite.js b/lib/waterline/query/composite.js index d1ce6d6bb..6bb9c26c8 100644 --- a/lib/waterline/query/composite.js +++ b/lib/waterline/query/composite.js @@ -21,7 +21,7 @@ module.exports = { * @return Deferred object if no callback */ - findOrCreate: function(criteria, values, cb) { + findOrCreate: function(criteria, values, cb, metaContainer) { var self = this; if (typeof values === 'function') { @@ -53,7 +53,13 @@ module.exports = { if (typeof cb !== 'function') return usageError('Invalid callback specified!', usage, cb); // Try a find first. - this.find(criteria).exec(function(err, results) { + var q = this.find(criteria); + + if(metaContainer) { + q.meta(metaContainer); + } + + q.exec(function(err, results) { if (err) return cb(err); if (results && results.length !== 0) { @@ -67,7 +73,13 @@ module.exports = { } // Create a new record if nothing is found. - self.create(values).exec(function(err, result) { + var q2 = self.create(values); + + if(metaContainer) { + q2.meta(metaContainer); + } + + q2.exec(function(err, result) { if (err) return cb(err); return cb(null, result); }); diff --git a/lib/waterline/query/deferred.js b/lib/waterline/query/deferred.js index a0547f902..2127d8280 100644 --- a/lib/waterline/query/deferred.js +++ b/lib/waterline/query/deferred.js @@ -502,6 +502,15 @@ Deferred.prototype.set = function(values) { return this; }; +/** + * Pass metadata down to the adapter that won't be processed or touched by Waterline + */ + +Deferred.prototype.meta = function(data) { + this._meta = data; + return this; +}; + /** * Execute a Query using the method passed into the * constuctor. @@ -523,6 +532,11 @@ Deferred.prototype.exec = function(cb) { var args = [this._criteria, cb]; if (this._values) args.splice(1, 0, this._values); + // If there is a meta value, throw it on the very end + if(this._meta) { + args.push(this._meta); + } + // Pass control to the adapter with the appropriate arguments. this._method.apply(this._context, args); }; diff --git a/lib/waterline/query/dql/count.js b/lib/waterline/query/dql/count.js index cc628d8a1..e8ef48327 100644 --- a/lib/waterline/query/dql/count.js +++ b/lib/waterline/query/dql/count.js @@ -17,7 +17,7 @@ var Deferred = require('../deferred'); * @return Deferred object if no callback */ -module.exports = function(criteria, options, cb) { +module.exports = function(criteria, options, cb, metaContainer) { var usage = utils.capitalize(this.identity) + '.count([criteria],[options],callback)'; if (typeof criteria === 'function') { @@ -56,5 +56,5 @@ module.exports = function(criteria, options, cb) { // Transform Search Criteria criteria = this._transformer.serialize(criteria); - this.adapter.count(criteria, cb); + this.adapter.count(criteria, cb, metaContainer); }; diff --git a/lib/waterline/query/dql/create.js b/lib/waterline/query/dql/create.js index f00e0edde..d63008757 100644 --- a/lib/waterline/query/dql/create.js +++ b/lib/waterline/query/dql/create.js @@ -19,17 +19,17 @@ var hop = utils.object.hasOwnProperty; * @return Deferred object if no callback */ -module.exports = function(values, cb) { +module.exports = function(values, cb, metaContainer) { var self = this; // Handle Deferred where it passes criteria first - if (arguments.length === 3) { - var args = Array.prototype.slice.call(arguments); - cb = args.pop(); - values = args.pop(); + if(_.isPlainObject(arguments[0]) && (_.isPlainObject(arguments[1]) || _.isArray(arguments[1]))) { + values = arguments[1]; + cb = arguments[2]; } + // Loop through values and pull out any buffers before cloning var bufferValues = {}; @@ -59,7 +59,7 @@ module.exports = function(values, cb) { // Handle Array of values if (Array.isArray(values)) { - return this.createEach(values, cb); + return this.createEach(values, cb, metaContainer); } // Process Values @@ -71,8 +71,8 @@ module.exports = function(values, cb) { beforeCallbacks.call(self, valuesObject, function(err) { if (err) return cb(err); - createValues.call(self, valuesObject, cb); - }); + createValues.call(self, valuesObject, cb, metaContainer); + }, metaContainer); }); }; @@ -113,7 +113,7 @@ function processValues(values) { * */ -function createBelongsTo(valuesObject, cb) { +function createBelongsTo(valuesObject, cb, metaContainer) { var self = this; async.each(valuesObject.associations.models, function(item, next) { @@ -145,6 +145,10 @@ function createBelongsTo(valuesObject, cb) { query = model.create(valuesObject.values[item]); } + if(metaContainer) { + query.meta(metaContainer); + } + query.exec(function(err, val) { if (err) return next(err); @@ -191,7 +195,7 @@ function beforeCallbacks(valuesObject, cb) { * @param {Function} cb */ -function createValues(valuesObject, cb) { +function createValues(valuesObject, cb, metaContainer) { var self = this; var date; @@ -249,5 +253,5 @@ function createValues(valuesObject, cb) { }); } - }); + }, metaContainer); } diff --git a/lib/waterline/query/dql/destroy.js b/lib/waterline/query/dql/destroy.js index f715d6dd0..04562cd08 100644 --- a/lib/waterline/query/dql/destroy.js +++ b/lib/waterline/query/dql/destroy.js @@ -20,7 +20,7 @@ var hasOwnProperty = utils.object.hasOwnProperty; * @return Deferred object if no callback */ -module.exports = function(criteria, cb) { +module.exports = function(criteria, cb, metaContainer) { var self = this; var pk; @@ -110,7 +110,13 @@ module.exports = function(criteria, cb) { if (mappedValues.length > 0) { criteria[refKey] = mappedValues; - collection.destroy(criteria).exec(next); + var q = collection.destroy(criteria); + + if(metaContainer) { + q.meta(metaContainer); + } + + q.exec(next); } else { return next(); } @@ -129,6 +135,6 @@ module.exports = function(criteria, cb) { }); } - }); + }, metaContainer); }); }; diff --git a/lib/waterline/query/dql/join.js b/lib/waterline/query/dql/join.js index 5f58152f0..1ded4fb9b 100644 --- a/lib/waterline/query/dql/join.js +++ b/lib/waterline/query/dql/join.js @@ -5,6 +5,6 @@ * (use optimized join in adapter if one was provided) */ -module.exports = function(collection, fk, pk, cb) { - this._adapter.join(collection, fk, pk, cb); +module.exports = function(collection, fk, pk, cb, metaContainer) { + this._adapter.join(collection, fk, pk, cb, metaContainer); }; diff --git a/lib/waterline/query/dql/update.js b/lib/waterline/query/dql/update.js index 9b09556d3..022d04456 100644 --- a/lib/waterline/query/dql/update.js +++ b/lib/waterline/query/dql/update.js @@ -22,7 +22,7 @@ var hop = utils.object.hasOwnProperty; * @return Deferred object if no callback */ -module.exports = function(criteria, values, cb) { +module.exports = function(criteria, values, cb, metaContainer) { var self = this; @@ -55,9 +55,9 @@ module.exports = function(criteria, values, cb) { beforeCallbacks.call(self, valuesObject.values, function(err) { if (err) return cb(err); - updateRecords.call(self, valuesObject, cb); + updateRecords.call(self, valuesObject, cb, metaContainer); }); - }); + }, metaContainer); }; @@ -102,7 +102,7 @@ function prepareArguments(criteria, values) { * */ -function createBelongsTo(valuesObject, cb) { +function createBelongsTo(valuesObject, cb, metaContainer) { var self = this; async.each(valuesObject.associations.models.slice(0), function(item, next) { @@ -137,6 +137,10 @@ function createBelongsTo(valuesObject, cb) { query = model.create(valuesObject.values[item]); } + if(metaContainer) { + query.meta(metaContainer); + } + query.exec(function(err, val) { if (err) return next(err); @@ -185,7 +189,7 @@ function beforeCallbacks(values, cb) { * @param {Function} cb */ -function updateRecords(valuesObject, cb) { +function updateRecords(valuesObject, cb, metaContainer) { var self = this; // Automatically change updatedAt (if enabled) @@ -235,7 +239,7 @@ function updateRecords(valuesObject, cb) { }); }); - }); + }, metaContainer); } /** diff --git a/lib/waterline/query/finders/basic.js b/lib/waterline/query/finders/basic.js index 9a4424e93..a74a7696a 100644 --- a/lib/waterline/query/finders/basic.js +++ b/lib/waterline/query/finders/basic.js @@ -25,7 +25,7 @@ module.exports = { * @return Deferred object if no callback */ - findOne: function(criteria, cb) { + findOne: function(criteria, cb, metaContainer) { var self = this; if (typeof criteria === 'function') { @@ -83,7 +83,7 @@ module.exports = { } // Build up an operations set - var operations = new Operations(self, criteria, 'findOne'); + var operations = new Operations(self, criteria, 'findOne', metaContainer); // Run the operations operations.run(function(err, values) { @@ -202,20 +202,33 @@ module.exports = { * @return Deferred object if no callback */ - find: function(criteria, options, cb) { + find: function(criteria, options, cb, metaContainer) { var self = this; - var usage = utils.capitalize(this.identity) + '.find([criteria],[options]).exec(callback|switchback)'; if (typeof criteria === 'function') { cb = criteria; criteria = null; - options = null; + + if(arguments.length === 1) { + options = null; + } } + // If options is a function, we want to check for any more values before nulling + // them out or overriding them. if (typeof options === 'function') { - cb = options; - options = null; + + // If cb also exists it means there is a metaContainer value + if (cb) { + metaContainer = cb; + cb = options; + options = null; + } else { + cb = options; + options = null; + } + } // If the criteria is an array of objects, wrap it in an "or" @@ -280,7 +293,7 @@ module.exports = { } // Build up an operations set - var operations = new Operations(self, criteria, 'find'); + var operations = new Operations(self, criteria, 'find', metaContainer); // Run the operations operations.run(function(err, values) { diff --git a/lib/waterline/query/finders/operations.js b/lib/waterline/query/finders/operations.js index 081b67fac..c5cb8803f 100644 --- a/lib/waterline/query/finders/operations.js +++ b/lib/waterline/query/finders/operations.js @@ -16,7 +16,7 @@ var hasOwnProperty = utils.object.hasOwnProperty; * on adapters that haven't implemented the join interface yet. */ -var Operations = module.exports = function(context, criteria, parent) { +var Operations = module.exports = function(context, criteria, parent, metaContainer) { // Build up a cache this.cache = {}; @@ -30,6 +30,8 @@ var Operations = module.exports = function(context, criteria, parent) { // Set parent this.parent = parent; + this.metaContainer = metaContainer; + // Hold a default value for pre-combined results (native joins) this.preCombined = false; @@ -405,7 +407,7 @@ Operations.prototype._runOperation = function _runOperation(collectionName, meth var collection = this.context.waterline.collections[collectionName]; // Run the operation - collection.adapter[method](criteria, cb); + collection.adapter[method](criteria, cb, this.metaContainer); }; diff --git a/lib/waterline/query/stream.js b/lib/waterline/query/stream.js index ce59d31a8..c069fd4d5 100644 --- a/lib/waterline/query/stream.js +++ b/lib/waterline/query/stream.js @@ -16,7 +16,7 @@ module.exports = { * @param {Object} transformation, defaults to JSON */ - stream: function(criteria, transformation) { + stream: function(criteria, transformation, metaContainer) { var self = this; var usage = utils.capitalize(this.identity) + '.stream([criteria],[options])'; @@ -39,7 +39,7 @@ module.exports = { stream.write(); // Trigger Adapter Method - self.adapter.stream(criteria, stream); + self.adapter.stream(criteria, stream, metaContainer); }); return stream;