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

Commit 803192aa by Sascha Depold

many-to-many connection is working. woot!

1 parent 832fa070
...@@ -17,7 +17,7 @@ var HasMany = module.exports = function(srcModel, targetModel, options) { ...@@ -17,7 +17,7 @@ var HasMany = module.exports = function(srcModel, targetModel, options) {
HasMany.prototype.injectAttributes = function() { HasMany.prototype.injectAttributes = function() {
this.identifier = this.options.foreignKey || Utils._.underscoredIf(this.source.tableName + "Id", this.options.underscored) this.identifier = this.options.foreignKey || Utils._.underscoredIf(this.source.tableName + "Id", this.options.underscored)
if(this.target.associations.hasOwnProperty(this.source.tableName)) { if (this.target.associations.hasOwnProperty(this.source.tableName)) {
// 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 this.foreignIdentifier = this.target.associations[this.source.tableName].identifier
delete this.source.attributes[this.foreignIdentifier] delete this.source.attributes[this.foreignIdentifier]
...@@ -30,6 +30,8 @@ HasMany.prototype.injectAttributes = function() { ...@@ -30,6 +30,8 @@ HasMany.prototype.injectAttributes = function() {
this.connectorModel = this.connectorModel =
this.target.associations[this.source.tableName].connectorModel = this.target.associations[this.source.tableName].connectorModel =
this.source.modelManager.sequelize.define(Utils.combineTableNames(this.source.tableName, this.target.tableName), combinedTableAttributes) this.source.modelManager.sequelize.define(Utils.combineTableNames(this.source.tableName, this.target.tableName), combinedTableAttributes)
this.connectorModel.sync()
} else { } else {
var newAttributes = {} var newAttributes = {}
newAttributes[this.identifier] = { type: DataTypes.INTEGER } newAttributes[this.identifier] = { type: DataTypes.INTEGER }
...@@ -43,13 +45,17 @@ HasMany.prototype.injectGetter = function(obj) { ...@@ -43,13 +45,17 @@ HasMany.prototype.injectGetter = function(obj) {
var self = this var self = this
obj[this.accessors.get] = function() { obj[this.accessors.get] = function() {
var instance = this
if(self.connectorModel) { if(self.connectorModel) {
var where = {} var customEventEmitter = new Utils.CustomEventEmitter(function() {
var where = {}
where[self.identifier] = instance.id
where[self.identifier] = this.id self.connectorModel.findAll({where: where}).on('success', function(associatedObjects) {
self.connectorModel.findAll({where: where}).on('success', function(associationObjects) { customEventEmitter.emit('success', associatedObjects)
console.log(associationObjects) })
}) })
return customEventEmitter.run()
} else { } else {
var where = {} var where = {}
...@@ -63,27 +69,39 @@ HasMany.prototype.injectGetter = function(obj) { ...@@ -63,27 +69,39 @@ HasMany.prototype.injectGetter = function(obj) {
HasMany.prototype.injectSetter = function(obj) { HasMany.prototype.injectSetter = function(obj) {
var self = this var self = this
obj[this.accessors.set] = function(newAssociatedObjects) { obj[this.accessors.set] = function(newAssociatedObjects) {
var instance = this var instance = this
// define the returned customEventEmitter, which will emit the success event once everything is done // define the returned customEventEmitter, which will emit the success event once everything is done
var customEventEmitter = new Utils.CustomEventEmitter(function() { var customEventEmitter = new Utils.CustomEventEmitter(function() {
instance[self.accessors.get]().on('success', function(oldAssociatedObjects) { instance[self.accessors.get]().on('success', function(oldAssociatedObjects) {
if(self.connectorModel) { if(self.connectorModel) {
var foreignIdentifier = self.target.associations[self.source.tableName].identifier
var destroyChainer = new QueryChainer
// destroy the old association objects // destroy the old association objects
oldAssociatedObjects.forEach(function(associatedObject) { oldAssociatedObjects.forEach(function(associatedObject) { destroyChainer.add(associatedObject.destroy()) })
associatedObject.destroy() destroyChainer
}) .run()
.on('failure', function(err) { customEventEmitter.emit('failure', err) })
// create new one .on('success', function() {
newAssociatedObjects.forEach(function(associatedObject) { // create new one
var attributes = {}
attributes[self.identifier] = instance.id var createChainer = new QueryChainer
attributes[self.foreignIdentifier] = associatedObject.id newAssociatedObjects.forEach(function(associatedObject) {
self.connectorModel.create(attributes) var attributes = {}
attributes[self.identifier] = instance.id
attributes[foreignIdentifier] = associatedObject.id
createChainer.add(self.connectorModel.create(attributes))
})
createChainer
.run()
.on('success', function() { customEventEmitter.emit('success', null) })
.on('failure', function(err) { customEventEmitter.emit('failure', err) })
}) })
customEventEmitter.emit('success', null)
} else { } else {
// clear the old associations // clear the old associations
oldAssociatedObjects.forEach(function(associatedObject) { oldAssociatedObjects.forEach(function(associatedObject) {
...@@ -97,13 +115,14 @@ HasMany.prototype.injectSetter = function(obj) { ...@@ -97,13 +115,14 @@ HasMany.prototype.injectSetter = function(obj) {
associatedObject[self.identifier] = instance.id associatedObject[self.identifier] = instance.id
chainer.add(associatedObject.save()) chainer.add(associatedObject.save())
}) })
chainer.run() chainer
.on('success', function() { customEventEmitter.emit('success', null) }) .run()
.on('failure', function() { customEventEmitter.emit('failure', null) }) .on('success', function() { customEventEmitter.emit('success', null) })
.on('failure', function() { customEventEmitter.emit('failure', null) })
} }
}) })
}) })
return customEventEmitter return customEventEmitter.run()
} }
return this return this
......
...@@ -48,14 +48,12 @@ HasOne.prototype.injectSetter = function(obj) { ...@@ -48,14 +48,12 @@ HasOne.prototype.injectSetter = function(obj) {
} }
associatedObject[self.identifier] = obj.id associatedObject[self.identifier] = obj.id
associatedObject.save().on('success', function() { associatedObject.save()
customEventEmitter.emit('success', '') .on('success', function() { customEventEmitter.emit('success', '') })
}).on('failure', function(err) { .on('failure', function(err) { customEventEmitter.emit('failure', err) })
customEventEmitter.emit('failure', err)
})
}) })
}) })
return customEventEmitter return customEventEmitter.run()
} }
return this return this
......
...@@ -70,7 +70,8 @@ Model.prototype.destroy = function() { ...@@ -70,7 +70,8 @@ Model.prototype.destroy = function() {
this[this.options.underscored ? 'deleted_at' : 'deletedAt'] = new Date() this[this.options.underscored ? 'deleted_at' : 'deletedAt'] = new Date()
return this.save() return this.save()
} else { } else {
return this.query(QueryGenerator.deleteQuery(this.definition.tableName, this.id)) var identifier = this.options.hasPrimaryKeys ? this.primaryKeyValues : this.id
return this.query(QueryGenerator.deleteQuery(this.definition.tableName, identifier))
} }
} }
...@@ -96,5 +97,16 @@ Model.prototype.__defineGetter__('values', function() { ...@@ -96,5 +97,16 @@ Model.prototype.__defineGetter__('values', function() {
return result return result
}) })
Model.prototype.__defineGetter__('primaryKeyValues', function() {
var result = {}
, self = this
Utils._.each(this.definition.primaryKeys, function(_, attr) {
result[attr] = self[attr]
})
return result
})
/* Add the instance methods to Model */ /* Add the instance methods to Model */
Utils._.map(Mixin.instanceMethods, function(fct, name) { Model.prototype[name] = fct}) Utils._.map(Mixin.instanceMethods, function(fct, name) { Model.prototype[name] = fct})
\ No newline at end of file
...@@ -8,7 +8,7 @@ var QueryChainer = module.exports = function(emitters) { ...@@ -8,7 +8,7 @@ var QueryChainer = module.exports = function(emitters) {
this.fails = [] this.fails = []
this.finished = false this.finished = false
this.runned = false this.runned = false
this.instance = null this.eventEmitter = null
emitters = emitters || [] emitters = emitters || []
emitters.forEach(function(emitter) { self.add(emitter) }) emitters.forEach(function(emitter) { self.add(emitter) })
...@@ -28,14 +28,16 @@ QueryChainer.prototype.observeEmitter = function(emitter) { ...@@ -28,14 +28,16 @@ QueryChainer.prototype.observeEmitter = function(emitter) {
QueryChainer.prototype.finish = function(result) { QueryChainer.prototype.finish = function(result) {
this.finished = (this.finishedEmits == this.emitters.length) this.finished = (this.finishedEmits == this.emitters.length)
if(this.finished && this.runned) { if(this.finished && this.runned) {
this.instance.emit(this.fails.length == 0 ? 'success' : 'failure', result) var status = this.fails.length == 0 ? 'success' : 'failure'
result = this.fails.length == 0 ? result : this.fails
this.eventEmitter.emit(status, result)
} }
} }
QueryChainer.prototype.run = function() { QueryChainer.prototype.run = function() {
var self = this var self = this
this.instance = new Utils.CustomEventEmitter(function() { this.eventEmitter = new Utils.CustomEventEmitter(function() {
self.runned = true self.runned = true
self.finish() self.finish()
}) })
return this.instance return this.eventEmitter.run()
} }
\ No newline at end of file
...@@ -9,8 +9,20 @@ var QueryGenerator = module.exports = { ...@@ -9,8 +9,20 @@ var QueryGenerator = module.exports = {
options = options || {} options = options || {}
var query = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>);" var query = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>);"
, attrStr = Utils._.map(attributes, function(dataType, attr) { return Utils.addTicks(attr) + " " + dataType}).join(", ") , primaryKeys = []
, attrStr = Utils._.map(attributes, function(dataType, attr) {
var dt = dataType
if (Utils._.includes(dt, 'PRIMARY KEY')) {
primaryKeys.push(attr)
return Utils.addTicks(attr) + " " + dt.replace(/PRIMARY KEY/, '')
} else {
return Utils.addTicks(attr) + " " + dt
}
}).join(", ")
, values = {table: Utils.addTicks(tableName), attributes: attrStr} , values = {table: Utils.addTicks(tableName), attributes: attrStr}
, pkString = primaryKeys.map(function(pk) {return Utils.addTicks(pk)}).join(", ")
if (pkString.length > 0) values.attributes += ", PRIMARY KEY (" + pkString + ")"
return Utils._.template(query)(values) return Utils._.template(query)(values)
}, },
......
...@@ -128,5 +128,13 @@ var Utils = module.exports = { ...@@ -128,5 +128,13 @@ var Utils = module.exports = {
} }
} }
Utils.CustomEventEmitter = function(fct) { fct() } var CustomEventEmitter = Utils.CustomEventEmitter = function(fct) {
Utils.addEventEmitter(Utils.CustomEventEmitter) this.fct = fct
\ No newline at end of file }
Utils.addEventEmitter(CustomEventEmitter)
CustomEventEmitter.prototype.run = function() {
var self = this
setTimeout(function(){ self.fct() }, 5) // delay the function call and return the emitter
return this
}
\ No newline at end of file
...@@ -157,5 +157,41 @@ module.exports = { ...@@ -157,5 +157,41 @@ module.exports = {
}) })
}) })
}) })
},
'it should set and get the correct objects - bidirectional': function(exit) {
var User = sequelize.define('User' + parseInt(Math.random() * 99999999), { username: Sequelize.STRING })
var Task = sequelize.define('Task' + parseInt(Math.random() * 99999999), { title: Sequelize.STRING })
User.hasMany(Task, {as: 'Tasks'})
Task.hasMany(User, {as: 'Users'})
User.sync({force: true}).on('success', function() {
Task.sync({force: true}).on('success', function() {
User.create({username: 'name'}).on('success', function(user1) {
User.create({username: 'name2'}).on('success', function(user2) {
Task.create({title: 'task1'}).on('success', function(task1) {
Task.create({title: 'task2'}).on('success', function(task2) {
user1.setTasks([task1, task2]).on('success', function() {
user1.getTasks().on('success', function(tasks) {
assert.eql(tasks.length, 2)
task2.setUsers([user1, user2]).on('success', function() {
task2.getUsers().on('success', function(users) {
assert.eql(users.length, 2)
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!