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

Commit 32be0612 by Scott BonAmi Committed by Simon Schick

fix(associations): check presence of multi-joined instances (#10853)

When entities in a HABTM relationship can be joined more than once, we
need to rely on more than the resulting length for verification of
presence.
1 parent 04e3592e
...@@ -466,8 +466,6 @@ class BelongsToMany extends Association { ...@@ -466,8 +466,6 @@ class BelongsToMany extends Association {
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
has(sourceInstance, instances, options) { has(sourceInstance, instances, options) {
const where = {};
if (!Array.isArray(instances)) { if (!Array.isArray(instances)) {
instances = [instances]; instances = [instances];
} }
...@@ -480,7 +478,7 @@ class BelongsToMany extends Association { ...@@ -480,7 +478,7 @@ class BelongsToMany extends Association {
joinTableAttributes: [] joinTableAttributes: []
}); });
where[Op.or] = instances.map(instance => { const instancePrimaryKeys = instances.map(instance => {
if (instance instanceof this.target) { if (instance instanceof this.target) {
return instance.where(); return instance.where();
} }
...@@ -491,12 +489,14 @@ class BelongsToMany extends Association { ...@@ -491,12 +489,14 @@ class BelongsToMany extends Association {
options.where = { options.where = {
[Op.and]: [ [Op.and]: [
where, { [Op.or]: instancePrimaryKeys },
options.where options.where
] ]
}; };
return this.get(sourceInstance, options).then(associatedObjects => associatedObjects.length === instances.length); return this.get(sourceInstance, options).then(associatedObjects =>
_.differenceBy(instancePrimaryKeys, associatedObjects, this.target.primaryKeyAttribute).length === 0
);
} }
/** /**
......
...@@ -556,6 +556,93 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => { ...@@ -556,6 +556,93 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => {
}); });
}); });
}); });
it('answers true for labels that have been assigned multitple times', function() {
this.ArticleLabel = this.sequelize.define('ArticleLabel', {
id: {
primaryKey: true,
type: DataTypes.INTEGER,
autoIncrement: true
},
relevance: {
type: DataTypes.DECIMAL,
validate: {
min: 0,
max: 1
}
}
});
this.Article.belongsToMany(this.Label, { through: { model: this.ArticleLabel, unique: false } });
this.Label.belongsToMany(this.Article, { through: { model: this.ArticleLabel, unique: false } });
return this.sequelize.sync({ force: true })
.then(() => Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]))
.then(([article, label1, label2]) => Promise.all([
article,
label1,
label2,
article.addLabel(label1, {
through: { relevance: 1 }
}),
article.addLabel(label2, {
through: { relevance: .54 }
}),
article.addLabel(label2, {
through: { relevance: .99 }
})
]))
.then(([article, label1, label2]) => article.hasLabels([label1, label2]))
.then(result => expect(result).to.be.true);
});
it('answers true for labels that have been assigned multitple times when passing a primary key instead of an object', function() {
this.ArticleLabel = this.sequelize.define('ArticleLabel', {
id: {
primaryKey: true,
type: DataTypes.INTEGER,
autoIncrement: true
},
relevance: {
type: DataTypes.DECIMAL,
validate: {
min: 0,
max: 1
}
}
});
this.Article.belongsToMany(this.Label, { through: { model: this.ArticleLabel, unique: false } });
this.Label.belongsToMany(this.Article, { through: { model: this.ArticleLabel, unique: false } });
return this.sequelize.sync({ force: true })
.then(() => Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]))
.then(([article, label1, label2]) => Promise.all([
article,
label1,
label2,
article.addLabel(label1, {
through: { relevance: 1 }
}),
article.addLabel(label2, {
through: { relevance: .54 }
}),
article.addLabel(label2, {
through: { relevance: .99 }
})
]))
.then(([article, label1, label2]) => article.hasLabels([
label1[this.Label.primaryKeyAttribute],
label2[this.Label.primaryKeyAttribute]
]))
.then(result => expect(result).to.be.true);
});
}); });
describe('countAssociations', () => { describe('countAssociations', () => {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!