diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..7a4be3f6c Binary files /dev/null and b/.DS_Store differ diff --git a/src/operation-node/alter-table-node.ts b/src/operation-node/alter-table-node.ts index 9ce9e4c32..b79fd3a3b 100644 --- a/src/operation-node/alter-table-node.ts +++ b/src/operation-node/alter-table-node.ts @@ -15,6 +15,7 @@ import type { RenameConstraintNode } from './rename-constraint-node.js' export type AlterTableNodeTableProps = Pick< AlterTableNode, + | 'ifExists' | 'renameTo' | 'setSchema' | 'addConstraint' @@ -34,6 +35,7 @@ export type AlterTableColumnAlterationNode = export interface AlterTableNode extends OperationNode { readonly kind: 'AlterTableNode' readonly table: TableNode + readonly ifExists?: boolean readonly renameTo?: TableNode readonly setSchema?: IdentifierNode readonly columnAlterations?: ReadonlyArray diff --git a/src/operation-node/operation-node-transformer.ts b/src/operation-node/operation-node-transformer.ts index 6a2da3c75..af39d0d8b 100644 --- a/src/operation-node/operation-node-transformer.ts +++ b/src/operation-node/operation-node-transformer.ts @@ -836,6 +836,7 @@ export class OperationNodeTransformer { return requireAllProps({ kind: 'AlterTableNode', table: this.transformNode(node.table, queryId), + ifExists: node.ifExists, renameTo: this.transformNode(node.renameTo, queryId), setSchema: this.transformNode(node.setSchema, queryId), columnAlterations: this.transformNodeList( diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index ba0fab177..7daf533d3 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -1165,6 +1165,11 @@ export class DefaultQueryCompiler protected override visitAlterTable(node: AlterTableNode): void { this.append('alter table ') + + if (node.ifExists) { + this.append('if exists ') + } + this.visitNode(node.table) this.append(' ') diff --git a/src/schema/alter-table-builder.ts b/src/schema/alter-table-builder.ts index f2f945782..af823ff70 100644 --- a/src/schema/alter-table-builder.ts +++ b/src/schema/alter-table-builder.ts @@ -66,6 +66,20 @@ export class AlterTableBuilder implements ColumnAlteringInterface { this.#props = freeze(props) } + /** + * Adds the "if exists" modifier. + * + * If the table doesn't exist, no error is thrown if this method has been called. + */ + ifExists(): AlterTableBuilder { + return new AlterTableBuilder({ + ...this.#props, + node: AlterTableNode.cloneWithTableProps(this.#props.node, { + ifExists: true, + }), + }) + } + renameTo(newTableName: string): AlterTableExecutor { return new AlterTableExecutor({ ...this.#props, diff --git a/test/node/src/schema.test.ts b/test/node/src/schema.test.ts index 868d0a7b7..29d0be2e7 100644 --- a/test/node/src/schema.test.ts +++ b/test/node/src/schema.test.ts @@ -1869,6 +1869,8 @@ for (const dialect of DIALECTS) { .createTable('test') .addColumn('id', 'bigint', (col) => col.primaryKey()) .addColumn('first_name', 'varchar(255)') + .addColumn('last_name', 'varchar(255)') + .addColumn('age', 'integer') .execute() await ctx.db.schema @@ -2544,6 +2546,31 @@ for (const dialect of DIALECTS) { .execute() }) + if (dialect === 'postgres' || dialect === 'mysql' || dialect === 'sqlite') { + it('should alter table with if exists', async () => { + const builder = ctx.db.schema + .alterTable('test') + .ifExists() + .addColumn('date_col', 'date') + + testSql(builder, dialect, { + postgres: { + sql: 'alter table if exists "test" add column "date_col" date', + parameters: [], + }, + mysql: { + sql: 'alter table if exists `test` add column `date_col` date', + parameters: [], + }, + mssql: NOT_SUPPORTED, + sqlite: { + sql: 'alter table if exists "test" add column "date_col" date', + parameters: [], + }, + }) + }) + } + describe('add column', () => { it('should add a column', async () => { const builder = ctx.db.schema