Skip to content

Commit 9adaf87

Browse files
aantiaigalklebanov
andcommitted
Support dropping multiple types with schema.dropType(), cascade. (#1516)
Co-authored-by: Igal Klebanov <igalklebanov@gmail.com>
1 parent a43ca4a commit 9adaf87

File tree

7 files changed

+127
-7
lines changed

7 files changed

+127
-7
lines changed

src/operation-node/drop-type-node.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ import { freeze } from '../util/object-utils.js'
22
import { OperationNode } from './operation-node.js'
33
import { SchemableIdentifierNode } from './schemable-identifier-node.js'
44

5-
export type DropTypeNodeParams = Omit<Partial<DropTypeNode>, 'kind' | 'name'>
5+
export type DropTypeNodeParams = Omit<
6+
Partial<DropTypeNode>,
7+
'kind' | 'name' | 'additionalNames'
8+
>
69

710
export interface DropTypeNode extends OperationNode {
811
readonly kind: 'DropTypeNode'
912
readonly name: SchemableIdentifierNode
13+
readonly additionalNames?: SchemableIdentifierNode[]
1014
readonly ifExists?: boolean
15+
readonly cascade?: boolean
1116
}
1217

1318
/**
@@ -18,10 +23,17 @@ export const DropTypeNode = freeze({
1823
return node.kind === 'DropTypeNode'
1924
},
2025

21-
create(name: SchemableIdentifierNode): DropTypeNode {
26+
create(
27+
names: SchemableIdentifierNode | SchemableIdentifierNode[],
28+
): DropTypeNode {
29+
if (!Array.isArray(names)) {
30+
names = [names]
31+
}
32+
2233
return freeze({
2334
kind: 'DropTypeNode',
24-
name,
35+
name: names[0],
36+
additionalNames: names.slice(1),
2537
})
2638
},
2739

src/operation-node/operation-node-transformer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,8 @@ export class OperationNodeTransformer {
10321032
return requireAllProps<DropTypeNode>({
10331033
kind: 'DropTypeNode',
10341034
name: this.transformNode(node.name, queryId),
1035+
additionalNames: this.transformNodeList(node.additionalNames, queryId),
1036+
cascade: node.cascade,
10351037
ifExists: node.ifExists,
10361038
})
10371039
}

src/parser/identifier-parser.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ export function parseSchemableIdentifier(id: string): SchemableIdentifierNode {
1616
}
1717
}
1818

19+
export function parseSchemableIdentifierArray(
20+
id: string | string[],
21+
): SchemableIdentifierNode[] {
22+
if (!Array.isArray(id)) {
23+
id = [id]
24+
}
25+
26+
return id.map(parseSchemableIdentifier)
27+
}
28+
1929
function trim(str: string): string {
2030
return str.trim()
2131
}

src/query-compiler/default-query-compiler.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,15 @@ export class DefaultQueryCompiler
14291429
}
14301430

14311431
this.visitNode(node.name)
1432+
1433+
if (node.additionalNames?.length) {
1434+
this.append(', ')
1435+
this.compileList(node.additionalNames)
1436+
}
1437+
1438+
if (node.cascade) {
1439+
this.append(' cascade')
1440+
}
14321441
}
14331442

14341443
protected override visitExplain(node: ExplainNode): void {

src/schema/drop-type-builder.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ export class DropTypeBuilder implements OperationNodeSource, Compilable {
1313
this.#props = freeze(props)
1414
}
1515

16+
/**
17+
* Adds `if exists` to the query.
18+
*/
1619
ifExists(): DropTypeBuilder {
1720
return new DropTypeBuilder({
1821
...this.#props,
@@ -22,6 +25,18 @@ export class DropTypeBuilder implements OperationNodeSource, Compilable {
2225
})
2326
}
2427

28+
/**
29+
* Adds `cascade` to the query.
30+
*/
31+
cascade(): DropTypeBuilder {
32+
return new DropTypeBuilder({
33+
...this.#props,
34+
node: DropTypeNode.cloneWith(this.#props.node, {
35+
cascade: true,
36+
}),
37+
})
38+
}
39+
2540
/**
2641
* Simply calls the provided function passing `this` as the only argument. `$call` returns
2742
* what the provided function returns.

src/schema/schema.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ import { CreateTypeBuilder } from './create-type-builder.js'
2525
import { DropTypeBuilder } from './drop-type-builder.js'
2626
import { CreateTypeNode } from '../operation-node/create-type-node.js'
2727
import { DropTypeNode } from '../operation-node/drop-type-node.js'
28-
import { parseSchemableIdentifier } from '../parser/identifier-parser.js'
28+
import {
29+
parseSchemableIdentifier,
30+
parseSchemableIdentifierArray,
31+
} from '../parser/identifier-parser.js'
2932
import { RefreshMaterializedViewBuilder } from './refresh-materialized-view-builder.js'
3033
import { RefreshMaterializedViewNode } from '../operation-node/refresh-materialized-view-node.js'
3134

@@ -311,12 +314,22 @@ export class SchemaModule {
311314
* .ifExists()
312315
* .execute()
313316
* ```
317+
*
318+
* You can also provide multiple type names:
319+
*
320+
* ```ts
321+
* await db.schema
322+
* .dropType(['species', 'colors'])
323+
* .ifExists()
324+
* .cascade()
325+
* .execute()
326+
* ```
314327
*/
315-
dropType(typeName: string): DropTypeBuilder {
328+
dropType(typeName: string | string[]): DropTypeBuilder {
316329
return new DropTypeBuilder({
317330
queryId: createQueryId(),
318331
executor: this.#executor,
319-
node: DropTypeNode.create(parseSchemableIdentifier(typeName)),
332+
node: DropTypeNode.create(parseSchemableIdentifierArray(typeName)),
320333
})
321334
}
322335

test/node/src/schema.test.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2457,6 +2457,7 @@ for (const dialect of DIALECTS) {
24572457
if (sqlSpec === 'postgres') {
24582458
it('should drop a schema cascade', async () => {
24592459
await ctx.db.schema.createSchema('pets').execute()
2460+
24602461
const builder = ctx.db.schema.dropSchema('pets').cascade()
24612462

24622463
testSql(builder, dialect, {
@@ -2561,10 +2562,68 @@ for (const dialect of DIALECTS) {
25612562

25622563
await builder.execute()
25632564
})
2565+
2566+
it('should drop multiple types', async () => {
2567+
await ctx.db.schema.createType('species').execute()
2568+
await ctx.db.schema.createType('colors').execute()
2569+
2570+
const builder = ctx.db.schema
2571+
.dropType(['species', 'colors'])
2572+
.ifExists()
2573+
2574+
testSql(builder, dialect, {
2575+
postgres: {
2576+
sql: `drop type if exists "species", "colors"`,
2577+
parameters: [],
2578+
},
2579+
mysql: NOT_SUPPORTED,
2580+
mssql: NOT_SUPPORTED,
2581+
sqlite: NOT_SUPPORTED,
2582+
})
2583+
2584+
await builder.execute()
2585+
})
2586+
2587+
it('should drop multiple types if exists', async () => {
2588+
await ctx.db.schema.createType('species').execute()
2589+
const builder = ctx.db.schema
2590+
.dropType(['species', 'colors'])
2591+
.ifExists()
2592+
2593+
testSql(builder, dialect, {
2594+
postgres: {
2595+
sql: `drop type if exists "species", "colors"`,
2596+
parameters: [],
2597+
},
2598+
mysql: NOT_SUPPORTED,
2599+
mssql: NOT_SUPPORTED,
2600+
sqlite: NOT_SUPPORTED,
2601+
})
2602+
2603+
await builder.execute()
2604+
})
2605+
2606+
it('should drop a type and cascade', async () => {
2607+
await ctx.db.schema.createType('species').execute()
2608+
2609+
const builder = ctx.db.schema.dropType('species').cascade()
2610+
2611+
testSql(builder, dialect, {
2612+
postgres: {
2613+
sql: `drop type "species" cascade`,
2614+
parameters: [],
2615+
},
2616+
mysql: NOT_SUPPORTED,
2617+
mssql: NOT_SUPPORTED,
2618+
sqlite: NOT_SUPPORTED,
2619+
})
2620+
2621+
await builder.execute()
2622+
})
25642623
}
25652624

25662625
async function cleanup() {
2567-
await ctx.db.schema.dropType('species').ifExists().execute()
2626+
await ctx.db.schema.dropType(['species', 'colors']).ifExists().execute()
25682627
}
25692628
})
25702629

0 commit comments

Comments
 (0)