Skip to content

Commit

Permalink
fix: fixes gets on many-to-many with non-primary target key sequelize…
Browse files Browse the repository at this point in the history
  • Loading branch information
aheuermann committed Dec 31, 2019
1 parent f3110e3 commit 081ec72
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 1 deletion.
3 changes: 3 additions & 0 deletions lib/associations/belongs-to-many.js
Expand Up @@ -355,6 +355,7 @@ class BelongsToMany extends Association {
});
this.oneFromSource = new HasOne(this.source, this.through.model, {
foreignKey: this.foreignKey,
sourceKey: this.sourceKey,
as: this.through.model.name
});

Expand All @@ -366,6 +367,7 @@ class BelongsToMany extends Association {
});
this.oneFromTarget = new HasOne(this.target, this.through.model, {
foreignKey: this.otherKey,
sourceKey: this.targetKey,
as: this.through.model.name
});

Expand All @@ -376,6 +378,7 @@ class BelongsToMany extends Association {

this.paired.oneFromTarget = new HasOne(this.paired.target, this.paired.through.model, {
foreignKey: this.paired.otherKey,
sourceKey: this.paired.targetKey,
as: this.paired.through.model.name
});
}
Expand Down
79 changes: 79 additions & 0 deletions test/integration/associations/belongs-to-many.test.js
Expand Up @@ -731,6 +731,85 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => {
});
});

it('supports non primary key attributes for joins for getting associations (sourceKey/targetKey)', function() {
const User = this.sequelize.define('User', {
userId: {
type: DataTypes.UUID,
allowNull: false,
primaryKey: true,
defaultValue: DataTypes.UUIDV4
},
userSecondId: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
field: 'user_second_id'
}
}, {
tableName: 'tbl_user',
indexes: [
{
unique: true,
fields: ['user_second_id']
}
]
});

const Group = this.sequelize.define('Group', {
groupId: {
type: DataTypes.UUID,
allowNull: false,
primaryKey: true,
defaultValue: DataTypes.UUIDV4
},
groupSecondId: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
field: 'group_second_id'
}
}, {
tableName: 'tbl_group',
indexes: [
{
unique: true,
fields: ['group_second_id']
}
]
});

User.belongsToMany(Group, { through: 'usergroups', sourceKey: 'userSecondId', targetKey: 'groupSecondId' });
Group.belongsToMany(User, { through: 'usergroups', sourceKey: 'groupSecondId', targetKey: 'userSecondId' });

return this.sequelize.sync({ force: true }).then(() => {
return Promise.join(
User.create(),
User.create(),
Group.create(),
Group.create()
).then(([user1, user2, group1, group2]) => {
return Promise.join(user1.addGroup(group1), user2.addGroup(group2))
.then(() => {
return Promise.join(
user1.getGroups(),
user2.getGroups(),
group1.getUsers(),
group2.getUsers()
);
}).then(([groups1, groups2, users1, users2]) => {
expect(groups1.length).to.be.equal(1);
expect(groups1[0].id).to.be.equal(group1.id);
expect(groups2.length).to.be.equal(1);
expect(groups2[0].id).to.be.equal(group2.id);
expect(users1.length).to.be.equal(1);
expect(users1[0].id).to.be.equal(user1.id);
expect(users2.length).to.be.equal(1);
expect(users2[0].id).to.be.equal(user2.id);
});
});
});
});

it('supports non primary key attributes for joins (custom foreignKey)', function() {
const User = this.sequelize.define('User', {
id: {
Expand Down
41 changes: 40 additions & 1 deletion test/unit/associations/belongs-to-many.test.js
Expand Up @@ -332,7 +332,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
expect(Object.keys(ProductTag.rawAttributes)).to.deep.equal(['id', 'priority', 'productId', 'tagId']);
});

it('should setup hasOne relations to source and target from join model with defined foreign/other keys', function() {
it('should setup hasMany relations to source and target from join model with defined foreign/other keys', function() {
const Product = this.sequelize.define('Product', {
title: DataTypes.STRING
}),
Expand Down Expand Up @@ -406,6 +406,45 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
expect(Object.keys(ProductTag.rawAttributes)).to.deep.equal(['id', 'priority', 'productId', 'tagId']);
});

it('should setup hasOne relations to source and target from join model with defined source keys', function() {
const Product = this.sequelize.define('Product', {
title: DataTypes.STRING,
productSecondaryId: DataTypes.STRING
}),
Tag = this.sequelize.define('Tag', {
name: DataTypes.STRING,
tagSecondaryId: DataTypes.STRING
}),
ProductTag = this.sequelize.define('ProductTag', {
id: {
primaryKey: true,
type: DataTypes.INTEGER,
autoIncrement: true
},
priority: DataTypes.INTEGER
}, {
timestamps: false
});

Product.Tags = Product.belongsToMany(Tag, { through: ProductTag, sourceKey: 'productSecondaryId' });
Tag.Products = Tag.belongsToMany(Product, { through: ProductTag, sourceKey: 'tagSecondaryId' });

expect(Product.Tags.oneFromSource).to.be.an.instanceOf(HasOne);
expect(Product.Tags.oneFromTarget).to.be.an.instanceOf(HasOne);

expect(Tag.Products.oneFromSource).to.be.an.instanceOf(HasOne);
expect(Tag.Products.oneFromTarget).to.be.an.instanceOf(HasOne);

expect(Tag.Products.oneFromSource.sourceKey).to.equal(Tag.Products.sourceKey);
expect(Tag.Products.oneFromTarget.sourceKey).to.equal(Tag.Products.targetKey);

expect(Product.Tags.oneFromSource.sourceKey).to.equal(Product.Tags.sourceKey);
expect(Product.Tags.oneFromTarget.sourceKey).to.equal(Product.Tags.targetKey);

expect(Object.keys(ProductTag.rawAttributes).length).to.equal(4);
expect(Object.keys(ProductTag.rawAttributes)).to.deep.equal(['id', 'priority', 'ProductProductSecondaryId', 'TagTagSecondaryId']);
});

it('should setup belongsTo relations to source and target from join model with only foreign keys defined', function() {
const Product = this.sequelize.define('Product', {
title: DataTypes.STRING
Expand Down

0 comments on commit 081ec72

Please sign in to comment.