From 871d6d08a6dc61b7dfaa454894a19f11807976c3 Mon Sep 17 00:00:00 2001 From: Mateusz Koteja Date: Sun, 28 May 2023 11:13:00 +0200 Subject: [PATCH] fix: disallow AlterColumn method chaining (#468) * fix: disallow chaining AlterColumnBuilder operations (#467) * chore: limit AlterColumnNode.create available params, change AlterColumnBuilder fields names --- src/operation-node/alter-column-node.ts | 15 ++------- src/schema/alter-column-builder.ts | 44 ++++++++++++------------- src/schema/alter-table-builder.ts | 4 +-- 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/operation-node/alter-column-node.ts b/src/operation-node/alter-column-node.ts index cb251e557..42e859dc3 100644 --- a/src/operation-node/alter-column-node.ts +++ b/src/operation-node/alter-column-node.ts @@ -1,8 +1,6 @@ import { OperationNode } from './operation-node.js' import { freeze } from '../util/object-utils.js' import { ColumnNode } from './column-node.js' -import { DataTypeNode } from './data-type-node.js' -import { ValueNode } from './value-node.js' import { RawNode } from './raw-node.js' export type AlterColumnNodeProps = Omit @@ -26,20 +24,11 @@ export const AlterColumnNode = freeze({ return node.kind === 'AlterColumnNode' }, - create(column: string): AlterColumnNode { + create(column: string, prop: T, value: Required[T]): AlterColumnNode { return freeze({ kind: 'AlterColumnNode', column: ColumnNode.create(column), - }) - }, - - cloneWith( - node: AlterColumnNode, - props: AlterColumnNodeProps - ): AlterColumnNode { - return freeze({ - ...node, - ...props, + [prop]: value }) }, }) diff --git a/src/schema/alter-column-builder.ts b/src/schema/alter-column-builder.ts index 23580068e..70b8ed0d6 100644 --- a/src/schema/alter-column-builder.ts +++ b/src/schema/alter-column-builder.ts @@ -10,49 +10,39 @@ import { } from '../parser/default-value-parser.js' export class AlterColumnBuilder { - protected readonly alterColumnNode: AlterColumnNode + readonly #column: string - constructor(alterColumnNode: AlterColumnNode) { - this.alterColumnNode = alterColumnNode + constructor(column: string) { + this.#column = column } setDataType(dataType: DataTypeExpression): AlteredColumnBuilder { return new AlteredColumnBuilder( - AlterColumnNode.cloneWith(this.alterColumnNode, { - dataType: parseDataTypeExpression(dataType), - }) + AlterColumnNode.create(this.#column, 'dataType', parseDataTypeExpression(dataType)) ) } setDefault(value: DefaultValueExpression): AlteredColumnBuilder { return new AlteredColumnBuilder( - AlterColumnNode.cloneWith(this.alterColumnNode, { - setDefault: parseDefaultValueExpression(value), - }) + AlterColumnNode.create(this.#column, 'setDefault', parseDefaultValueExpression(value)) ) } dropDefault(): AlteredColumnBuilder { return new AlteredColumnBuilder( - AlterColumnNode.cloneWith(this.alterColumnNode, { - dropDefault: true, - }) + AlterColumnNode.create(this.#column, 'dropDefault', true) ) } setNotNull(): AlteredColumnBuilder { return new AlteredColumnBuilder( - AlterColumnNode.cloneWith(this.alterColumnNode, { - setNotNull: true, - }) + AlterColumnNode.create(this.#column, 'setNotNull', true) ) } dropNotNull(): AlteredColumnBuilder { return new AlteredColumnBuilder( - AlterColumnNode.cloneWith(this.alterColumnNode, { - dropNotNull: true, - }) + AlterColumnNode.create(this.#column, 'dropNotNull', true) ) } @@ -66,22 +56,30 @@ export class AlterColumnBuilder { } /** - * Allows us to force consumers to do something, anything, when altering a column. + * Allows us to force consumers to do exactly one alteration to a column. * * Basically, deny the following: * * ```ts * db.schema.alterTable('person').alterColumn('age', (ac) => ac) * ``` + * + * ```ts + * db.schema.alterTable('person').alterColumn('age', (ac) => ac.dropNotNull().setNotNull()) + * ``` * * Which would now throw a compilation error, instead of a runtime error. */ -export class AlteredColumnBuilder - extends AlterColumnBuilder - implements OperationNodeSource +export class AlteredColumnBuilder implements OperationNodeSource { + readonly #alterColumnNode: AlterColumnNode + + constructor(alterColumnNode: AlterColumnNode) { + this.#alterColumnNode = alterColumnNode + } + toOperationNode(): AlterColumnNode { - return this.alterColumnNode + return this.#alterColumnNode } } diff --git a/src/schema/alter-table-builder.ts b/src/schema/alter-table-builder.ts index ce0bd51d4..fc87a8409 100644 --- a/src/schema/alter-table-builder.ts +++ b/src/schema/alter-table-builder.ts @@ -75,7 +75,7 @@ export class AlterTableBuilder implements ColumnAlteringInterface { alteration: AlterColumnBuilderCallback ): AlterTableColumnAlteringBuilder { const builder = alteration( - new AlterColumnBuilder(AlterColumnNode.create(column)) + new AlterColumnBuilder(column) ) return new AlterTableColumnAlteringBuilder({ @@ -315,7 +315,7 @@ export class AlterTableColumnAlteringBuilder alteration: AlterColumnBuilderCallback ): AlterTableColumnAlteringBuilder { const builder = alteration( - new AlterColumnBuilder(AlterColumnNode.create(column)) + new AlterColumnBuilder(column) ) return new AlterTableColumnAlteringBuilder({