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

Commit 7bb9c07e by Mick Hansen

fix(associations): fix bug with associatons and field, closes #2361, #2350

1 parent 0d20e13d
...@@ -83,6 +83,8 @@ module.exports = (function() { ...@@ -83,6 +83,8 @@ module.exports = (function() {
Helpers.addForeignKeyConstraints(newAttributes[this.identifier], this.target, this.source, this.options); Helpers.addForeignKeyConstraints(newAttributes[this.identifier], this.target, this.source, this.options);
Utils.mergeDefaults(this.source.rawAttributes, newAttributes); Utils.mergeDefaults(this.source.rawAttributes, newAttributes);
this.identifierField = this.source.rawAttributes[this.identifier].field || this.identifier;
// Sync attributes and setters/getters to DAO prototype // Sync attributes and setters/getters to DAO prototype
this.source.refreshAttributes(); this.source.refreshAttributes();
......
...@@ -49,7 +49,8 @@ module.exports = (function() { ...@@ -49,7 +49,8 @@ module.exports = (function() {
isSingleAssociation: true, isSingleAssociation: true,
source: self.association.target, source: self.association.target,
target: self.association.source, target: self.association.source,
identifier: self.association.foreignIdentifier identifier: self.association.foreignIdentifier,
identifierField: self.association.foreignIdentifierField
}, },
required: true, required: true,
where: throughWhere, where: throughWhere,
......
...@@ -279,6 +279,16 @@ module.exports = (function() { ...@@ -279,6 +279,16 @@ module.exports = (function() {
this.through.model.rawAttributes[this.identifier] = Utils._.extend(this.through.model.rawAttributes[this.identifier], sourceAttribute); this.through.model.rawAttributes[this.identifier] = Utils._.extend(this.through.model.rawAttributes[this.identifier], sourceAttribute);
this.through.model.rawAttributes[this.foreignIdentifier] = Utils._.extend(this.through.model.rawAttributes[this.foreignIdentifier], targetAttribute); this.through.model.rawAttributes[this.foreignIdentifier] = Utils._.extend(this.through.model.rawAttributes[this.foreignIdentifier], targetAttribute);
this.identifierField = this.through.model.rawAttributes[this.identifier].field || this.identifier;
this.foreignIdentifierField = this.through.model.rawAttributes[this.foreignIdentifier].field || this.foreignIdentifier;
if (this.targetAssociation.identifier) {
this.targetAssociation.identifierField = this.through.model.rawAttributes[this.targetAssociation.identifier].field || this.targetAssociation.identifier;
}
if (this.targetAssociation.foreignIdentifier) {
this.targetAssociation.foreignIdentifierField = this.through.model.rawAttributes[this.targetAssociation.foreignIdentifier].field || this.targetAssociation.foreignIdentifier;
}
this.through.model.init(this.through.model.daoFactoryManager); this.through.model.init(this.through.model.daoFactoryManager);
} else { } else {
var newAttributes = {}; var newAttributes = {};
...@@ -291,6 +301,8 @@ module.exports = (function() { ...@@ -291,6 +301,8 @@ module.exports = (function() {
} }
Helpers.addForeignKeyConstraints(newAttributes[this.identifier], this.source, this.target, constraintOptions); Helpers.addForeignKeyConstraints(newAttributes[this.identifier], this.source, this.target, constraintOptions);
Utils.mergeDefaults(this.target.rawAttributes, newAttributes); Utils.mergeDefaults(this.target.rawAttributes, newAttributes);
this.identifierField = this.target.rawAttributes[this.identifier].field || this.identifier;
} }
// Sync attributes and setters/getters to DAO prototype // Sync attributes and setters/getters to DAO prototype
......
...@@ -72,6 +72,8 @@ module.exports = (function() { ...@@ -72,6 +72,8 @@ module.exports = (function() {
newAttributes[this.identifier] = Utils._.defaults(this.foreignKeyAttribute, { type: this.options.keyType || keyType }); newAttributes[this.identifier] = Utils._.defaults(this.foreignKeyAttribute, { type: this.options.keyType || keyType });
Utils.mergeDefaults(this.target.rawAttributes, newAttributes); Utils.mergeDefaults(this.target.rawAttributes, newAttributes);
this.identifierField = this.target.rawAttributes[this.identifier].field || this.identifier;
if (this.options.constraints !== false) { if (this.options.constraints !== false) {
this.options.onDelete = this.options.onDelete || 'SET NULL'; this.options.onDelete = this.options.onDelete || 'SET NULL';
this.options.onUpdate = this.options.onUpdate || 'CASCADE'; this.options.onUpdate = this.options.onUpdate || 'CASCADE';
......
...@@ -856,23 +856,24 @@ module.exports = (function() { ...@@ -856,23 +856,24 @@ module.exports = (function() {
} }
} }
if (through) { if (through) {
var throughTable = through.model.getTableName() var throughTable = through.model.getTableName()
, throughAs = as + '.' + through.as , throughAs = as + '.' + through.as
, throughAttributes = through.attributes.map(function(attr) { , throughAttributes = through.attributes.map(function(attr) {
return self.quoteIdentifier(throughAs) + '.' + self.quoteIdentifier(attr) + ' AS ' + self.quoteIdentifier(throughAs + '.' + attr); return self.quoteIdentifier(throughAs) + '.' + self.quoteIdentifier(Array.isArray(attr) ? attr[0] : attr) +
' AS ' +
self.quoteIdentifier(throughAs + '.' + (Array.isArray(attr) ? attr[1] : attr));
}) })
, primaryKeysSource = association.source.primaryKeyAttributes , primaryKeysSource = association.source.primaryKeyAttributes
, tableSource = parentTable , tableSource = parentTable
, identSource = association.identifier , identSource = association.identifierField
, attrSource = primaryKeysSource[0] , attrSource = association.source.rawAttributes[primaryKeysSource[0]].field || primaryKeysSource[0]
, where , where
, primaryKeysTarget = association.target.primaryKeyAttributes , primaryKeysTarget = association.target.primaryKeyAttributes
, tableTarget = as , tableTarget = as
, identTarget = association.foreignIdentifier , identTarget = association.foreignIdentifierField
, attrTarget = primaryKeysTarget[0] , attrTarget = association.target.rawAttributes[primaryKeysTarget[0]].field || primaryKeysTarget[0]
, sourceJoinOn , sourceJoinOn
, targetJoinOn , targetJoinOn
...@@ -934,7 +935,7 @@ module.exports = (function() { ...@@ -934,7 +935,7 @@ module.exports = (function() {
, tableLeft = association.associationType === 'BelongsTo' ? as : parentTable , tableLeft = association.associationType === 'BelongsTo' ? as : parentTable
, attrLeft = primaryKeysLeft[0] , attrLeft = primaryKeysLeft[0]
, tableRight = association.associationType === 'BelongsTo' ? parentTable : as , tableRight = association.associationType === 'BelongsTo' ? parentTable : as
, attrRight = association.identifier , attrRight = association.identifierField || association.identifier
, joinOn; , joinOn;
// Alias the left attribute if the left attribute is not from a subqueried main table // Alias the left attribute if the left attribute is not from a subqueried main table
......
...@@ -304,6 +304,44 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -304,6 +304,44 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
expect(User.rawAttributes.AccountId).to.exist; expect(User.rawAttributes.AccountId).to.exist;
}); });
it('should support specifying the field of a foreign key', function () {
var User = this.sequelize.define('User', { username: Sequelize.STRING }, { underscored: false })
, Account = this.sequelize.define('Account', { title: Sequelize.STRING }, { underscored: false });
User.belongsTo(Account, {
foreignKey: {
name: 'AccountId',
field: 'account_id'
}
});
expect(User.rawAttributes.AccountId).to.exist;
expect(User.rawAttributes.AccountId.field).to.equal('account_id');
return Account.sync({ force: true }).then(function () {
// Can't use Promise.all cause of foreign key references
return User.sync({ force: true });
}).then(function () {
return Promise.all([
User.create({ username: 'foo' }),
Account.create({ title: 'pepsico' })
]);
}).spread(function (user, account) {
return user.setAccount(account).then(function () {
return user.getAccount();
});
}).then(function (user) {
// the sql query should correctly look at task_id instead of taskId
expect(user).to.not.be.null;
return User.find({
where: {username: 'foo'},
include: [ Account ]
})
}).then(function(task) {
expect(task.Account).to.exist;
});
});
}); });
describe("foreign key constraints", function() { describe("foreign key constraints", function() {
......
...@@ -1497,7 +1497,7 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -1497,7 +1497,7 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
it('should correctly get associations', function() { it('should correctly get associations', function() {
var self = this; var self = this;
return this.sequelize.sync().then(function() { return this.sequelize.sync({force: true}).then(function() {
return Promise.all([ return Promise.all([
self.User.create({name: 'Matt'}), self.User.create({name: 'Matt'}),
self.Project.create({name: 'Good Will Hunting'}) self.Project.create({name: 'Good Will Hunting'})
...@@ -1525,13 +1525,21 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -1525,13 +1525,21 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
name: 'groupId' name: 'groupId'
} }
}); });
this.User.hasMany(this.Group, {
through: 'group_users',
as: 'Groups',
foreignKey: {
field: 'user_id',
name: 'userId'
}
});
return this.sequelize.sync().then(function() { return this.sequelize.sync({force: true}).then(function() {
return Promise.all([ return Promise.join(
self.Group.create({groupName: 'The Illuminati'}), self.Group.create({groupName: 'The Illuminati'}),
self.User.create({name: 'Matt'}), self.User.create({name: 'Matt'}),
self.Project.create({name: 'Good Will Hunting'}) self.Project.create({name: 'Good Will Hunting'})
]); );
}).spread(function (group, user, project) { }).spread(function (group, user, project) {
return user.addProject(project).then(function() { return user.addProject(project).then(function() {
return group.addUser(user).return(group); return group.addUser(user).return(group);
...@@ -1543,10 +1551,13 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -1543,10 +1551,13 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
include: [ include: [
{ {
model: self.User, model: self.User,
include: [ self.Project ] as: 'Users',
include: [
{ model: self.Project, as: 'Projects' }
]
} }
] ]
}) });
}).then(function(groups) { }).then(function(groups) {
var group = groups[0]; var group = groups[0];
expect(group).to.be.defined; expect(group).to.be.defined;
......
...@@ -269,8 +269,8 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -269,8 +269,8 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
} }
}); });
expect(User.rawAttributes.taskId).to.exist expect(User.rawAttributes.taskId).to.exist;
expect(User.rawAttributes.taskId.field).to.equal('task_id') expect(User.rawAttributes.taskId.field).to.equal('task_id');
return Task.sync({ force: true }).then(function () { return Task.sync({ force: true }).then(function () {
// Can't use Promise.all cause of foreign key references // Can't use Promise.all cause of foreign key references
return User.sync({ force: true }); return User.sync({ force: true });
...@@ -291,7 +291,7 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -291,7 +291,7 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
include: [ User ] include: [ User ]
}) })
}).then(function(task) { }).then(function(task) {
expect(task.UserXYZ).to.exist expect(task.UserXYZ).to.exist;
}); });
}); });
}) })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!