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

Commit e879460c by Benoit MERIAUX Committed by Sushant

fix(associations): fix foreign key with a targetkey on table without pk or with unique key (#10654)

1 parent 258d8aa0
......@@ -20,7 +20,7 @@ function addForeignKeyConstraints(newAttribute, source, target, options, key) {
const primaryKeys = Object.keys(source.primaryKeys)
.map(primaryKeyAttribute => source.rawAttributes[primaryKeyAttribute].field || primaryKeyAttribute);
if (primaryKeys.length === 1) {
if (primaryKeys.length === 1 || !primaryKeys.includes(key)) {
if (source._schema) {
newAttribute.references = {
model: source.sequelize.getQueryInterface().QueryGenerator.addSchema({
......
......@@ -803,81 +803,127 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
});
it('should support a non-primary key as the association column on a target without a primary key', function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING });
const User = this.sequelize.define('User', { username: { type: DataTypes.STRING, unique: true } });
const Task = this.sequelize.define('Task', { title: DataTypes.STRING });
User.removeAttribute('id');
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'bob' }).then(newUser => {
return Task.create({ title: 'some task' }).then(newTask => {
return newTask.setUser(newUser).then(() => {
return Task.findOne({ where: { title: 'some task' } }).then(foundTask => {
return foundTask.getUser().then(foundUser => {
expect(foundUser.username).to.equal('bob');
});
});
});
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob' }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'username',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
});
});
it('should support a non-primary unique key as the association column', function() {
const User = this.sequelize.define('User', {
username: {
type: DataTypes.STRING,
field: 'user_name',
unique: true
}
}),
Task = this.sequelize.define('Task', {
title: DataTypes.STRING
});
username: {
type: DataTypes.STRING,
field: 'user_name',
unique: true
}
});
const Task = this.sequelize.define('Task', {
title: DataTypes.STRING
});
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'bob' }).then(newUser => {
return Task.create({ title: 'some task' }).then(newTask => {
return newTask.setUser(newUser).then(() => {
return Task.findOne({ where: { title: 'some task' } }).then(foundTask => {
return foundTask.getUser().then(foundUser => {
expect(foundUser.username).to.equal('bob');
});
});
});
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob' }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'user_name',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
});
});
it('should support a non-primary key as the association column with a field option', function() {
const User = this.sequelize.define('User', {
username: {
type: DataTypes.STRING,
field: 'the_user_name_field'
}
}),
Task = this.sequelize.define('Task', { title: DataTypes.STRING });
username: {
type: DataTypes.STRING,
field: 'the_user_name_field',
unique: true
}
});
const Task = this.sequelize.define('Task', { title: DataTypes.STRING });
User.removeAttribute('id');
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'bob' }).then(newUser => {
return Task.create({ title: 'some task' }).then(newTask => {
return newTask.setUser(newUser).then(() => {
return Task.findOne({ where: { title: 'some task' } }).then(foundTask => {
return foundTask.getUser().then(foundUser => {
expect(foundUser.username).to.equal('bob');
});
});
});
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob' }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'the_user_name_field',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
});
it('should support a non-primary key as the association column in a table with a composite primary key', function() {
const User = this.sequelize.define('User', {
username: {
type: DataTypes.STRING,
field: 'the_user_name_field',
unique: true
},
age: {
type: DataTypes.INTEGER,
field: 'the_user_age_field',
primaryKey: true
},
weight: {
type: DataTypes.INTEGER,
field: 'the_user_weight_field',
primaryKey: true
}
});
const Task = this.sequelize.define('Task', { title: DataTypes.STRING });
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob', age: 18, weight: 40 }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'the_user_name_field',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
});
});
......
......@@ -247,7 +247,7 @@ describe(Support.getTestDialectTeaser('Include'), () => {
});
it('should support a belongsTo with the targetKey option', function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
const User = this.sequelize.define('User', { username: { type: DataTypes.STRING, unique: true } }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING });
User.removeAttribute('id');
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!