不要怂,就是干,撸起袖子干!

Commit d8c32ff4 by Mick Hansen

feat(promises): more refactoring

1 parent f10c6929
Notice: All 1.7.x changes are present in 2.0.x aswell Notice: All 1.7.x changes are present in 2.0.x aswell
# next
#### Breaking changes
- Sequelize now returns promises instead of its custom event emitter from most calls. This affects methods that return multiple values (like `findOrCreate` or `findOrInitialize`). If your current callbacks do not accept the 2nd success parameter you might be seeing an array as the first param. Either use `.spread()` for these methods or add another argument to your callback: `.success(instance)` -> `.success(instance, created)`.
- `.success()`/`.done()` and any other non promise methods are now deprecated (we will keep the codebase around for a few versions though). on('sql') persists for debugging purposes.
# v2.0.0-dev11 # v2.0.0-dev11
### Caution: This release contains many changes and is highly experimental ### Caution: This release contains many changes and is highly experimental
- [PERFORMANCE] increased build performance when using include, which speeds up findAll etc. - [PERFORMANCE] increased build performance when using include, which speeds up findAll etc.
......
...@@ -113,15 +113,9 @@ module.exports = (function() { ...@@ -113,15 +113,9 @@ module.exports = (function() {
options.transaction = fieldsOrOptions.transaction options.transaction = fieldsOrOptions.transaction
} }
return new Utils.CustomEventEmitter(function(emitter) { return association.target.create(values, fieldsOrOptions).then(function(newAssociatedObject) {
association.target return instance[association.accessors.set](newAssociatedObject, options)
.create(values, fieldsOrOptions) })
.proxy(emitter, { events: ['error', 'sql'] })
.success(function(newAssociatedObject) {
instance[association.accessors.set](newAssociatedObject, options)
.proxy(emitter)
})
}).run()
} }
return this return this
......
...@@ -330,7 +330,7 @@ module.exports = (function() { ...@@ -330,7 +330,7 @@ module.exports = (function() {
/** /**
* Sync this DAOFactory to the DB, that is create the table. Upon success, the callback will be called with the model instance (this) * Sync this DAOFactory to the DB, that is create the table. Upon success, the callback will be called with the model instance (this)
* @see {Sequelize#sync} for options * @see {Sequelize#sync} for options
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.sync = function(options) { DAOFactory.prototype.sync = function(options) {
options = Utils._.extend({}, this.options, options || {}) options = Utils._.extend({}, this.options, options || {})
...@@ -353,7 +353,7 @@ module.exports = (function() { ...@@ -353,7 +353,7 @@ module.exports = (function() {
* Drop the table represented by this Model * Drop the table represented by this Model
* @param {Object} [options] * @param {Object} [options]
* @param {Boolean} [options.cascade=false] Also drop all objects depending on this table, such as views. Only works in postgres * @param {Boolean} [options.cascade=false] Also drop all objects depending on this table, such as views. Only works in postgres
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.drop = function(options) { DAOFactory.prototype.drop = function(options) {
return this.QueryInterface.dropTable(this.getTableName(), options) return this.QueryInterface.dropTable(this.getTableName(), options)
...@@ -593,7 +593,7 @@ module.exports = (function() { ...@@ -593,7 +593,7 @@ module.exports = (function() {
* @param {Transaction} [queryOptions.transaction] * @param {Transaction} [queryOptions.transaction]
* *
* @see {Sequelize#query} * @see {Sequelize#query}
* @return {EventEmitter} * @return {Promise}
* @alias all * @alias all
*/ */
DAOFactory.prototype.findAll = function(options, queryOptions) { DAOFactory.prototype.findAll = function(options, queryOptions) {
...@@ -649,7 +649,7 @@ module.exports = (function() { ...@@ -649,7 +649,7 @@ module.exports = (function() {
* @param {Object} [queryOptions] * @param {Object} [queryOptions]
* *
* @see {DAOFactory#findAll} for an explanation of options and queryOptions * @see {DAOFactory#findAll} for an explanation of options and queryOptions
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.find = function(options, queryOptions) { DAOFactory.prototype.find = function(options, queryOptions) {
var hasJoin = false var hasJoin = false
...@@ -657,9 +657,7 @@ module.exports = (function() { ...@@ -657,9 +657,7 @@ module.exports = (function() {
// no options defined? // no options defined?
// return an emitter which emits null // return an emitter which emits null
if ([null, undefined].indexOf(options) !== -1) { if ([null, undefined].indexOf(options) !== -1) {
return new Utils.CustomEventEmitter(function(emitter) { return Utils.Promise.resolve(null)
setTimeout(function() { emitter.emit('success', null) }, 10)
}).run()
} }
var primaryKeys = this.primaryKeys var primaryKeys = this.primaryKeys
...@@ -742,7 +740,7 @@ module.exports = (function() { ...@@ -742,7 +740,7 @@ module.exports = (function() {
* @param {Object} [options] Query options. See sequelize.query for full options * @param {Object} [options] Query options. See sequelize.query for full options
* @param {DataType|String} [options.dataType] The type of the result. If field is a field in the DAO, the default will be the type of that field, otherwise defaults to float. * @param {DataType|String} [options.dataType] The type of the result. If field is a field in the DAO, the default will be the type of that field, otherwise defaults to float.
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.aggregate = function(field, aggregateFunction, options) { DAOFactory.prototype.aggregate = function(field, aggregateFunction, options) {
var tableField; var tableField;
...@@ -773,23 +771,24 @@ module.exports = (function() { ...@@ -773,23 +771,24 @@ module.exports = (function() {
DAOFactory.prototype.count = function(options) { DAOFactory.prototype.count = function(options) {
options = Utils._.clone(options || {}) options = Utils._.clone(options || {})
return new Utils.CustomEventEmitter(function (emitter) { var col = this.sequelize.col('*')
var col = this.sequelize.col('*') if (options.include) {
if (options.include) { col = this.sequelize.col(this.name+'.'+(this.primaryKeyAttribute))
col = this.sequelize.col(this.name+'.'+(this.primaryKeyAttribute)) }
}
options.attributes = [ options.attributes = [
[this.sequelize.fn('COUNT', col), 'count'] [this.sequelize.fn('COUNT', col), 'count']
] ]
options.includeIgnoreAttributes = false options.includeIgnoreAttributes = false
options.limit = null options.limit = null
this.find(options, {raw: true, transaction: options.transaction}).proxy(emitter, {events: ['sql', 'error']}).success(function (result) { return this.find(options, {
emitter.emit('success', parseInt(result.count, 10)) raw: true,
}) transaction: options.transaction
}.bind(this)).run() }).then(function (result) {
return parseInt(result.count, 10)
})
} }
/** /**
...@@ -809,38 +808,27 @@ module.exports = (function() { ...@@ -809,38 +808,27 @@ module.exports = (function() {
* @param {Object} [queryOptions] See Sequelize.query * @param {Object} [queryOptions] See Sequelize.query
* *
* @see {DAOFactory#findAll} for a specification of find and query options * @see {DAOFactory#findAll} for a specification of find and query options
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.findAndCountAll = function(findOptions, queryOptions) { DAOFactory.prototype.findAndCountAll = function(findOptions, queryOptions) {
var self = this var self = this
// no limit, offset, order, attributes for the options given to count() // no limit, offset, order, attributes for the options given to count()
, countOptions = Utils._.omit(findOptions ? Utils._.merge({}, findOptions) : {}, ['offset', 'limit', 'order', 'attributes']) , countOptions = Utils._.omit(findOptions ? Utils._.merge({}, findOptions) : {}, ['offset', 'limit', 'order', 'attributes'])
return new Utils.CustomEventEmitter(function (emitter) { return self.count(countOptions).then(function (count) {
var emit = { if (count === 0) {
okay : function(count, results) { // emit success return {
emitter.emit('success', { count: count || 0,
count: count || 0, rows: []
rows : (results && Array.isArray(results) ? results : [])
})
} }
} }
return self.findAll(findOptions, queryOptions).then(function (results) {
self.count(countOptions) return {
.proxy(emitter, {events: ['sql', 'error']}) count: count || 0,
.success(function(count) { rows: (results && Array.isArray(results) ? results : [])
if (count === 0) { }
return emit.okay(count) // no records, no need for another query })
} })
self.findAll(findOptions, queryOptions)
.proxy(emitter, {events: ['sql', 'error']})
.success(function(results) {
emit.okay(count, results)
})
})
}).run()
} }
/** /**
...@@ -850,7 +838,7 @@ module.exports = (function() { ...@@ -850,7 +838,7 @@ module.exports = (function() {
* @param {Object} [options] See aggregate * @param {Object} [options] See aggregate
* @see {DAOFactory#aggregate} for options * @see {DAOFactory#aggregate} for options
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.max = function(field, options) { DAOFactory.prototype.max = function(field, options) {
return this.aggregate(field, 'max', options) return this.aggregate(field, 'max', options)
...@@ -863,7 +851,7 @@ module.exports = (function() { ...@@ -863,7 +851,7 @@ module.exports = (function() {
* @param {Object} [options] See aggregate * @param {Object} [options] See aggregate
* @see {DAOFactory#aggregate} for options * @see {DAOFactory#aggregate} for options
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.min = function(field, options) { DAOFactory.prototype.min = function(field, options) {
return this.aggregate(field, 'min', options) return this.aggregate(field, 'min', options)
...@@ -876,7 +864,7 @@ module.exports = (function() { ...@@ -876,7 +864,7 @@ module.exports = (function() {
* @param {Object} [options] See aggregate * @param {Object} [options] See aggregate
* @see {DAOFactory#aggregate} for options * @see {DAOFactory#aggregate} for options
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.sum = function(field, options) { DAOFactory.prototype.sum = function(field, options) {
return this.aggregate(field, 'sum', options) return this.aggregate(field, 'sum', options)
...@@ -947,7 +935,7 @@ module.exports = (function() { ...@@ -947,7 +935,7 @@ module.exports = (function() {
* @param {Array} [options.include] an array of include options - Used to build prefetched/included model instances * @param {Array} [options.include] an array of include options - Used to build prefetched/included model instances
* @param {Transaction} [options.transaction] * @param {Transaction} [options.transaction]
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.create = function(values, options) { DAOFactory.prototype.create = function(values, options) {
Utils.validateParameter(values, Object, { optional: true }) Utils.validateParameter(values, Object, { optional: true })
...@@ -975,7 +963,7 @@ module.exports = (function() { ...@@ -975,7 +963,7 @@ module.exports = (function() {
* @param {Object} [options] Options passed to the find call * @param {Object} [options] Options passed to the find call
* @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API * @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API
* *
* @return {EventEmitter} * @return {Promise}
* @alias findOrBuild * @alias findOrBuild
*/ */
DAOFactory.prototype.findOrInitialize = DAOFactory.prototype.findOrBuild = function (params, defaults, options) { DAOFactory.prototype.findOrInitialize = DAOFactory.prototype.findOrBuild = function (params, defaults, options) {
...@@ -991,32 +979,25 @@ module.exports = (function() { ...@@ -991,32 +979,25 @@ module.exports = (function() {
delete defaults.transaction delete defaults.transaction
} }
return new Utils.CustomEventEmitter(function (emitter) { return self.find({
self.find({ where: params
where: params }, options).then(function (instance) {
}, options).success(function (instance) { if (instance === null) {
if (instance === null) { var i = 0
var i = 0
for (i = 0; i < defaultLength; i++) { for (i = 0; i < defaultLength; i++) {
params[defaultKeys[i]] = defaults[defaultKeys[i]] params[defaultKeys[i]] = defaults[defaultKeys[i]]
} }
var build = self.build(params) var build = self.build(params)
build.hookValidate({skip: Object.keys(params)}).success(function (instance) { return build.hookValidate({skip: Object.keys(params)}).then(function () {
emitter.emit('success', build, true) return Utils.Promise.resolve([build, true])
}) })
.error(function (error) { }
emitter.emit('error', error)
}) return Utils.Promise.resolve([instance, false])
} else { })
emitter.emit('success', instance, false)
}
}).error(function (error) {
emitter.emit('error', error)
})
}).run()
} }
/** /**
...@@ -1027,7 +1008,7 @@ module.exports = (function() { ...@@ -1027,7 +1008,7 @@ module.exports = (function() {
* @param {Object} [options] Options passed to the find and create calls * @param {Object} [options] Options passed to the find and create calls
* @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API * @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.findOrCreate = function (where, defaults, options) { DAOFactory.prototype.findOrCreate = function (where, defaults, options) {
var self = this var self = this
...@@ -1043,32 +1024,23 @@ module.exports = (function() { ...@@ -1043,32 +1024,23 @@ module.exports = (function() {
} }
} }
return new Utils.CustomEventEmitter(function (emitter) { return self.find({
self.find({ where: where
where: where }, {
}, { transaction: options.transaction
transaction: options.transaction }).then(function (instance) {
}).success(function (instance) { if (instance === null) {
if (instance === null) { for (var attrname in defaults) {
for (var attrname in defaults) { values[attrname] = defaults[attrname]
values[attrname] = defaults[attrname]
}
self
.create(values, options)
.success(function (instance) {
emitter.emit('success', instance, true)
})
.error( function (error) {
emitter.emit('error', error)
})
} else {
emitter.emit('success', instance, false)
} }
}).error(function (error) {
emitter.emit('error', error) return self.create(values, options).then(function (instance) {
}); return Utils.Promise.resolve([instance, true])
}).run() });
}
return Utils.Promise.resolve([instance, false])
})
} }
/** /**
...@@ -1084,16 +1056,16 @@ module.exports = (function() { ...@@ -1084,16 +1056,16 @@ module.exports = (function() {
* @param {Boolean} [options.hooks=false] Run before / after bulkCreate hooks? * @param {Boolean} [options.hooks=false] Run before / after bulkCreate hooks?
* @param {Boolean} [options.ignoreDuplicates=false] Ignore duplicate values for primary keys? (not supported by postgres) * @param {Boolean} [options.ignoreDuplicates=false] Ignore duplicate values for primary keys? (not supported by postgres)
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.bulkCreate = function(records, fieldsOrOptions, options) { DAOFactory.prototype.bulkCreate = function(records, fieldsOrOptions, options) {
Utils.validateParameter(fieldsOrOptions, Object, { deprecated: Array, optional: true, index: 2, method: 'DAOFactory#bulkCreate' }) Utils.validateParameter(fieldsOrOptions, Object, { deprecated: Array, optional: true, index: 2, method: 'DAOFactory#bulkCreate' })
Utils.validateParameter(options, 'undefined', { deprecated: Object, optional: true, index: 3, method: 'DAOFactory#bulkCreate' }) Utils.validateParameter(options, 'undefined', { deprecated: Object, optional: true, index: 3, method: 'DAOFactory#bulkCreate' })
if (!records.length) { if (!records.length) {
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.Promise(function(resolve) {
emitter.emit('success', []) resolve([])
}).run(); })
} }
options = Utils._.extend({ options = Utils._.extend({
...@@ -1110,9 +1082,9 @@ module.exports = (function() { ...@@ -1110,9 +1082,9 @@ module.exports = (function() {
} }
if(this.daoFactoryManager.sequelize.options.dialect === 'postgres' && options.ignoreDuplicates ) { if(this.daoFactoryManager.sequelize.options.dialect === 'postgres' && options.ignoreDuplicates ) {
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.Promise(function(resolve, reject) {
emitter.emit('error', new Error('Postgres does not support the \'ignoreDuplicates\' option.')) reject(new Error('Postgres does not support the \'ignoreDuplicates\' option.'))
}).run(); });
} }
var self = this var self = this
...@@ -1269,7 +1241,7 @@ module.exports = (function() { ...@@ -1269,7 +1241,7 @@ module.exports = (function() {
* @param {Number} [options.limit] How many rows to delete * @param {Number} [options.limit] How many rows to delete
* @param {Boolean} [options.truncate] If set to true, dialects that support it will use TRUNCATE instead of DELETE FROM. If a table is truncated the where and limit options are ignored * @param {Boolean} [options.truncate] If set to true, dialects that support it will use TRUNCATE instead of DELETE FROM. If a table is truncated the where and limit options are ignored
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAOFactory.prototype.destroy = function(where, options) { DAOFactory.prototype.destroy = function(where, options) {
options = options || {} options = options || {}
......
...@@ -400,7 +400,7 @@ module.exports = (function() { ...@@ -400,7 +400,7 @@ module.exports = (function() {
* @param {Object} [options.fields] An alternative way of setting which fields should be persisted * @param {Object} [options.fields] An alternative way of setting which fields should be persisted
* @param {Transaction} [options.transaction] * @param {Transaction} [options.transaction]
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAO.prototype.save = function(fieldsOrOptions, options) { DAO.prototype.save = function(fieldsOrOptions, options) {
if (fieldsOrOptions instanceof Array) { if (fieldsOrOptions instanceof Array) {
...@@ -585,7 +585,7 @@ module.exports = (function() { ...@@ -585,7 +585,7 @@ module.exports = (function() {
* @param {Array} [options.skip] An array of strings. All properties that are in this array will not be validated * @param {Array} [options.skip] An array of strings. All properties that are in this array will not be validated
* @see {DAOValidator} * @see {DAOValidator}
* *
* @return {EventEmitter} * @return {Promise}
*/ */
DAO.prototype.validate = function(options) { DAO.prototype.validate = function(options) {
return new DaoValidator(this, options).validate() return new DaoValidator(this, options).validate()
......
...@@ -139,7 +139,7 @@ SequelizePromise.prototype.emit = function(evt) { ...@@ -139,7 +139,7 @@ SequelizePromise.prototype.emit = function(evt) {
if (evt === 'success') { if (evt === 'success') {
this.seqResolve.apply(this, args); this.seqResolve.apply(this, args);
} else if (evt === 'error') {; } else if (evt === 'error') {
this.seqReject.apply(this, args); this.seqReject.apply(this, args);
} else { } else {
// Needed to transfer sql across .then() calls // Needed to transfer sql across .then() calls
...@@ -170,7 +170,11 @@ SequelizePromise.prototype.emit = function(evt) { ...@@ -170,7 +170,11 @@ SequelizePromise.prototype.emit = function(evt) {
SequelizePromise.prototype.success = SequelizePromise.prototype.success =
SequelizePromise.prototype.ok = function(fct) { SequelizePromise.prototype.ok = function(fct) {
return this.then(fct); if (fct.length > 1) {
return this.spread(fct);
} else {
return this.then(fct);
}
} }
/** /**
......
...@@ -569,9 +569,9 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -569,9 +569,9 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
sequelize.transaction(function(t) { sequelize.transaction(function(t) {
User.create({ username: 'foo' }, { transaction: t }).success(function() { User.create({ username: 'foo' }, { transaction: t }).success(function() {
User.findOrInitialize({ username: 'foo' }).success(function(user1) { User.findOrInitialize({ username: 'foo' }).spread(function(user1) {
User.findOrInitialize({ username: 'foo' }, { transaction: t }).success(function(user2) { User.findOrInitialize({ username: 'foo' }, { transaction: t }).spread(function(user2) {
User.findOrInitialize({ username: 'foo' }, { foo: 'asd' }, { transaction: t }).success(function(user3) { User.findOrInitialize({ username: 'foo' }, { foo: 'asd' }, { transaction: t }).spread(function(user3) {
expect(user1.isNewRecord).to.be.true expect(user1.isNewRecord).to.be.true
expect(user2.isNewRecord).to.be.false expect(user2.isNewRecord).to.be.false
expect(user3.isNewRecord).to.be.false expect(user3.isNewRecord).to.be.false
...@@ -592,7 +592,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -592,7 +592,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
this.User.create({ username: 'Username' }).success(function (user) { this.User.create({ username: 'Username' }).success(function (user) {
self.User.findOrInitialize({ self.User.findOrInitialize({
username: user.username username: user.username
}).success(function (_user, initialized) { }).spread(function (_user, initialized) {
expect(_user.id).to.equal(user.id) expect(_user.id).to.equal(user.id)
expect(_user.username).to.equal('Username') expect(_user.username).to.equal('Username')
expect(initialized).to.be.false expect(initialized).to.be.false
...@@ -608,7 +608,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -608,7 +608,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
self.User.findOrInitialize({ self.User.findOrInitialize({
username: user.username, username: user.username,
data: user.data data: user.data
}).success(function (_user, initialized) { }).spread(function (_user, initialized) {
expect(_user.id).to.equal(user.id) expect(_user.id).to.equal(user.id)
expect(_user.username).to.equal('Username') expect(_user.username).to.equal('Username')
expect(_user.data).to.equal('data') expect(_user.data).to.equal('data')
...@@ -626,7 +626,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -626,7 +626,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
data: 'ThisIsData' data: 'ThisIsData'
} }
this.User.findOrInitialize(data, default_values).success(function(user, initialized) { this.User.findOrInitialize(data, default_values).spread(function(user, initialized) {
expect(user.id).to.be.null expect(user.id).to.be.null
expect(user.username).to.equal('Username') expect(user.username).to.equal('Username')
expect(user.data).to.equal('ThisIsData') expect(user.data).to.equal('ThisIsData')
......
...@@ -67,7 +67,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -67,7 +67,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
this.User.create(data).success(function (user) { this.User.create(data).success(function (user) {
self.User.findOrCreate({ self.User.findOrCreate({
username: user.username username: user.username
}).success(function (_user, created) { }).spread(function (_user, created) {
expect(_user.id).to.equal(user.id) expect(_user.id).to.equal(user.id)
expect(_user.username).to.equal('Username') expect(_user.username).to.equal('Username')
expect(created).to.be.false expect(created).to.be.false
......
...@@ -245,7 +245,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -245,7 +245,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
it("should have no problem performing findOrCreate", function(done) { it("should have no problem performing findOrCreate", function(done) {
this.ScopeMe.findOrCreate({username: 'fake'}).success(function(user) { this.ScopeMe.findOrCreate({username: 'fake'}).spread(function(user) {
expect(user.username).to.equal('fake') expect(user.username).to.equal('fake')
done() done()
}) })
......
...@@ -319,16 +319,6 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -319,16 +319,6 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done) this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
}) })
it('with then', function (done) {
this.User
.findOrCreate({ id: 1})
.then(function(user) {
expect(user.id).to.equal(1)
expect(arguments.length).to.equal(1)
done()
})
})
describe('with spread', function () { describe('with spread', function () {
it('user not created', function (done) { it('user not created', function (done) {
this.User this.User
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!