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

Commit 43ab707d by RobertYoung Committed by Sushant

feat(associations): enable overwrite unique constraint key name (#10045)

1 parent 8fe475b6
...@@ -285,6 +285,11 @@ User.findAll({ ...@@ -285,6 +285,11 @@ User.findAll({
}] }]
}); });
``` ```
Belongs-To-Many creates a unique key when primary key is not present on through model. This unique key name can be overridden using **uniqueKey** option.
```js
Project.belongsToMany(User, { through: UserProjects, uniqueKey: 'my_custom_unique' })
```
## Scopes ## Scopes
This section concerns association scopes. For a definition of association scopes vs. scopes on associated models, see [Scopes](/manual/tutorial/scopes.html). This section concerns association scopes. For a definition of association scopes vs. scopes on associated models, see [Scopes](/manual/tutorial/scopes.html).
......
...@@ -259,7 +259,12 @@ class BelongsToMany extends Association { ...@@ -259,7 +259,12 @@ class BelongsToMany extends Association {
if (this.primaryKeyDeleted === true) { if (this.primaryKeyDeleted === true) {
targetAttribute.primaryKey = sourceAttribute.primaryKey = true; targetAttribute.primaryKey = sourceAttribute.primaryKey = true;
} else if (this.through.unique !== false) { } else if (this.through.unique !== false) {
const uniqueKey = [this.through.model.tableName, this.foreignKey, this.otherKey, 'unique'].join('_'); let uniqueKey;
if (typeof this.options.uniqueKey === 'string' && this.options.uniqueKey !== '') {
uniqueKey = this.options.uniqueKey;
} else {
uniqueKey = [this.through.model.tableName, this.foreignKey, this.otherKey, 'unique'].join('_');
}
targetAttribute.unique = sourceAttribute.unique = uniqueKey; targetAttribute.unique = sourceAttribute.unique = uniqueKey;
} }
......
...@@ -3212,6 +3212,7 @@ class Model { ...@@ -3212,6 +3212,7 @@ class Model {
*/ */
setDataValue(key, value) { setDataValue(key, value) {
const originalValue = this._previousDataValues[key]; const originalValue = this._previousDataValues[key];
if (!Utils.isPrimitive(value) || value !== originalValue) { if (!Utils.isPrimitive(value) || value !== originalValue) {
this.changed(key, true); this.changed(key, true);
} }
...@@ -4177,6 +4178,7 @@ class Model { ...@@ -4177,6 +4178,7 @@ class Model {
* @param {string} [options.onDelete='SET NULL|CASCADE'] SET NULL if foreignKey allows nulls, CASCADE if otherwise * @param {string} [options.onDelete='SET NULL|CASCADE'] SET NULL if foreignKey allows nulls, CASCADE if otherwise
* @param {string} [options.onUpdate='CASCADE'] * @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key. * @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
* @param {string} [options.uniqueKey] The custom name for unique constraint.
* @returns {HasOne} * @returns {HasOne}
* @example * @example
* User.hasOne(Profile) // This will add userId to the profile table * User.hasOne(Profile) // This will add userId to the profile table
......
...@@ -2157,6 +2157,35 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => { ...@@ -2157,6 +2157,35 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => {
expect(ut2).to.have.length(1); expect(ut2).to.have.length(1);
}); });
}); });
it('create custom unique identifier', function() {
this.UserTasksLong = this.sequelize.define('table_user_task_with_very_long_name', {
id_user_very_long_field: {
type: DataTypes.INTEGER(1)
},
id_task_very_long_field: {
type: DataTypes.INTEGER(1)
}
},
{ tableName: 'table_user_task_with_very_long_name' }
);
this.User.belongsToMany(this.Task, {
as: 'MyTasks',
through: this.UserTasksLong,
foreignKey: 'id_user_very_long_field'
});
this.Task.belongsToMany(this.User, {
as: 'MyUsers',
through: this.UserTasksLong,
foreignKey: 'id_task_very_long_field',
uniqueKey: 'custom_user_group_unique'
});
return this.sequelize.sync({ force: true }).then(() => {
expect(this.Task.associations.MyUsers.through.model.rawAttributes.id_user_very_long_field.unique).to.equal('custom_user_group_unique');
expect(this.Task.associations.MyUsers.through.model.rawAttributes.id_task_very_long_field.unique).to.equal('custom_user_group_unique');
});
});
}); });
describe('Association options', () => { describe('Association options', () => {
......
...@@ -214,7 +214,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -214,7 +214,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
if (dialect === 'sqlite') { if (dialect === 'sqlite') {
expect(created).to.be.undefined; expect(created).to.be.undefined;
} else { } else {
expect(created).to.be.okay; expect(created).to.be.ok;
} }
}); });
}); });
......
...@@ -585,5 +585,67 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => { ...@@ -585,5 +585,67 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
expect(Group.associations.MyUsers.through.model.rawAttributes.GroupId.onUpdate).to.equal('SET NULL'); expect(Group.associations.MyUsers.through.model.rawAttributes.GroupId.onUpdate).to.equal('SET NULL');
expect(Group.associations.MyUsers.through.model.rawAttributes.GroupId.onDelete).to.equal('RESTRICT'); expect(Group.associations.MyUsers.through.model.rawAttributes.GroupId.onDelete).to.equal('RESTRICT');
}); });
it('generate unique identifier with very long length', function() {
const User = this.sequelize.define('User', {}, { tableName: 'table_user_with_very_long_name' }),
Group = this.sequelize.define('Group', {}, { tableName: 'table_group_with_very_long_name' }),
UserGroup = this.sequelize.define(
'GroupUser',
{
id_user_very_long_field: {
type: DataTypes.INTEGER(1)
},
id_group_very_long_field: {
type: DataTypes.INTEGER(1)
}
},
{tableName: 'table_user_group_with_very_long_name'}
);
User.belongsToMany(Group, { as: 'MyGroups', through: UserGroup, foreignKey: 'id_user_very_long_field' });
Group.belongsToMany(User, { as: 'MyUsers', through: UserGroup, foreignKey: 'id_group_very_long_field' });
expect(Group.associations.MyUsers.through.model === User.associations.MyGroups.through.model);
expect(Group.associations.MyUsers.through.model.rawAttributes.id_user_very_long_field.unique).to.have.lengthOf(92);
expect(Group.associations.MyUsers.through.model.rawAttributes.id_group_very_long_field.unique).to.have.lengthOf(92);
expect(Group.associations.MyUsers.through.model.rawAttributes.id_user_very_long_field.unique).to.equal('table_user_group_with_very_long_name_id_group_very_long_field_id_user_very_long_field_unique');
expect(Group.associations.MyUsers.through.model.rawAttributes.id_group_very_long_field.unique).to.equal('table_user_group_with_very_long_name_id_group_very_long_field_id_user_very_long_field_unique');
});
it('generate unique identifier with custom name', function() {
const User = this.sequelize.define('User', {}, { tableName: 'table_user_with_very_long_name' }),
Group = this.sequelize.define('Group', {}, { tableName: 'table_group_with_very_long_name' }),
UserGroup = this.sequelize.define(
'GroupUser',
{
id_user_very_long_field: {
type: DataTypes.INTEGER(1)
},
id_group_very_long_field: {
type: DataTypes.INTEGER(1)
}
},
{tableName: 'table_user_group_with_very_long_name'}
);
User.belongsToMany(Group, {
as: 'MyGroups',
through: UserGroup,
foreignKey: 'id_user_very_long_field',
uniqueKey: 'custom_user_group_unique'
});
Group.belongsToMany(User, {
as: 'MyUsers',
through: UserGroup,
foreignKey: 'id_group_very_long_field',
uniqueKey: 'custom_user_group_unique'
});
expect(Group.associations.MyUsers.through.model === User.associations.MyGroups.through.model);
expect(Group.associations.MyUsers.through.model.rawAttributes.id_user_very_long_field.unique).to.have.lengthOf(24);
expect(Group.associations.MyUsers.through.model.rawAttributes.id_group_very_long_field.unique).to.have.lengthOf(24);
expect(Group.associations.MyUsers.through.model.rawAttributes.id_user_very_long_field.unique).to.equal('custom_user_group_unique');
expect(Group.associations.MyUsers.through.model.rawAttributes.id_group_very_long_field.unique).to.equal('custom_user_group_unique');
});
}); });
}); });
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!