Skip to content

Commit 8423759

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

7 files changed

Lines changed: 127 additions & 7 deletions

File tree

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 type { OperationNode } from './operation-node.js'
33
import type { 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
type DropTypeNodeFactory = Readonly<{
@@ -27,10 +32,17 @@ export const DropTypeNode: DropTypeNodeFactory = freeze<DropTypeNodeFactory>({
2732
return node.kind === 'DropTypeNode'
2833
},
2934

30-
create(name) {
35+
create(
36+
names: SchemableIdentifierNode | SchemableIdentifierNode[],
37+
): DropTypeNode {
38+
if (!Array.isArray(names)) {
39+
names = [names]
40+
}
41+
3142
return freeze({
3243
kind: 'DropTypeNode',
33-
name,
44+
name: names[0],
45+
additionalNames: names.slice(1),
3446
})
3547
},
3648

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
@@ -1440,6 +1440,15 @@ export class DefaultQueryCompiler
14401440
}
14411441

14421442
this.visitNode(node.name)
1443+
1444+
if (node.additionalNames?.length) {
1445+
this.append(', ')
1446+
this.compileList(node.additionalNames)
1447+
}
1448+
1449+
if (node.cascade) {
1450+
this.append(' cascade')
1451+
}
14431452
}
14441453

14451454
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
@@ -2482,6 +2482,7 @@ for (const dialect of DIALECTS) {
24822482
if (sqlSpec === 'postgres') {
24832483
it('should drop a schema cascade', async () => {
24842484
await ctx.db.schema.createSchema('pets').execute()
2485+
24852486
const builder = ctx.db.schema.dropSchema('pets').cascade()
24862487

24872488
testSql(builder, dialect, {
@@ -2586,10 +2587,68 @@ for (const dialect of DIALECTS) {
25862587

25872588
await builder.execute()
25882589
})
2590+
2591+
it('should drop multiple types', async () => {
2592+
await ctx.db.schema.createType('species').execute()
2593+
await ctx.db.schema.createType('colors').execute()
2594+
2595+
const builder = ctx.db.schema
2596+
.dropType(['species', 'colors'])
2597+
.ifExists()
2598+
2599+
testSql(builder, dialect, {
2600+
postgres: {
2601+
sql: `drop type if exists "species", "colors"`,
2602+
parameters: [],
2603+
},
2604+
mysql: NOT_SUPPORTED,
2605+
mssql: NOT_SUPPORTED,
2606+
sqlite: NOT_SUPPORTED,
2607+
})
2608+
2609+
await builder.execute()
2610+
})
2611+
2612+
it('should drop multiple types if exists', async () => {
2613+
await ctx.db.schema.createType('species').execute()
2614+
const builder = ctx.db.schema
2615+
.dropType(['species', 'colors'])
2616+
.ifExists()
2617+
2618+
testSql(builder, dialect, {
2619+
postgres: {
2620+
sql: `drop type if exists "species", "colors"`,
2621+
parameters: [],
2622+
},
2623+
mysql: NOT_SUPPORTED,
2624+
mssql: NOT_SUPPORTED,
2625+
sqlite: NOT_SUPPORTED,
2626+
})
2627+
2628+
await builder.execute()
2629+
})
2630+
2631+
it('should drop a type and cascade', async () => {
2632+
await ctx.db.schema.createType('species').execute()
2633+
2634+
const builder = ctx.db.schema.dropType('species').cascade()
2635+
2636+
testSql(builder, dialect, {
2637+
postgres: {
2638+
sql: `drop type "species" cascade`,
2639+
parameters: [],
2640+
},
2641+
mysql: NOT_SUPPORTED,
2642+
mssql: NOT_SUPPORTED,
2643+
sqlite: NOT_SUPPORTED,
2644+
})
2645+
2646+
await builder.execute()
2647+
})
25892648
}
25902649

25912650
async function cleanup() {
2592-
await ctx.db.schema.dropType('species').ifExists().execute()
2651+
await ctx.db.schema.dropType(['species', 'colors']).ifExists().execute()
25932652
}
25942653
})
25952654

0 commit comments

Comments
 (0)