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

Commit 72941d80 by Mick Hansen

Tests for fetching N:M with aliases + more refactoring

1 parent 23c6c854
......@@ -2,8 +2,8 @@ var Utils = require('./../utils')
, Transaction = require('./../transaction')
module.exports = (function() {
var HasManyDoubleLinked = function(definition, instance) {
this.__factory = definition
var HasManyDoubleLinked = function(association, instance) {
this.association = association
this.instance = instance
// Alias the quoting methods for code brevity
......@@ -17,32 +17,32 @@ module.exports = (function() {
var customEventEmitter = new Utils.CustomEventEmitter(function() {
var where = {}
, through = self.__factory.through
, through = self.association.through
, options = _options || {}
, queryOptions = {}
, association = self.__factory.target.associations[self.__factory.associationAccessor]
, targetAssociation = self.association.targetAssociation
//fully qualify
var instancePrimaryKeys = Object.keys(self.instance.daoFactory.primaryKeys)
, instancePrimaryKey = instancePrimaryKeys.length > 0 ? instancePrimaryKeys[0] : 'id'
where[through.tableName+"."+self.__factory.identifier] = self.instance[instancePrimaryKey]
where[through.tableName+"."+self.association.identifier] = self.instance[instancePrimaryKey]
var primaryKeys = Object.keys(through.primaryKeys)
, foreignKey = primaryKeys.filter(function(pk) { return pk != self.__factory.identifier })[0]
, foreignPrimary = Object.keys(self.__factory.target.primaryKeys)
, foreignKey = primaryKeys.filter(function(pk) { return pk != self.association.identifier })[0]
, foreignPrimary = Object.keys(self.association.target.primaryKeys)
foreignPrimary = foreignPrimary.length === 1 ? foreignPrimary[0] : 'id'
where[through.tableName+"."+foreignKey] = {join: self.__factory.target.tableName+"."+foreignPrimary}
where[through.tableName+"."+foreignKey] = {join: self.association.target.tableName+"."+foreignPrimary}
if (Object(association.through) === association.through) {
if (Object(targetAssociation.through) === targetAssociation.through) {
queryOptions.hasJoinTableModel = true
queryOptions.joinTableModel = through
if (!options.attributes) {
options.attributes = [
self.QueryInterface.quoteIdentifier(self.__factory.target.tableName)+".*"
self.QueryInterface.quoteIdentifier(self.association.target.tableName)+".*"
]
}
......@@ -65,14 +65,14 @@ module.exports = (function() {
if (options.where) {
if (Array.isArray(options.where)) {
smart = Utils.smartWhere([where, options.where], self.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.__factory.target, smart, self.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.smartWhere([where, options.where], self.association.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.association.target, smart, self.association.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) {
options.where = smart
}
} else {
smart = Utils.smartWhere([where, options.where], self.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.__factory.target, smart, self.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.smartWhere([where, options.where], self.association.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.association.target, smart, self.association.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) {
options.where = smart
}
......@@ -81,7 +81,7 @@ module.exports = (function() {
options.where = where;
}
self.__factory.target.findAllJoin(through.tableName, options, queryOptions)
self.association.target.findAllJoin(through.tableName, 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)})
......@@ -93,10 +93,10 @@ module.exports = (function() {
HasManyDoubleLinked.prototype.injectSetter = function(emitterProxy, oldAssociations, newAssociations, defaultAttributes) {
var self = this
, chainer = new Utils.QueryChainer()
, association = self.__factory.target.associations[self.__factory.associationAccessor]
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier
, sourceKeys = Object.keys(self.__factory.source.primaryKeys)
, targetKeys = Object.keys(self.__factory.target.primaryKeys)
, targetAssociation = self.association.targetAssociation
, foreignIdentifier = targetAssociation.isSelfAssociation ? targetAssociation.foreignIdentifier : targetAssociation.identifier
, sourceKeys = Object.keys(self.association.source.primaryKeys)
, targetKeys = Object.keys(self.association.target.primaryKeys)
, obsoleteAssociations = []
, changedAssociations = []
, options = {}
......@@ -120,13 +120,13 @@ module.exports = (function() {
if (!newObj) {
obsoleteAssociations.push(old)
} else if (Object(association.through) === association.through) {
} else if (Object(targetAssociation.through) === targetAssociation.through) {
var changedAssociation = {
where: {},
attributes: Utils._.defaults({}, newObj[self.__factory.through.name], defaultAttributes)
attributes: Utils._.defaults({}, newObj[self.association.through.name], defaultAttributes)
}
changedAssociation.where[self.__factory.identifier] = self.instance[self.__factory.identifier] || self.instance.id
changedAssociation.where[self.association.identifier] = self.instance[self.association.identifier] || self.instance.id
changedAssociation.where[foreignIdentifier] = newObj[foreignIdentifier] || newObj.id
changedAssociations.push(changedAssociation)
......@@ -140,32 +140,32 @@ module.exports = (function() {
var where = {}
where[self.__factory.identifier] = ((sourceKeys.length === 1) ? self.instance[sourceKeys[0]] : self.instance.id)
where[self.association.identifier] = ((sourceKeys.length === 1) ? self.instance[sourceKeys[0]] : self.instance.id)
where[foreignIdentifier] = foreignIds
chainer.add(self.__factory.through.destroy(where, options))
chainer.add(self.association.through.destroy(where, options))
}
if (unassociatedObjects.length > 0) {
var bulk = unassociatedObjects.map(function(unassociatedObject) {
var attributes = {}
attributes[self.__factory.identifier] = ((sourceKeys.length === 1) ? self.instance[sourceKeys[0]] : self.instance.id)
attributes[self.association.identifier] = ((sourceKeys.length === 1) ? self.instance[sourceKeys[0]] : self.instance.id)
attributes[foreignIdentifier] = ((targetKeys.length === 1) ? unassociatedObject[targetKeys[0]] : unassociatedObject.id)
if (Object(association.through) === association.through) {
attributes = Utils._.defaults(attributes, unassociatedObject[association.through.name], defaultAttributes)
if (Object(targetAssociation.through) === targetAssociation.through) {
attributes = Utils._.defaults(attributes, unassociatedObject[targetAssociation.through.name], defaultAttributes)
}
return attributes
})
chainer.add(self.__factory.through.bulkCreate(bulk, options))
chainer.add(self.association.through.bulkCreate(bulk, options))
}
if (changedAssociations.length > 0) {
changedAssociations.forEach(function (assoc) {
chainer.add(self.__factory.through.update(assoc.attributes, assoc.where, options))
chainer.add(self.association.through.update(assoc.attributes, assoc.where, options))
})
}
......@@ -177,27 +177,25 @@ module.exports = (function() {
}
HasManyDoubleLinked.prototype.injectAdder = function(emitterProxy, newAssociation, additionalAttributes, exists) {
var attributes = {}
, association = this.__factory.target.associations[this.__factory.associationAccessor]
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier;
var attributes = {}
, targetAssociation = this.association.targetAssociation
, foreignIdentifier = targetAssociation.isSelfAssociation ? targetAssociation.foreignIdentifier : targetAssociation.identifier;
var sourceKeys = Object.keys(this.__factory.source.primaryKeys);
var targetKeys = Object.keys(this.__factory.target.primaryKeys);
var sourceKeys = Object.keys(this.association.source.primaryKeys);
var targetKeys = Object.keys(this.association.target.primaryKeys);
attributes[this.__factory.identifier] = ((sourceKeys.length === 1) ? this.instance[sourceKeys[0]] : this.instance.id)
attributes[this.association.identifier] = ((sourceKeys.length === 1) ? this.instance[sourceKeys[0]] : this.instance.id)
attributes[foreignIdentifier] = ((targetKeys.length === 1) ? newAssociation[targetKeys[0]] : newAssociation.id)
if (exists) { // implies hasJoinTableModel === true
var where = attributes
attributes = Utils._.defaults({}, newAssociation[association.through.name], additionalAttributes)
association.through.update(attributes, where).proxy(emitterProxy)
targetAssociation.through.update(attributes, where).proxy(emitterProxy)
} else {
if (Object(association.through) === association.through) {
attributes = Utils._.defaults(attributes, newAssociation[association.through.name], additionalAttributes)
}
attributes = Utils._.defaults(attributes, newAssociation[targetAssociation.through.name], additionalAttributes)
this.__factory.through.create(attributes)
this.association.through.create(attributes)
.success(function() { emitterProxy.emit('success', newAssociation) })
.error(function(err) { emitterProxy.emit('error', err) })
.on('sql', function(sql) { emitterProxy.emit('sql', sql) })
......
......@@ -231,7 +231,7 @@ module.exports = (function() {
return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]()
.success(function(oldAssociatedObjects) {
var Class = Object(self.through) === self.through ? HasManyMultiLinked : HasManySingleLinked
var Class = self.doubleLinked ? HasManyMultiLinked : HasManySingleLinked
new Class(self, instance).injectSetter(emitter, oldAssociatedObjects, newAssociatedObjects, defaultAttributes)
})
.error(function(err) {
......@@ -256,7 +256,7 @@ module.exports = (function() {
.error(function(err){ emitter.emit('error', err)})
.success(function(currentAssociatedObjects) {
if (currentAssociatedObjects.length === 0 || self.hasJoinTableModel === true) {
var Class = Object(self.through) === self.through ? HasManyMultiLinked : HasManySingleLinked
var Class = self.doubleLinked ? HasManyMultiLinked : HasManySingleLinked
new Class(self, instance).injectAdder(emitter, newAssociatedObject, additionalAttributes, !!currentAssociatedObjects.length)
} else {
emitter.emit('success', newAssociatedObject);
......
......@@ -64,7 +64,8 @@
"chai-spies": "~0.5.1",
"lcov-result-merger": "0.0.2",
"istanbul": "~0.1.45",
"coveralls": "~2.5.0"
"coveralls": "~2.5.0",
"async": "~0.2.9"
},
"keywords": [
"mysql",
......@@ -84,4 +85,4 @@
"node": ">=0.6.21"
},
"license": "MIT"
}
\ No newline at end of file
}
......@@ -909,9 +909,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
Group.hasMany(User, { as: 'MyUsers', through: 'group_user'})
this.sequelize.sync({force:true}).success(function () {
self.sequelize.query("SHOW TABLES LIKE 'group_user'").success(function (res) {
expect(res).to.deep.equal(['group_user'])
done()
self.sequelize.getQueryInterface().showAllTables().success(function (result) {
expect(result.indexOf('group_user')).not.to.equal(-1)
done()
})
})
})
......@@ -926,9 +926,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
Group.hasMany(User, { as: 'MyUsers', through: UserGroup})
this.sequelize.sync({force:true}).success(function () {
self.sequelize.query("SHOW TABLES LIKE 'user_groups'").success(function (res) {
expect(res).to.deep.equal(['user_groups'])
done()
self.sequelize.getQueryInterface().showAllTables().success(function (result) {
expect(result.indexOf('user_groups')).not.to.equal(-1)
done()
})
})
})
......
......@@ -11,6 +11,7 @@ var chai = require('chai')
, datetime = require('chai-datetime')
, _ = require('lodash')
, moment = require('moment')
, async = require('async')
chai.use(datetime)
chai.Assertion.includeStack = true
......@@ -2451,6 +2452,120 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
})
})
describe('hasMany (N:M) with alias', function () {
beforeEach(function (done) {
this.Product = this.sequelize.define('Product', { title: Sequelize.STRING })
this.Tag = this.sequelize.define('Tag', { name: Sequelize.STRING })
done();
})
it('returns the associated models when using through as string and alias', function (done) {
var self = this
this.Product.hasMany(this.Tag, {as: 'Tags', through: 'product_tag'})
this.Tag.hasMany(this.Product, {as: 'Products', through: 'product_tag'})
this.sequelize.sync().done(function (err) {
async.auto({
createProducts: function (callback) {
self.Product.bulkCreate([
{title: 'Chair'},
{title: 'Desk'},
{title: 'Handbag'},
{title: 'Dress'},
{title: 'Jan'}
]).done(callback)
},
// bulkCreate doesn't include id for some reason, not going to fix tis now
products: ['createProducts', function (callback) {
self.Product.findAll().done(callback)
}],
createTags: function (callback) {
self.Tag.bulkCreate([
{title: 'Furniture'},
{title: 'Clothing'},
{title: 'People'}
]).done(callback)
},
tags: ['createTags', function (callback) {
self.Tag.findAll().done(callback)
}],
}, function (err, results) {
expect(err).not.to.exist
var products = results.products
, tags = results.tags
async.parallel([
function (callback) {
products[0].setTags([tags[0], tags[1]]).done(callback)
},
function (callback) {
products[1].addTag(tags[0]).done(callback)
},
function (callback) {
products[2].addTag(tags[1]).done(callback)
},
function (callback) {
products[3].setTags([tags[1]]).done(callback)
},
function (callback) {
products[4].setTags([tags[2]]).done(callback)
}
], function (err) {
expect(err).not.to.exist
async.parallel([
function (callback) {
self.Tag.find({
where: {
id: tags[0].id
},
include: [
{model: self.Product, as: 'Products'}
]
}).done(function (err, tag) {
expect(tag).to.exist
expect(tag.products.length).to.equal(2)
callback()
})
},
function (callback) {
tags[1].getProducts().done(function (err, products) {
expect(products.length).to.equal(3)
callback()
})
},
function (callback) {
self.Product.find({
where: {
id: products[0].id
},
include: [
{model: self.Tag, as: 'Tags'}
]
}).done(function (err, product) {
expect(product).to.exist
expect(product.tags.length).to.equal(2)
callback()
})
},
function (callback) {
products[1].getTags().done(function (err, tags) {
expect(tags.length).to.equal(1)
callback()
})
},
], done)
})
})
})
})
it('returns the associated models when using through as model and alias')
})
})
describe('queryOptions', function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!