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

Commit 8347de69 by Sascha Depold

added self association

1 parent 300f8263
...@@ -36,7 +36,7 @@ HasManyDoubleLinked.prototype.destroyObsoleteAssociations = function(oldAssociat ...@@ -36,7 +36,7 @@ HasManyDoubleLinked.prototype.destroyObsoleteAssociations = function(oldAssociat
var emitter = new Utils.CustomEventEmitter(function() { var emitter = new Utils.CustomEventEmitter(function() {
var chainer = new Utils.QueryChainer var chainer = new Utils.QueryChainer
var foreignIdentifier = self.definition.target.associations[self.definition.source.tableName].identifier var foreignIdentifier = self.definition.target.associations[self.definition.combinedName].identifier
var obsoleteAssociations = oldAssociations.filter(function(obj) { return !obj.equalsOneOf(newAssociations) }) var obsoleteAssociations = oldAssociations.filter(function(obj) { return !obj.equalsOneOf(newAssociations) })
if(obsoleteAssociations.length == 0) if(obsoleteAssociations.length == 0)
...@@ -72,18 +72,19 @@ HasManyDoubleLinked.prototype.injectSetter = function(emitter, oldAssociations, ...@@ -72,18 +72,19 @@ HasManyDoubleLinked.prototype.injectSetter = function(emitter, oldAssociations,
this.destroyObsoleteAssociations(oldAssociations, newAssociations) this.destroyObsoleteAssociations(oldAssociations, newAssociations)
.on('failure', function(err) { emitter.emit('failure', err) }) .on('failure', function(err) { emitter.emit('failure', err) })
.on('success', function() { .on('success', function() {
var chainer = new Utils.QueryChainer var chainer = new Utils.QueryChainer
var foreignIdentifier = self.definition.target.associations[self.definition.source.tableName].identifier , association = self.definition.target.associations[self.definition.combinedName]
var unassociatedObjects = newAssociations.filter(function(obj) { return !obj.equalsOneOf(oldAssociations) }) , foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier
, unassociatedObjects = newAssociations.filter(function(obj) { return !obj.equalsOneOf(oldAssociations) })
unassociatedObjects.forEach(function(unassociatedObject) { unassociatedObjects.forEach(function(unassociatedObject) {
var attributes = {} var attributes = {}
attributes[self.definition.identifier] = self.instance.id attributes[self.definition.identifier] = self.instance.id
attributes[foreignIdentifier] = unassociatedObject.id attributes[foreignIdentifier] = unassociatedObject.id
chainer.add(self.definition.connectorModel.create(attributes)) chainer.add(self.definition.connectorModel.create(attributes))
}) })
chainer chainer
.run() .run()
.on('success', function() { emitter.emit('success', newAssociations) }) .on('success', function() { emitter.emit('success', newAssociations) })
......
...@@ -8,6 +8,12 @@ var HasMany = module.exports = function(srcModel, targetModel, options) { ...@@ -8,6 +8,12 @@ var HasMany = module.exports = function(srcModel, targetModel, options) {
this.source = srcModel this.source = srcModel
this.target = targetModel this.target = targetModel
this.options = options this.options = options
this.isSelfAssociation = (this.source.tableName == this.target.tableName)
this.combinedName = Utils.combineTableNames(
this.source.tableName,
this.isSelfAssociation ? (this.options.as || this.target.tableName) : this.target.tableName
)
var as = (this.options.as || Utils.pluralize(this.target.tableName)) var as = (this.options.as || Utils.pluralize(this.target.tableName))
...@@ -22,21 +28,27 @@ var HasMany = module.exports = function(srcModel, targetModel, options) { ...@@ -22,21 +28,27 @@ var HasMany = module.exports = function(srcModel, targetModel, options) {
// the id is in the target table // the id is in the target table
// or in an extra table which connects two tables // or in an extra table which connects two tables
HasMany.prototype.injectAttributes = function() { HasMany.prototype.injectAttributes = function() {
var multiAssociation = this.target.associations.hasOwnProperty(this.combinedName)
this.identifier = this.options.foreignKey || Utils._.underscoredIf(Utils.singularize(this.source.tableName) + "Id", this.options.underscored) this.identifier = this.options.foreignKey || Utils._.underscoredIf(Utils.singularize(this.source.tableName) + "Id", this.options.underscored)
if (this.target.associations.hasOwnProperty(this.source.tableName)) { // is there already a single sided association between the source and the target?
// or is the association on the model itself?
if (this.isSelfAssociation || multiAssociation) {
// remove the obsolete association identifier from the source // remove the obsolete association identifier from the source
this.foreignIdentifier = this.target.associations[this.source.tableName].identifier if(this.isSelfAssociation) {
delete this.source.attributes[this.foreignIdentifier] this.foreignIdentifier = (this.options.as || this.target.tableName) + 'Id'
} else {
this.foreignIdentifier = this.target.associations[this.combinedName].identifier
delete this.source.attributes[this.foreignIdentifier]
}
// define a new model, which connects the models // define a new model, which connects the models
var combinedTableAttributes = {} var combinedTableAttributes = {}
combinedTableAttributes[this.identifier] = {type:DataTypes.INTEGER, primaryKey: true} combinedTableAttributes[this.identifier] = {type:DataTypes.INTEGER, primaryKey: true}
combinedTableAttributes[this.foreignIdentifier] = {type:DataTypes.INTEGER, primaryKey: true} combinedTableAttributes[this.foreignIdentifier] = {type:DataTypes.INTEGER, primaryKey: true}
this.connectorModel = this.connectorModel = this.source.modelManager.sequelize.define( this.combinedName, combinedTableAttributes )
this.target.associations[this.source.tableName].connectorModel = if(!this.isSelfAssociation) this.target.associations[this.combinedName].connectorModel = this.connectorModel
this.source.modelManager.sequelize.define(Utils.combineTableNames(this.source.tableName, this.target.tableName), combinedTableAttributes)
this.connectorModel.sync() this.connectorModel.sync()
} else { } else {
...@@ -50,7 +62,7 @@ HasMany.prototype.injectAttributes = function() { ...@@ -50,7 +62,7 @@ HasMany.prototype.injectAttributes = function() {
HasMany.prototype.injectGetter = function(obj) { HasMany.prototype.injectGetter = function(obj) {
var self = this var self = this
obj[this.accessors.get] = function() { obj[this.accessors.get] = function() {
var Class = self.connectorModel ? HasManyMultiLinked : HasManySingleLinked var Class = self.connectorModel ? HasManyMultiLinked : HasManySingleLinked
return new Class(self, this).injectGetter() return new Class(self, this).injectGetter()
......
...@@ -21,7 +21,7 @@ var Associations = module.exports = { ...@@ -21,7 +21,7 @@ var Associations = module.exports = {
// the id is in the foreign table or in a connecting table // the id is in the foreign table or in a connecting table
var HasMany = require("./has-many") var HasMany = require("./has-many")
var association = new HasMany(this, associatedModel, Utils._.extend((options||{}), this.options)) var association = new HasMany(this, associatedModel, Utils._.extend((options||{}), this.options))
this.associations[associatedModel.tableName] = association.injectAttributes() this.associations[association.combinedName] = association.injectAttributes()
} }
}, },
instanceMethods: { instanceMethods: {
......
...@@ -140,7 +140,6 @@ ModelDefinition.prototype.build = function(values, options) { ...@@ -140,7 +140,6 @@ ModelDefinition.prototype.build = function(values, options) {
} }
}) })
Utils._.each(this.options.instanceMethods || {}, function(fct, name) { instance[name] = fct }) Utils._.each(this.options.instanceMethods || {}, function(fct, name) { instance[name] = fct })
Utils._.each(this.associations, function(association, associationName) { Utils._.each(this.associations, function(association, associationName) {
association.injectGetter(instance) association.injectGetter(instance)
association.injectSetter(instance) association.injectSetter(instance)
......
...@@ -19,7 +19,7 @@ module.exports = { ...@@ -19,7 +19,7 @@ module.exports = {
Task.hasMany(User) Task.hasMany(User)
User.hasMany(Task) User.hasMany(Task)
assert.isUndefined(Task.attributes['User'+num+'Id']) assert.isUndefined(Task.attributes['User'+num+'Id'])
assert.isUndefined(User.attributes['User'+num+'Id']) assert.isUndefined(User.attributes['User'+num+'Id'])
...@@ -196,5 +196,46 @@ module.exports = { ...@@ -196,5 +196,46 @@ module.exports = {
}) })
}) })
}) })
},
'it should correctly build the connector model names': function(exit){
var num = parseInt(Math.random() * 99999999)
, Person = sequelize.define('Person' + num, { name: Sequelize.STRING })
Person.hasMany(Person, {as: 'Children'})
Person.hasMany(Person, {as: 'Friends'})
Person.hasMany(Person, {as: 'CoWorkers'})
Person.sync({force: true}).on('success', function() {
var modelNames = sequelize.modelManager.models.map(function(model) { return model.tableName })
, expectation = ["Person" + num + "s", "ChildrenPerson" + num + "s", "CoWorkersPerson" + num + "s", "FriendsPerson" + num + "s"]
expectation.forEach(function(ex) {
assert.eql(modelNames.indexOf(ex) > -1, true)
})
exit(function(){})
})
},
'it should correctly get and set the connected models': function(exit) {
var num = parseInt(Math.random() * 99999999)
, Person = sequelize.define('Person' + num, { name: Sequelize.STRING })
Person.hasMany(Person, {as: 'Children'})
Person.hasMany(Person, {as: 'Friends'})
Person.hasMany(Person, {as: 'CoWorkers'})
Person.sync({force: true}).on('success', function() {
Person.create({name: 'foobar'}).on('success', function(person) {
Person.create({name: 'friend'}).on('success', function(friend) {
person.setFriends([friend]).on('success', function() {
person.getFriends().on('success', function(friends) {
assert.eql(friends.length, 1)
assert.eql(friends[0].name, 'friend')
exit(function(){})
})
})
})
})
})
} }
} }
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!