Skip to content

Commit

Permalink
fix: @unique constraint is not created with specified name
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexMesser committed Apr 12, 2021
1 parent 8edc634 commit beea2e1
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
21 changes: 19 additions & 2 deletions src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,17 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen
});
});

// find unique constraints from CREATE TABLE sql
let uniqueRegexResult;
const uniqueMappings: { name: string, columns: string[] }[] = []
const uniqueRegex = /CONSTRAINT "([^"]*)" UNIQUE \((.*?)\)/g;
while ((uniqueRegexResult = uniqueRegex.exec(sql)) !== null) {
uniqueMappings.push({
name: uniqueRegexResult[1],
columns: uniqueRegexResult[2].substr(1, uniqueRegexResult[2].length - 2).split(`", "`)
});
}

// build unique constraints
const tableUniquePromises = dbIndices
.filter(dbIndex => dbIndex["origin"] === "u")
Expand All @@ -919,9 +930,15 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen
column.isUnique = true;
}

// Sqlite does not store unique constraint name, so we generate its name manually.
// find existent mapping by a column names
const foundMapping = uniqueMappings.find(mapping => {
return mapping!.columns.every(column =>
indexColumns.indexOf(column) !== -1
)
})

return new TableUnique({
name: this.connection.namingStrategy.uniqueConstraintName(table, indexColumns),
name: foundMapping ? foundMapping.name : this.connection.namingStrategy.uniqueConstraintName(table, indexColumns),
columnNames: indexColumns
});
});
Expand Down
19 changes: 19 additions & 0 deletions test/github-issues/2376/entity/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Column, Entity, PrimaryGeneratedColumn, Unique} from "../../../../src";

@Entity()
@Unique(["age"])
@Unique("unique-email", ["email"])
@Unique("unique-email-nickname", ["email", "nickname"])
export class User {
@PrimaryGeneratedColumn()
id: number;

@Column()
email: string;

@Column()
nickname: string;

@Column()
age: number;
}
35 changes: 35 additions & 0 deletions test/github-issues/2376/issue-2376.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import "reflect-metadata";
import {Connection} from "../../../src";
import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils";
import {User} from "./entity/User";
import {expect} from "chai";
import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver";

describe("github issues > #2376 Naming single column unique constraint with decorator not working as expected", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
schemaCreate: true,
dropSchema: true,
entities: [User],
}));
after(() => closeTestingConnections(connections));

it("should keep user-specified Unique constraint name", () => Promise.all(connections.map(async connection => {
const queryRunner = connection.createQueryRunner();

const table = await queryRunner.getTable("user");
await queryRunner.release()

let unique1 = table!.uniques.find(it => it.name === "unique-email");
let unique2 = table!.uniques.find(it => it.name === "unique-email-nickname");

if (connection.driver instanceof MysqlDriver) {
unique1 = table!.indices.find(it => it.name === "unique-email");
unique2 = table!.indices.find(it => it.name === "unique-email-nickname");
}

expect(unique1).to.be.not.undefined
expect(unique2).to.be.not.undefined

})));
});

0 comments on commit beea2e1

Please sign in to comment.