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

Commit c20fa816 by Mick Hansen

Merge pull request #1744 from sequelize/addRelations

addRelations feature
2 parents 7e9679be b67058a6
var Utils = require("./../utils")
, DataTypes = require('./../data-types')
, Helpers = require('./helpers')
, Transaction = require('../transaction')
, _ = require('lodash')
module.exports = (function() {
var BelongsTo = function(source, target, options) {
......
......@@ -12,16 +12,12 @@ module.exports = (function() {
HasManyDoubleLinked.prototype.injectGetter = function(options) {
var self = this
, _options = options
, smart
var customEventEmitter = new Utils.CustomEventEmitter(function() {
var where = []
, through = self.association.through
, options = _options || {}
, queryOptions = {}
, targetAssociation = self.association.targetAssociation
options = options || {}
//fully qualify
var instancePrimaryKey = self.instance.Model.primaryKeyAttribute
, foreignPrimaryKey = self.association.target.primaryKeyAttribute
......@@ -70,18 +66,11 @@ module.exports = (function() {
}
}
self.association.target.findAllJoin([through.getTableName(), through.name], options, queryOptions)
.on('success', function(objects) { customEventEmitter.emit('success', objects) })
.on('error', function(err){ customEventEmitter.emit('error', err) })
.on('sql', function(sql) { customEventEmitter.emit('sql', sql)})
})
return customEventEmitter.run()
return self.association.target.findAllJoin([through.getTableName(), through.name], options, queryOptions)
}
HasManyDoubleLinked.prototype.injectSetter = function(emitterProxy, oldAssociations, newAssociations, defaultAttributes) {
HasManyDoubleLinked.prototype.injectSetter = function(oldAssociations, newAssociations, defaultAttributes) {
var self = this
, chainer = new Utils.QueryChainer()
, targetAssociation = self.association.targetAssociation
, foreignIdentifier = self.association.foreignIdentifier
, sourceKeys = Object.keys(self.association.source.primaryKeys)
......@@ -89,6 +78,7 @@ module.exports = (function() {
, obsoleteAssociations = []
, changedAssociations = []
, options = {}
, promises = []
, unassociatedObjects;
if ((defaultAttributes || {}).transaction instanceof Transaction) {
......@@ -140,7 +130,7 @@ module.exports = (function() {
where[self.association.identifier] = ((sourceKeys.length === 1) ? self.instance[sourceKeys[0]] : self.instance.id)
where[foreignIdentifier] = foreignIds
chainer.add(self.association.through.destroy(where, options))
promises.push(self.association.through.destroy(where, options))
}
if (unassociatedObjects.length > 0) {
......@@ -157,23 +147,19 @@ module.exports = (function() {
return attributes
})
chainer.add(self.association.through.bulkCreate(bulk, options))
promises.push(self.association.through.bulkCreate(bulk, options))
}
if (changedAssociations.length > 0) {
changedAssociations.forEach(function (assoc) {
chainer.add(self.association.through.update(assoc.attributes, assoc.where, options))
promises.push(self.association.through.update(assoc.attributes, assoc.where, options))
})
}
chainer
.run()
.success(function() { emitterProxy.emit('success', newAssociations) })
.error(function(err) { emitterProxy.emit('error', err) })
.on('sql', function(sql) { emitterProxy.emit('sql', sql) })
return Utils.Promise.all(promises)
}
HasManyDoubleLinked.prototype.injectAdder = function(emitterProxy, newAssociation, additionalAttributes, exists) {
HasManyDoubleLinked.prototype.injectAdder = function(newAssociation, additionalAttributes, exists) {
var attributes = {}
, targetAssociation = this.association.targetAssociation
, foreignIdentifier = targetAssociation.identifier
......@@ -195,17 +181,14 @@ module.exports = (function() {
attributes = Utils._.defaults({}, newAssociation[targetAssociation.through.name], additionalAttributes)
if (Object.keys(attributes).length) {
targetAssociation.through.update(attributes, where).proxy(emitterProxy)
return targetAssociation.through.update(attributes, where)
} else {
emitterProxy.emit('success')
return Utils.Promise.resolve()
}
} else {
attributes = Utils._.defaults(attributes, newAssociation[targetAssociation.through.name], additionalAttributes)
this.association.through.create(attributes, options)
.success(function() { emitterProxy.emit('success', newAssociation) })
.error(function(err) { emitterProxy.emit('error', err) })
.on('sql', function(sql) { emitterProxy.emit('sql', sql) })
return this.association.through.create(attributes, options)
}
}
......
......@@ -24,12 +24,12 @@ module.exports = (function() {
return this.association.target.all(options)
}
HasManySingleLinked.prototype.injectSetter = function(emitter, oldAssociations, newAssociations, defaultAttributes) {
HasManySingleLinked.prototype.injectSetter = function(oldAssociations, newAssociations, defaultAttributes) {
var self = this
, associationKeys = Object.keys((oldAssociations[0] || newAssociations[0] || {Model: {primaryKeys: {}}}).Model.primaryKeys || {})
, associationKey = (associationKeys.length === 1) ? associationKeys[0] : 'id'
, chainer = new Utils.QueryChainer()
, options = {}
, promises = []
, obsoleteAssociations = oldAssociations.filter(function (old) {
return !Utils._.find(newAssociations, function (obj) {
return obj[associationKey] === old[associationKey]
......@@ -62,7 +62,7 @@ module.exports = (function() {
, updateWhere = {}
updateWhere[primaryKey] = obsoleteIds
chainer.add(this.__factory.target.update(
promises.push(this.__factory.target.update(
update,
updateWhere,
Utils._.extend(options, { allowNull: [self.__factory.identifier] })
......@@ -88,21 +88,17 @@ module.exports = (function() {
update[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance[pkey] || self.instance.id)
updateWhere[primaryKey] = unassociatedIds
chainer.add(this.__factory.target.update(
promises.push(this.__factory.target.update(
update,
updateWhere,
Utils._.extend(options, { allowNull: [self.__factory.identifier] })
))
}
chainer
.run()
.success(function() { emitter.emit('success', newAssociations) })
.error(function(err) { emitter.emit('error', err) })
.on('sql', function(sql) { emitter.emit('sql', sql) })
return Utils.Promise.all(promises)
}
HasManySingleLinked.prototype.injectAdder = function(emitterProxy, newAssociation, additionalAttributes) {
HasManySingleLinked.prototype.injectAdder = function(newAssociation, additionalAttributes) {
var primaryKeys = Object.keys(this.instance.Model.primaryKeys)
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
, options = {}
......@@ -114,10 +110,7 @@ module.exports = (function() {
newAssociation[this.__factory.identifier] = this.instance[primaryKey]
newAssociation.save(options)
.success(function() { emitterProxy.emit('success', newAssociation) })
.error(function(err) { emitterProxy.emit('error', err) })
.on('sql', function(sql) { emitterProxy.emit('sql', sql) })
return newAssociation.save(options)
}
return HasManySingleLinked
......
var Utils = require("./../utils")
, DataTypes = require('./../data-types')
, Helpers = require('./helpers')
, _ = require('lodash')
, Transaction = require('../transaction')
......@@ -122,6 +121,7 @@ module.exports = (function() {
this.accessors = {
get: Utils._.camelize('get_' + this.as),
set: Utils._.camelize('set_' + this.as),
addMultiple: Utils._.camelize('add_' + this.as, this.target.options.language),
add: Utils._.camelize(Utils.singularize('add_' + this.as, this.target.options.language)),
create: Utils._.camelize(Utils.singularize('create_' + this.as, this.target.options.language)),
remove: Utils._.camelize(Utils.singularize('remove_' + this.as, this.target.options.language)),
......@@ -262,40 +262,26 @@ module.exports = (function() {
obj[this.accessors.hasAll] = function(objects, options) {
var instance = this;
var customEventEmitter = new Utils.CustomEventEmitter(function() {
instance[self.accessors.get](options)
.error(function(err) { customEventEmitter.emit('error', err) })
.success(function(associatedObjects) {
customEventEmitter.emit('success',
Utils._.all(objects, function(o) {
return instance[self.accessors.get](options).then(function(associatedObjects) {
return Utils._.all(objects, function(o) {
return Utils._.any(associatedObjects, function(associatedObject) {
return Utils._.all(associatedObject.identifiers, function(key, identifier) {
return o[identifier] == associatedObject[identifier];
});
})
})
)
})
})
return customEventEmitter.run()
}
obj[this.accessors.hasSingle] = function(o, options) {
var instance = this
var customEventEmitter = new Utils.CustomEventEmitter(function() {
instance[self.accessors.get](options)
.error(function(err){ customEventEmitter.emit('error', err)})
.success(function(associatedObjects) {
customEventEmitter.emit('success',
Utils._.any(associatedObjects, function(associatedObject) {
return instance[self.accessors.get](options).then(function(associatedObjects) {
return Utils._.any(associatedObjects, function(associatedObject) {
return Utils._.all(associatedObject.identifiers, function(key, identifier) {
return o[identifier] == associatedObject[identifier];
});
})
)
})
})
return customEventEmitter.run()
}
return this
}
......@@ -303,56 +289,55 @@ module.exports = (function() {
HasMany.prototype.injectSetter = function(obj) {
var self = this
obj[this.accessors.set] = function(newAssociatedObjects, defaultAttributes) {
obj[this.accessors.set] = function (newAssociatedObjects, additionalAttributes) {
if (newAssociatedObjects === null) {
newAssociatedObjects = []
}
var instance = this
// define the returned customEventEmitter, which will emit the success event once everything is done
return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]({
transaction: (defaultAttributes || {}).transaction
})
.success(function(oldAssociatedObjects) {
return instance[self.accessors.get]({
transaction: (additionalAttributes || {}).transaction
}).then(function(oldAssociatedObjects) {
var Class = Object(self.through) === self.through ? HasManyDoubleLinked : HasManySingleLinked
new Class(self, instance).injectSetter(emitter, oldAssociatedObjects, newAssociatedObjects, defaultAttributes)
return new Class(self, instance).injectSetter(oldAssociatedObjects, newAssociatedObjects, additionalAttributes)
})
.proxy(emitter, {events: ['error', 'sql']})
}).run()
}
obj[this.accessors.add] = function(newInstance, additionalAttributes) {
obj[this.accessors.add] = function (newInstance, additionalAttributes) {
var instance = this
, primaryKey = newInstance.Model.primaryKeyAttribute
, where = new Utils.where(self.target.rawAttributes[primaryKey], newInstance[primaryKey])
return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]({
if (Array.isArray(newInstance)) {
return obj[self.accessors.addMultiple](newInstance, additionalAttributes)
} else {
return instance[self.accessors.get]({
where: where,
transaction: (additionalAttributes || {}).transaction
})
.proxy(emitter, {events: ['error', 'sql']})
.success(function(currentAssociatedObjects) {
}).then(function(currentAssociatedObjects) {
if (currentAssociatedObjects.length === 0 || Object(self.through) === self.through) {
var Class = Object(self.through) === self.through ? HasManyDoubleLinked : HasManySingleLinked
new Class(self, instance).injectAdder(emitter, newInstance, additionalAttributes, !!currentAssociatedObjects.length)
return new Class(self, instance).injectAdder(newInstance, additionalAttributes, !!currentAssociatedObjects.length)
} else {
emitter.emit('success', newInstance);
return Utils.Promise.resolve(newInstance)
}
})
}).run()
}
}
obj[this.accessors.addMultiple] = function (newInstances, additionalAttributes) {
var Class = Object(self.through) === self.through ? HasManyDoubleLinked : HasManySingleLinked
return new Class(self, this).injectSetter([], newInstances, additionalAttributes)
}
obj[this.accessors.remove] = function(oldAssociatedObject, options) {
obj[this.accessors.remove] = function (oldAssociatedObject, options) {
var instance = this
return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]({
return instance[self.accessors.get]({
transaction: (options || {}).transaction
}).success(function(currentAssociatedObjects) {
}).then(function(currentAssociatedObjects) {
var newAssociations = []
, oldAssociations = []
currentAssociatedObjects.forEach(function(association) {
if (!Utils._.isEqual(oldAssociatedObject.identifiers, association.identifiers)) {
......@@ -360,36 +345,8 @@ module.exports = (function() {
}
})
var tick = 0
var next = function(err, i) {
if (!!err || i >= oldAssociations.length) {
return run(err)
}
oldAssociations[i].destroy().error(function(err) {
next(err)
})
.success(function() {
tick++
next(null, tick)
})
}
var run = function(err) {
if (!!err) {
return emitter.emit('error', err)
}
instance[self.accessors.set](newAssociations).proxy(emitter)
}
if (oldAssociations.length > 0) {
next(null, tick)
} else {
run()
}
return instance[self.accessors.set](newAssociations)
})
}).run()
}
return this
......@@ -407,16 +364,10 @@ module.exports = (function() {
}
if (Object(self.through) === self.through) {
return new Utils.CustomEventEmitter(function(emitter) {
// Create the related model instance
self.target
.create(values, fieldsOrOptions)
.proxy(emitter, { events: ['error', 'sql'] })
.success(function(newAssociatedObject) {
instance[self.accessors.add](newAssociatedObject, options)
.proxy(emitter)
return self.target.create(values, fieldsOrOptions).then(function(newAssociatedObject) {
return instance[self.accessors.add](newAssociatedObject, options)
})
}).run()
} else {
values[self.identifier] = instance.get(self.source.primaryKeyAttribute);
return self.target.create(values, fieldsOrOptions)
......
var Utils = require("./../utils")
, DataTypes = require('./../data-types')
, Helpers = require("./helpers")
, Transaction = require("../transaction")
......@@ -118,15 +117,9 @@ module.exports = (function() {
options.transaction = fieldsOrOptions.transaction
}
return new Utils.CustomEventEmitter(function(emitter) {
association.target
.create(values, fieldsOrOptions)
.proxy(emitter, { events: ['error', 'sql'] })
.success(function(associationInstance) {
instance[association.accessors.set](associationInstance, options)
.proxy(emitter)
return association.target.create(values, fieldsOrOptions).then(function(associationInstance) {
return instance[association.accessors.set](associationInstance, options)
})
}).run()
}
return this
......
......@@ -69,7 +69,7 @@ var Mixin = module.exports = function(){}
* * set[AS] - for example setProfile(instance, options). Options are passed to `target.save`
* * create[AS] - for example createProfile(value, options). Builds and saves a new instance of the associated model. Values and options are passed on to `target.create`
*
* All methods return an event emitter.
* All methods return a promise
*
* @param {Model} target
* @param {object} [options]
......@@ -110,7 +110,7 @@ Mixin.hasOne = function(targetModel, options) {
* * set[AS] - for example setUser(instance, options). Options are passed to this.save
* * create[AS] - for example createUser(value, options). Builds and saves a new instance of the associated model. Values and options are passed on to target.create
*
* All methods return an event emitter.
* All methods return a promise
*
* @param {Model} target
* @param {object} [options]
......@@ -158,13 +158,14 @@ Mixin.belongsTo = function(targetModel, options) {
*
* * get[AS] - for example getPictures().
* * set[AS] - for example setPictures(instances, defaultAttributes|options). Update the associations. All currently associated models that are not in instances will be removed.
* * add[AS] - for example addPicture(instance, defaultAttributes|options). Add another association.
* * add[AS] - for example addPicture(instance, defaultAttributes|options). Add another associated object.
* * add[AS] [plural] - for example addPictures([instance1, instance2], defaultAttributes|options). Add some more associated objects.
* * create[AS] - for example createPicture(values, options). Build and save a new association.
* * remove[AS] - for example removePicture(instance). Remove a single association
* * has[AS] - for example hasPicture(instance). Is source associated to this target?
* * has[AS] [plural] - for example hasPictures(instances). Is source associated to all these targets?
*
* All methods return an event emitter.
* All methods return a promise
*
* If you use a through model with custom attributes, these attributes can be set when adding / setting new associations in two ways. Consider users and projects from before
* with a join table that stores whether the project has been started yet:
......
......@@ -92,7 +92,9 @@ Hooks.runHooks = function() {
if (!!arguments[0]) {
return reject(arguments[0])
}
if (arguments.length) {
resolveArgs = Array.prototype.slice.call(arguments, 1)
}
return run(hooks[tick])
}))
......@@ -101,7 +103,9 @@ Hooks.runHooks = function() {
maybePromise.spread(function () {
tick++
if (arguments.length) {
resolveArgs = Array.prototype.slice.call(arguments)
}
return run(hooks[tick])
}, reject)
......
......@@ -1266,12 +1266,7 @@ module.exports = (function() {
, query = null
, args = []
return new Utils.CustomEventEmitter(function(emitter) {
self.runHooks(self.options.hooks.beforeBulkDestroy, where, function(err, newWhere) {
if (!!err) {
return emitter.emit('error', err)
}
return self.runHooks(self.options.hooks.beforeBulkDestroy, where).then(function(newWhere) {
where = newWhere || where
if (self._timestampAttributes.deletedAt && options.force === false) {
......@@ -1284,88 +1279,52 @@ module.exports = (function() {
args = [self.getTableName(), where, options, self]
}
var runQuery = function(err, records) {
if (!!err) {
return emitter.emit('error', err)
}
query = self.QueryInterface[query].apply(self.QueryInterface, args)
query.on('sql', function(sql) {
emitter.emit('sql', sql)
})
.error(function(err) {
emitter.emit('error', err)
})
.success(function(results) {
var finished = function(err) {
if (!!err) {
return emitter.emit('error', err)
}
self.runHooks(self.options.hooks.afterBulkDestroy, where, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
emitter.emit('success', results)
})
}
var runQuery = function(records) {
return self.QueryInterface[query].apply(self.QueryInterface, args).then(function(results) {
if (options && options.hooks === true) {
var tick = 0
var next = function(i) {
self.runHooks(self.options.hooks.afterDestroy, records[i], function(err, newValues) {
if (!!err) {
return finished(err)
}
return self.runHooks(self.options.hooks.afterDestroy, records[i]).then(function(newValues) {
records[i].dataValues = !!newValues ? newValues.dataValues : records[i].dataValues
tick++
if (tick >= records.length) {
return finished()
return self.runHooks(self.options.hooks.afterBulkDestroy, where).return(results)
}
next(tick)
return next(tick)
})
}
next(tick)
return next(tick)
} else {
finished()
return self.runHooks(self.options.hooks.afterBulkDestroy, where).return(results)
}
})
}
if (options && options.hooks === true) {
var tick = 0
self.all({where: where}).error(function(err) { emitter.emit('error', err) })
.success(function(records) {
return self.all({where: where}).then(function(records) {
var next = function(i) {
self.runHooks(self.options.hooks.beforeDestroy, records[i], function(err, newValues) {
if (!!err) {
return runQuery(err)
}
return self.runHooks(self.options.hooks.beforeDestroy, records[i]).then(function(newValues) {
records[i].dataValues = !!newValues ? newValues.dataValues : records[i].dataValues
tick++
if (tick >= records.length) {
return runQuery(null, records)
return runQuery(records)
}
next(tick)
return next(tick)
})
}
next(tick)
return next(tick)
})
//
} else {
runQuery()
return runQuery()
}
})
}).run()
}
/**
......@@ -1383,7 +1342,6 @@ module.exports = (function() {
*/
Model.prototype.update = function(attrValueHash, where, options) {
var self = this
, query = null
, tick = 0
options = options || {}
......@@ -1395,97 +1353,58 @@ module.exports = (function() {
attrValueHash[self._timestampAttributes.updatedAt] = Utils.now()
}
return new Utils.CustomEventEmitter(function(emitter) {
var runSave = function() {
self.runHooks(self.options.hooks.beforeBulkUpdate, attrValueHash, where, function(err, attributes, _where) {
if (!!err) {
return emitter.emit('error', err)
}
return self.runHooks(self.options.hooks.beforeBulkUpdate, attrValueHash, where).spread(function(attributes, _where) {
where = _where || where
attrValueHash = attributes || attrValueHash
var runQuery = function(err, records) {
if (!!err) {
return emitter.emit('error', err)
}
query = self.QueryInterface.bulkUpdate(self.getTableName(), attrValueHash, where, options, self.rawAttributes)
query.on('sql', function(sql) {
emitter.emit('sql', sql)
})
.error(function(err) {
emitter.emit('error', err)
})
.success(function(results) {
var finished = function(err, records) {
if (!!err) {
return emitter.emit('error', err)
}
self.runHooks(self.options.hooks.afterBulkUpdate, attrValueHash, where, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
emitter.emit('success', records)
})
}
var runQuery = function(records) {
return self.QueryInterface.bulkUpdate(self.getTableName(), attrValueHash, where, options, self.rawAttributes).then(function(results) {
if (options && options.hooks === true && !!records && records.length > 0) {
var tick = 0
var next = function(i) {
self.runHooks(self.options.hooks.afterUpdate, records[i], function(err, newValues) {
if (!!err) {
return finished(err)
}
records[i].dataValues = !!newValues ? newValues.dataValues : records[i].dataValues
return self.runHooks(self.options.hooks.afterUpdate, records[i]).then(function(newValues) {
records[i].dataValues = (!!newValues && newValues.dataValues) ? newValues.dataValues : records[i].dataValues
tick++
if (tick >= records.length) {
return finished(null, records)
return self.runHooks(self.options.hooks.afterBulkUpdate, attrValueHash, where).return(records)
}
next(tick)
return next(tick)
})
}
next(tick)
return next(tick)
} else {
finished(null, results)
return self.runHooks(self.options.hooks.afterBulkUpdate, attrValueHash, where).return(results)
}
})
}
if (options.hooks === true) {
self.all({where: where}).error(function(err) { emitter.emit('error', err) })
.success(function(records) {
return self.all({where: where}).then(function(records) {
if (records === null || records.length < 1) {
return runQuery(null)
return runQuery()
}
var next = function(i) {
self.runHooks(self.options.hooks.beforeUpdate, records[i], function(err, newValues) {
if (!!err) {
return runQuery(err)
}
records[i].dataValues = !!newValues ? newValues.dataValues : records[i].dataValues
return self.runHooks(self.options.hooks.beforeUpdate, records[i]).then(function(newValues) {
records[i].dataValues = (!!newValues && newValues.dataValues) ? newValues.dataValues : records[i].dataValues
tick++
if (tick >= records.length) {
return runQuery(null, records)
return runQuery(records)
}
next(tick)
return next(tick)
})
}
next(tick)
return next(tick)
})
} else {
runQuery()
return runQuery()
}
})
}
......@@ -1497,19 +1416,16 @@ module.exports = (function() {
var updatedFields = Object.keys(attrValueHash)
var skippedFields = Utils._.difference(Object.keys(self.attributes), updatedFields)
build.hookValidate({skip: skippedFields}).error(function(err) {
emitter.emit('error', err)
}).success(function(attributes) {
return build.hookValidate({skip: skippedFields}).then(function(attributes) {
if (!!attributes && !!attributes.dataValues) {
attrValueHash = Utils._.pick.apply(Utils._, [].concat(attributes.dataValues).concat(Object.keys(attrValueHash)))
}
runSave()
return runSave()
})
} else {
runSave()
return runSave()
}
}).run()
}
/**
......
var util = require("util")
, Promise
var Promise
, EventEmitter = require("events").EventEmitter
, proxyEventKeys = ['success', 'error', 'sql']
, Utils = require('./utils')
......@@ -12,7 +11,7 @@ var util = require("util")
* @mixes https://github.com/petkaantonov/bluebird/blob/master/API.md
* @class Promise
*/
var SequelizePromise = Promise = require('bluebird')
var SequelizePromise = Promise = require('sequelize-bluebird')
/**
* Listen for events, event emitter style. Mostly for backwards compat. with EventEmitter
......
......@@ -51,7 +51,7 @@
"generic-pool": "2.0.4",
"sql": "~0.35.0",
"circular-json": "~0.1.5",
"bluebird": "git://github.com/sequelize/bluebird.git",
"sequelize-bluebird": "git://github.com/sequelize/bluebird.git",
"node-uuid": "~1.4.1"
},
"devDependencies": {
......
......@@ -293,6 +293,35 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
})
})
describe('addMultipleAssociations', function () {
it('adds associations without removing the current ones', function () {
var User = this.sequelize.define('User', { username: DataTypes.STRING })
, Task = this.sequelize.define('Task', { title: DataTypes.STRING })
Task.hasMany(User)
return this.sequelize.sync({ force: true }).then(function() {
return User.bulkCreate([
{ username: 'foo '},
{ username: 'bar '},
{ username: 'baz '}
]).then(function () {
return Task.create({ title: 'task' }).then(function (task) {
return User.findAll().then(function(users) {
return task.setUsers([users[0]]).then(function () {
return task.addUsers([users[1], users[2]]).then(function () {
return task.getUsers().then(function (users) {
expect(users).to.have.length(3)
})
})
})
})
})
})
})
})
})
it("clears associations when passing null to the set-method with omitNull set to true", function(done) {
this.sequelize.options.omitNull = true
......@@ -923,6 +952,36 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
})
})
describe('addMultipleAssociations', function () {
it('adds associations without removing the current ones', function () {
var User = this.sequelize.define('User', { username: DataTypes.STRING })
, Task = this.sequelize.define('Task', { title: DataTypes.STRING })
User.hasMany(Task)
Task.hasMany(User)
return this.sequelize.sync({ force: true }).then(function() {
return User.bulkCreate([
{ username: 'foo '},
{ username: 'bar '},
{ username: 'baz '}
]).then(function () {
return Task.create({ title: 'task' }).then(function (task) {
return User.findAll().then(function(users) {
return task.setUsers([users[0]]).then(function () {
return task.addUsers([users[1], users[2]]).then(function () {
return task.getUsers().then(function (users) {
expect(users).to.have.length(3)
})
})
})
})
})
})
})
})
})
describe('optimizations using bulk create, destroy and update', function () {
beforeEach(function (done) {
this.User = this.sequelize.define('User', { username: DataTypes.STRING }, {timestamps: false})
......
......@@ -3,7 +3,6 @@ var chai = require('chai')
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, SequelizePromise = require(__dirname + "/../lib/promise")
, Promise = require('bluebird')
, dialect = Support.getTestDialect()
, _ = require('lodash')
, sinon = require('sinon')
......@@ -389,7 +388,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
it('should still work with .done() when resolving multiple results', function(done) {
var spy = sinon.spy()
, promise = new SequelizePromise(function (resolve, reject) {
resolve(Promise.all(['MyModel', true]));
resolve(SequelizePromise.all(['MyModel', true]));
});
promise.spread(spy);
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!