Skip to content

Commit

Permalink
Make assertion errors in build.test fail the test if they occur. Trea…
Browse files Browse the repository at this point in the history
…t single column unique indexes as a primary key if no other primary key was found. Fixes sequelize#638 and implement sequelize#639.
  • Loading branch information
Harold Howe committed Mar 11, 2023
1 parent 4197141 commit e410a5c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 8 deletions.
26 changes: 20 additions & 6 deletions src/auto-builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from "lodash";
import { Dialect, QueryInterface, QueryTypes, Sequelize } from "sequelize";
import { ColumnsDescription, Dialect, QueryInterface, QueryTypes, Sequelize } from 'sequelize';
import { AutoOptions } from ".";
import { ColumnElementType, ColumnPrecision, DialectOptions, FKRow, FKSpec, TriggerCount } from "./dialects/dialect-options";
import { dialects } from "./dialects/dialects";
Expand Down Expand Up @@ -187,12 +187,11 @@ export class AutoBuilder {
this.tableData.indexes[makeTableQName(table)] = await this.queryInterface.showIndex(
{ tableName: table.table_name, schema: table.table_schema }) as IndexSpec[];

// if there is no primaryKey, and `id` field exists, then make id the primaryKey (#480)
// if there is no primaryKey, and a single column unique index exists, or an `id` field exists, then make that field the primaryKey (#480)
if (!_.some(fields, { primaryKey: true })) {
const idname = _.keys(fields).find(f => f.toLowerCase() === 'id');
const idfield = idname && fields[idname];
if (idfield) {
idfield.primaryKey = true;
const pkField = this.getUniqueIndexField(fields, this.tableData.indexes[makeTableQName(table)]) || this.getIdField(fields);
if (pkField) {
pkField.primaryKey = true;
}
}

Expand All @@ -207,6 +206,21 @@ export class AutoBuilder {
}
}

private getUniqueIndexField(fields: ColumnsDescription, tableIndexes: IndexSpec[]) {
const uniqueIndex = tableIndexes.find(index => index.unique && index.fields.length === 1 );
if(uniqueIndex) {
const indexColumnName = uniqueIndex.fields[0].attribute.toLowerCase();
const fieldName = _.keys(fields).find(f => f.toLowerCase() === indexColumnName);
return fieldName && fields[fieldName];
}
}


private getIdField(fields: ColumnsDescription) {
const idname = _.keys(fields).find(f => f.toLowerCase() === 'id');
return idname && fields[idname];
}

private executeQuery<T>(query: string): Promise<T[]> {
return this.sequelize.query(query, {
type: QueryTypes.SELECT,
Expand Down
6 changes: 5 additions & 1 deletion test/build.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ describe(helpers.getTestDialectTeaser("sequelize-auto build"), function() {

auto.build().then(tableData => {
callback(tableData);
}).finally(() => {
done();
}).catch((e) => {
done(e);
})
}

Expand Down Expand Up @@ -71,6 +72,9 @@ describe(helpers.getTestDialectTeaser("sequelize-auto build"), function() {
const fkParents = foreignKeys[isSnakeTables ? 'parents': 'Parents'];
const fkKids = foreignKeys[isSnakeTables ? 'kids': 'Kids'];

const paranoidPkColumn = tables[isSnakeTables ? 'paranoid_users': 'ParanoidUsers'].username;
expect(paranoidPkColumn.primaryKey).to.equal(true);

if (helpers.getTestDialect() === "sqlite") {
expect(foreignKeys).to.have.keys(['Kids', 'Parents', 'ParanoidUsers']);
expect(fkParanoidUsers).to.include.keys(['UserId']);
Expand Down
3 changes: 2 additions & 1 deletion test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ module.exports = {
});

test.ParanoidUser = test.sequelize.define('ParanoidUser', {
username: { type: Sequelize.STRING }
username: { type: Sequelize.STRING, unique: true }
},
{
paranoid: true,
tableName: isSnakeTables ? 'paranoid_users' : undefined
}
);

test.ParanoidUser.removeAttribute('id');
test.ParanoidUser.belongsTo(test.User);

// test data for relationships across schemas
Expand Down

0 comments on commit e410a5c

Please sign in to comment.