From c4700f98da469f0a3807cb29de348510537c1ece Mon Sep 17 00:00:00 2001 From: CodeYJ Date: Sat, 11 Jan 2025 17:41:09 +0800 Subject: [PATCH] feat: alterColumn with expressionGenerated (#1305) --- src/operations/tables/alterColumn.ts | 12 +++++ test/migration.spec.ts | 8 ++-- .../migrations/093_alter_column_expression.js | 25 ++++++++++ test/operations/columns/alterColumn.spec.ts | 47 ++++++++++++++++++- 4 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 test/migrations/093_alter_column_expression.js diff --git a/src/operations/tables/alterColumn.ts b/src/operations/tables/alterColumn.ts index 0660b1fd..eb4deaa9 100644 --- a/src/operations/tables/alterColumn.ts +++ b/src/operations/tables/alterColumn.ts @@ -30,6 +30,7 @@ export interface AlterColumnOptions { generated?: null | false | SequenceGeneratedOptions; sequenceGenerated?: null | false | SequenceGeneratedOptions; + expressionGenerated?: null | string; } export type AlterColumn = ( @@ -48,6 +49,7 @@ export function alterColumn(mOptions: MigrationOptions): AlterColumn { notNull, allowNull, comment, + expressionGenerated, } = options; const sequenceGenerated = @@ -92,6 +94,16 @@ export function alterColumn(mOptions: MigrationOptions): AlterColumn { } } + if (expressionGenerated !== undefined) { + if (typeof expressionGenerated === 'string') { + actions.push(`SET EXPRESSION AS (${expressionGenerated})`); + } + + if (expressionGenerated === null) { + actions.push('DROP EXPRESSION'); + } + } + const queries: string[] = []; if (actions.length > 0) { diff --git a/test/migration.spec.ts b/test/migration.spec.ts index 20d3c7d6..293c96df 100644 --- a/test/migration.spec.ts +++ b/test/migration.spec.ts @@ -57,7 +57,7 @@ describe('migration', () => { const filePaths = await getMigrationFilePaths(dir, { logger }); expect(Array.isArray(filePaths)).toBeTruthy(); - expect(filePaths).toHaveLength(92); + expect(filePaths).toHaveLength(93); expect(filePaths).not.toContainEqual(expect.stringContaining('nested')); for (const filePath of filePaths) { @@ -78,7 +78,7 @@ describe('migration', () => { }); expect(Array.isArray(filePaths)).toBeTruthy(); - expect(filePaths).toHaveLength(67); + expect(filePaths).toHaveLength(68); for (const filePath of filePaths) { expect(isAbsolute(filePath)).toBeTruthy(); @@ -94,7 +94,7 @@ describe('migration', () => { }); expect(Array.isArray(filePaths)).toBeTruthy(); - expect(filePaths).toHaveLength(105); + expect(filePaths).toHaveLength(106); expect(filePaths).toContainEqual(expect.stringContaining('nested')); for (const filePath of filePaths) { @@ -114,7 +114,7 @@ describe('migration', () => { }); expect(Array.isArray(filePaths)).toBeTruthy(); - expect(filePaths).toHaveLength(104); + expect(filePaths).toHaveLength(105); expect(filePaths).toContainEqual(expect.stringContaining('nested')); for (const filePath of filePaths) { diff --git a/test/migrations/093_alter_column_expression.js b/test/migrations/093_alter_column_expression.js new file mode 100644 index 00000000..4bda61c5 --- /dev/null +++ b/test/migrations/093_alter_column_expression.js @@ -0,0 +1,25 @@ +const getMajorVersion = async (pgm) => { + const [{ server_version: version }] = await pgm.db.select( + 'SHOW "server_version"' + ); + const [major] = version.split('.'); + return Number(major); +}; + +const isSupportedVersion = (major) => major >= 17; + +exports.up = async (pgm) => { + const major = await getMajorVersion(pgm); + if (isSupportedVersion(major)) { + pgm.createTable('t093', { id: { type: 'integer', notNull: true } }); + pgm.alterColumn('t093', 'col1', { expressionGenerated: 'other + 1' }); + pgm.alterColumn('t093', 'col2', { expressionGenerated: null }); + } +}; + +exports.down = async (pgm) => { + const major = await getMajorVersion(pgm); + if (isSupportedVersion(major)) { + pgm.dropTable('t093'); + } +}; diff --git a/test/operations/columns/alterColumn.spec.ts b/test/operations/columns/alterColumn.spec.ts index 1ed4a9fc..916b9645 100644 --- a/test/operations/columns/alterColumn.spec.ts +++ b/test/operations/columns/alterColumn.spec.ts @@ -28,7 +28,6 @@ describe('operations', () => { sequenceGenerated: null, comment: 'Address of the distributor', }); - expect(statement).toBeTypeOf('string'); expect(statement).toBe( `ALTER TABLE "distributors" @@ -36,6 +35,52 @@ describe('operations', () => { ALTER "address" SET DATA TYPE varchar(30) COLLATE C USING address::text, ALTER "address" DROP NOT NULL, ALTER "address" DROP IDENTITY; +COMMENT ON COLUMN "distributors"."address" IS $pga$Address of the distributor$pga$;` + ); + }); + + it('should return sql statement with columnOptions and expressionGenerated', () => { + const statement = alterColumnFn('distributors', 'address', { + default: null, + type: 'varchar(30)', + collation: 'C', + using: 'address::text', + notNull: false, + sequenceGenerated: null, + comment: 'Address of the distributor', + expressionGenerated: 'other+1', + }); + expect(statement).toBeTypeOf('string'); + expect(statement).toBe( + `ALTER TABLE "distributors" + ALTER "address" DROP DEFAULT, + ALTER "address" SET DATA TYPE varchar(30) COLLATE C USING address::text, + ALTER "address" DROP NOT NULL, + ALTER "address" DROP IDENTITY, + ALTER "address" SET EXPRESSION AS (other+1); +COMMENT ON COLUMN "distributors"."address" IS $pga$Address of the distributor$pga$;` + ); + }); + + it('should return sql statement with columnOptions and drop expression', () => { + const statement = alterColumnFn('distributors', 'address', { + default: null, + type: 'varchar(30)', + collation: 'C', + using: 'address::text', + notNull: false, + sequenceGenerated: null, + comment: 'Address of the distributor', + expressionGenerated: null, + }); + expect(statement).toBeTypeOf('string'); + expect(statement).toBe( + `ALTER TABLE "distributors" + ALTER "address" DROP DEFAULT, + ALTER "address" SET DATA TYPE varchar(30) COLLATE C USING address::text, + ALTER "address" DROP NOT NULL, + ALTER "address" DROP IDENTITY, + ALTER "address" DROP EXPRESSION; COMMENT ON COLUMN "distributors"."address" IS $pga$Address of the distributor$pga$;` ); });