Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that resolves to the value normally passed to the callback of that method. If a callback is provided, behave normally. This API will use native ES6 promises if available. If not available, or to force the use of another Promise library, you must assign the global.Promise object. e.g.: global.Promise = require('bluebird') Class methods affected: - create - updateOrCreate / upsert - findOrCreate - exists - find - findOne - findById - findByIds - remove / deleteAll / destroyAll - removeById / deleteById / destroyById - count - update / updateAll Prototype methods affected: - save - delete / remove / destroy - updateAttribute - updateAttributes - reload Exceptions / edge cases: - create() used to return the data object that was passed in, even if no callback was provided. Now, if a callback is provided, it will return the data object, otherwise it will return a Promise. - If create() is provided an array of data objects for creation, it will continue to always return the array. This batch creation mode does not support promises. - findOrCreate() has a callback of the form: cb(err, instance, created), with the extra parameter indicating whether the instance was created or not. When called with its promise variant, the resolver will receive a single array parameter: [instance, created]
This commit is contained in:
parent
6891da4535
commit
1e6c453191
220
lib/dao.js
220
lib/dao.js
|
@ -148,7 +148,10 @@ function noCallback(err, result) {
|
|||
* - instance (null or Model)
|
||||
*/
|
||||
DataAccessObject.create = function (data, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
var Model = this;
|
||||
var self = this;
|
||||
|
@ -167,9 +170,9 @@ DataAccessObject.create = function (data, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
data = data || {};
|
||||
options = options || {};
|
||||
cb = cb || (Array.isArray(data) ? noCallback : utils.createPromiseCallback());
|
||||
|
||||
assert(typeof data === 'object', 'The data argument must be an object or array');
|
||||
assert(typeof options === 'object', 'The options argument must be an object');
|
||||
|
@ -276,12 +279,27 @@ DataAccessObject.create = function (data, options, cb) {
|
|||
}, obj, cb);
|
||||
}
|
||||
|
||||
// Does this make any sense? How would chaining be used here? -partap
|
||||
|
||||
// for chaining
|
||||
return obj;
|
||||
return cb.promise || obj;
|
||||
};
|
||||
|
||||
function stillConnecting(dataSource, obj, args) {
|
||||
return dataSource.ready(obj, args);
|
||||
if (typeof args[args.length-1] === 'function') {
|
||||
return dataSource.ready(obj, args);
|
||||
}
|
||||
|
||||
// promise variant
|
||||
var promiseArgs = Array.prototype.slice.call(args);
|
||||
promiseArgs.callee = args.callee
|
||||
var cb = utils.createPromiseCallback();
|
||||
promiseArgs.push(cb);
|
||||
if (dataSource.ready(obj, promiseArgs)) {
|
||||
return cb.promise;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -298,8 +316,9 @@ function stillConnecting(dataSource, obj, args) {
|
|||
// 'upsert' will be used as the name for strong-remoting to keep it backward
|
||||
// compatible for angular SDK
|
||||
DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) {
|
||||
return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
if (options === undefined && cb === undefined) {
|
||||
|
@ -316,7 +335,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
data = data || {};
|
||||
options = options || {};
|
||||
|
||||
|
@ -404,6 +423,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
|
|||
});
|
||||
}
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -418,10 +438,19 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
|
|||
* @param {Function} cb Callback called with (err, instance, created)
|
||||
*/
|
||||
DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
assert(arguments.length >= 2, 'At least two arguments are required');
|
||||
if (options === undefined && cb === undefined) {
|
||||
assert(arguments.length >= 1, 'At least one argument is required');
|
||||
if (data === undefined && options === undefined && cb === undefined) {
|
||||
assert(typeof query === 'object', 'Single argument must be data object');
|
||||
// findOrCreate(data);
|
||||
// query will be built from data, and method will return Promise
|
||||
data = query;
|
||||
query = {where: data};
|
||||
} else if (options === undefined && cb === undefined) {
|
||||
if (typeof data === 'function') {
|
||||
// findOrCreate(data, cb);
|
||||
// query will be built from data
|
||||
|
@ -437,7 +466,7 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
query = query || {where: {}};
|
||||
data = data || {};
|
||||
options = options || {};
|
||||
|
@ -466,11 +495,19 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
|
|||
if (created) {
|
||||
Model.notifyObserversOf('after save', { Model: Model, instance: obj },
|
||||
function(err) {
|
||||
cb(err, obj, created);
|
||||
if (cb.promise) {
|
||||
cb(err, [obj, created]);
|
||||
} else {
|
||||
cb(err, obj, created);
|
||||
}
|
||||
if (!err) Model.emit('changed', obj);
|
||||
});
|
||||
} else {
|
||||
cb(err, obj, created);
|
||||
if (cb.promise) {
|
||||
cb(err, [obj, created]);
|
||||
} else {
|
||||
cb(err, obj, created);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -481,9 +518,10 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
|
|||
try {
|
||||
this._normalize(query);
|
||||
} catch (err) {
|
||||
return process.nextTick(function () {
|
||||
process.nextTick(function () {
|
||||
cb(err);
|
||||
});
|
||||
return cb.promise;
|
||||
}
|
||||
|
||||
this.applyScope(query);
|
||||
|
@ -521,12 +559,23 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
|
|||
} else {
|
||||
Model.findOne(query, options, function (err, record) {
|
||||
if (err) return cb(err);
|
||||
if (record) return cb(null, record, false);
|
||||
if (record) {
|
||||
if (cb.promise) {
|
||||
return cb(null, [record, false]);
|
||||
} else {
|
||||
return cb(null, record, false);
|
||||
}
|
||||
}
|
||||
Model.create(data, options, function (err, record) {
|
||||
cb(err, record, record != null);
|
||||
if (cb.promise) {
|
||||
cb(err, [record, record != null]);
|
||||
} else {
|
||||
cb(err, record, record != null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -537,7 +586,10 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
|
|||
* @param {Function} cb Callback function called with (err, exists: Bool)
|
||||
*/
|
||||
DataAccessObject.exists = function exists(id, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
assert(arguments.length >= 1, 'The id argument is required');
|
||||
if (cb === undefined) {
|
||||
|
@ -548,7 +600,7 @@ DataAccessObject.exists = function exists(id, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
options = options || {};
|
||||
|
||||
assert(typeof options === 'object', 'The options argument must be an object');
|
||||
|
@ -559,10 +611,11 @@ DataAccessObject.exists = function exists(id, options, cb) {
|
|||
cb(err, err ? false : count === 1);
|
||||
});
|
||||
} else {
|
||||
return process.nextTick(function() {
|
||||
process.nextTick(function() {
|
||||
cb(new Error('Model::exists requires the id argument'));
|
||||
});
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -580,7 +633,10 @@ DataAccessObject.exists = function exists(id, options, cb) {
|
|||
* @param {Function} cb Callback called with (err, instance)
|
||||
*/
|
||||
DataAccessObject.findById = function find(id, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
assert(arguments.length >= 1, 'The id argument is required');
|
||||
if (cb === undefined) {
|
||||
|
@ -590,18 +646,20 @@ DataAccessObject.findById = function find(id, options, cb) {
|
|||
options = {};
|
||||
}
|
||||
}
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
options = options || {};
|
||||
|
||||
assert(typeof options === 'object', 'The options argument must be an object');
|
||||
assert(typeof cb === 'function', 'The cb argument must be a function');
|
||||
|
||||
if (id == null || id === '') {
|
||||
return process.nextTick(function() {
|
||||
process.nextTick(function() {
|
||||
cb(new Error('Model::findById requires the id argument'));
|
||||
});
|
||||
} else {
|
||||
this.findOne(byIdQuery(this, id), options, cb);
|
||||
}
|
||||
this.findOne(byIdQuery(this, id), options, cb);
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -626,7 +684,7 @@ DataAccessObject.findByIds = function(ids, query, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
options = options || {};
|
||||
query = query || {};
|
||||
|
||||
|
@ -638,7 +696,7 @@ DataAccessObject.findByIds = function(ids, query, options, cb) {
|
|||
var pk = idName(this);
|
||||
if (ids.length === 0) {
|
||||
process.nextTick(function() { cb(null, []); });
|
||||
return;
|
||||
return cb.promise;;
|
||||
}
|
||||
|
||||
var filter = { where: {} };
|
||||
|
@ -647,6 +705,7 @@ DataAccessObject.findByIds = function(ids, query, options, cb) {
|
|||
this.find(filter, options, function(err, results) {
|
||||
cb(err, err ? results : utils.sortObjectsByIds(pk, ids, results));
|
||||
});
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
function convertNullToNotFoundError(ctx, cb) {
|
||||
|
@ -662,7 +721,7 @@ function convertNullToNotFoundError(ctx, cb) {
|
|||
|
||||
// alias function for backwards compat.
|
||||
DataAccessObject.all = function () {
|
||||
DataAccessObject.find.apply(this, arguments);
|
||||
return DataAccessObject.find.apply(this, arguments);
|
||||
};
|
||||
|
||||
var operators = {
|
||||
|
@ -994,7 +1053,10 @@ DataAccessObject._coerce = function (where) {
|
|||
*/
|
||||
|
||||
DataAccessObject.find = function find(query, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
if (options === undefined && cb === undefined) {
|
||||
if (typeof query === 'function') {
|
||||
|
@ -1010,7 +1072,7 @@ DataAccessObject.find = function find(query, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
query = query || {};
|
||||
options = options || {};
|
||||
|
||||
|
@ -1023,9 +1085,10 @@ DataAccessObject.find = function find(query, options, cb) {
|
|||
try {
|
||||
this._normalize(query);
|
||||
} catch (err) {
|
||||
return process.nextTick(function () {
|
||||
process.nextTick(function () {
|
||||
cb(err);
|
||||
});
|
||||
return cb.promise;
|
||||
}
|
||||
|
||||
this.applyScope(query);
|
||||
|
@ -1073,7 +1136,7 @@ DataAccessObject.find = function find(query, options, cb) {
|
|||
});
|
||||
|
||||
// already handled
|
||||
return;
|
||||
return cb.promise;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1135,6 +1198,7 @@ DataAccessObject.find = function find(query, options, cb) {
|
|||
self.getDataSource().connector.all(self.modelName, query, allCb);
|
||||
});
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1146,7 +1210,10 @@ DataAccessObject.find = function find(query, options, cb) {
|
|||
* @param {Function} cb Callback function called with (err, instance)
|
||||
*/
|
||||
DataAccessObject.findOne = function findOne(query, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
if (options === undefined && cb === undefined) {
|
||||
if (typeof query === 'function') {
|
||||
|
@ -1160,7 +1227,7 @@ DataAccessObject.findOne = function findOne(query, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
query = query || {};
|
||||
options = options || {};
|
||||
|
||||
|
@ -1173,6 +1240,7 @@ DataAccessObject.findOne = function findOne(query, options, cb) {
|
|||
if (err || !collection || !collection.length > 0) return cb(err, null);
|
||||
cb(err, collection[0]);
|
||||
});
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1190,7 +1258,10 @@ DataAccessObject.findOne = function findOne(query, options, cb) {
|
|||
* @param {Function} [cb] Callback called with (err)
|
||||
*/
|
||||
DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyAll = function destroyAll(where, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
var Model = this;
|
||||
|
||||
|
@ -1206,7 +1277,7 @@ DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyA
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
where = where || {};
|
||||
options = options || {};
|
||||
|
||||
|
@ -1267,6 +1338,7 @@ DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyA
|
|||
});
|
||||
}
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
function whereIsEmpty(where) {
|
||||
|
@ -1285,7 +1357,10 @@ function whereIsEmpty(where) {
|
|||
// 'deleteById' will be used as the name for strong-remoting to keep it backward
|
||||
// compatible for angular SDK
|
||||
DataAccessObject.removeById = DataAccessObject.destroyById = DataAccessObject.deleteById = function deleteById(id, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
assert(arguments.length >= 1, 'The id argument is required');
|
||||
if (cb === undefined) {
|
||||
|
@ -1297,15 +1372,16 @@ DataAccessObject.removeById = DataAccessObject.destroyById = DataAccessObject.de
|
|||
}
|
||||
|
||||
options = options || {};
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
|
||||
assert(typeof options === 'object', 'The options argument must be an object');
|
||||
assert(typeof cb === 'function', 'The cb argument must be a function');
|
||||
|
||||
if (id == null || id === '') {
|
||||
return process.nextTick(function() {
|
||||
process.nextTick(function() {
|
||||
cb(new Error('Model::deleteById requires the id argument'));
|
||||
});
|
||||
return cb.promise;
|
||||
}
|
||||
|
||||
var Model = this;
|
||||
|
@ -1316,6 +1392,7 @@ DataAccessObject.removeById = DataAccessObject.destroyById = DataAccessObject.de
|
|||
}
|
||||
if(!err) Model.emit('deleted', id);
|
||||
});
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1333,7 +1410,10 @@ DataAccessObject.removeById = DataAccessObject.destroyById = DataAccessObject.de
|
|||
* @param {Function} cb Callback, called with (err, count)
|
||||
*/
|
||||
DataAccessObject.count = function (where, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
if (options === undefined && cb === undefined) {
|
||||
if (typeof where === 'function') {
|
||||
|
@ -1349,7 +1429,7 @@ DataAccessObject.count = function (where, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
where = where || {};
|
||||
options = options || {};
|
||||
|
||||
|
@ -1365,9 +1445,10 @@ DataAccessObject.count = function (where, options, cb) {
|
|||
where = removeUndefined(where);
|
||||
where = this._coerce(where);
|
||||
} catch (err) {
|
||||
return process.nextTick(function () {
|
||||
process.nextTick(function () {
|
||||
cb(err);
|
||||
});
|
||||
return cb.promise;
|
||||
}
|
||||
|
||||
var Model = this;
|
||||
|
@ -1376,6 +1457,7 @@ DataAccessObject.count = function (where, options, cb) {
|
|||
where = ctx.query.where;
|
||||
Model.getDataSource().connector.count(Model.modelName, cb, where);
|
||||
});
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1387,7 +1469,10 @@ DataAccessObject.count = function (where, options, cb) {
|
|||
* @param {Function} cb Callback function with err and object arguments
|
||||
*/
|
||||
DataAccessObject.prototype.save = function (options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
var Model = this.constructor;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
|
@ -1395,7 +1480,7 @@ DataAccessObject.prototype.save = function (options, cb) {
|
|||
options = {};
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
options = options || {};
|
||||
|
||||
assert(typeof options === 'object', 'The options argument should be an object');
|
||||
|
@ -1466,6 +1551,7 @@ DataAccessObject.prototype.save = function (options, cb) {
|
|||
}, data, cb);
|
||||
}
|
||||
});
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1486,27 +1572,39 @@ DataAccessObject.prototype.save = function (options, cb) {
|
|||
*/
|
||||
DataAccessObject.update =
|
||||
DataAccessObject.updateAll = function (where, data, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
assert(arguments.length >= 2, 'At least two arguments are required');
|
||||
if (options === undefined && cb === undefined) {
|
||||
assert(arguments.length >= 1, 'At least one argument is required');
|
||||
|
||||
if (data === undefined && options === undefined && cb === undefined && arguments.length === 1) {
|
||||
data = where;
|
||||
where = {};
|
||||
} else if (options === undefined && cb === undefined) {
|
||||
// One of:
|
||||
// updateAll(data, cb)
|
||||
// updateAll(where, data) -> Promise
|
||||
if (typeof data === 'function') {
|
||||
// updateAll(data, cb);
|
||||
cb = data;
|
||||
data = where;
|
||||
where = {};
|
||||
}
|
||||
|
||||
} else if (cb === undefined) {
|
||||
// One of:
|
||||
// updateAll(where, data, options) -> Promise
|
||||
// updateAll(where, data, cb)
|
||||
if (typeof options === 'function') {
|
||||
// updateAll(query, data, cb)
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
data = data || {};
|
||||
options = options || {};
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
|
||||
assert(typeof where === 'object', 'The where argument must be an object');
|
||||
assert(typeof data === 'object', 'The data argument must be an object');
|
||||
|
@ -1564,6 +1662,7 @@ DataAccessObject.updateAll = function (where, data, options, cb) {
|
|||
});
|
||||
});
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
DataAccessObject.prototype.isNewRecord = function () {
|
||||
|
@ -1589,14 +1688,17 @@ DataAccessObject.prototype._adapter = function () {
|
|||
DataAccessObject.prototype.remove =
|
||||
DataAccessObject.prototype.delete =
|
||||
DataAccessObject.prototype.destroy = function (options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
if (cb === undefined && typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
options = options || {};
|
||||
|
||||
assert(typeof options === 'object', 'The options argument should be an object');
|
||||
|
@ -1650,6 +1752,7 @@ DataAccessObject.prototype.remove =
|
|||
});
|
||||
}, null, cb);
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1674,7 +1777,7 @@ DataAccessObject.prototype.setAttribute = function setAttribute(name, value) {
|
|||
DataAccessObject.prototype.updateAttribute = function updateAttribute(name, value, cb) {
|
||||
var data = {};
|
||||
data[name] = value;
|
||||
this.updateAttributes(data, cb);
|
||||
return this.updateAttributes(data, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1718,7 +1821,10 @@ DataAccessObject.prototype.unsetAttribute = function unsetAttribute(name, nullif
|
|||
* @param {Function} cb Callback function called with (err, instance)
|
||||
*/
|
||||
DataAccessObject.prototype.updateAttributes = function updateAttributes(data, options, cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
if (options === undefined && cb === undefined) {
|
||||
if (typeof data === 'function') {
|
||||
|
@ -1734,7 +1840,7 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
|
|||
}
|
||||
}
|
||||
|
||||
cb = cb || noCallback;
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
options = options || {};
|
||||
|
||||
assert((typeof data === 'object') && (data !== null),
|
||||
|
@ -1803,6 +1909,7 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
|
|||
}, data, cb);
|
||||
}, data);
|
||||
});
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1812,11 +1919,12 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
|
|||
* @private
|
||||
*/
|
||||
DataAccessObject.prototype.reload = function reload(cb) {
|
||||
if (stillConnecting(this.getDataSource(), this, arguments)) {
|
||||
return;
|
||||
var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
this.constructor.findById(getIdValue(this.constructor, this), cb);
|
||||
return this.constructor.findById(getIdValue(this.constructor, this), cb);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -59,6 +59,21 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should create instance (promise variant)', function (done) {
|
||||
Person.create({name: 'Anatoliy'})
|
||||
.then (function (p) {
|
||||
p.name.should.equal('Anatoliy');
|
||||
should.exist(p);
|
||||
return Person.findById(p.id)
|
||||
.then (function (person) {
|
||||
person.id.should.eql(p.id);
|
||||
person.name.should.equal('Anatoliy');
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should instantiate an object', function (done) {
|
||||
var p = new Person({name: 'Anatoliy'});
|
||||
p.name.should.equal('Anatoliy');
|
||||
|
@ -71,6 +86,20 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should instantiate an object (promise variant)', function (done) {
|
||||
var p = new Person({name: 'Anatoliy'});
|
||||
p.name.should.equal('Anatoliy');
|
||||
p.isNewRecord().should.be.true;
|
||||
p.save()
|
||||
.then (function(inst) {
|
||||
inst.isNewRecord().should.be.false;
|
||||
inst.should.equal(p);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
|
||||
});
|
||||
|
||||
it('should return instance of object', function (done) {
|
||||
var person = Person.create(function (err, p) {
|
||||
p.id.should.eql(person.id);
|
||||
|
@ -93,6 +122,19 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should not allow user-defined value for the id of object - create (promise variant)', function (done) {
|
||||
Person.create({id: 123456})
|
||||
.then (function (p) {
|
||||
done(new Error('Person.create should have failed.'));
|
||||
}, function (err) {
|
||||
err.should.be.instanceof(ValidationError);
|
||||
err.statusCode.should.equal(422);
|
||||
err.details.messages.id.should.eql(['can\'t be set']);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should not allow user-defined value for the id of object - save', function (done) {
|
||||
var p = new Person({id: 123456});
|
||||
p.isNewRecord().should.be.true;
|
||||
|
@ -106,6 +148,21 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should not allow user-defined value for the id of object - save (promise variant)', function (done) {
|
||||
var p = new Person({id: 123456});
|
||||
p.isNewRecord().should.be.true;
|
||||
p.save()
|
||||
.then (function(inst) {
|
||||
done(new Error('save should have failed.'));
|
||||
}, function (err) {
|
||||
err.should.be.instanceof(ValidationError);
|
||||
err.statusCode.should.equal(422);
|
||||
err.details.messages.id.should.eql(['can\'t be set']);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should work when called without callback', function (done) {
|
||||
Person.afterCreate = function (next) {
|
||||
this.should.be.an.instanceOf(Person);
|
||||
|
@ -131,6 +188,20 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should create instance with blank data (promise variant)', function (done) {
|
||||
Person.create()
|
||||
.then (function (p) {
|
||||
should.exist(p);
|
||||
should.not.exists(p.name);
|
||||
return Person.findById(p.id)
|
||||
.then (function (person) {
|
||||
person.id.should.eql(p.id);
|
||||
should.not.exists(person.name);
|
||||
done();
|
||||
});
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should work when called with no data and callback', function (done) {
|
||||
Person.afterCreate = function (next) {
|
||||
this.should.be.an.instanceOf(Person);
|
||||
|
@ -219,6 +290,7 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('save', function () {
|
||||
|
@ -232,6 +304,16 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should save new object (promise variant)', function (done) {
|
||||
var p = new Person;
|
||||
p.save()
|
||||
.then(function () {
|
||||
should.exist(p.id);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should save existing object', function (done) {
|
||||
Person.findOne(function (err, p) {
|
||||
should.not.exist(err);
|
||||
|
@ -247,6 +329,22 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should save existing object (promise variant)', function (done) {
|
||||
Person.findOne()
|
||||
.then(function (p) {
|
||||
p.name = 'Fritz';
|
||||
return p.save()
|
||||
.then(function () {
|
||||
return Person.findOne()
|
||||
.then(function (p) {
|
||||
p.name.should.equal('Fritz');
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should save invalid object (skipping validation)', function (done) {
|
||||
Person.findOne(function (err, p) {
|
||||
should.not.exist(err);
|
||||
|
@ -265,6 +363,29 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should save invalid object (skipping validation - promise variant)', function (done) {
|
||||
Person.findOne()
|
||||
.then(function (p) {
|
||||
p.isValid = function (done) {
|
||||
process.nextTick(done);
|
||||
return false;
|
||||
};
|
||||
p.name = 'Nana';
|
||||
return p.save()
|
||||
.then(function (d) {
|
||||
done(new Error('save should have failed.'));
|
||||
}, function (err) {
|
||||
should.exist(err);
|
||||
p.save({validate: false})
|
||||
.then(function (d) {
|
||||
should.exist(d);
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should save throw error on validation', function () {
|
||||
Person.findOne(function (err, p) {
|
||||
should.not.exist(err);
|
||||
|
@ -312,7 +433,7 @@ describe('manipulation', function () {
|
|||
person.updateAttribute('name', 'Paul Graham', function (err, p) {
|
||||
should.not.exist(err);
|
||||
Person.all(function (e, ps) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(e);
|
||||
ps.should.have.lengthOf(1);
|
||||
ps.pop().name.should.equal('Paul Graham');
|
||||
done();
|
||||
|
@ -320,12 +441,24 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should update one attribute (promise variant)', function (done) {
|
||||
person.updateAttribute('name', 'Teddy Graham')
|
||||
.then(function (p) {
|
||||
return Person.all()
|
||||
.then(function (ps) {
|
||||
ps.should.have.lengthOf(1);
|
||||
ps.pop().name.should.equal('Teddy Graham');
|
||||
done();
|
||||
});
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should ignore undefined values on updateAttributes', function(done) {
|
||||
person.updateAttributes({'name': 'John', age: undefined},
|
||||
function(err, p) {
|
||||
should.not.exist(err);
|
||||
Person.findById(p.id, function(e, p) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(e);
|
||||
p.name.should.equal('John');
|
||||
p.age.should.equal(15);
|
||||
done();
|
||||
|
@ -338,7 +471,7 @@ describe('manipulation', function () {
|
|||
function(err, p) {
|
||||
should.not.exist(err);
|
||||
Person.findById(p.id, function(e, p) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(e);
|
||||
p.name.should.equal('John');
|
||||
p.age.should.equal(15);
|
||||
done();
|
||||
|
@ -346,6 +479,19 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allows model instance on updateAttributes (promise variant)', function(done) {
|
||||
person.updateAttributes(new Person({'name': 'Jane', age: undefined}))
|
||||
.then(function(p) {
|
||||
return Person.findById(p.id)
|
||||
.then(function(p) {
|
||||
p.name.should.equal('Jane');
|
||||
p.age.should.equal(15);
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('updateOrCreate', function() {
|
||||
|
@ -404,6 +550,71 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('findOrCreate', function() {
|
||||
it('should create a record with if new', function(done) {
|
||||
Person.findOrCreate({ name: 'Zed', gender: 'male' },
|
||||
function(err, p, created) {
|
||||
if (err) return done(err);
|
||||
should.exist(p);
|
||||
p.should.be.instanceOf(Person);
|
||||
p.name.should.equal('Zed');
|
||||
p.gender.should.equal('male');
|
||||
created.should.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should find a record if exists', function(done) {
|
||||
Person.findOrCreate(
|
||||
{where: {name: 'Zed'}},
|
||||
{name: 'Zed', gender: 'male'},
|
||||
function(err, p, created) {
|
||||
if (err) return done(err);
|
||||
should.exist(p);
|
||||
p.should.be.instanceOf(Person);
|
||||
p.name.should.equal('Zed');
|
||||
p.gender.should.equal('male');
|
||||
created.should.equal(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a record with if new (promise variant)', function(done) {
|
||||
Person.findOrCreate({ name: 'Jed', gender: 'male' })
|
||||
.then(function(res) {
|
||||
should.exist(res);
|
||||
res.should.be.instanceOf(Array);
|
||||
res.should.have.lengthOf(2);
|
||||
var p = res[0];
|
||||
var created = res[1];
|
||||
p.should.be.instanceOf(Person);
|
||||
p.name.should.equal('Jed');
|
||||
p.gender.should.equal('male');
|
||||
created.should.equal(true);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should find a record if exists (promise variant)', function(done) {
|
||||
Person.findOrCreate(
|
||||
{where: {name: 'Jed'}},
|
||||
{name: 'Jed', gender: 'male'})
|
||||
.then(function(res) {
|
||||
res.should.be.instanceOf(Array);
|
||||
res.should.have.lengthOf(2);
|
||||
var p = res[0];
|
||||
var created = res[1];
|
||||
p.should.be.instanceOf(Person);
|
||||
p.name.should.equal('Jed');
|
||||
p.gender.should.equal('male');
|
||||
created.should.equal(false);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('destroy', function () {
|
||||
|
||||
it('should destroy record', function (done) {
|
||||
|
@ -418,6 +629,21 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should destroy record (promise variant)', function (done) {
|
||||
Person.create()
|
||||
.then(function (p) {
|
||||
return p.destroy()
|
||||
.then(function () {
|
||||
return Person.exists(p.id)
|
||||
.then(function (ex) {
|
||||
ex.should.not.be.ok;
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should destroy all records', function (done) {
|
||||
Person.destroyAll(function (err) {
|
||||
should.not.exist(err);
|
||||
|
@ -431,6 +657,26 @@ describe('manipulation', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should destroy all records (promise variant)', function (done) {
|
||||
Person.create()
|
||||
.then(function() {
|
||||
return Person.destroyAll()
|
||||
.then(function () {
|
||||
return Person.all()
|
||||
.then(function (ps) {
|
||||
ps.should.have.lengthOf(0);
|
||||
return Person.count()
|
||||
.then(function (count) {
|
||||
count.should.eql(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(done);
|
||||
|
||||
});
|
||||
|
||||
// TODO: implement destroy with filtered set
|
||||
it('should destroy filtered set of records');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue