mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fix: resolve issues for mssql migration when simple-enum was changed
* fix: resolve issues for mssql migration when simple-enum was changed - Changes are now detected - Incorrect update Statement was split into a DROP CONSTRAINT and ADD CONSTRAINT Statement Closes: #7785 #9457 * fix: resolve issues for mssql migration when simple-enum was changed - Changes are now detected - Incorrect update Statement was split into a DROP CONSTRAINT and ADD CONSTRAINT Statement Closes: #7785 #9457 * code refactoring; changed `enumName` usage to generated name; improvements in test; --------- Co-authored-by: ke <ke@sbs.co.at> Co-authored-by: Alex Messer <dmzt08@gmail.com>
This commit is contained in:
parent
4fa14e396a
commit
cb154d4ca3
@ -795,7 +795,14 @@ export class SqlServerDriver implements Driver {
|
||||
tableColumn.isNullable !== columnMetadata.isNullable ||
|
||||
tableColumn.asExpression !== columnMetadata.asExpression ||
|
||||
tableColumn.generatedType !== columnMetadata.generatedType ||
|
||||
tableColumn.isUnique !== this.normalizeIsUnique(columnMetadata)
|
||||
tableColumn.isUnique !==
|
||||
this.normalizeIsUnique(columnMetadata) ||
|
||||
(tableColumn.enum &&
|
||||
columnMetadata.enum &&
|
||||
!OrmUtils.isArraysEqual(
|
||||
tableColumn.enum,
|
||||
columnMetadata.enum.map((val) => val + ""),
|
||||
))
|
||||
|
||||
// DEBUG SECTION
|
||||
// if (isColumnChanged) {
|
||||
|
||||
@ -1566,7 +1566,9 @@ export class SqlServerQueryRunner
|
||||
oldColumn.name = newColumn.name
|
||||
}
|
||||
|
||||
if (this.isColumnChanged(oldColumn, newColumn, false)) {
|
||||
if (
|
||||
this.isColumnChanged(oldColumn, newColumn, false, false, false)
|
||||
) {
|
||||
upQueries.push(
|
||||
new Query(
|
||||
`ALTER TABLE ${this.escapePath(
|
||||
@ -1576,6 +1578,7 @@ export class SqlServerQueryRunner
|
||||
newColumn,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
)}`,
|
||||
),
|
||||
)
|
||||
@ -1588,11 +1591,40 @@ export class SqlServerQueryRunner
|
||||
oldColumn,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
)}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (this.isEnumChanged(oldColumn, newColumn)) {
|
||||
const oldExpression = this.getEnumExpression(oldColumn)
|
||||
const oldCheck = new TableCheck({
|
||||
name: this.connection.namingStrategy.checkConstraintName(
|
||||
table,
|
||||
oldExpression,
|
||||
true,
|
||||
),
|
||||
expression: oldExpression,
|
||||
})
|
||||
|
||||
const newExpression = this.getEnumExpression(newColumn)
|
||||
const newCheck = new TableCheck({
|
||||
name: this.connection.namingStrategy.checkConstraintName(
|
||||
table,
|
||||
newExpression,
|
||||
true,
|
||||
),
|
||||
expression: newExpression,
|
||||
})
|
||||
|
||||
upQueries.push(this.dropCheckConstraintSql(table, oldCheck))
|
||||
upQueries.push(this.createCheckConstraintSql(table, newCheck))
|
||||
|
||||
downQueries.push(this.dropCheckConstraintSql(table, newCheck))
|
||||
downQueries.push(this.createCheckConstraintSql(table, oldCheck))
|
||||
}
|
||||
|
||||
if (newColumn.isPrimary !== oldColumn.isPrimary) {
|
||||
const primaryColumns = clonedTable.primaryColumns
|
||||
|
||||
@ -3904,17 +3936,14 @@ export class SqlServerQueryRunner
|
||||
column: TableColumn,
|
||||
skipIdentity: boolean,
|
||||
createDefault: boolean,
|
||||
skipEnum?: boolean,
|
||||
) {
|
||||
let c = `"${column.name}" ${this.connection.driver.createFullType(
|
||||
column,
|
||||
)}`
|
||||
|
||||
if (column.enum) {
|
||||
const expression =
|
||||
column.name +
|
||||
" IN (" +
|
||||
column.enum.map((val) => "'" + val + "'").join(",") +
|
||||
")"
|
||||
if (!skipEnum && column.enum) {
|
||||
const expression = this.getEnumExpression(column)
|
||||
const checkName =
|
||||
this.connection.namingStrategy.checkConstraintName(
|
||||
table,
|
||||
@ -3976,6 +4005,18 @@ export class SqlServerQueryRunner
|
||||
return c
|
||||
}
|
||||
|
||||
private getEnumExpression(column: TableColumn) {
|
||||
if (!column.enum) {
|
||||
throw new Error(`Enum is not defined in column ${column.name}`)
|
||||
}
|
||||
return (
|
||||
column.name +
|
||||
" IN (" +
|
||||
column.enum.map((val) => "'" + val + "'").join(",") +
|
||||
")"
|
||||
)
|
||||
}
|
||||
|
||||
protected isEnumCheckConstraint(name: string): boolean {
|
||||
return name.indexOf("CHK_") !== -1 && name.indexOf("_ENUM") !== -1
|
||||
}
|
||||
|
||||
@ -472,6 +472,7 @@ export abstract class BaseQueryRunner {
|
||||
newColumn: TableColumn,
|
||||
checkDefault?: boolean,
|
||||
checkComment?: boolean,
|
||||
checkEnum = true,
|
||||
): boolean {
|
||||
// this logs need to debug issues in column change detection. Do not delete it!
|
||||
|
||||
@ -513,7 +514,14 @@ export abstract class BaseQueryRunner {
|
||||
oldColumn.onUpdate !== newColumn.onUpdate || // MySQL only
|
||||
oldColumn.isNullable !== newColumn.isNullable ||
|
||||
(checkComment && oldColumn.comment !== newColumn.comment) ||
|
||||
!OrmUtils.isArraysEqual(oldColumn.enum || [], newColumn.enum || [])
|
||||
(checkEnum && this.isEnumChanged(oldColumn, newColumn))
|
||||
)
|
||||
}
|
||||
|
||||
protected isEnumChanged(oldColumn: TableColumn, newColumn: TableColumn) {
|
||||
return !OrmUtils.isArraysEqual(
|
||||
oldColumn.enum || [],
|
||||
newColumn.enum || [],
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
25
test/github-issues/9457/entity/ExampleEntity.ts
Normal file
25
test/github-issues/9457/entity/ExampleEntity.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Entity } from "../../../../src/decorator/entity/Entity"
|
||||
import { Column } from "../../../../src/decorator/columns/Column"
|
||||
import { PrimaryGeneratedColumn } from "../../../../src/decorator/columns/PrimaryGeneratedColumn"
|
||||
import { Generated } from "../../../../src"
|
||||
|
||||
export enum ExampleEnum {
|
||||
EnumValue1 = "enumvalue1",
|
||||
EnumValue2 = "enumvalue2",
|
||||
EnumValue3 = "enumvalue3",
|
||||
EnumValue4 = "enumvalue4",
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class ExampleEntity {
|
||||
@Generated("increment")
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number
|
||||
|
||||
@Column({
|
||||
length: 255,
|
||||
type: "simple-enum",
|
||||
enum: ExampleEnum,
|
||||
})
|
||||
enumcolumn: ExampleEnum
|
||||
}
|
||||
48
test/github-issues/9457/issue-9457.ts
Normal file
48
test/github-issues/9457/issue-9457.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import "reflect-metadata"
|
||||
import {
|
||||
createTestingConnections,
|
||||
closeTestingConnections,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { expect } from "chai"
|
||||
|
||||
describe("github issues > #9457 No changes in database schema were found, when simple-enum is changed.", () => {
|
||||
let dataSources: DataSource[]
|
||||
before(async () => {
|
||||
dataSources = await createTestingConnections({
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
migrations: [__dirname + "/migration/*{.js,.ts}"],
|
||||
schemaCreate: false,
|
||||
dropSchema: true,
|
||||
enabledDrivers: ["mssql"],
|
||||
})
|
||||
})
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
|
||||
it("should drop and recreate 'CHECK' constraint to match enum values", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
await dataSource.runMigrations()
|
||||
|
||||
const sqlInMemory = await dataSource.driver
|
||||
.createSchemaBuilder()
|
||||
.log()
|
||||
|
||||
expect(sqlInMemory.upQueries.length).to.eql(2)
|
||||
expect(sqlInMemory.upQueries[0].query).to.eql(
|
||||
'ALTER TABLE "example_entity" DROP CONSTRAINT "CHK_a80c9d6a2a8749d7aadb857dc6_ENUM"',
|
||||
)
|
||||
expect(sqlInMemory.upQueries[1].query).to.eql(
|
||||
`ALTER TABLE "example_entity" ADD CONSTRAINT "CHK_be8ed063b3976da24df4213baf_ENUM" CHECK (enumcolumn IN ('enumvalue1','enumvalue2','enumvalue3','enumvalue4'))`,
|
||||
)
|
||||
|
||||
expect(sqlInMemory.downQueries.length).to.eql(2)
|
||||
expect(sqlInMemory.downQueries[0].query).to.eql(
|
||||
'ALTER TABLE "example_entity" DROP CONSTRAINT "CHK_be8ed063b3976da24df4213baf_ENUM"',
|
||||
)
|
||||
expect(sqlInMemory.downQueries[1].query).to.eql(
|
||||
`ALTER TABLE "example_entity" ADD CONSTRAINT "CHK_a80c9d6a2a8749d7aadb857dc6_ENUM" CHECK (enumcolumn IN ('enumvalue1','enumvalue2','enumvalue3'))`,
|
||||
)
|
||||
}),
|
||||
))
|
||||
})
|
||||
20
test/github-issues/9457/migration/1676011161422-init.ts
Normal file
20
test/github-issues/9457/migration/1676011161422-init.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { MigrationInterface, QueryRunner } from "../../../../src"
|
||||
|
||||
export class init1676011161422 implements MigrationInterface {
|
||||
name = "init1676011161422"
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "example_entity"
|
||||
(
|
||||
"id" int NOT NULL IDENTITY(1,1),
|
||||
"enumcolumn" nvarchar(255) CONSTRAINT CHK_a80c9d6a2a8749d7aadb857dc6_ENUM CHECK (enumcolumn IN ('enumvalue1','enumvalue2','enumvalue3')) NOT NULL,
|
||||
CONSTRAINT "PK_fccd73330168066a434dbac114f" PRIMARY KEY ("id")
|
||||
)`,
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP TABLE "example_entity"`)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user