@prisma-next/target-postgres 0.13.0 → 0.14.0-dev.2

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 (190) hide show
  1. package/dist/{codec-ids-CTikp1if.mjs → codec-ids-BvytN2P8.mjs} +3 -3
  2. package/dist/codec-ids-BvytN2P8.mjs.map +1 -0
  3. package/dist/{codec-ids-B1vOchLE.d.mts → codec-ids-CnXu9Qy3.d.mts} +3 -3
  4. package/dist/codec-ids-CnXu9Qy3.d.mts.map +1 -0
  5. package/dist/codec-ids.d.mts +2 -2
  6. package/dist/codec-ids.mjs +2 -2
  7. package/dist/{codec-types-CnFiNML4.d.mts → codec-types-DHCkwPKE.d.mts} +3 -3
  8. package/dist/{codec-types-CnFiNML4.d.mts.map → codec-types-DHCkwPKE.d.mts.map} +1 -1
  9. package/dist/codec-types.d.mts +1 -1
  10. package/dist/{codecs-CBpEv4s5.d.mts → codecs--0A5_4Bq.d.mts} +26 -23
  11. package/dist/codecs--0A5_4Bq.d.mts.map +1 -0
  12. package/dist/codecs.d.mts +2 -2
  13. package/dist/codecs.mjs +28 -35
  14. package/dist/codecs.mjs.map +1 -1
  15. package/dist/contract-free.d.mts +163 -15
  16. package/dist/contract-free.d.mts.map +1 -1
  17. package/dist/contract-free.mjs +4 -17
  18. package/dist/contract-free.mjs.map +1 -1
  19. package/dist/control.d.mts.map +1 -1
  20. package/dist/control.mjs +21 -27
  21. package/dist/control.mjs.map +1 -1
  22. package/dist/{data-transform-D25tLeYU.mjs → data-transform-BOWpliq8.mjs} +9 -17
  23. package/dist/data-transform-BOWpliq8.mjs.map +1 -0
  24. package/dist/{data-transform-DGOqcLrf.d.mts → data-transform-DDgWdB5o.d.mts} +2 -2
  25. package/dist/data-transform-DDgWdB5o.d.mts.map +1 -0
  26. package/dist/data-transform.d.mts +1 -1
  27. package/dist/data-transform.mjs +1 -1
  28. package/dist/ddl-QDyOSeLc.mjs +251 -0
  29. package/dist/ddl-QDyOSeLc.mjs.map +1 -0
  30. package/dist/ddl.d.mts +2 -2
  31. package/dist/ddl.mjs +2 -2
  32. package/dist/descriptor-meta-CpGygXpI.mjs +140 -0
  33. package/dist/descriptor-meta-CpGygXpI.mjs.map +1 -0
  34. package/dist/{issue-planner-Br0pt1Ea.mjs → issue-planner-DL6g3CmE.mjs} +52 -366
  35. package/dist/issue-planner-DL6g3CmE.mjs.map +1 -0
  36. package/dist/issue-planner.d.mts +8 -11
  37. package/dist/issue-planner.d.mts.map +1 -1
  38. package/dist/issue-planner.mjs +1 -1
  39. package/dist/migration.d.mts +5 -92
  40. package/dist/migration.d.mts.map +1 -1
  41. package/dist/migration.mjs +4 -4
  42. package/dist/{nodes-DZk2JZG3.mjs → nodes-Bbhs2rwj.mjs} +31 -2
  43. package/dist/nodes-Bbhs2rwj.mjs.map +1 -0
  44. package/dist/{nodes-779hmCfL.d.mts → nodes-pLeLgdis.d.mts} +30 -3
  45. package/dist/nodes-pLeLgdis.d.mts.map +1 -0
  46. package/dist/{op-factory-call-D2aAUhmS.mjs → op-factory-call-D_p5vxwt.mjs} +601 -418
  47. package/dist/op-factory-call-D_p5vxwt.mjs.map +1 -0
  48. package/dist/{op-factory-call-DMA86_2D.d.mts → op-factory-call-DmQEc3XV.d.mts} +119 -72
  49. package/dist/op-factory-call-DmQEc3XV.d.mts.map +1 -0
  50. package/dist/op-factory-call.d.mts +2 -2
  51. package/dist/op-factory-call.mjs +2 -2
  52. package/dist/pack.d.mts +36 -15
  53. package/dist/pack.d.mts.map +1 -1
  54. package/dist/pack.mjs +1 -1
  55. package/dist/{planner-CAYPJObw.mjs → planner-Bs_baQax.mjs} +25 -45
  56. package/dist/planner-Bs_baQax.mjs.map +1 -0
  57. package/dist/{planner-ddl-builders-Cw2n2llW.mjs → planner-ddl-builders-B2wOwLqI.mjs} +2 -2
  58. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +1 -0
  59. package/dist/planner-ddl-builders.d.mts +4 -4
  60. package/dist/planner-ddl-builders.d.mts.map +1 -1
  61. package/dist/planner-ddl-builders.mjs +1 -1
  62. package/dist/{planner-identity-values-BIpa5p2I.mjs → planner-identity-values-CJPha2Sz.mjs} +3 -9
  63. package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -0
  64. package/dist/planner-identity-values.d.mts +1 -1
  65. package/dist/planner-identity-values.d.mts.map +1 -1
  66. package/dist/planner-identity-values.mjs +1 -1
  67. package/dist/{planner-produced-postgres-migration-NSEhWL0L.mjs → planner-produced-postgres-migration-Cji5vxUf.mjs} +6 -4
  68. package/dist/planner-produced-postgres-migration-Cji5vxUf.mjs.map +1 -0
  69. package/dist/{planner-produced-postgres-migration-B4EDvLdz.d.mts → planner-produced-postgres-migration-QqHa2C2l.d.mts} +5 -6
  70. package/dist/planner-produced-postgres-migration-QqHa2C2l.d.mts.map +1 -0
  71. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  72. package/dist/planner-produced-postgres-migration.mjs +1 -1
  73. package/dist/planner-sql-checks-jqUUGyQR.mjs +152 -0
  74. package/dist/planner-sql-checks-jqUUGyQR.mjs.map +1 -0
  75. package/dist/planner-sql-checks.d.mts +3 -49
  76. package/dist/planner-sql-checks.d.mts.map +1 -1
  77. package/dist/planner-sql-checks.mjs +2 -2
  78. package/dist/{planner-type-resolution-836DExFN.mjs → planner-type-resolution-Bt2f_q-F.mjs} +1 -6
  79. package/dist/planner-type-resolution-Bt2f_q-F.mjs.map +1 -0
  80. package/dist/planner.d.mts +4 -4
  81. package/dist/planner.d.mts.map +1 -1
  82. package/dist/planner.mjs +1 -1
  83. package/dist/{postgres-contract-serializer-DYTyXjPf.mjs → postgres-contract-serializer-k3TAcPMY.mjs} +30 -37
  84. package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +1 -0
  85. package/dist/postgres-migration-B5jKrXv3.mjs +145 -0
  86. package/dist/postgres-migration-B5jKrXv3.mjs.map +1 -0
  87. package/dist/postgres-migration-Y4YBJqkS.d.mts +181 -0
  88. package/dist/postgres-migration-Y4YBJqkS.d.mts.map +1 -0
  89. package/dist/{postgres-schema-BuxCxbvB.mjs → postgres-schema-COGZ1ark.mjs} +82 -23
  90. package/dist/postgres-schema-COGZ1ark.mjs.map +1 -0
  91. package/dist/{render-ops-BpjstrKQ.mjs → render-ops-BREh1kHe.mjs} +10 -5
  92. package/dist/render-ops-BREh1kHe.mjs.map +1 -0
  93. package/dist/render-ops.d.mts +2 -2
  94. package/dist/render-ops.d.mts.map +1 -1
  95. package/dist/render-ops.mjs +1 -1
  96. package/dist/runtime.d.mts +1 -0
  97. package/dist/runtime.d.mts.map +1 -1
  98. package/dist/runtime.mjs +2 -2
  99. package/dist/table-source-BvFo7gVs.d.mts +15 -0
  100. package/dist/table-source-BvFo7gVs.d.mts.map +1 -0
  101. package/dist/types.d.mts +34 -19
  102. package/dist/types.d.mts.map +1 -1
  103. package/dist/types.mjs +2 -3
  104. package/package.json +17 -18
  105. package/src/contract-free/checks.ts +363 -0
  106. package/src/contract-free/ddl.ts +28 -1
  107. package/src/core/authoring.ts +43 -44
  108. package/src/core/codec-helpers.ts +0 -17
  109. package/src/core/codec-ids.ts +1 -1
  110. package/src/core/codec-type-map.ts +2 -2
  111. package/src/core/codecs.ts +43 -48
  112. package/src/core/ddl/nodes.ts +59 -1
  113. package/src/core/migrations/control-policy.ts +17 -47
  114. package/src/core/migrations/issue-planner.ts +34 -70
  115. package/src/core/migrations/op-factory-call.ts +486 -215
  116. package/src/core/migrations/operations/columns.ts +175 -140
  117. package/src/core/migrations/operations/constraints.ts +79 -108
  118. package/src/core/migrations/operations/data-transform.ts +15 -18
  119. package/src/core/migrations/operations/dependencies.ts +16 -14
  120. package/src/core/migrations/operations/indexes.ts +31 -28
  121. package/src/core/migrations/operations/shared.ts +2 -2
  122. package/src/core/migrations/operations/tables.ts +13 -14
  123. package/src/core/migrations/planner-ddl-builders.ts +3 -4
  124. package/src/core/migrations/planner-identity-values.ts +4 -28
  125. package/src/core/migrations/planner-produced-postgres-migration.ts +15 -7
  126. package/src/core/migrations/planner-recipes.ts +44 -39
  127. package/src/core/migrations/planner-sql-checks.ts +3 -178
  128. package/src/core/migrations/planner-strategies.ts +76 -449
  129. package/src/core/migrations/planner-type-resolution.ts +2 -20
  130. package/src/core/migrations/planner.ts +6 -6
  131. package/src/core/migrations/postgres-migration.ts +287 -7
  132. package/src/core/migrations/render-ops.ts +26 -13
  133. package/src/core/migrations/runner.ts +26 -20
  134. package/src/core/postgres-contract-serializer.ts +37 -54
  135. package/src/core/postgres-enum-type-schema.ts +17 -0
  136. package/src/core/postgres-schema.ts +86 -46
  137. package/src/exports/codecs.ts +2 -2
  138. package/src/exports/contract-free.ts +22 -1
  139. package/src/exports/control.ts +0 -22
  140. package/src/exports/ddl.ts +4 -0
  141. package/src/exports/migration.ts +1 -29
  142. package/src/exports/op-factory-call.ts +0 -4
  143. package/src/exports/planner-sql-checks.ts +0 -7
  144. package/src/exports/types.ts +0 -1
  145. package/dist/codec-ids-B1vOchLE.d.mts.map +0 -1
  146. package/dist/codec-ids-CTikp1if.mjs.map +0 -1
  147. package/dist/codecs-CBpEv4s5.d.mts.map +0 -1
  148. package/dist/data-transform-D25tLeYU.mjs.map +0 -1
  149. package/dist/data-transform-DGOqcLrf.d.mts.map +0 -1
  150. package/dist/ddl-77SyXgFt.mjs +0 -30
  151. package/dist/ddl-77SyXgFt.mjs.map +0 -1
  152. package/dist/descriptor-meta-DKmj-IMN.mjs +0 -14
  153. package/dist/descriptor-meta-DKmj-IMN.mjs.map +0 -1
  154. package/dist/descriptor-meta-runtime-My8_s4cs.mjs +0 -130
  155. package/dist/descriptor-meta-runtime-My8_s4cs.mjs.map +0 -1
  156. package/dist/enum-planning-BCyvlFHk.mjs +0 -0
  157. package/dist/enum-planning-BCyvlFHk.mjs.map +0 -1
  158. package/dist/enum-planning.d.mts +0 -86
  159. package/dist/enum-planning.d.mts.map +0 -1
  160. package/dist/enum-planning.mjs +0 -2
  161. package/dist/issue-planner-Br0pt1Ea.mjs.map +0 -1
  162. package/dist/nodes-779hmCfL.d.mts.map +0 -1
  163. package/dist/nodes-DZk2JZG3.mjs.map +0 -1
  164. package/dist/op-factory-call-D2aAUhmS.mjs.map +0 -1
  165. package/dist/op-factory-call-DMA86_2D.d.mts.map +0 -1
  166. package/dist/planner-CAYPJObw.mjs.map +0 -1
  167. package/dist/planner-ddl-builders-Cw2n2llW.mjs.map +0 -1
  168. package/dist/planner-identity-values-BIpa5p2I.mjs.map +0 -1
  169. package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +0 -1
  170. package/dist/planner-produced-postgres-migration-NSEhWL0L.mjs.map +0 -1
  171. package/dist/planner-sql-checks-DAdhnI2c.mjs +0 -272
  172. package/dist/planner-sql-checks-DAdhnI2c.mjs.map +0 -1
  173. package/dist/planner-type-resolution-836DExFN.mjs.map +0 -1
  174. package/dist/postgres-contract-serializer-DYTyXjPf.mjs.map +0 -1
  175. package/dist/postgres-enum-type-BVn63a89.d.mts +0 -72
  176. package/dist/postgres-enum-type-BVn63a89.d.mts.map +0 -1
  177. package/dist/postgres-enum-type-DPKqCBem.mjs +0 -62
  178. package/dist/postgres-enum-type-DPKqCBem.mjs.map +0 -1
  179. package/dist/postgres-migration-COore9Mz.mjs +0 -71
  180. package/dist/postgres-migration-COore9Mz.mjs.map +0 -1
  181. package/dist/postgres-migration-DZ_gLUOW.d.mts +0 -72
  182. package/dist/postgres-migration-DZ_gLUOW.d.mts.map +0 -1
  183. package/dist/postgres-schema-BuxCxbvB.mjs.map +0 -1
  184. package/dist/render-ops-BpjstrKQ.mjs.map +0 -1
  185. package/dist/shared-DarONYBZ.d.mts +0 -43
  186. package/dist/shared-DarONYBZ.d.mts.map +0 -1
  187. package/src/core/migrations/enum-planning.ts +0 -213
  188. package/src/core/migrations/operations/enums.ts +0 -114
  189. package/src/core/postgres-enum-type.ts +0 -89
  190. package/src/exports/enum-planning.ts +0 -11
@@ -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
  }
@@ -61,8 +61,8 @@ import type {
61
61
  SqlMigrationPlanOperationStep,
62
62
  } from '@prisma-next/family-sql/control';
63
63
  import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
64
- import type { SerializedQueryPlan } from '@prisma-next/framework-components/control';
65
64
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
65
+ import type { SqlExecuteRequest } from '@prisma-next/sql-relational-core/ast';
66
66
  import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
67
67
  import { ifDefined } from '@prisma-next/utils/defined';
68
68
  import type { PostgresPlanTargetDetails } from '../planner-target-details';
@@ -96,25 +96,29 @@ export interface DataTransformOptions {
96
96
  readonly run: DataTransformClosure | readonly DataTransformClosure[];
97
97
  }
98
98
 
99
- export function dataTransform<TContract extends Contract<SqlStorage>>(
99
+ export async function dataTransform<TContract extends Contract<SqlStorage>>(
100
100
  contract: TContract,
101
101
  name: string,
102
102
  options: DataTransformOptions,
103
103
  adapter: SqlControlAdapter<'postgres'>,
104
- ): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
104
+ ): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
105
105
  const runClosures: readonly DataTransformClosure[] = Array.isArray(options.run)
106
106
  ? options.run
107
107
  : [options.run as DataTransformClosure];
108
108
 
109
- const checkPlan = options.check ? invokeAndLower(options.check, contract, adapter, name) : null;
110
- const runPlans = runClosures.map((closure) => invokeAndLower(closure, contract, adapter, name));
109
+ const checkPlan = options.check
110
+ ? await invokeAndLower(options.check, contract, adapter, name)
111
+ : null;
112
+ const runPlans = await Promise.all(
113
+ runClosures.map((closure) => invokeAndLower(closure, contract, adapter, name)),
114
+ );
111
115
 
112
116
  const precheck: readonly SqlMigrationPlanOperationStep[] = checkPlan
113
117
  ? [
114
118
  {
115
119
  description: `Check ${name} has work to do`,
116
120
  sql: `SELECT EXISTS (${checkPlan.sql}) AS ok`,
117
- params: checkPlan.params,
121
+ params: checkPlan.params ?? [],
118
122
  },
119
123
  ]
120
124
  : [];
@@ -122,7 +126,7 @@ export function dataTransform<TContract extends Contract<SqlStorage>>(
122
126
  const execute: readonly SqlMigrationPlanOperationStep[] = runPlans.map((plan) => ({
123
127
  description: `Run ${name}`,
124
128
  sql: plan.sql,
125
- params: plan.params,
129
+ params: plan.params ?? [],
126
130
  }));
127
131
 
128
132
  const postcheck: readonly SqlMigrationPlanOperationStep[] = checkPlan
@@ -130,7 +134,7 @@ export function dataTransform<TContract extends Contract<SqlStorage>>(
130
134
  {
131
135
  description: `Verify ${name} resolved all violations`,
132
136
  sql: `SELECT NOT EXISTS (${checkPlan.sql}) AS ok`,
133
- params: checkPlan.params,
137
+ params: checkPlan.params ?? [],
134
138
  },
135
139
  ]
136
140
  : [];
@@ -147,23 +151,16 @@ export function dataTransform<TContract extends Contract<SqlStorage>>(
147
151
  };
148
152
  }
149
153
 
150
- function invokeAndLower(
154
+ async function invokeAndLower(
151
155
  closure: DataTransformClosure,
152
156
  contract: Contract<SqlStorage>,
153
157
  adapter: SqlControlAdapter<'postgres'>,
154
158
  name: string,
155
- ): SerializedQueryPlan {
159
+ ): Promise<SqlExecuteRequest> {
156
160
  const result = closure();
157
161
  const plan = isBuildable(result) ? result.build() : result;
158
162
  assertContractMatches(plan, contract, name);
159
- const lowered = adapter.lower(plan.ast, { contract });
160
- const params = lowered.params.map((slot) => {
161
- if (slot.kind === 'literal') return slot.value;
162
- throw new Error(
163
- `data-transform: bind-site slot '${slot.name}' is not allowed in migration plans`,
164
- );
165
- });
166
- return { sql: lowered.sql, params };
163
+ return adapter.lowerToExecuteRequest(plan.ast, { contract });
167
164
  }
168
165
 
169
166
  function isBuildable(value: unknown): value is Buildable {
@@ -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,6 +1,5 @@
1
1
  import type { CodecControlHooks } from '@prisma-next/family-sql/control';
2
2
  import type {
3
- PostgresEnumStorageEntry,
4
3
  StorageColumn,
5
4
  StorageTable,
6
5
  StorageTypeInstance,
@@ -14,7 +13,7 @@ export function buildCreateTableSql(
14
13
  qualifiedTableName: string,
15
14
  table: StorageTable,
16
15
  codecHooks: ReadonlyMap<string, CodecControlHooks>,
17
- storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
16
+ storageTypes: Record<string, StorageTypeInstance> = {},
18
17
  ): string {
19
18
  const columnDefinitions = Object.entries(table.columns).map(
20
19
  ([columnName, column]: [string, StorageColumn]) => {
@@ -79,7 +78,7 @@ function assertSafeDefaultExpression(expression: string): void {
79
78
  export function buildColumnTypeSql(
80
79
  column: StorageColumn,
81
80
  codecHooks: ReadonlyMap<string, CodecControlHooks>,
82
- storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
81
+ storageTypes: Record<string, StorageTypeInstance> = {},
83
82
  allowPseudoTypes = true,
84
83
  ): string {
85
84
  const resolved = resolveColumnTypeMetadata(column, storageTypes);
@@ -200,7 +199,7 @@ export function buildAddColumnSql(
200
199
  column: StorageColumn,
201
200
  codecHooks: ReadonlyMap<string, CodecControlHooks>,
202
201
  temporaryDefault?: string | null,
203
- storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
202
+ storageTypes: Record<string, StorageTypeInstance> = {},
204
203
  ): string {
205
204
  const typeSql = buildColumnTypeSql(column, codecHooks, storageTypes);
206
205
  const defaultSql =