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

Commit c9675356 by Simon Gaeremynck

#2338 - Associations remove[AS][plural]

1 parent ffc50e13
# Next # Next
- [FEATURE] Added the possibility of removing multiple associations in 1 call [#2338](https://github.com/sequelize/sequelize/issues/2338)
- [BUG] Add support for `field` named the same as the attribute in `reload`, `bulkCreate` and `save` [#2348](https://github.com/sequelize/sequelize/issues/2348) - [BUG] Add support for `field` named the same as the attribute in `reload`, `bulkCreate` and `save` [#2348](https://github.com/sequelize/sequelize/issues/2348)
- [BUG] Copy the options object in association getters. [#2311](https://github.com/sequelize/sequelize/issues/2311) - [BUG] Copy the options object in association getters. [#2311](https://github.com/sequelize/sequelize/issues/2311)
- [BUG] `Model#destroy()` now supports `field`, this also fixes an issue with `N:M#removeAssociation` and `field` - [BUG] `Model#destroy()` now supports `field`, this also fixes an issue with `N:M#removeAssociation` and `field`
......
...@@ -176,6 +176,7 @@ module.exports = (function() { ...@@ -176,6 +176,7 @@ module.exports = (function() {
add: 'add' + singular, add: 'add' + singular,
create: 'create' + singular, create: 'create' + singular,
remove: 'remove' + singular, remove: 'remove' + singular,
removeMultiple: 'remove' + plural,
hasSingle: 'has' + singular, hasSingle: 'has' + singular,
hasAll: 'has' + plural hasAll: 'has' + plural
}; };
...@@ -483,6 +484,29 @@ module.exports = (function() { ...@@ -483,6 +484,29 @@ module.exports = (function() {
}); });
}; };
obj[this.accessors.removeMultiple] = function(oldAssociatedObjects, options) {
var instance = this;
return instance[association.accessors.get]({}, options).then(function(currentAssociatedObjects) {
var newAssociations = [];
currentAssociatedObjects.forEach(function(association) {
// Determine is this is an association we want to remove
var obj = Utils._.find(oldAssociatedObjects, function(oldAssociatedObject) {
return Utils._.isEqual(oldAssociatedObject.identifiers, association.identifiers);
});
// This is not an association we want to remove. Add it back
// to the set of associations we will associate our instance with
if (!obj) {
newAssociations.push(association);
}
});
return instance[association.accessors.set](newAssociations, options);
});
};
return this; return this;
}; };
......
...@@ -187,7 +187,8 @@ Mixin.belongsTo = singleLinked(BelongsTo); ...@@ -187,7 +187,8 @@ Mixin.belongsTo = singleLinked(BelongsTo);
* * add[AS] - for example addPicture(instance, defaultAttributes|options). Add another associated object. * * 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. * * 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. * * create[AS] - for example createPicture(values, options). Build and save a new association.
* * remove[AS] - for example removePicture(instance). Remove a single association * * remove[AS] - for example removePicture(instance). Remove a single association.
* * remove[AS] [plural] - for example removePictures(instance). Remove multiple association.
* * has[AS] - for example hasPicture(instance). Is source associated to this target? * * 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? * * has[AS] [plural] - for example hasPictures(instances). Is source associated to all these targets?
* *
......
...@@ -1986,6 +1986,34 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -1986,6 +1986,34 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
expect(tasks.length).to.equal(1); expect(tasks.length).to.equal(1);
}); });
}); });
it('should remove multiple entries without any attributes (and timestamps off) on the through model', function () {
var Worker = this.sequelize.define('Worker', {}, {timestamps: false})
, Task = this.sequelize.define('Task', {}, {timestamps: false})
, WorkerTasks = this.sequelize.define('WorkerTasks', {}, {timestamps: false});
Worker.hasMany(Task, { through: WorkerTasks });
Task.hasMany(Worker, { through: WorkerTasks });
// Test setup
return this.sequelize.sync().then(function() {
return Sequelize.Promise.all([
Worker.create({}),
Task.bulkCreate([{}, {}, {}]).then(function () {
return Task.findAll();
})
]);
}).spread(function (worker, tasks) {
// Set all tasks, then remove two tasks, then return all tasks
return worker.setTasks(tasks).then(function () {
return worker.removeTasks([tasks[0], tasks[1]]);
}).then(function () {
return worker.getTasks();
});
}).then(function (tasks) {
expect(tasks.length).to.equal(1);
});
});
}); });
}); });
......
...@@ -137,6 +137,9 @@ if (Support.dialectIsMySQL()) { ...@@ -137,6 +137,9 @@ if (Support.dialectIsMySQL()) {
self.user.removeTask(self.tasks[0]).on('success', function() { self.user.removeTask(self.tasks[0]).on('success', function() {
self.user.getTasks().on('success', function(_tasks) { self.user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).to.equal(self.tasks.length - 1) expect(_tasks.length).to.equal(self.tasks.length - 1)
self.user.removeTasks([self.tasks[1], self.tasks[2]]).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks).to.have.length(self.tasks.length - 3)
done() done()
}) })
}) })
...@@ -147,4 +150,6 @@ if (Support.dialectIsMySQL()) { ...@@ -147,4 +150,6 @@ if (Support.dialectIsMySQL()) {
}) })
}) })
}) })
})
})
} }
...@@ -151,6 +151,9 @@ if (dialect.match(/^postgres/)) { ...@@ -151,6 +151,9 @@ if (dialect.match(/^postgres/)) {
self.user.removeTask(self.tasks[0]).on('success', function() { self.user.removeTask(self.tasks[0]).on('success', function() {
self.user.getTasks().on('success', function(_tasks) { self.user.getTasks().on('success', function(_tasks) {
expect(_tasks).to.have.length(self.tasks.length - 1) expect(_tasks).to.have.length(self.tasks.length - 1)
self.user.removeTasks([self.tasks[1], self.tasks[2]]).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks).to.have.length(self.tasks.length - 3)
done() done()
}) })
}) })
...@@ -166,4 +169,6 @@ if (dialect.match(/^postgres/)) { ...@@ -166,4 +169,6 @@ if (dialect.match(/^postgres/)) {
}) })
}) })
}) })
})
})
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!