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

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') ...@@ -2,8 +2,8 @@ var Utils = require('./../utils')
, Transaction = require('./../transaction') , Transaction = require('./../transaction')
module.exports = (function() { module.exports = (function() {
var HasManyDoubleLinked = function(definition, instance) { var HasManyDoubleLinked = function(association, instance) {
this.__factory = definition this.association = association
this.instance = instance this.instance = instance
// Alias the quoting methods for code brevity // Alias the quoting methods for code brevity
...@@ -17,32 +17,32 @@ module.exports = (function() { ...@@ -17,32 +17,32 @@ module.exports = (function() {
var customEventEmitter = new Utils.CustomEventEmitter(function() { var customEventEmitter = new Utils.CustomEventEmitter(function() {
var where = {} var where = {}
, through = self.__factory.through , through = self.association.through
, options = _options || {} , options = _options || {}
, queryOptions = {} , queryOptions = {}
, association = self.__factory.target.associations[self.__factory.associationAccessor] , targetAssociation = self.association.targetAssociation
//fully qualify //fully qualify
var instancePrimaryKeys = Object.keys(self.instance.daoFactory.primaryKeys) var instancePrimaryKeys = Object.keys(self.instance.daoFactory.primaryKeys)
, instancePrimaryKey = instancePrimaryKeys.length > 0 ? instancePrimaryKeys[0] : 'id' , 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) var primaryKeys = Object.keys(through.primaryKeys)
, foreignKey = primaryKeys.filter(function(pk) { return pk != self.__factory.identifier })[0] , foreignKey = primaryKeys.filter(function(pk) { return pk != self.association.identifier })[0]
, foreignPrimary = Object.keys(self.__factory.target.primaryKeys) , foreignPrimary = Object.keys(self.association.target.primaryKeys)
foreignPrimary = foreignPrimary.length === 1 ? foreignPrimary[0] : 'id' 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.hasJoinTableModel = true
queryOptions.joinTableModel = through queryOptions.joinTableModel = through
if (!options.attributes) { if (!options.attributes) {
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() { ...@@ -65,14 +65,14 @@ module.exports = (function() {
if (options.where) { if (options.where) {
if (Array.isArray(options.where)) { if (Array.isArray(options.where)) {
smart = Utils.smartWhere([where, options.where], 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.__factory.target, smart, self.__factory.target.daoFactoryManager.sequelize.options.dialect) smart = Utils.compileSmartWhere.call(self.association.target, smart, self.association.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) { if (smart.length > 0) {
options.where = smart options.where = smart
} }
} else { } else {
smart = Utils.smartWhere([where, options.where], 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.__factory.target, smart, self.__factory.target.daoFactoryManager.sequelize.options.dialect) smart = Utils.compileSmartWhere.call(self.association.target, smart, self.association.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) { if (smart.length > 0) {
options.where = smart options.where = smart
} }
...@@ -81,7 +81,7 @@ module.exports = (function() { ...@@ -81,7 +81,7 @@ module.exports = (function() {
options.where = where; 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('success', function(objects) { customEventEmitter.emit('success', objects) })
.on('error', function(err){ customEventEmitter.emit('error', err) }) .on('error', function(err){ customEventEmitter.emit('error', err) })
.on('sql', function(sql) { customEventEmitter.emit('sql', sql)}) .on('sql', function(sql) { customEventEmitter.emit('sql', sql)})
...@@ -93,10 +93,10 @@ module.exports = (function() { ...@@ -93,10 +93,10 @@ module.exports = (function() {
HasManyDoubleLinked.prototype.injectSetter = function(emitterProxy, oldAssociations, newAssociations, defaultAttributes) { HasManyDoubleLinked.prototype.injectSetter = function(emitterProxy, oldAssociations, newAssociations, defaultAttributes) {
var self = this var self = this
, chainer = new Utils.QueryChainer() , chainer = new Utils.QueryChainer()
, association = self.__factory.target.associations[self.__factory.associationAccessor] , targetAssociation = self.association.targetAssociation
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier , foreignIdentifier = targetAssociation.isSelfAssociation ? targetAssociation.foreignIdentifier : targetAssociation.identifier
, sourceKeys = Object.keys(self.__factory.source.primaryKeys) , sourceKeys = Object.keys(self.association.source.primaryKeys)
, targetKeys = Object.keys(self.__factory.target.primaryKeys) , targetKeys = Object.keys(self.association.target.primaryKeys)
, obsoleteAssociations = [] , obsoleteAssociations = []
, changedAssociations = [] , changedAssociations = []
, options = {} , options = {}
...@@ -120,13 +120,13 @@ module.exports = (function() { ...@@ -120,13 +120,13 @@ module.exports = (function() {
if (!newObj) { if (!newObj) {
obsoleteAssociations.push(old) obsoleteAssociations.push(old)
} else if (Object(association.through) === association.through) { } else if (Object(targetAssociation.through) === targetAssociation.through) {
var changedAssociation = { var changedAssociation = {
where: {}, 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 changedAssociation.where[foreignIdentifier] = newObj[foreignIdentifier] || newObj.id
changedAssociations.push(changedAssociation) changedAssociations.push(changedAssociation)
...@@ -140,32 +140,32 @@ module.exports = (function() { ...@@ -140,32 +140,32 @@ module.exports = (function() {
var where = {} 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 where[foreignIdentifier] = foreignIds
chainer.add(self.__factory.through.destroy(where, options)) chainer.add(self.association.through.destroy(where, options))
} }
if (unassociatedObjects.length > 0) { if (unassociatedObjects.length > 0) {
var bulk = unassociatedObjects.map(function(unassociatedObject) { var bulk = unassociatedObjects.map(function(unassociatedObject) {
var attributes = {} 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) attributes[foreignIdentifier] = ((targetKeys.length === 1) ? unassociatedObject[targetKeys[0]] : unassociatedObject.id)
if (Object(association.through) === association.through) { if (Object(targetAssociation.through) === targetAssociation.through) {
attributes = Utils._.defaults(attributes, unassociatedObject[association.through.name], defaultAttributes) attributes = Utils._.defaults(attributes, unassociatedObject[targetAssociation.through.name], defaultAttributes)
} }
return attributes return attributes
}) })
chainer.add(self.__factory.through.bulkCreate(bulk, options)) chainer.add(self.association.through.bulkCreate(bulk, options))
} }
if (changedAssociations.length > 0) { if (changedAssociations.length > 0) {
changedAssociations.forEach(function (assoc) { 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() { ...@@ -177,27 +177,25 @@ module.exports = (function() {
} }
HasManyDoubleLinked.prototype.injectAdder = function(emitterProxy, newAssociation, additionalAttributes, exists) { HasManyDoubleLinked.prototype.injectAdder = function(emitterProxy, newAssociation, additionalAttributes, exists) {
var attributes = {} var attributes = {}
, association = this.__factory.target.associations[this.__factory.associationAccessor] , targetAssociation = this.association.targetAssociation
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier; , foreignIdentifier = targetAssociation.isSelfAssociation ? targetAssociation.foreignIdentifier : targetAssociation.identifier;
var sourceKeys = Object.keys(this.__factory.source.primaryKeys); var sourceKeys = Object.keys(this.association.source.primaryKeys);
var targetKeys = Object.keys(this.__factory.target.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) attributes[foreignIdentifier] = ((targetKeys.length === 1) ? newAssociation[targetKeys[0]] : newAssociation.id)
if (exists) { // implies hasJoinTableModel === true if (exists) { // implies hasJoinTableModel === true
var where = attributes var where = attributes
attributes = Utils._.defaults({}, newAssociation[association.through.name], additionalAttributes) attributes = Utils._.defaults({}, newAssociation[association.through.name], additionalAttributes)
association.through.update(attributes, where).proxy(emitterProxy) targetAssociation.through.update(attributes, where).proxy(emitterProxy)
} else { } else {
if (Object(association.through) === association.through) { attributes = Utils._.defaults(attributes, newAssociation[targetAssociation.through.name], additionalAttributes)
attributes = Utils._.defaults(attributes, newAssociation[association.through.name], additionalAttributes)
}
this.__factory.through.create(attributes) this.association.through.create(attributes)
.success(function() { emitterProxy.emit('success', newAssociation) }) .success(function() { emitterProxy.emit('success', newAssociation) })
.error(function(err) { emitterProxy.emit('error', err) }) .error(function(err) { emitterProxy.emit('error', err) })
.on('sql', function(sql) { emitterProxy.emit('sql', sql) }) .on('sql', function(sql) { emitterProxy.emit('sql', sql) })
......
...@@ -231,7 +231,7 @@ module.exports = (function() { ...@@ -231,7 +231,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 = Object(self.through) === self.through ? HasManyMultiLinked : HasManySingleLinked var Class = self.doubleLinked ? HasManyMultiLinked : HasManySingleLinked
new Class(self, instance).injectSetter(emitter, oldAssociatedObjects, newAssociatedObjects, defaultAttributes) new Class(self, instance).injectSetter(emitter, oldAssociatedObjects, newAssociatedObjects, defaultAttributes)
}) })
.error(function(err) { .error(function(err) {
...@@ -256,7 +256,7 @@ module.exports = (function() { ...@@ -256,7 +256,7 @@ module.exports = (function() {
.error(function(err){ emitter.emit('error', err)}) .error(function(err){ emitter.emit('error', err)})
.success(function(currentAssociatedObjects) { .success(function(currentAssociatedObjects) {
if (currentAssociatedObjects.length === 0 || self.hasJoinTableModel === true) { 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) new Class(self, instance).injectAdder(emitter, newAssociatedObject, additionalAttributes, !!currentAssociatedObjects.length)
} else { } else {
emitter.emit('success', newAssociatedObject); emitter.emit('success', newAssociatedObject);
......
...@@ -64,7 +64,8 @@ ...@@ -64,7 +64,8 @@
"chai-spies": "~0.5.1", "chai-spies": "~0.5.1",
"lcov-result-merger": "0.0.2", "lcov-result-merger": "0.0.2",
"istanbul": "~0.1.45", "istanbul": "~0.1.45",
"coveralls": "~2.5.0" "coveralls": "~2.5.0",
"async": "~0.2.9"
}, },
"keywords": [ "keywords": [
"mysql", "mysql",
...@@ -84,4 +85,4 @@ ...@@ -84,4 +85,4 @@
"node": ">=0.6.21" "node": ">=0.6.21"
}, },
"license": "MIT" "license": "MIT"
} }
\ No newline at end of file
...@@ -909,9 +909,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -909,9 +909,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
Group.hasMany(User, { as: 'MyUsers', through: 'group_user'}) Group.hasMany(User, { as: 'MyUsers', through: 'group_user'})
this.sequelize.sync({force:true}).success(function () { this.sequelize.sync({force:true}).success(function () {
self.sequelize.query("SHOW TABLES LIKE 'group_user'").success(function (res) { self.sequelize.getQueryInterface().showAllTables().success(function (result) {
expect(res).to.deep.equal(['group_user']) expect(result.indexOf('group_user')).not.to.equal(-1)
done() done()
}) })
}) })
}) })
...@@ -926,9 +926,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -926,9 +926,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
Group.hasMany(User, { as: 'MyUsers', through: UserGroup}) Group.hasMany(User, { as: 'MyUsers', through: UserGroup})
this.sequelize.sync({force:true}).success(function () { this.sequelize.sync({force:true}).success(function () {
self.sequelize.query("SHOW TABLES LIKE 'user_groups'").success(function (res) { self.sequelize.getQueryInterface().showAllTables().success(function (result) {
expect(res).to.deep.equal(['user_groups']) expect(result.indexOf('user_groups')).not.to.equal(-1)
done() done()
}) })
}) })
}) })
......
...@@ -11,6 +11,7 @@ var chai = require('chai') ...@@ -11,6 +11,7 @@ var chai = require('chai')
, datetime = require('chai-datetime') , datetime = require('chai-datetime')
, _ = require('lodash') , _ = require('lodash')
, moment = require('moment') , moment = require('moment')
, async = require('async')
chai.use(datetime) chai.use(datetime)
chai.Assertion.includeStack = true chai.Assertion.includeStack = true
...@@ -2451,6 +2452,120 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -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() { describe('queryOptions', function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!