Skip to content

Commit

Permalink
fix(postgres): respect column length in down migrations
Browse files Browse the repository at this point in the history
Closes #5048
  • Loading branch information
B4nan committed Dec 30, 2023
1 parent beaad2c commit 222e2b8
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 21 deletions.
14 changes: 13 additions & 1 deletion packages/postgresql/src/PostgreSqlSchemaHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,21 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
const increments = col.column_default?.includes('nextval') && connection.getPlatform().isNumericColumn(mappedType);
const key = this.getTableKey(col);
ret[key] ??= [];
let type = col.data_type.toLowerCase() === 'array'
? col.udt_name.replace(/^_(.*)$/, '$1[]')
: col.udt_name;

if (col.length != null && !type.endsWith(`(${col.length})`)) {
type += `(${col.length})`;
}

if (type === 'numeric' && col.numeric_precision != null && col.numeric_scale != null) {
type += `(${col.numeric_precision},${col.numeric_scale})`;
}

ret[key].push({
name: col.column_name,
type: col.data_type.toLowerCase() === 'array' ? col.udt_name.replace(/^_(.*)$/, '$1[]') : col.udt_name,
type,
mappedType,
length: col.length,
precision: col.numeric_precision,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports[`changing PK column type [postgres] (GH 1480) changing PK type: 0. creat

exports[`changing PK column type [postgres] (GH 1480) changing PK type: 1. change PK type from text to int 1`] = `
{
"down": "alter table "user" alter column "id" type varchar using ("id"::varchar);
"down": "alter table "user" alter column "id" type varchar(255) using ("id"::varchar(255));
",
"up": "alter table "user" alter column "id" type int using ("id"::int);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`length diffing in mysql schema generator updates column types when length changes (varchar, decimal, ...) 1`] = `
"alter table \`book\` modify \`id\` bigint unsigned not null auto_increment, modify \`name\` varchar(100) not null, modify \`length\` int unsigned not null, modify \`price\` numeric(16,0) not null;
{
"down": "alter table \`book\` modify \`id\` int unsigned not null auto_increment, modify \`name\` varchar(255) not null, modify \`length\` int not null, modify \`price\` decimal(10,0) not null, modify \`created_at\` datetime(2) not null;
"
",
"up": "alter table \`book\` modify \`id\` bigint unsigned not null auto_increment, modify \`name\` varchar(100) not null, modify \`length\` int unsigned not null, modify \`price\` numeric(16,0) not null, modify \`created_at\` datetime(3) not null;
",
}
`;

exports[`length diffing in mysql schema generator updates column types when length changes (varchar, decimal, ...) 2`] = `
"alter table \`book\` modify \`name\` varchar(150) not null, modify \`price\` numeric(16,4) not null;
{
"down": "alter table \`book\` modify \`name\` varchar(100) not null, modify \`price\` decimal(16,0) not null;
",
"up": "alter table \`book\` modify \`name\` varchar(150) not null, modify \`price\` numeric(16,4) not null;
"
",
}
`;

exports[`length diffing in mysql schema generator updates column types when length changes (varchar, decimal, ...) 3`] = `
"alter table \`book\` modify \`name\` varchar(100) not null;
{
"down": "alter table \`book\` modify \`name\` varchar(150) not null;
",
"up": "alter table \`book\` modify \`name\` varchar(100) not null;
"
",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`length diffing in postgres schema orm.schema updates column types when length changes (varchar, decimal, ...) 1`] = `
{
"down": "alter table "book" alter column "id" type int4 using ("id"::int4);
alter table "book" alter column "name" type varchar(255) using ("name"::varchar(255));
alter table "book" alter column "price" type numeric(10,0) using ("price"::numeric(10,0));
alter table "book" alter column "created_at" type timestamptz(2) using ("created_at"::timestamptz(2));
",
"up": "alter table "book" alter column "id" type bigint using ("id"::bigint);
alter table "book" alter column "name" type varchar(100) using ("name"::varchar(100));
alter table "book" alter column "price" type numeric(16,0) using ("price"::numeric(16,0));
alter table "book" alter column "created_at" type timestamptz(3) using ("created_at"::timestamptz(3));
",
}
`;

exports[`length diffing in postgres schema orm.schema updates column types when length changes (varchar, decimal, ...) 2`] = `
{
"down": "alter table "book" alter column "name" type varchar(100) using ("name"::varchar(100));
alter table "book" alter column "price" type numeric(16,0) using ("price"::numeric(16,0));
",
"up": "alter table "book" alter column "name" type varchar(150) using ("name"::varchar(150));
alter table "book" alter column "price" type numeric(16,4) using ("price"::numeric(16,4));
",
}
`;

exports[`length diffing in postgres schema orm.schema updates column types when length changes (varchar, decimal, ...) 3`] = `
{
"down": "alter table "book" alter column "name" type varchar(150) using ("name"::varchar(150));
",
"up": "alter table "book" alter column "name" type varchar(100) using ("name"::varchar(100));
",
}
`;
42 changes: 29 additions & 13 deletions tests/features/schema-generator/length-diffing.mysql.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Entity, MikroORM, PrimaryKey, Property, t } from '@mikro-orm/core';
import type { PostgreSqlDriver, SchemaGenerator } from '@mikro-orm/postgresql';
import { MySqlDriver } from '@mikro-orm/mysql';

@Entity({ tableName: 'book' })
Expand All @@ -17,6 +16,9 @@ export class Book0 {
@Property({ type: t.decimal })
price!: string;

@Property({ length: 2 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
Expand All @@ -34,6 +36,9 @@ export class Book1 {
@Property({ type: t.decimal, precision: 16 })
price!: string;

@Property({ length: 3 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
Expand All @@ -51,6 +56,9 @@ export class Book2 {
@Property({ type: t.decimal, precision: 16, scale: 4 })
price!: number;

@Property({ length: 3 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
Expand All @@ -68,6 +76,9 @@ export class Book3 {
@Property({ columnType: 'decimal(16,4)' })
price!: number;

@Property({ length: 3 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
Expand All @@ -85,12 +96,14 @@ export class Book4 {
@Property({ columnType: 'decimal(16,4)' })
price!: number;

@Property({ length: 3 })
createdAt!: Date;

}

describe('length diffing in mysql', () => {

let orm: MikroORM<MySqlDriver>;
let generator: SchemaGenerator;

beforeAll(async () => {
orm = await MikroORM.init({
Expand All @@ -99,37 +112,40 @@ describe('length diffing in mysql', () => {
driver: MySqlDriver,
port: 3308,
});
generator = orm.schema;
await generator.ensureDatabase();
await generator.execute('drop table if exists book');
await generator.createSchema();

await orm.schema.ensureDatabase();
await orm.schema.execute('drop table if exists book');
await orm.schema.createSchema();
});

afterAll(() => orm.close(true));

test('schema generator updates column types when length changes (varchar, decimal, ...)', async () => {
orm.getMetadata().reset('Book0');
await orm.discoverEntity(Book1);
const diff1 = await generator.getUpdateSchemaSQL({ wrap: false });
const diff1 = await orm.schema.getUpdateSchemaMigrationSQL({ wrap: false });
expect(diff1).toMatchSnapshot();
await generator.execute(diff1);
await orm.schema.execute(diff1.up);

orm.getMetadata().reset('Book1');
await orm.discoverEntity(Book2);
const diff2 = await generator.getUpdateSchemaSQL({ wrap: false });
const diff2 = await orm.schema.getUpdateSchemaMigrationSQL({ wrap: false });
expect(diff2).toMatchSnapshot();
await generator.execute(diff2);
await orm.schema.execute(diff2.up);

orm.getMetadata().reset('Book2');
await orm.discoverEntity(Book3);
const diff3 = await generator.getUpdateSchemaSQL({ wrap: false });
const diff3 = await orm.schema.getUpdateSchemaMigrationSQL({ wrap: false });
expect(diff3).toMatchSnapshot();
await generator.execute(diff3);
await orm.schema.execute(diff3.up);

orm.getMetadata().reset('Book3');
await orm.discoverEntity(Book4);

await expect(generator.getUpdateSchemaSQL({ wrap: false })).resolves.toBe('');
await expect(orm.schema.getUpdateSchemaMigrationSQL({ wrap: false })).resolves.toEqual({
down: '',
up: '',
});
});

});
148 changes: 148 additions & 0 deletions tests/features/schema-generator/length-diffing.postgres.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { Entity, PrimaryKey, Property, t } from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/postgresql';

@Entity({ tableName: 'book' })
export class Book0 {

@PrimaryKey()
id!: number;

@Property()
name!: string;

@Property()
length!: number;

@Property({ type: t.decimal })
price!: string;

@Property({ length: 2 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
export class Book1 {

@PrimaryKey({ type: t.bigint })
id!: string;

@Property({ length: 100 })
name!: string;

@Property({ unsigned: true })
length!: number;

@Property({ type: t.decimal, precision: 16 })
price!: string;

@Property({ length: 3 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
export class Book2 {

@PrimaryKey({ type: t.bigint })
id!: string;

@Property({ length: 150 })
name!: string;

@Property({ unsigned: true })
length!: number;

@Property({ type: t.decimal, precision: 16, scale: 4 })
price!: number;

@Property({ length: 3 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
export class Book3 {

@PrimaryKey({ type: t.bigint })
id!: string;

@Property({ length: 100 })
name!: string;

@Property({ unsigned: true })
length!: number;

@Property({ columnType: 'decimal(16,4)' })
price!: number;

@Property({ length: 3 })
createdAt!: Date;

}

@Entity({ tableName: 'book' })
export class Book4 {

@PrimaryKey({ type: t.bigint })
id!: string;

@Property({ columnType: 'varchar(100)' })
name!: string;

@Property({ unsigned: true })
length!: number;

@Property({ columnType: 'decimal(16,4)' })
price!: number;

@Property({ length: 3 })
createdAt!: Date;

}

describe('length diffing in postgres', () => {

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
entities: [Book0],
dbName: `mikro_orm_test_length_diffing`,
});
await orm.schema.ensureDatabase();
await orm.schema.execute('drop table if exists book');
await orm.schema.createSchema();
});

afterAll(() => orm.close(true));

test('schema orm.schema updates column types when length changes (varchar, decimal, ...)', async () => {
orm.getMetadata().reset('Book0');
await orm.discoverEntity(Book1);
const diff1 = await orm.schema.getUpdateSchemaMigrationSQL({ wrap: false });
expect(diff1).toMatchSnapshot();
await orm.schema.execute(diff1.up);

orm.getMetadata().reset('Book1');
await orm.discoverEntity(Book2);
const diff2 = await orm.schema.getUpdateSchemaMigrationSQL({ wrap: false });
expect(diff2).toMatchSnapshot();
await orm.schema.execute(diff2.up);

orm.getMetadata().reset('Book2');
await orm.discoverEntity(Book3);
const diff3 = await orm.schema.getUpdateSchemaMigrationSQL({ wrap: false });
expect(diff3).toMatchSnapshot();
await orm.schema.execute(diff3.up);

orm.getMetadata().reset('Book3');
await orm.discoverEntity(Book4);

await expect(orm.schema.getUpdateSchemaMigrationSQL({ wrap: false })).resolves.toEqual({
down: '',
up: '',
});
});

});

0 comments on commit 222e2b8

Please sign in to comment.