@prisma-next/target-postgres 0.4.0-dev.8 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/control.d.mts +1 -9
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +1693 -4798
- package/dist/control.mjs.map +1 -1
- package/dist/migration.d.mts +164 -0
- package/dist/migration.d.mts.map +1 -0
- package/dist/migration.mjs +446 -0
- package/dist/migration.mjs.map +1 -0
- package/dist/planner-target-details-MXb3oeul.d.mts +11 -0
- package/dist/planner-target-details-MXb3oeul.d.mts.map +1 -0
- package/dist/postgres-migration-BsHJHV9O.mjs +2793 -0
- package/dist/postgres-migration-BsHJHV9O.mjs.map +1 -0
- package/package.json +21 -19
- package/src/core/migrations/issue-planner.ts +832 -0
- package/src/core/migrations/op-factory-call.ts +862 -0
- package/src/core/migrations/operations/columns.ts +285 -0
- package/src/core/migrations/operations/constraints.ts +191 -0
- package/src/core/migrations/operations/data-transform.ts +113 -0
- package/src/core/migrations/operations/dependencies.ts +36 -0
- package/src/core/migrations/operations/enums.ts +113 -0
- package/src/core/migrations/operations/indexes.ts +61 -0
- package/src/core/migrations/operations/raw.ts +15 -0
- package/src/core/migrations/operations/shared.ts +67 -0
- package/src/core/migrations/operations/tables.ts +63 -0
- package/src/core/migrations/planner-produced-postgres-migration.ts +67 -0
- package/src/core/migrations/planner-strategies.ts +592 -151
- package/src/core/migrations/planner-target-details.ts +0 -6
- package/src/core/migrations/planner.ts +63 -781
- package/src/core/migrations/postgres-migration.ts +20 -0
- package/src/core/migrations/render-ops.ts +9 -0
- package/src/core/migrations/render-typescript.ts +95 -0
- package/src/exports/control.ts +9 -142
- package/src/exports/migration.ts +40 -0
- package/dist/migration-builders.d.mts +0 -88
- package/dist/migration-builders.d.mts.map +0 -1
- package/dist/migration-builders.mjs +0 -3
- package/dist/operation-descriptors-CxymFSgK.mjs +0 -52
- package/dist/operation-descriptors-CxymFSgK.mjs.map +0 -1
- package/src/core/migrations/descriptor-planner.ts +0 -464
- package/src/core/migrations/operation-descriptors.ts +0 -166
- package/src/core/migrations/operation-resolver.ts +0 -929
- package/src/core/migrations/planner-reconciliation.ts +0 -798
- package/src/core/migrations/scaffolding.ts +0 -140
- package/src/exports/migration-builders.ts +0 -56
|
@@ -1,929 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolves thin operation descriptors into SqlMigrationPlanOperation objects
|
|
3
|
-
* by looking up contract types and calling existing planner SQL helpers.
|
|
4
|
-
*
|
|
5
|
-
* This is the bridge between the ergonomic builder API (descriptors) and
|
|
6
|
-
* the planner's SQL generation pipeline. It runs at verification time.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { createPostgresAdapter } from '@prisma-next/adapter-postgres/adapter';
|
|
10
|
-
import type { Contract } from '@prisma-next/contract/types';
|
|
11
|
-
import type {
|
|
12
|
-
CodecControlHooks,
|
|
13
|
-
ComponentDatabaseDependency,
|
|
14
|
-
SqlMigrationPlanOperation,
|
|
15
|
-
} from '@prisma-next/family-sql/control';
|
|
16
|
-
import type {
|
|
17
|
-
DataTransformOperation,
|
|
18
|
-
SerializedQueryPlan,
|
|
19
|
-
} from '@prisma-next/framework-components/control';
|
|
20
|
-
import type { SqlStorage, StorageColumn, StorageTable } from '@prisma-next/sql-contract/types';
|
|
21
|
-
import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
|
|
22
|
-
import { lowerSqlPlan } from '@prisma-next/sql-runtime';
|
|
23
|
-
import { ifDefined } from '@prisma-next/utils/defined';
|
|
24
|
-
import type {
|
|
25
|
-
AddColumnDescriptor,
|
|
26
|
-
AddEnumValuesDescriptor,
|
|
27
|
-
AddForeignKeyDescriptor,
|
|
28
|
-
AddPrimaryKeyDescriptor,
|
|
29
|
-
AddUniqueDescriptor,
|
|
30
|
-
AlterColumnTypeDescriptor,
|
|
31
|
-
CreateDependencyDescriptor,
|
|
32
|
-
CreateEnumTypeDescriptor,
|
|
33
|
-
CreateIndexDescriptor,
|
|
34
|
-
CreateTableDescriptor,
|
|
35
|
-
DataTransformDescriptor,
|
|
36
|
-
DropColumnDescriptor,
|
|
37
|
-
DropConstraintDescriptor,
|
|
38
|
-
DropDefaultDescriptor,
|
|
39
|
-
DropEnumTypeDescriptor,
|
|
40
|
-
DropIndexDescriptor,
|
|
41
|
-
DropNotNullDescriptor,
|
|
42
|
-
DropTableDescriptor,
|
|
43
|
-
PostgresMigrationOpDescriptor,
|
|
44
|
-
RenameTypeDescriptor,
|
|
45
|
-
SetDefaultDescriptor,
|
|
46
|
-
SetNotNullDescriptor,
|
|
47
|
-
} from './operation-descriptors';
|
|
48
|
-
import {
|
|
49
|
-
buildAddColumnSql,
|
|
50
|
-
buildColumnDefaultSql,
|
|
51
|
-
buildCreateTableSql,
|
|
52
|
-
buildForeignKeySql,
|
|
53
|
-
} from './planner-ddl-builders';
|
|
54
|
-
import {
|
|
55
|
-
buildExpectedFormatType,
|
|
56
|
-
columnExistsCheck,
|
|
57
|
-
columnNullabilityCheck,
|
|
58
|
-
columnTypeCheck,
|
|
59
|
-
constraintExistsCheck,
|
|
60
|
-
qualifyTableName,
|
|
61
|
-
toRegclassLiteral,
|
|
62
|
-
} from './planner-sql-checks';
|
|
63
|
-
import type { OperationClass, PostgresPlanTargetDetails } from './planner-target-details';
|
|
64
|
-
|
|
65
|
-
export interface OperationResolverContext {
|
|
66
|
-
readonly toContract: Contract<SqlStorage>;
|
|
67
|
-
readonly schemaName: string;
|
|
68
|
-
readonly codecHooks: Map<string, CodecControlHooks>;
|
|
69
|
-
readonly dependencies?: readonly ComponentDatabaseDependency<unknown>[];
|
|
70
|
-
readonly db?: unknown;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
type ResolvedOp = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
|
|
74
|
-
|
|
75
|
-
function getTable(contract: Contract<SqlStorage>, tableName: string): StorageTable | undefined {
|
|
76
|
-
return contract.storage.tables[tableName];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function getColumn(
|
|
80
|
-
contract: Contract<SqlStorage>,
|
|
81
|
-
tableName: string,
|
|
82
|
-
columnName: string,
|
|
83
|
-
): StorageColumn | undefined {
|
|
84
|
-
return getTable(contract, tableName)?.columns[columnName];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function targetDetails(
|
|
88
|
-
objectType: OperationClass,
|
|
89
|
-
name: string,
|
|
90
|
-
schema: string,
|
|
91
|
-
table?: string,
|
|
92
|
-
): { readonly id: 'postgres'; readonly details: PostgresPlanTargetDetails } {
|
|
93
|
-
return {
|
|
94
|
-
id: 'postgres',
|
|
95
|
-
details: { schema, objectType, name, ...ifDefined('table', table) },
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function step(description: string, sql: string) {
|
|
100
|
-
return { description, sql };
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function resolveCreateTable(
|
|
104
|
-
desc: CreateTableDescriptor,
|
|
105
|
-
ctx: OperationResolverContext,
|
|
106
|
-
): ResolvedOp {
|
|
107
|
-
const table = getTable(ctx.toContract, desc.table);
|
|
108
|
-
if (!table) throw new Error(`Table "${desc.table}" not found in destination contract`);
|
|
109
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
110
|
-
return {
|
|
111
|
-
id: `table.${desc.table}`,
|
|
112
|
-
label: `Create table "${desc.table}"`,
|
|
113
|
-
summary: `Creates table "${desc.table}"`,
|
|
114
|
-
operationClass: 'additive',
|
|
115
|
-
target: targetDetails('table', desc.table, ctx.schemaName),
|
|
116
|
-
precheck: [
|
|
117
|
-
step(
|
|
118
|
-
`ensure table "${desc.table}" does not exist`,
|
|
119
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, desc.table)}) IS NULL`,
|
|
120
|
-
),
|
|
121
|
-
],
|
|
122
|
-
execute: [
|
|
123
|
-
step(`create table "${desc.table}"`, buildCreateTableSql(qualified, table, ctx.codecHooks)),
|
|
124
|
-
],
|
|
125
|
-
postcheck: [
|
|
126
|
-
step(
|
|
127
|
-
`verify table "${desc.table}" exists`,
|
|
128
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, desc.table)}) IS NOT NULL`,
|
|
129
|
-
),
|
|
130
|
-
],
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function resolveDropTable(desc: DropTableDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
135
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
136
|
-
return {
|
|
137
|
-
id: `dropTable.${desc.table}`,
|
|
138
|
-
label: `Drop table "${desc.table}"`,
|
|
139
|
-
operationClass: 'destructive',
|
|
140
|
-
target: targetDetails('table', desc.table, ctx.schemaName),
|
|
141
|
-
precheck: [
|
|
142
|
-
step(
|
|
143
|
-
`ensure table "${desc.table}" exists`,
|
|
144
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, desc.table)}) IS NOT NULL`,
|
|
145
|
-
),
|
|
146
|
-
],
|
|
147
|
-
execute: [step(`drop table "${desc.table}"`, `DROP TABLE ${qualified}`)],
|
|
148
|
-
postcheck: [
|
|
149
|
-
step(
|
|
150
|
-
`verify table "${desc.table}" does not exist`,
|
|
151
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, desc.table)}) IS NULL`,
|
|
152
|
-
),
|
|
153
|
-
],
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function resolveAddColumn(desc: AddColumnDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
158
|
-
const contractColumn = getColumn(ctx.toContract, desc.table, desc.column);
|
|
159
|
-
if (!contractColumn)
|
|
160
|
-
throw new Error(`Column "${desc.table}"."${desc.column}" not found in destination contract`);
|
|
161
|
-
// Apply overrides — e.g., nullable: true for the add-nullable → backfill → setNotNull pattern
|
|
162
|
-
const column: StorageColumn = {
|
|
163
|
-
...contractColumn,
|
|
164
|
-
nullable:
|
|
165
|
-
desc.overrides?.nullable !== undefined ? desc.overrides.nullable : contractColumn.nullable,
|
|
166
|
-
};
|
|
167
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
168
|
-
return {
|
|
169
|
-
id: `column.${desc.table}.${desc.column}`,
|
|
170
|
-
label: `Add column "${desc.column}" to "${desc.table}"`,
|
|
171
|
-
operationClass: 'additive',
|
|
172
|
-
target: targetDetails('column', desc.column, ctx.schemaName, desc.table),
|
|
173
|
-
precheck: [
|
|
174
|
-
step(
|
|
175
|
-
`ensure column "${desc.column}" is missing`,
|
|
176
|
-
columnExistsCheck({
|
|
177
|
-
schema: ctx.schemaName,
|
|
178
|
-
table: desc.table,
|
|
179
|
-
column: desc.column,
|
|
180
|
-
exists: false,
|
|
181
|
-
}),
|
|
182
|
-
),
|
|
183
|
-
],
|
|
184
|
-
execute: [
|
|
185
|
-
step(
|
|
186
|
-
`add column "${desc.column}"`,
|
|
187
|
-
buildAddColumnSql(qualified, desc.column, column, ctx.codecHooks),
|
|
188
|
-
),
|
|
189
|
-
],
|
|
190
|
-
postcheck: [
|
|
191
|
-
step(
|
|
192
|
-
`verify column "${desc.column}" exists`,
|
|
193
|
-
columnExistsCheck({ schema: ctx.schemaName, table: desc.table, column: desc.column }),
|
|
194
|
-
),
|
|
195
|
-
],
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function resolveDropColumn(desc: DropColumnDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
200
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
201
|
-
return {
|
|
202
|
-
id: `dropColumn.${desc.table}.${desc.column}`,
|
|
203
|
-
label: `Drop column "${desc.column}" from "${desc.table}"`,
|
|
204
|
-
operationClass: 'destructive',
|
|
205
|
-
target: targetDetails('column', desc.column, ctx.schemaName, desc.table),
|
|
206
|
-
precheck: [
|
|
207
|
-
step(
|
|
208
|
-
`ensure column "${desc.column}" exists`,
|
|
209
|
-
columnExistsCheck({ schema: ctx.schemaName, table: desc.table, column: desc.column }),
|
|
210
|
-
),
|
|
211
|
-
],
|
|
212
|
-
execute: [
|
|
213
|
-
step(
|
|
214
|
-
`drop column "${desc.column}"`,
|
|
215
|
-
`ALTER TABLE ${qualified} DROP COLUMN ${quoteId(desc.column)}`,
|
|
216
|
-
),
|
|
217
|
-
],
|
|
218
|
-
postcheck: [
|
|
219
|
-
step(
|
|
220
|
-
`verify column "${desc.column}" does not exist`,
|
|
221
|
-
columnExistsCheck({
|
|
222
|
-
schema: ctx.schemaName,
|
|
223
|
-
table: desc.table,
|
|
224
|
-
column: desc.column,
|
|
225
|
-
exists: false,
|
|
226
|
-
}),
|
|
227
|
-
),
|
|
228
|
-
],
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function resolveAlterColumnType(
|
|
233
|
-
desc: AlterColumnTypeDescriptor,
|
|
234
|
-
ctx: OperationResolverContext,
|
|
235
|
-
): ResolvedOp {
|
|
236
|
-
const column = getColumn(ctx.toContract, desc.table, desc.column);
|
|
237
|
-
if (!column)
|
|
238
|
-
throw new Error(`Column "${desc.table}"."${desc.column}" not found in destination contract`);
|
|
239
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
240
|
-
const qualifiedTargetType = desc.toType
|
|
241
|
-
? qualifyName(ctx.schemaName, desc.toType)
|
|
242
|
-
: buildExpectedFormatType(column, ctx.codecHooks);
|
|
243
|
-
// format_type() returns unqualified names for types in search_path
|
|
244
|
-
const formatTypeExpected = desc.toType ?? buildExpectedFormatType(column, ctx.codecHooks);
|
|
245
|
-
return {
|
|
246
|
-
id: `alterType.${desc.table}.${desc.column}`,
|
|
247
|
-
label: `Alter type of "${desc.table}"."${desc.column}" to ${desc.toType ?? column.nativeType}`,
|
|
248
|
-
operationClass: 'destructive',
|
|
249
|
-
target: targetDetails('column', desc.column, ctx.schemaName, desc.table),
|
|
250
|
-
precheck: [
|
|
251
|
-
step(
|
|
252
|
-
`ensure column "${desc.column}" exists`,
|
|
253
|
-
columnExistsCheck({ schema: ctx.schemaName, table: desc.table, column: desc.column }),
|
|
254
|
-
),
|
|
255
|
-
],
|
|
256
|
-
execute: [
|
|
257
|
-
step(
|
|
258
|
-
`alter type of "${desc.column}"`,
|
|
259
|
-
`ALTER TABLE ${qualified} ALTER COLUMN ${quoteId(desc.column)} TYPE ${qualifiedTargetType}${desc.using ? ` USING ${desc.using}` : ` USING ${quoteId(desc.column)}::${qualifiedTargetType}`}`,
|
|
260
|
-
),
|
|
261
|
-
],
|
|
262
|
-
postcheck: [
|
|
263
|
-
step(
|
|
264
|
-
`verify column "${desc.column}" has type "${formatTypeExpected}"`,
|
|
265
|
-
columnTypeCheck({
|
|
266
|
-
schema: ctx.schemaName,
|
|
267
|
-
table: desc.table,
|
|
268
|
-
column: desc.column,
|
|
269
|
-
expectedType: formatTypeExpected,
|
|
270
|
-
}),
|
|
271
|
-
),
|
|
272
|
-
],
|
|
273
|
-
meta: { warning: 'TABLE_REWRITE' },
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function resolveSetNotNull(desc: SetNotNullDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
278
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
279
|
-
return {
|
|
280
|
-
id: `alterNullability.${desc.table}.${desc.column}`,
|
|
281
|
-
label: `Set NOT NULL on "${desc.table}"."${desc.column}"`,
|
|
282
|
-
operationClass: 'destructive',
|
|
283
|
-
target: targetDetails('column', desc.column, ctx.schemaName, desc.table),
|
|
284
|
-
precheck: [
|
|
285
|
-
step(
|
|
286
|
-
`ensure column "${desc.column}" exists`,
|
|
287
|
-
columnExistsCheck({ schema: ctx.schemaName, table: desc.table, column: desc.column }),
|
|
288
|
-
),
|
|
289
|
-
step(
|
|
290
|
-
`ensure no NULL values in "${desc.column}"`,
|
|
291
|
-
`SELECT NOT EXISTS (SELECT 1 FROM ${qualified} WHERE ${quoteId(desc.column)} IS NULL)`,
|
|
292
|
-
),
|
|
293
|
-
],
|
|
294
|
-
execute: [
|
|
295
|
-
step(
|
|
296
|
-
`set NOT NULL on "${desc.column}"`,
|
|
297
|
-
`ALTER TABLE ${qualified} ALTER COLUMN ${quoteId(desc.column)} SET NOT NULL`,
|
|
298
|
-
),
|
|
299
|
-
],
|
|
300
|
-
postcheck: [
|
|
301
|
-
step(
|
|
302
|
-
`verify column "${desc.column}" is NOT NULL`,
|
|
303
|
-
columnNullabilityCheck({
|
|
304
|
-
schema: ctx.schemaName,
|
|
305
|
-
table: desc.table,
|
|
306
|
-
column: desc.column,
|
|
307
|
-
nullable: false,
|
|
308
|
-
}),
|
|
309
|
-
),
|
|
310
|
-
],
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function resolveDropNotNull(
|
|
315
|
-
desc: DropNotNullDescriptor,
|
|
316
|
-
ctx: OperationResolverContext,
|
|
317
|
-
): ResolvedOp {
|
|
318
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
319
|
-
return {
|
|
320
|
-
id: `alterNullability.${desc.table}.${desc.column}`,
|
|
321
|
-
label: `Drop NOT NULL on "${desc.table}"."${desc.column}"`,
|
|
322
|
-
operationClass: 'widening',
|
|
323
|
-
target: targetDetails('column', desc.column, ctx.schemaName, desc.table),
|
|
324
|
-
precheck: [
|
|
325
|
-
step(
|
|
326
|
-
`ensure column "${desc.column}" exists`,
|
|
327
|
-
columnExistsCheck({ schema: ctx.schemaName, table: desc.table, column: desc.column }),
|
|
328
|
-
),
|
|
329
|
-
],
|
|
330
|
-
execute: [
|
|
331
|
-
step(
|
|
332
|
-
`drop NOT NULL on "${desc.column}"`,
|
|
333
|
-
`ALTER TABLE ${qualified} ALTER COLUMN ${quoteId(desc.column)} DROP NOT NULL`,
|
|
334
|
-
),
|
|
335
|
-
],
|
|
336
|
-
postcheck: [
|
|
337
|
-
step(
|
|
338
|
-
`verify column "${desc.column}" is nullable`,
|
|
339
|
-
columnNullabilityCheck({
|
|
340
|
-
schema: ctx.schemaName,
|
|
341
|
-
table: desc.table,
|
|
342
|
-
column: desc.column,
|
|
343
|
-
nullable: true,
|
|
344
|
-
}),
|
|
345
|
-
),
|
|
346
|
-
],
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function resolveSetDefault(desc: SetDefaultDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
351
|
-
const column = getColumn(ctx.toContract, desc.table, desc.column);
|
|
352
|
-
if (!column)
|
|
353
|
-
throw new Error(`Column "${desc.table}"."${desc.column}" not found in destination contract`);
|
|
354
|
-
const defaultSql = buildColumnDefaultSql(column.default, column);
|
|
355
|
-
if (!defaultSql)
|
|
356
|
-
throw new Error(
|
|
357
|
-
`Column "${desc.table}"."${desc.column}" has no default in destination contract`,
|
|
358
|
-
);
|
|
359
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
360
|
-
return {
|
|
361
|
-
id: `setDefault.${desc.table}.${desc.column}`,
|
|
362
|
-
label: `Set default on "${desc.table}"."${desc.column}"`,
|
|
363
|
-
operationClass: 'additive',
|
|
364
|
-
target: targetDetails('column', desc.column, ctx.schemaName, desc.table),
|
|
365
|
-
precheck: [
|
|
366
|
-
step(
|
|
367
|
-
`ensure column "${desc.column}" exists`,
|
|
368
|
-
columnExistsCheck({ schema: ctx.schemaName, table: desc.table, column: desc.column }),
|
|
369
|
-
),
|
|
370
|
-
],
|
|
371
|
-
execute: [
|
|
372
|
-
step(
|
|
373
|
-
`set default on "${desc.column}"`,
|
|
374
|
-
`ALTER TABLE ${qualified} ALTER COLUMN ${quoteId(desc.column)} ${defaultSql}`,
|
|
375
|
-
),
|
|
376
|
-
],
|
|
377
|
-
postcheck: [],
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function resolveDropDefault(
|
|
382
|
-
desc: DropDefaultDescriptor,
|
|
383
|
-
ctx: OperationResolverContext,
|
|
384
|
-
): ResolvedOp {
|
|
385
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
386
|
-
return {
|
|
387
|
-
id: `dropDefault.${desc.table}.${desc.column}`,
|
|
388
|
-
label: `Drop default on "${desc.table}"."${desc.column}"`,
|
|
389
|
-
operationClass: 'destructive',
|
|
390
|
-
target: targetDetails('column', desc.column, ctx.schemaName, desc.table),
|
|
391
|
-
precheck: [
|
|
392
|
-
step(
|
|
393
|
-
`ensure column "${desc.column}" exists`,
|
|
394
|
-
columnExistsCheck({ schema: ctx.schemaName, table: desc.table, column: desc.column }),
|
|
395
|
-
),
|
|
396
|
-
],
|
|
397
|
-
execute: [
|
|
398
|
-
step(
|
|
399
|
-
`drop default on "${desc.column}"`,
|
|
400
|
-
`ALTER TABLE ${qualified} ALTER COLUMN ${quoteId(desc.column)} DROP DEFAULT`,
|
|
401
|
-
),
|
|
402
|
-
],
|
|
403
|
-
postcheck: [],
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function resolveAddPrimaryKey(
|
|
408
|
-
desc: AddPrimaryKeyDescriptor,
|
|
409
|
-
ctx: OperationResolverContext,
|
|
410
|
-
): ResolvedOp {
|
|
411
|
-
const table = getTable(ctx.toContract, desc.table);
|
|
412
|
-
if (!table?.primaryKey)
|
|
413
|
-
throw new Error(`Table "${desc.table}" has no primary key in destination contract`);
|
|
414
|
-
const constraintName = table.primaryKey.name ?? `${desc.table}_pkey`;
|
|
415
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
416
|
-
const columnList = table.primaryKey.columns.map(quoteId).join(', ');
|
|
417
|
-
return {
|
|
418
|
-
id: `primaryKey.${desc.table}.${constraintName}`,
|
|
419
|
-
label: `Add primary key on "${desc.table}"`,
|
|
420
|
-
operationClass: 'additive',
|
|
421
|
-
target: targetDetails('primaryKey', constraintName, ctx.schemaName, desc.table),
|
|
422
|
-
precheck: [
|
|
423
|
-
step(
|
|
424
|
-
`ensure primary key "${constraintName}" does not exist`,
|
|
425
|
-
constraintExistsCheck({
|
|
426
|
-
constraintName,
|
|
427
|
-
schema: ctx.schemaName,
|
|
428
|
-
table: desc.table,
|
|
429
|
-
exists: false,
|
|
430
|
-
}),
|
|
431
|
-
),
|
|
432
|
-
],
|
|
433
|
-
execute: [
|
|
434
|
-
step(
|
|
435
|
-
`add primary key "${constraintName}"`,
|
|
436
|
-
`ALTER TABLE ${qualified} ADD CONSTRAINT ${quoteId(constraintName)} PRIMARY KEY (${columnList})`,
|
|
437
|
-
),
|
|
438
|
-
],
|
|
439
|
-
postcheck: [
|
|
440
|
-
step(
|
|
441
|
-
`verify primary key "${constraintName}" exists`,
|
|
442
|
-
constraintExistsCheck({ constraintName, schema: ctx.schemaName, table: desc.table }),
|
|
443
|
-
),
|
|
444
|
-
],
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function resolveAddUnique(desc: AddUniqueDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
449
|
-
const table = getTable(ctx.toContract, desc.table);
|
|
450
|
-
const unique = table?.uniques?.find((u) => u.columns.join(',') === desc.columns.join(','));
|
|
451
|
-
const constraintName = unique?.name ?? `${desc.table}_${desc.columns.join('_')}_key`;
|
|
452
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
453
|
-
const columnList = desc.columns.map(quoteId).join(', ');
|
|
454
|
-
return {
|
|
455
|
-
id: `unique.${desc.table}.${constraintName}`,
|
|
456
|
-
label: `Add unique constraint on "${desc.table}" (${desc.columns.join(', ')})`,
|
|
457
|
-
operationClass: 'additive',
|
|
458
|
-
target: targetDetails('unique', constraintName, ctx.schemaName, desc.table),
|
|
459
|
-
precheck: [
|
|
460
|
-
step(
|
|
461
|
-
`ensure constraint "${constraintName}" does not exist`,
|
|
462
|
-
constraintExistsCheck({
|
|
463
|
-
constraintName,
|
|
464
|
-
schema: ctx.schemaName,
|
|
465
|
-
table: desc.table,
|
|
466
|
-
exists: false,
|
|
467
|
-
}),
|
|
468
|
-
),
|
|
469
|
-
],
|
|
470
|
-
execute: [
|
|
471
|
-
step(
|
|
472
|
-
`add unique constraint "${constraintName}"`,
|
|
473
|
-
`ALTER TABLE ${qualified} ADD CONSTRAINT ${quoteId(constraintName)} UNIQUE (${columnList})`,
|
|
474
|
-
),
|
|
475
|
-
],
|
|
476
|
-
postcheck: [
|
|
477
|
-
step(
|
|
478
|
-
`verify constraint "${constraintName}" exists`,
|
|
479
|
-
constraintExistsCheck({ constraintName, schema: ctx.schemaName, table: desc.table }),
|
|
480
|
-
),
|
|
481
|
-
],
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function resolveAddForeignKey(
|
|
486
|
-
desc: AddForeignKeyDescriptor,
|
|
487
|
-
ctx: OperationResolverContext,
|
|
488
|
-
): ResolvedOp {
|
|
489
|
-
const table = getTable(ctx.toContract, desc.table);
|
|
490
|
-
const fk = table?.foreignKeys?.find((f) => f.columns.join(',') === desc.columns.join(','));
|
|
491
|
-
|
|
492
|
-
if (!fk) {
|
|
493
|
-
throw new Error(
|
|
494
|
-
`Foreign key on "${desc.table}" (${desc.columns.join(', ')}) not found in destination contract. ` +
|
|
495
|
-
'Ensure the FK is declared in the contract before authoring a migration that adds it.',
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const fkName = fk.name ?? `${desc.table}_${desc.columns.join('_')}_fkey`;
|
|
500
|
-
|
|
501
|
-
return {
|
|
502
|
-
id: `foreignKey.${desc.table}.${fkName}`,
|
|
503
|
-
label: `Add foreign key "${fkName}" on "${desc.table}"`,
|
|
504
|
-
operationClass: 'additive',
|
|
505
|
-
target: targetDetails('foreignKey', fkName, ctx.schemaName, desc.table),
|
|
506
|
-
precheck: [
|
|
507
|
-
step(
|
|
508
|
-
`ensure FK "${fkName}" does not exist`,
|
|
509
|
-
constraintExistsCheck({
|
|
510
|
-
constraintName: fkName,
|
|
511
|
-
schema: ctx.schemaName,
|
|
512
|
-
table: desc.table,
|
|
513
|
-
exists: false,
|
|
514
|
-
}),
|
|
515
|
-
),
|
|
516
|
-
],
|
|
517
|
-
execute: [
|
|
518
|
-
step(`add FK "${fkName}"`, buildForeignKeySql(ctx.schemaName, desc.table, fkName, fk)),
|
|
519
|
-
],
|
|
520
|
-
postcheck: [
|
|
521
|
-
step(
|
|
522
|
-
`verify FK "${fkName}" exists`,
|
|
523
|
-
constraintExistsCheck({
|
|
524
|
-
constraintName: fkName,
|
|
525
|
-
schema: ctx.schemaName,
|
|
526
|
-
table: desc.table,
|
|
527
|
-
}),
|
|
528
|
-
),
|
|
529
|
-
],
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
function resolveDropConstraint(
|
|
534
|
-
desc: DropConstraintDescriptor,
|
|
535
|
-
ctx: OperationResolverContext,
|
|
536
|
-
): ResolvedOp {
|
|
537
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
538
|
-
return {
|
|
539
|
-
id: `dropConstraint.${desc.table}.${desc.constraintName}`,
|
|
540
|
-
label: `Drop constraint "${desc.constraintName}" on "${desc.table}"`,
|
|
541
|
-
operationClass: 'destructive',
|
|
542
|
-
target: targetDetails('unique', desc.constraintName, ctx.schemaName, desc.table),
|
|
543
|
-
precheck: [
|
|
544
|
-
step(
|
|
545
|
-
`ensure constraint "${desc.constraintName}" exists`,
|
|
546
|
-
constraintExistsCheck({
|
|
547
|
-
constraintName: desc.constraintName,
|
|
548
|
-
schema: ctx.schemaName,
|
|
549
|
-
table: desc.table,
|
|
550
|
-
}),
|
|
551
|
-
),
|
|
552
|
-
],
|
|
553
|
-
execute: [
|
|
554
|
-
step(
|
|
555
|
-
`drop constraint "${desc.constraintName}"`,
|
|
556
|
-
`ALTER TABLE ${qualified} DROP CONSTRAINT ${quoteId(desc.constraintName)}`,
|
|
557
|
-
),
|
|
558
|
-
],
|
|
559
|
-
postcheck: [
|
|
560
|
-
step(
|
|
561
|
-
`verify constraint "${desc.constraintName}" does not exist`,
|
|
562
|
-
constraintExistsCheck({
|
|
563
|
-
constraintName: desc.constraintName,
|
|
564
|
-
schema: ctx.schemaName,
|
|
565
|
-
table: desc.table,
|
|
566
|
-
exists: false,
|
|
567
|
-
}),
|
|
568
|
-
),
|
|
569
|
-
],
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
function resolveCreateIndex(
|
|
574
|
-
desc: CreateIndexDescriptor,
|
|
575
|
-
ctx: OperationResolverContext,
|
|
576
|
-
): ResolvedOp {
|
|
577
|
-
const table = getTable(ctx.toContract, desc.table);
|
|
578
|
-
const index = table?.indexes?.find((i) => i.columns.join(',') === desc.columns.join(','));
|
|
579
|
-
const indexName = index?.name ?? `${desc.table}_${desc.columns.join('_')}_idx`;
|
|
580
|
-
const qualified = qualifyTableName(ctx.schemaName, desc.table);
|
|
581
|
-
const columnList = desc.columns.map(quoteId).join(', ');
|
|
582
|
-
return {
|
|
583
|
-
id: `index.${desc.table}.${indexName}`,
|
|
584
|
-
label: `Create index "${indexName}" on "${desc.table}"`,
|
|
585
|
-
operationClass: 'additive',
|
|
586
|
-
target: targetDetails('index', indexName, ctx.schemaName, desc.table),
|
|
587
|
-
precheck: [
|
|
588
|
-
step(
|
|
589
|
-
`ensure index "${indexName}" does not exist`,
|
|
590
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, indexName)}) IS NULL`,
|
|
591
|
-
),
|
|
592
|
-
],
|
|
593
|
-
execute: [
|
|
594
|
-
step(
|
|
595
|
-
`create index "${indexName}"`,
|
|
596
|
-
`CREATE INDEX ${quoteId(indexName)} ON ${qualified} (${columnList})`,
|
|
597
|
-
),
|
|
598
|
-
],
|
|
599
|
-
postcheck: [
|
|
600
|
-
step(
|
|
601
|
-
`verify index "${indexName}" exists`,
|
|
602
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, indexName)}) IS NOT NULL`,
|
|
603
|
-
),
|
|
604
|
-
],
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
function resolveDropIndex(desc: DropIndexDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
609
|
-
return {
|
|
610
|
-
id: `dropIndex.${desc.table}.${desc.indexName}`,
|
|
611
|
-
label: `Drop index "${desc.indexName}"`,
|
|
612
|
-
operationClass: 'destructive',
|
|
613
|
-
target: targetDetails('index', desc.indexName, ctx.schemaName, desc.table),
|
|
614
|
-
precheck: [
|
|
615
|
-
step(
|
|
616
|
-
`ensure index "${desc.indexName}" exists`,
|
|
617
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, desc.indexName)}) IS NOT NULL`,
|
|
618
|
-
),
|
|
619
|
-
],
|
|
620
|
-
execute: [
|
|
621
|
-
step(
|
|
622
|
-
`drop index "${desc.indexName}"`,
|
|
623
|
-
`DROP INDEX ${qualifyTableName(ctx.schemaName, desc.indexName)}`,
|
|
624
|
-
),
|
|
625
|
-
],
|
|
626
|
-
postcheck: [
|
|
627
|
-
step(
|
|
628
|
-
`verify index "${desc.indexName}" does not exist`,
|
|
629
|
-
`SELECT to_regclass(${toRegclassLiteral(ctx.schemaName, desc.indexName)}) IS NULL`,
|
|
630
|
-
),
|
|
631
|
-
],
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
function enumTypeExistsCheck(schemaName: string, nativeType: string, exists = true): string {
|
|
636
|
-
const clause = exists ? 'EXISTS' : 'NOT EXISTS';
|
|
637
|
-
return `SELECT ${clause} (
|
|
638
|
-
SELECT 1
|
|
639
|
-
FROM pg_type t
|
|
640
|
-
JOIN pg_namespace n ON t.typnamespace = n.oid
|
|
641
|
-
WHERE n.nspname = '${escapeLiteral(schemaName)}'
|
|
642
|
-
AND t.typname = '${escapeLiteral(nativeType)}'
|
|
643
|
-
)`;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
function resolveCreateEnumType(
|
|
647
|
-
desc: CreateEnumTypeDescriptor,
|
|
648
|
-
ctx: OperationResolverContext,
|
|
649
|
-
): ResolvedOp {
|
|
650
|
-
// When explicit values are provided (e.g., temp type in rebuild recipe), use them directly.
|
|
651
|
-
// The typeName may be a temp name not in the contract.
|
|
652
|
-
const nativeType = desc.typeName;
|
|
653
|
-
let values: readonly string[];
|
|
654
|
-
if (desc.values) {
|
|
655
|
-
values = desc.values;
|
|
656
|
-
} else {
|
|
657
|
-
const typeInstance = ctx.toContract.storage.types?.[desc.typeName];
|
|
658
|
-
if (!typeInstance) {
|
|
659
|
-
throw new Error(`Type "${desc.typeName}" not found in destination contract storage.types`);
|
|
660
|
-
}
|
|
661
|
-
const typeValues = typeInstance.typeParams?.['values'];
|
|
662
|
-
if (
|
|
663
|
-
!Array.isArray(typeValues) ||
|
|
664
|
-
!typeValues.every((v): v is string => typeof v === 'string')
|
|
665
|
-
) {
|
|
666
|
-
throw new Error(`Type "${desc.typeName}" has no valid enum values in typeParams`);
|
|
667
|
-
}
|
|
668
|
-
values = typeValues;
|
|
669
|
-
}
|
|
670
|
-
const qualifiedType = qualifyName(ctx.schemaName, nativeType);
|
|
671
|
-
const literalValues = values.map((v) => `'${escapeLiteral(v)}'`).join(', ');
|
|
672
|
-
return {
|
|
673
|
-
id: `type.${nativeType}`,
|
|
674
|
-
label: `Create enum type "${nativeType}"`,
|
|
675
|
-
operationClass: 'additive',
|
|
676
|
-
target: targetDetails('type', nativeType, ctx.schemaName),
|
|
677
|
-
precheck: [
|
|
678
|
-
step(
|
|
679
|
-
`ensure type "${nativeType}" does not exist`,
|
|
680
|
-
enumTypeExistsCheck(ctx.schemaName, nativeType, false),
|
|
681
|
-
),
|
|
682
|
-
],
|
|
683
|
-
execute: [
|
|
684
|
-
step(
|
|
685
|
-
`create enum type "${nativeType}"`,
|
|
686
|
-
`CREATE TYPE ${qualifiedType} AS ENUM (${literalValues})`,
|
|
687
|
-
),
|
|
688
|
-
],
|
|
689
|
-
postcheck: [
|
|
690
|
-
step(`verify type "${nativeType}" exists`, enumTypeExistsCheck(ctx.schemaName, nativeType)),
|
|
691
|
-
],
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
function resolveAddEnumValues(
|
|
696
|
-
desc: AddEnumValuesDescriptor,
|
|
697
|
-
ctx: OperationResolverContext,
|
|
698
|
-
): ResolvedOp {
|
|
699
|
-
const typeInstance = ctx.toContract.storage.types?.[desc.typeName];
|
|
700
|
-
if (!typeInstance) {
|
|
701
|
-
throw new Error(`Type "${desc.typeName}" not found in destination contract storage.types`);
|
|
702
|
-
}
|
|
703
|
-
const qualifiedType = qualifyName(ctx.schemaName, typeInstance.nativeType);
|
|
704
|
-
return {
|
|
705
|
-
id: `type.${desc.typeName}.addValues`,
|
|
706
|
-
label: `Add values to enum type "${desc.typeName}": ${desc.values.join(', ')}`,
|
|
707
|
-
operationClass: 'additive',
|
|
708
|
-
target: targetDetails('type', desc.typeName, ctx.schemaName),
|
|
709
|
-
precheck: [
|
|
710
|
-
step(
|
|
711
|
-
`ensure type "${typeInstance.nativeType}" exists`,
|
|
712
|
-
enumTypeExistsCheck(ctx.schemaName, typeInstance.nativeType),
|
|
713
|
-
),
|
|
714
|
-
],
|
|
715
|
-
execute: desc.values.map((value) =>
|
|
716
|
-
step(
|
|
717
|
-
`add value '${value}' to enum "${typeInstance.nativeType}"`,
|
|
718
|
-
`ALTER TYPE ${qualifiedType} ADD VALUE '${escapeLiteral(value)}'`,
|
|
719
|
-
),
|
|
720
|
-
),
|
|
721
|
-
postcheck: [
|
|
722
|
-
step(
|
|
723
|
-
`verify type "${typeInstance.nativeType}" exists`,
|
|
724
|
-
enumTypeExistsCheck(ctx.schemaName, typeInstance.nativeType),
|
|
725
|
-
),
|
|
726
|
-
],
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
function resolveDropEnumType(
|
|
731
|
-
desc: DropEnumTypeDescriptor,
|
|
732
|
-
ctx: OperationResolverContext,
|
|
733
|
-
): ResolvedOp {
|
|
734
|
-
const qualified = qualifyName(ctx.schemaName, desc.typeName);
|
|
735
|
-
return {
|
|
736
|
-
id: `type.${desc.typeName}.drop`,
|
|
737
|
-
label: `Drop enum type "${desc.typeName}"`,
|
|
738
|
-
operationClass: 'destructive',
|
|
739
|
-
target: targetDetails('type', desc.typeName, ctx.schemaName),
|
|
740
|
-
precheck: [
|
|
741
|
-
step(
|
|
742
|
-
`ensure type "${desc.typeName}" exists`,
|
|
743
|
-
enumTypeExistsCheck(ctx.schemaName, desc.typeName),
|
|
744
|
-
),
|
|
745
|
-
],
|
|
746
|
-
execute: [step(`drop enum type "${desc.typeName}"`, `DROP TYPE ${qualified}`)],
|
|
747
|
-
postcheck: [
|
|
748
|
-
step(
|
|
749
|
-
`verify type "${desc.typeName}" removed`,
|
|
750
|
-
enumTypeExistsCheck(ctx.schemaName, desc.typeName, false),
|
|
751
|
-
),
|
|
752
|
-
],
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
function resolveRenameType(desc: RenameTypeDescriptor, ctx: OperationResolverContext): ResolvedOp {
|
|
757
|
-
const qualifiedFrom = qualifyName(ctx.schemaName, desc.fromName);
|
|
758
|
-
return {
|
|
759
|
-
id: `type.${desc.fromName}.rename`,
|
|
760
|
-
label: `Rename type "${desc.fromName}" to "${desc.toName}"`,
|
|
761
|
-
operationClass: 'destructive',
|
|
762
|
-
target: targetDetails('type', desc.fromName, ctx.schemaName),
|
|
763
|
-
precheck: [
|
|
764
|
-
step(
|
|
765
|
-
`ensure type "${desc.fromName}" exists`,
|
|
766
|
-
enumTypeExistsCheck(ctx.schemaName, desc.fromName),
|
|
767
|
-
),
|
|
768
|
-
],
|
|
769
|
-
execute: [
|
|
770
|
-
step(
|
|
771
|
-
`rename type "${desc.fromName}" to "${desc.toName}"`,
|
|
772
|
-
`ALTER TYPE ${qualifiedFrom} RENAME TO ${quoteId(desc.toName)}`,
|
|
773
|
-
),
|
|
774
|
-
],
|
|
775
|
-
postcheck: [
|
|
776
|
-
step(`verify type "${desc.toName}" exists`, enumTypeExistsCheck(ctx.schemaName, desc.toName)),
|
|
777
|
-
],
|
|
778
|
-
};
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
function resolveCreateDependency(
|
|
782
|
-
desc: CreateDependencyDescriptor,
|
|
783
|
-
ctx: OperationResolverContext,
|
|
784
|
-
): readonly ResolvedOp[] {
|
|
785
|
-
const dep = ctx.dependencies?.find((d) => d.id === desc.dependencyId);
|
|
786
|
-
if (!dep) {
|
|
787
|
-
throw new Error(
|
|
788
|
-
`Dependency "${desc.dependencyId}" not found in resolver context. ` +
|
|
789
|
-
'Ensure frameworkComponents are passed to resolveDescriptors.',
|
|
790
|
-
);
|
|
791
|
-
}
|
|
792
|
-
return dep.install as readonly ResolvedOp[];
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
const postgresAdapter = createPostgresAdapter();
|
|
796
|
-
|
|
797
|
-
function lowerToSql(plan: SqlQueryPlan, contract: Contract<SqlStorage>): SerializedQueryPlan {
|
|
798
|
-
const lowered = lowerSqlPlan(postgresAdapter, contract, plan);
|
|
799
|
-
return { sql: lowered.sql, params: lowered.params };
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
function resolveBuildable(input: unknown, contract: Contract<SqlStorage>): SerializedQueryPlan {
|
|
803
|
-
if (
|
|
804
|
-
typeof input === 'object' &&
|
|
805
|
-
input !== null &&
|
|
806
|
-
'build' in input &&
|
|
807
|
-
typeof (input as { build: unknown }).build === 'function'
|
|
808
|
-
) {
|
|
809
|
-
return lowerToSql((input as { build(): unknown }).build() as SqlQueryPlan, contract);
|
|
810
|
-
}
|
|
811
|
-
return lowerToSql(input as SqlQueryPlan, contract);
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
/** Resolves a single QueryPlanInput to one or more lowered SQL statements. */
|
|
815
|
-
function resolvePlanInput(
|
|
816
|
-
input: symbol | object | ((...args: never[]) => unknown),
|
|
817
|
-
db: unknown,
|
|
818
|
-
contract: Contract<SqlStorage>,
|
|
819
|
-
): readonly SerializedQueryPlan[] {
|
|
820
|
-
if (typeof input === 'symbol') {
|
|
821
|
-
throw new Error(
|
|
822
|
-
'Data transform contains an unimplemented TODO placeholder. ' +
|
|
823
|
-
'Fill in the check/run queries in migration.ts before running verify.',
|
|
824
|
-
);
|
|
825
|
-
}
|
|
826
|
-
if (typeof input === 'function') {
|
|
827
|
-
const result = input(db as never);
|
|
828
|
-
if (Array.isArray(result)) {
|
|
829
|
-
return result.map((item) => resolveBuildable(item, contract));
|
|
830
|
-
}
|
|
831
|
-
return [resolveBuildable(result, contract)];
|
|
832
|
-
}
|
|
833
|
-
return [resolveBuildable(input, contract)];
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
function resolveCheck(
|
|
837
|
-
check: DataTransformDescriptor['check'],
|
|
838
|
-
db: unknown,
|
|
839
|
-
contract: Contract<SqlStorage>,
|
|
840
|
-
): SerializedQueryPlan | boolean | null {
|
|
841
|
-
if (typeof check === 'boolean') return check;
|
|
842
|
-
const resolved = resolvePlanInput(check, db, contract);
|
|
843
|
-
const first = resolved[0];
|
|
844
|
-
if (!first) return null;
|
|
845
|
-
return first;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
function resolveDataTransform(
|
|
849
|
-
desc: DataTransformDescriptor,
|
|
850
|
-
ctx: OperationResolverContext,
|
|
851
|
-
): DataTransformOperation {
|
|
852
|
-
const { db, toContract } = ctx;
|
|
853
|
-
return {
|
|
854
|
-
id: `data_migration.${desc.name}`,
|
|
855
|
-
label: `Data transform: ${desc.name}`,
|
|
856
|
-
operationClass: 'data',
|
|
857
|
-
name: desc.name,
|
|
858
|
-
source: desc.source,
|
|
859
|
-
check: resolveCheck(desc.check, db, toContract),
|
|
860
|
-
run: desc.run.flatMap((input) => resolvePlanInput(input, db, toContract)),
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
import {
|
|
865
|
-
escapeLiteral,
|
|
866
|
-
qualifyName,
|
|
867
|
-
quoteIdentifier as quoteId,
|
|
868
|
-
} from '@prisma-next/adapter-postgres/control';
|
|
869
|
-
|
|
870
|
-
/**
|
|
871
|
-
* Resolves an array of operation descriptors into SqlMigrationPlanOperation objects.
|
|
872
|
-
* Most descriptors resolve 1:1, but createType and createDependency may expand to multiple ops.
|
|
873
|
-
*/
|
|
874
|
-
export function resolveOperations(
|
|
875
|
-
descriptors: readonly PostgresMigrationOpDescriptor[],
|
|
876
|
-
context: OperationResolverContext,
|
|
877
|
-
): readonly (ResolvedOp | DataTransformOperation)[] {
|
|
878
|
-
return descriptors.flatMap((desc) => resolveOperation(desc, context));
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
function resolveOperation(
|
|
882
|
-
desc: PostgresMigrationOpDescriptor,
|
|
883
|
-
ctx: OperationResolverContext,
|
|
884
|
-
): readonly (ResolvedOp | DataTransformOperation)[] {
|
|
885
|
-
switch (desc.kind) {
|
|
886
|
-
case 'createTable':
|
|
887
|
-
return [resolveCreateTable(desc, ctx)];
|
|
888
|
-
case 'dropTable':
|
|
889
|
-
return [resolveDropTable(desc, ctx)];
|
|
890
|
-
case 'addColumn':
|
|
891
|
-
return [resolveAddColumn(desc, ctx)];
|
|
892
|
-
case 'dropColumn':
|
|
893
|
-
return [resolveDropColumn(desc, ctx)];
|
|
894
|
-
case 'alterColumnType':
|
|
895
|
-
return [resolveAlterColumnType(desc, ctx)];
|
|
896
|
-
case 'setNotNull':
|
|
897
|
-
return [resolveSetNotNull(desc, ctx)];
|
|
898
|
-
case 'dropNotNull':
|
|
899
|
-
return [resolveDropNotNull(desc, ctx)];
|
|
900
|
-
case 'setDefault':
|
|
901
|
-
return [resolveSetDefault(desc, ctx)];
|
|
902
|
-
case 'dropDefault':
|
|
903
|
-
return [resolveDropDefault(desc, ctx)];
|
|
904
|
-
case 'addPrimaryKey':
|
|
905
|
-
return [resolveAddPrimaryKey(desc, ctx)];
|
|
906
|
-
case 'addUnique':
|
|
907
|
-
return [resolveAddUnique(desc, ctx)];
|
|
908
|
-
case 'addForeignKey':
|
|
909
|
-
return [resolveAddForeignKey(desc, ctx)];
|
|
910
|
-
case 'dropConstraint':
|
|
911
|
-
return [resolveDropConstraint(desc, ctx)];
|
|
912
|
-
case 'createIndex':
|
|
913
|
-
return [resolveCreateIndex(desc, ctx)];
|
|
914
|
-
case 'dropIndex':
|
|
915
|
-
return [resolveDropIndex(desc, ctx)];
|
|
916
|
-
case 'createEnumType':
|
|
917
|
-
return [resolveCreateEnumType(desc, ctx)];
|
|
918
|
-
case 'addEnumValues':
|
|
919
|
-
return [resolveAddEnumValues(desc, ctx)];
|
|
920
|
-
case 'dropEnumType':
|
|
921
|
-
return [resolveDropEnumType(desc, ctx)];
|
|
922
|
-
case 'renameType':
|
|
923
|
-
return [resolveRenameType(desc, ctx)];
|
|
924
|
-
case 'createDependency':
|
|
925
|
-
return resolveCreateDependency(desc, ctx);
|
|
926
|
-
case 'dataTransform':
|
|
927
|
-
return [resolveDataTransform(desc, ctx)];
|
|
928
|
-
}
|
|
929
|
-
}
|