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

Commit 09ac0969 by Mick Hansen

Merge pull request #1194 from mickhansen/has-many-through-self-association-fix

Add test and fix for hasMany selfAssociation with through option (Fixes #1184)
2 parents 9a219699 033e0939
...@@ -56,9 +56,16 @@ module.exports = (function() { ...@@ -56,9 +56,16 @@ module.exports = (function() {
} }
/* /*
* Find partner DAOFactory if present, to identify double linked association * If self association, this association is target association
*/ */
if (this.through) { if (this.isSelfAssociation) {
this.targetAssociation = this
}
/*
* Else find partner DAOFactory if present, to identify double linked association
*/
else if (this.through) {
_.each(this.target.associations, function (association, accessor) { _.each(this.target.associations, function (association, accessor) {
if (self.source === association.target) { if (self.source === association.target) {
var paired = false var paired = false
...@@ -90,13 +97,14 @@ module.exports = (function() { ...@@ -90,13 +97,14 @@ module.exports = (function() {
if (this.through === true) { if (this.through === true) {
this.through = this.combinedTableName this.through = this.combinedTableName
} }
}
if (typeof this.through === "string") { if (typeof this.through === "string") {
this.through = this.sequelize.define(this.through, {}, _.extend(this.options, { this.through = this.sequelize.define(this.through, {}, _.extend(this.options, {
tableName: this.through tableName: this.through
})) }))
this.targetAssociation.through = this.through if (this.targetAssociation) this.targetAssociation.through = this.through
}
} }
this.options.tableName = this.combinedName = (this.through === Object(this.through) ? this.through.tableName : this.through) this.options.tableName = this.combinedName = (this.through === Object(this.through) ? this.through.tableName : this.through)
...@@ -238,7 +246,7 @@ module.exports = (function() { ...@@ -238,7 +246,7 @@ module.exports = (function() {
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]() instance[self.accessors.get]()
.success(function(oldAssociatedObjects) { .success(function(oldAssociatedObjects) {
var Class = self.doubleLinked ? HasManyMultiLinked : HasManySingleLinked var Class = Object(self.through) === self.through ? HasManyMultiLinked : HasManySingleLinked
new Class(self, instance).injectSetter(emitter, oldAssociatedObjects, newAssociatedObjects, defaultAttributes) new Class(self, instance).injectSetter(emitter, oldAssociatedObjects, newAssociatedObjects, defaultAttributes)
}) })
.proxy(emitter, {events: ['error', 'sql']}) .proxy(emitter, {events: ['error', 'sql']})
...@@ -258,7 +266,7 @@ module.exports = (function() { ...@@ -258,7 +266,7 @@ module.exports = (function() {
.proxy(emitter, {events: ['error', 'sql']}) .proxy(emitter, {events: ['error', 'sql']})
.success(function(currentAssociatedObjects) { .success(function(currentAssociatedObjects) {
if (currentAssociatedObjects.length === 0 || Object(self.through) === self.through) { if (currentAssociatedObjects.length === 0 || Object(self.through) === self.through) {
var Class = self.doubleLinked ? HasManyMultiLinked : HasManySingleLinked var Class = Object(self.through) === self.through ? HasManyMultiLinked : HasManySingleLinked
new Class(self, instance).injectAdder(emitter, newAssociatedObject, additionalAttributes, !!currentAssociatedObjects.length) new Class(self, instance).injectAdder(emitter, newAssociatedObject, additionalAttributes, !!currentAssociatedObjects.length)
} else { } else {
emitter.emit('success', newAssociatedObject); emitter.emit('success', newAssociatedObject);
......
...@@ -399,7 +399,7 @@ module.exports = (function() { ...@@ -399,7 +399,7 @@ module.exports = (function() {
optAttributes = optAttributes.concat(attributes) optAttributes = optAttributes.concat(attributes)
if (include.association.doubleLinked) { if (Object(include.association.through) === include.association.through) {
var primaryKeysSource = Object.keys(include.association.source.primaryKeys) var primaryKeysSource = Object.keys(include.association.source.primaryKeys)
, tableSource = parentTable , tableSource = parentTable
, identSource = include.association.identifier , identSource = include.association.identifier
......
...@@ -429,6 +429,19 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -429,6 +429,19 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) // end optimization using bulk create, destroy and update }) // end optimization using bulk create, destroy and update
describe('selfAssociations', function () {
it('should work', function (done) {
var Group = this.sequelize.define('Group', {})
Group.hasMany(Group, { through: 'groups_outsourcing_companies', as: 'OutsourcingCompanies'});
this.sequelize.sync().done(function (err) {
expect(err).not.to.be.ok
done()
})
})
})
}) })
describe('(N:M)', function() { describe('(N:M)', function() {
......
...@@ -478,6 +478,40 @@ describe(Support.getTestDialectTeaser("Include"), function () { ...@@ -478,6 +478,40 @@ describe(Support.getTestDialectTeaser("Include"), function () {
}) })
}) })
}) })
it('should support self associated hasMany (with through) include', function (done) {
var Group = this.sequelize.define('Group', {
name: DataTypes.STRING
})
Group.hasMany(Group, { through: 'groups_outsourcing_companies', as: 'OutsourcingCompanies'});
this.sequelize.sync().done(function (err) {
Group.bulkCreate([
{name: 'SoccerMoms'},
{name: 'Coca Cola'},
{name: 'Dell'},
{name: 'Pepsi'}
]).done(function () {
Group.findAll().done(function (err, groups) {
groups[0].setOutsourcingCompanies(groups.slice(1)).done(function (err) {
expect(err).not.to.be.ok
Group.find({
where: {
id: groups[0].id,
},
include: [{model: Group, as: 'OutsourcingCompanies'}]
}).done(function (err, group) {
expect(err).not.to.be.ok
expect(group.outsourcingCompanies.length).to.equal(3)
done()
})
})
})
})
})
})
}) })
describe('findAll', function () { describe('findAll', function () {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!