@prisma-next/target-postgres 0.13.0-dev.35 → 0.13.0-dev.37

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.
Files changed (81) hide show
  1. package/dist/contract-free.d.mts +147 -14
  2. package/dist/contract-free.d.mts.map +1 -1
  3. package/dist/contract-free.mjs +3 -16
  4. package/dist/contract-free.mjs.map +1 -1
  5. package/dist/control.mjs +2 -2
  6. package/dist/ddl-QDyOSeLc.mjs +251 -0
  7. package/dist/ddl-QDyOSeLc.mjs.map +1 -0
  8. package/dist/{issue-planner-9AVUEL74.mjs → issue-planner-CoI_0uM1.mjs} +8 -118
  9. package/dist/issue-planner-CoI_0uM1.mjs.map +1 -0
  10. package/dist/issue-planner.d.mts +1 -1
  11. package/dist/issue-planner.d.mts.map +1 -1
  12. package/dist/issue-planner.mjs +1 -1
  13. package/dist/migration.d.mts +4 -80
  14. package/dist/migration.d.mts.map +1 -1
  15. package/dist/migration.mjs +3 -3
  16. package/dist/{op-factory-call-CvDOetGa.mjs → op-factory-call-B1bXWtfa.mjs} +551 -241
  17. package/dist/op-factory-call-B1bXWtfa.mjs.map +1 -0
  18. package/dist/{op-factory-call-CdtMyrlU.d.mts → op-factory-call-DmQEc3XV.d.mts} +111 -20
  19. package/dist/op-factory-call-DmQEc3XV.d.mts.map +1 -0
  20. package/dist/op-factory-call.d.mts +1 -1
  21. package/dist/op-factory-call.mjs +1 -1
  22. package/dist/{planner-BZxjjT8T.mjs → planner-DS5XBhmi.mjs} +4 -4
  23. package/dist/{planner-BZxjjT8T.mjs.map → planner-DS5XBhmi.mjs.map} +1 -1
  24. package/dist/{planner-produced-postgres-migration-CkECqqTy.mjs → planner-produced-postgres-migration-DTwCCek_.mjs} +2 -2
  25. package/dist/{planner-produced-postgres-migration-CkECqqTy.mjs.map → planner-produced-postgres-migration-DTwCCek_.mjs.map} +1 -1
  26. package/dist/{planner-produced-postgres-migration-wLhnJMMA.d.mts → planner-produced-postgres-migration-QqHa2C2l.d.mts} +2 -2
  27. package/dist/{planner-produced-postgres-migration-wLhnJMMA.d.mts.map → planner-produced-postgres-migration-QqHa2C2l.d.mts.map} +1 -1
  28. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  29. package/dist/planner-produced-postgres-migration.mjs +1 -1
  30. package/dist/planner-sql-checks-jqUUGyQR.mjs +152 -0
  31. package/dist/planner-sql-checks-jqUUGyQR.mjs.map +1 -0
  32. package/dist/planner-sql-checks.d.mts +1 -47
  33. package/dist/planner-sql-checks.d.mts.map +1 -1
  34. package/dist/planner-sql-checks.mjs +2 -2
  35. package/dist/planner.d.mts +1 -1
  36. package/dist/planner.mjs +1 -1
  37. package/dist/{postgres-contract-serializer-sdg1B6Og.mjs → postgres-contract-serializer-E92REOFk.mjs} +2 -2
  38. package/dist/{postgres-contract-serializer-sdg1B6Og.mjs.map → postgres-contract-serializer-E92REOFk.mjs.map} +1 -1
  39. package/dist/postgres-migration-Y4YBJqkS.d.mts +181 -0
  40. package/dist/postgres-migration-Y4YBJqkS.d.mts.map +1 -0
  41. package/dist/postgres-migration-otiaw3Ru.mjs +145 -0
  42. package/dist/postgres-migration-otiaw3Ru.mjs.map +1 -0
  43. package/dist/{postgres-schema-CDaLWZwd.mjs → postgres-schema-COGZ1ark.mjs} +61 -8
  44. package/dist/postgres-schema-COGZ1ark.mjs.map +1 -0
  45. package/dist/runtime.mjs +1 -1
  46. package/dist/table-source-BvFo7gVs.d.mts +15 -0
  47. package/dist/table-source-BvFo7gVs.d.mts.map +1 -0
  48. package/dist/types.d.mts +26 -6
  49. package/dist/types.d.mts.map +1 -1
  50. package/dist/types.mjs +1 -1
  51. package/package.json +17 -17
  52. package/src/contract-free/checks.ts +363 -0
  53. package/src/core/migrations/op-factory-call.ts +417 -94
  54. package/src/core/migrations/operations/columns.ts +175 -140
  55. package/src/core/migrations/operations/constraints.ts +79 -108
  56. package/src/core/migrations/operations/dependencies.ts +16 -14
  57. package/src/core/migrations/operations/indexes.ts +31 -28
  58. package/src/core/migrations/operations/shared.ts +2 -2
  59. package/src/core/migrations/operations/tables.ts +13 -14
  60. package/src/core/migrations/planner-recipes.ts +42 -33
  61. package/src/core/migrations/planner-sql-checks.ts +1 -172
  62. package/src/core/migrations/planner-strategies.ts +25 -73
  63. package/src/core/migrations/postgres-migration.ts +272 -7
  64. package/src/core/postgres-schema.ts +47 -6
  65. package/src/exports/contract-free.ts +21 -0
  66. package/src/exports/migration.ts +1 -22
  67. package/src/exports/planner-sql-checks.ts +0 -7
  68. package/dist/ddl-DY2R_Yqz.mjs +0 -45
  69. package/dist/ddl-DY2R_Yqz.mjs.map +0 -1
  70. package/dist/issue-planner-9AVUEL74.mjs.map +0 -1
  71. package/dist/op-factory-call-CdtMyrlU.d.mts.map +0 -1
  72. package/dist/op-factory-call-CvDOetGa.mjs.map +0 -1
  73. package/dist/planner-sql-checks-Bj4G0_gO.mjs +0 -272
  74. package/dist/planner-sql-checks-Bj4G0_gO.mjs.map +0 -1
  75. package/dist/postgres-migration-DLXL0GBf.d.mts +0 -77
  76. package/dist/postgres-migration-DLXL0GBf.d.mts.map +0 -1
  77. package/dist/postgres-migration-DMnWjdni.mjs +0 -75
  78. package/dist/postgres-migration-DMnWjdni.mjs.map +0 -1
  79. package/dist/postgres-schema-CDaLWZwd.mjs.map +0 -1
  80. package/dist/shared-jcsbXxiW.d.mts +0 -25
  81. package/dist/shared-jcsbXxiW.d.mts.map +0 -1
@@ -1,8 +1,23 @@
1
+ import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
1
2
  import { REFERENTIAL_ACTION_SQL } from '@prisma-next/sql-contract/referential-action-sql';
3
+ import { constraintExistsAst } from '../../../contract-free/checks';
2
4
  import { escapeLiteral, quoteIdentifier } from '../../sql-utils';
3
- import { constraintExistsCheck, qualifyTableName } from '../planner-sql-checks';
5
+ import { qualifyTableName } from '../planner-sql-checks';
4
6
  import { type ForeignKeySpec, type Op, step, targetDetails } from './shared';
5
7
 
8
+ async function constraintCheckSteps(
9
+ lowerer: ExecuteRequestLowerer,
10
+ options: { constraintName: string; schema: string; table: string },
11
+ ): Promise<{
12
+ absent: { sql: string; params?: readonly unknown[] };
13
+ present: { sql: string; params?: readonly unknown[] };
14
+ }> {
15
+ const checks = constraintExistsAst(options);
16
+ const absent = await lowerer.lowerToExecuteRequest(checks.constraintAbsent());
17
+ const present = await lowerer.lowerToExecuteRequest(checks.constraintPresent());
18
+ return { absent, present };
19
+ }
20
+
6
21
  function renderForeignKeySql(schemaName: string, tableName: string, fk: ForeignKeySpec): string {
7
22
  let sql = `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
8
23
  ADD CONSTRAINT ${quoteIdentifier(fk.name)}
@@ -28,29 +43,27 @@ REFERENCES ${qualifyTableName(fk.references.schema, fk.references.table)} (${fk.
28
43
  return sql;
29
44
  }
30
45
 
31
- export function addPrimaryKey(
46
+ export async function addPrimaryKey(
32
47
  schemaName: string,
33
48
  tableName: string,
34
49
  constraintName: string,
35
50
  columns: readonly string[],
36
- ): Op {
51
+ lowerer: ExecuteRequestLowerer,
52
+ ): Promise<Op> {
37
53
  const qualified = qualifyTableName(schemaName, tableName);
38
54
  const columnList = columns.map(quoteIdentifier).join(', ');
55
+ const { absent, present } = await constraintCheckSteps(lowerer, {
56
+ constraintName,
57
+ schema: schemaName,
58
+ table: tableName,
59
+ });
39
60
  return {
40
61
  id: `primaryKey.${tableName}.${constraintName}`,
41
62
  label: `Add primary key on "${tableName}"`,
42
63
  operationClass: 'additive',
43
64
  target: targetDetails('primaryKey', constraintName, schemaName, tableName),
44
65
  precheck: [
45
- step(
46
- `ensure primary key "${constraintName}" does not exist`,
47
- constraintExistsCheck({
48
- constraintName,
49
- schema: schemaName,
50
- table: tableName,
51
- exists: false,
52
- }),
53
- ),
66
+ step(`ensure primary key "${constraintName}" does not exist`, absent.sql, absent.params),
54
67
  ],
55
68
  execute: [
56
69
  step(
@@ -58,38 +71,31 @@ export function addPrimaryKey(
58
71
  `ALTER TABLE ${qualified} ADD CONSTRAINT ${quoteIdentifier(constraintName)} PRIMARY KEY (${columnList})`,
59
72
  ),
60
73
  ],
61
- postcheck: [
62
- step(
63
- `verify primary key "${constraintName}" exists`,
64
- constraintExistsCheck({ constraintName, schema: schemaName, table: tableName }),
65
- ),
66
- ],
74
+ postcheck: [step(`verify primary key "${constraintName}" exists`, present.sql, present.params)],
67
75
  };
68
76
  }
69
77
 
70
- export function addUnique(
78
+ export async function addUnique(
71
79
  schemaName: string,
72
80
  tableName: string,
73
81
  constraintName: string,
74
82
  columns: readonly string[],
75
- ): Op {
83
+ lowerer: ExecuteRequestLowerer,
84
+ ): Promise<Op> {
76
85
  const qualified = qualifyTableName(schemaName, tableName);
77
86
  const columnList = columns.map(quoteIdentifier).join(', ');
87
+ const { absent, present } = await constraintCheckSteps(lowerer, {
88
+ constraintName,
89
+ schema: schemaName,
90
+ table: tableName,
91
+ });
78
92
  return {
79
93
  id: `unique.${tableName}.${constraintName}`,
80
94
  label: `Add unique constraint on "${tableName}" (${columns.join(', ')})`,
81
95
  operationClass: 'additive',
82
96
  target: targetDetails('unique', constraintName, schemaName, tableName),
83
97
  precheck: [
84
- step(
85
- `ensure constraint "${constraintName}" does not exist`,
86
- constraintExistsCheck({
87
- constraintName,
88
- schema: schemaName,
89
- table: tableName,
90
- exists: false,
91
- }),
92
- ),
98
+ step(`ensure constraint "${constraintName}" does not exist`, absent.sql, absent.params),
93
99
  ],
94
100
  execute: [
95
101
  step(
@@ -97,70 +103,54 @@ export function addUnique(
97
103
  `ALTER TABLE ${qualified} ADD CONSTRAINT ${quoteIdentifier(constraintName)} UNIQUE (${columnList})`,
98
104
  ),
99
105
  ],
100
- postcheck: [
101
- step(
102
- `verify constraint "${constraintName}" exists`,
103
- constraintExistsCheck({ constraintName, schema: schemaName, table: tableName }),
104
- ),
105
- ],
106
+ postcheck: [step(`verify constraint "${constraintName}" exists`, present.sql, present.params)],
106
107
  };
107
108
  }
108
109
 
109
- export function addForeignKey(schemaName: string, tableName: string, fk: ForeignKeySpec): Op {
110
+ export async function addForeignKey(
111
+ schemaName: string,
112
+ tableName: string,
113
+ fk: ForeignKeySpec,
114
+ lowerer: ExecuteRequestLowerer,
115
+ ): Promise<Op> {
116
+ const { absent, present } = await constraintCheckSteps(lowerer, {
117
+ constraintName: fk.name,
118
+ schema: schemaName,
119
+ table: tableName,
120
+ });
110
121
  return {
111
122
  id: `foreignKey.${tableName}.${fk.name}`,
112
123
  label: `Add foreign key "${fk.name}" on "${tableName}"`,
113
124
  operationClass: 'additive',
114
125
  target: targetDetails('foreignKey', fk.name, schemaName, tableName),
115
- precheck: [
116
- step(
117
- `ensure FK "${fk.name}" does not exist`,
118
- constraintExistsCheck({
119
- constraintName: fk.name,
120
- schema: schemaName,
121
- table: tableName,
122
- exists: false,
123
- }),
124
- ),
125
- ],
126
+ precheck: [step(`ensure FK "${fk.name}" does not exist`, absent.sql, absent.params)],
126
127
  execute: [step(`add FK "${fk.name}"`, renderForeignKeySql(schemaName, tableName, fk))],
127
- postcheck: [
128
- step(
129
- `verify FK "${fk.name}" exists`,
130
- constraintExistsCheck({
131
- constraintName: fk.name,
132
- schema: schemaName,
133
- table: tableName,
134
- }),
135
- ),
136
- ],
128
+ postcheck: [step(`verify FK "${fk.name}" exists`, present.sql, present.params)],
137
129
  };
138
130
  }
139
131
 
140
- export function addCheckConstraint(
132
+ export async function addCheckConstraint(
141
133
  schemaName: string,
142
134
  tableName: string,
143
135
  constraintName: string,
144
136
  column: string,
145
137
  values: readonly string[],
146
- ): Op {
138
+ lowerer: ExecuteRequestLowerer,
139
+ ): Promise<Op> {
147
140
  const qualified = qualifyTableName(schemaName, tableName);
148
141
  const valueList = values.map((v) => `'${escapeLiteral(v)}'`).join(', ');
142
+ const { absent, present } = await constraintCheckSteps(lowerer, {
143
+ constraintName,
144
+ schema: schemaName,
145
+ table: tableName,
146
+ });
149
147
  return {
150
148
  id: `checkConstraint.${tableName}.${constraintName}`,
151
149
  label: `Add check constraint "${constraintName}" on "${tableName}"."${column}"`,
152
150
  operationClass: 'additive',
153
151
  target: targetDetails('checkConstraint', constraintName, schemaName, tableName),
154
152
  precheck: [
155
- step(
156
- `ensure constraint "${constraintName}" does not exist`,
157
- constraintExistsCheck({
158
- constraintName,
159
- schema: schemaName,
160
- table: tableName,
161
- exists: false,
162
- }),
163
- ),
153
+ step(`ensure constraint "${constraintName}" does not exist`, absent.sql, absent.params),
164
154
  ],
165
155
  execute: [
166
156
  step(
@@ -168,32 +158,28 @@ export function addCheckConstraint(
168
158
  `ALTER TABLE ${qualified} ADD CONSTRAINT ${quoteIdentifier(constraintName)} CHECK (${quoteIdentifier(column)} IN (${valueList}))`,
169
159
  ),
170
160
  ],
171
- postcheck: [
172
- step(
173
- `verify constraint "${constraintName}" exists`,
174
- constraintExistsCheck({ constraintName, schema: schemaName, table: tableName }),
175
- ),
176
- ],
161
+ postcheck: [step(`verify constraint "${constraintName}" exists`, present.sql, present.params)],
177
162
  };
178
163
  }
179
164
 
180
- export function dropCheckConstraint(
165
+ export async function dropCheckConstraint(
181
166
  schemaName: string,
182
167
  tableName: string,
183
168
  constraintName: string,
184
- ): Op {
169
+ lowerer: ExecuteRequestLowerer,
170
+ ): Promise<Op> {
185
171
  const qualified = qualifyTableName(schemaName, tableName);
172
+ const { absent, present } = await constraintCheckSteps(lowerer, {
173
+ constraintName,
174
+ schema: schemaName,
175
+ table: tableName,
176
+ });
186
177
  return {
187
178
  id: `dropCheckConstraint.${tableName}.${constraintName}`,
188
179
  label: `Drop check constraint "${constraintName}" on "${tableName}"`,
189
180
  operationClass: 'destructive',
190
181
  target: targetDetails('checkConstraint', constraintName, schemaName, tableName),
191
- precheck: [
192
- step(
193
- `ensure constraint "${constraintName}" exists`,
194
- constraintExistsCheck({ constraintName, schema: schemaName, table: tableName }),
195
- ),
196
- ],
182
+ precheck: [step(`ensure constraint "${constraintName}" exists`, present.sql, present.params)],
197
183
  execute: [
198
184
  step(
199
185
  `drop check constraint "${constraintName}"`,
@@ -201,15 +187,7 @@ export function dropCheckConstraint(
201
187
  ),
202
188
  ],
203
189
  postcheck: [
204
- step(
205
- `verify constraint "${constraintName}" does not exist`,
206
- constraintExistsCheck({
207
- constraintName,
208
- schema: schemaName,
209
- table: tableName,
210
- exists: false,
211
- }),
212
- ),
190
+ step(`verify constraint "${constraintName}" does not exist`, absent.sql, absent.params),
213
191
  ],
214
192
  };
215
193
  }
@@ -221,24 +199,25 @@ export function dropCheckConstraint(
221
199
  * (`'foreignKey'`, `'primaryKey'`, or `'unique'`) based on the `SchemaIssue`
222
200
  * that produced the drop.
223
201
  */
224
- export function dropConstraint(
202
+ export async function dropConstraint(
225
203
  schemaName: string,
226
204
  tableName: string,
227
205
  constraintName: string,
206
+ lowerer: ExecuteRequestLowerer,
228
207
  kind: 'foreignKey' | 'unique' | 'primaryKey' = 'unique',
229
- ): Op {
208
+ ): Promise<Op> {
230
209
  const qualified = qualifyTableName(schemaName, tableName);
210
+ const { absent, present } = await constraintCheckSteps(lowerer, {
211
+ constraintName,
212
+ schema: schemaName,
213
+ table: tableName,
214
+ });
231
215
  return {
232
216
  id: `dropConstraint.${tableName}.${constraintName}`,
233
217
  label: `Drop constraint "${constraintName}" on "${tableName}"`,
234
218
  operationClass: 'destructive',
235
219
  target: targetDetails(kind, constraintName, schemaName, tableName),
236
- precheck: [
237
- step(
238
- `ensure constraint "${constraintName}" exists`,
239
- constraintExistsCheck({ constraintName, schema: schemaName, table: tableName }),
240
- ),
241
- ],
220
+ precheck: [step(`ensure constraint "${constraintName}" exists`, present.sql, present.params)],
242
221
  execute: [
243
222
  step(
244
223
  `drop constraint "${constraintName}"`,
@@ -246,15 +225,7 @@ export function dropConstraint(
246
225
  ),
247
226
  ],
248
227
  postcheck: [
249
- step(
250
- `verify constraint "${constraintName}" does not exist`,
251
- constraintExistsCheck({
252
- constraintName,
253
- schema: schemaName,
254
- table: tableName,
255
- exists: false,
256
- }),
257
- ),
228
+ step(`verify constraint "${constraintName}" does not exist`, absent.sql, absent.params),
258
229
  ],
259
230
  };
260
231
  }
@@ -1,3 +1,5 @@
1
+ import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
2
+ import { extensionExistsAst } from '../../../contract-free/checks';
1
3
  import { quoteIdentifier } from '../../sql-utils';
2
4
  import { type Op, step } from './shared';
3
5
 
@@ -32,14 +34,20 @@ export function createExtension(extensionName: string): Op {
32
34
  * use the bare {@link createExtension} for planner-emitted ops where the
33
35
  * caller already controls idempotency through the surrounding plan.
34
36
  */
35
- export function installExtension(options: {
36
- readonly extensionName: string;
37
- readonly invariantId: string;
38
- readonly id: string;
39
- readonly label?: string;
40
- }): Op {
37
+ export async function installExtension(
38
+ options: {
39
+ readonly extensionName: string;
40
+ readonly invariantId: string;
41
+ readonly id: string;
42
+ readonly label?: string;
43
+ },
44
+ lowerer: ExecuteRequestLowerer,
45
+ ): Promise<Op> {
41
46
  const { extensionName, invariantId, id } = options;
42
47
  const label = options.label ?? `Enable extension "${extensionName}"`;
48
+ const checks = extensionExistsAst(extensionName);
49
+ const absent = await lowerer.lowerToExecuteRequest(checks.extensionAbsent());
50
+ const present = await lowerer.lowerToExecuteRequest(checks.extensionPresent());
43
51
  return {
44
52
  id,
45
53
  label,
@@ -50,10 +58,7 @@ export function installExtension(options: {
50
58
  details: { schema: 'public', objectType: 'dependency', name: extensionName },
51
59
  },
52
60
  precheck: [
53
- step(
54
- `verify extension "${extensionName}" is not already enabled`,
55
- `SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${extensionName}')`,
56
- ),
61
+ step(`verify extension "${extensionName}" is not already enabled`, absent.sql, absent.params),
57
62
  ],
58
63
  execute: [
59
64
  step(
@@ -62,10 +67,7 @@ export function installExtension(options: {
62
67
  ),
63
68
  ],
64
69
  postcheck: [
65
- step(
66
- `confirm extension "${extensionName}" is enabled`,
67
- `SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${extensionName}')`,
68
- ),
70
+ step(`confirm extension "${extensionName}" is enabled`, present.sql, present.params),
69
71
  ],
70
72
  };
71
73
  }
@@ -1,7 +1,22 @@
1
+ import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
2
+ import { indexExistsAst } from '../../../contract-free/checks';
1
3
  import { escapeLiteral, quoteIdentifier } from '../../sql-utils';
2
- import { qualifyTableName, toRegclassLiteral } from '../planner-sql-checks';
4
+ import { qualifyTableName } from '../planner-sql-checks';
3
5
  import { type Op, step, targetDetails } from './shared';
4
6
 
7
+ type CheckStep = { sql: string; params?: readonly unknown[] };
8
+
9
+ async function indexExistsSteps(
10
+ lowerer: ExecuteRequestLowerer,
11
+ schemaName: string,
12
+ indexName: string,
13
+ ): Promise<{ present: CheckStep; absent: CheckStep }> {
14
+ const checks = indexExistsAst(schemaName, indexName);
15
+ const present = await lowerer.lowerToExecuteRequest(checks.indexPresent());
16
+ const absent = await lowerer.lowerToExecuteRequest(checks.indexAbsent());
17
+ return { present, absent };
18
+ }
19
+
5
20
  export interface CreateIndexExtras {
6
21
  readonly type?: string;
7
22
  readonly options?: Record<string, unknown>;
@@ -22,65 +37,53 @@ function renderIndexOptions(options: Record<string, unknown>): string {
22
37
  .join(', ');
23
38
  }
24
39
 
25
- export function createIndex(
40
+ export async function createIndex(
26
41
  schemaName: string,
27
42
  tableName: string,
28
43
  indexName: string,
29
44
  columns: readonly string[],
45
+ lowerer: ExecuteRequestLowerer,
30
46
  extras?: CreateIndexExtras,
31
- ): Op {
47
+ ): Promise<Op> {
32
48
  const qualified = qualifyTableName(schemaName, tableName);
33
49
  const columnList = columns.map(quoteIdentifier).join(', ');
34
50
  const using = extras?.type ? ` USING ${quoteIdentifier(extras.type)}` : '';
35
51
  const options = extras?.options;
36
52
  const withClause =
37
53
  options && Object.keys(options).length > 0 ? ` WITH (${renderIndexOptions(options)})` : '';
54
+ const { present, absent } = await indexExistsSteps(lowerer, schemaName, indexName);
38
55
  return {
39
56
  id: `index.${tableName}.${indexName}`,
40
57
  label: `Create index "${indexName}" on "${tableName}"`,
41
58
  operationClass: 'additive',
42
59
  target: targetDetails('index', indexName, schemaName, tableName),
43
- precheck: [
44
- step(
45
- `ensure index "${indexName}" does not exist`,
46
- `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NULL`,
47
- ),
48
- ],
60
+ precheck: [step(`ensure index "${indexName}" does not exist`, absent.sql, absent.params)],
49
61
  execute: [
50
62
  step(
51
63
  `create index "${indexName}"`,
52
64
  `CREATE INDEX ${quoteIdentifier(indexName)} ON ${qualified}${using} (${columnList})${withClause}`,
53
65
  ),
54
66
  ],
55
- postcheck: [
56
- step(
57
- `verify index "${indexName}" exists`,
58
- `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NOT NULL`,
59
- ),
60
- ],
67
+ postcheck: [step(`verify index "${indexName}" exists`, present.sql, present.params)],
61
68
  };
62
69
  }
63
70
 
64
- export function dropIndex(schemaName: string, tableName: string, indexName: string): Op {
71
+ export async function dropIndex(
72
+ schemaName: string,
73
+ tableName: string,
74
+ indexName: string,
75
+ lowerer: ExecuteRequestLowerer,
76
+ ): Promise<Op> {
77
+ const { present, absent } = await indexExistsSteps(lowerer, schemaName, indexName);
65
78
  return {
66
79
  id: `dropIndex.${tableName}.${indexName}`,
67
80
  label: `Drop index "${indexName}"`,
68
81
  operationClass: 'destructive',
69
82
  target: targetDetails('index', indexName, schemaName, tableName),
70
- precheck: [
71
- step(
72
- `ensure index "${indexName}" exists`,
73
- `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NOT NULL`,
74
- ),
75
- ],
83
+ precheck: [step(`ensure index "${indexName}" exists`, present.sql, present.params)],
76
84
  execute: [
77
85
  step(`drop index "${indexName}"`, `DROP INDEX ${qualifyTableName(schemaName, indexName)}`),
78
86
  ],
79
- postcheck: [
80
- step(
81
- `verify index "${indexName}" does not exist`,
82
- `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NULL`,
83
- ),
84
- ],
87
+ postcheck: [step(`verify index "${indexName}" does not exist`, absent.sql, absent.params)],
85
88
  };
86
89
  }
@@ -42,8 +42,8 @@ export interface ForeignKeySpec {
42
42
  readonly onUpdate?: ReferentialAction;
43
43
  }
44
44
 
45
- export function step(description: string, sql: string) {
46
- return { description, sql };
45
+ export function step(description: string, sql: string, params?: readonly unknown[]) {
46
+ return { description, sql, ...ifDefined('params', params) };
47
47
  }
48
48
 
49
49
  export function targetDetails(
@@ -1,25 +1,24 @@
1
- import { qualifyTableName, toRegclassLiteral } from '../planner-sql-checks';
1
+ import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
2
+ import { tableExistsAst } from '../../../contract-free/checks';
3
+ import { qualifyTableName } from '../planner-sql-checks';
2
4
  import { type Op, step, targetDetails } from './shared';
3
5
 
4
- export function dropTable(schemaName: string, tableName: string): Op {
6
+ export async function dropTable(
7
+ schemaName: string,
8
+ tableName: string,
9
+ lowerer: ExecuteRequestLowerer,
10
+ ): Promise<Op> {
5
11
  const qualified = qualifyTableName(schemaName, tableName);
12
+ const checks = tableExistsAst(schemaName, tableName);
13
+ const present = await lowerer.lowerToExecuteRequest(checks.tablePresent());
14
+ const absent = await lowerer.lowerToExecuteRequest(checks.tableAbsent());
6
15
  return {
7
16
  id: `dropTable.${tableName}`,
8
17
  label: `Drop table "${tableName}"`,
9
18
  operationClass: 'destructive',
10
19
  target: targetDetails('table', tableName, schemaName),
11
- precheck: [
12
- step(
13
- `ensure table "${tableName}" exists`,
14
- `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NOT NULL`,
15
- ),
16
- ],
20
+ precheck: [step(`ensure table "${tableName}" exists`, present.sql, present.params)],
17
21
  execute: [step(`drop table "${tableName}"`, `DROP TABLE ${qualified}`)],
18
- postcheck: [
19
- step(
20
- `verify table "${tableName}" does not exist`,
21
- `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NULL`,
22
- ),
23
- ],
22
+ postcheck: [step(`verify table "${tableName}" does not exist`, absent.sql, absent.params)],
24
23
  };
25
24
  }
@@ -1,13 +1,15 @@
1
1
  import type { CodecControlHooks, SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
2
+ import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
2
3
  import type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';
4
+ import {
5
+ columnDefaultAst,
6
+ columnExistsAst,
7
+ columnNullabilityAst,
8
+ } from '../../contract-free/checks';
3
9
  import { quoteIdentifier } from '../sql-utils';
10
+ import { step } from './operations/shared';
4
11
  import { buildAddColumnSql } from './planner-ddl-builders';
5
- import {
6
- columnExistsCheck,
7
- columnHasNoDefaultCheck,
8
- columnNullabilityCheck,
9
- qualifyTableName,
10
- } from './planner-sql-checks';
12
+ import { qualifyTableName } from './planner-sql-checks';
11
13
  import { buildTargetDetails, type PostgresPlanTargetDetails } from './planner-target-details';
12
14
 
13
15
  export function buildAddColumnOperationIdentity(
@@ -29,7 +31,7 @@ export function buildAddColumnOperationIdentity(
29
31
  };
30
32
  }
31
33
 
32
- export function buildAddNotNullColumnWithTemporaryDefaultOperation(options: {
34
+ export async function buildAddNotNullColumnWithTemporaryDefaultOperation(options: {
33
35
  readonly schema: string;
34
36
  readonly tableName: string;
35
37
  readonly columnName: string;
@@ -37,20 +39,37 @@ export function buildAddNotNullColumnWithTemporaryDefaultOperation(options: {
37
39
  readonly codecHooks: Map<string, CodecControlHooks>;
38
40
  readonly storageTypes: Record<string, StorageTypeInstance>;
39
41
  readonly temporaryDefault: string;
40
- }): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
41
- const { schema, tableName, columnName, column, codecHooks, storageTypes, temporaryDefault } =
42
- options;
42
+ readonly lowerer: ExecuteRequestLowerer;
43
+ }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
44
+ const {
45
+ schema,
46
+ tableName,
47
+ columnName,
48
+ column,
49
+ codecHooks,
50
+ storageTypes,
51
+ temporaryDefault,
52
+ lowerer,
53
+ } = options;
43
54
  const qualified = qualifyTableName(schema, tableName);
44
55
 
56
+ const absent = await lowerer.lowerToExecuteRequest(
57
+ columnExistsAst({ schema, table: tableName, column: columnName }).columnAbsent(),
58
+ );
59
+ const present = await lowerer.lowerToExecuteRequest(
60
+ columnExistsAst({ schema, table: tableName, column: columnName }).columnPresent(),
61
+ );
62
+ const notNullable = await lowerer.lowerToExecuteRequest(
63
+ columnNullabilityAst({ schema, table: tableName, column: columnName, nullable: false }),
64
+ );
65
+ const noDefault = await lowerer.lowerToExecuteRequest(
66
+ columnDefaultAst({ schema, table: tableName, column: columnName }).noDefault(),
67
+ );
68
+
45
69
  return {
46
70
  ...buildAddColumnOperationIdentity(schema, tableName, columnName),
47
71
  operationClass: 'additive',
48
- precheck: [
49
- {
50
- description: `ensure column "${columnName}" is missing`,
51
- sql: columnExistsCheck({ schema, table: tableName, column: columnName, exists: false }),
52
- },
53
- ],
72
+ precheck: [step(`ensure column "${columnName}" is missing`, absent.sql, absent.params)],
54
73
  execute: [
55
74
  {
56
75
  description: `add column "${columnName}"`,
@@ -69,23 +88,13 @@ export function buildAddNotNullColumnWithTemporaryDefaultOperation(options: {
69
88
  },
70
89
  ],
71
90
  postcheck: [
72
- {
73
- description: `verify column "${columnName}" exists`,
74
- sql: columnExistsCheck({ schema, table: tableName, column: columnName }),
75
- },
76
- {
77
- description: `verify column "${columnName}" is NOT NULL`,
78
- sql: columnNullabilityCheck({
79
- schema,
80
- table: tableName,
81
- column: columnName,
82
- nullable: false,
83
- }),
84
- },
85
- {
86
- description: `verify column "${columnName}" has no default after temporary default removal`,
87
- sql: columnHasNoDefaultCheck({ schema, table: tableName, column: columnName }),
88
- },
91
+ step(`verify column "${columnName}" exists`, present.sql, present.params),
92
+ step(`verify column "${columnName}" is NOT NULL`, notNullable.sql, notNullable.params),
93
+ step(
94
+ `verify column "${columnName}" has no default after temporary default removal`,
95
+ noDefault.sql,
96
+ noDefault.params,
97
+ ),
89
98
  ],
90
99
  };
91
100
  }