@prisma-next/target-postgres 0.12.0 → 0.13.0-dev.10

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 (211) hide show
  1. package/dist/{codec-ids-D9fJ4HP5.d.mts → codec-ids-B1vOchLE.d.mts} +3 -2
  2. package/dist/codec-ids-B1vOchLE.d.mts.map +1 -0
  3. package/dist/{codec-ids-C5qzBqus.mjs → codec-ids-CTikp1if.mjs} +3 -2
  4. package/dist/codec-ids-CTikp1if.mjs.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-CRlHq7Cz.d.mts → codec-types-CnFiNML4.d.mts} +8 -9
  8. package/dist/codec-types-CnFiNML4.d.mts.map +1 -0
  9. package/dist/codec-types.d.mts +2 -2
  10. package/dist/{codecs-Dud5KDNk.d.mts → codecs-CBpEv4s5.d.mts} +33 -35
  11. package/dist/codecs-CBpEv4s5.d.mts.map +1 -0
  12. package/dist/codecs.d.mts +1 -1
  13. package/dist/codecs.mjs +37 -2
  14. package/dist/codecs.mjs.map +1 -1
  15. package/dist/contract-free.d.mts +80 -0
  16. package/dist/contract-free.d.mts.map +1 -0
  17. package/dist/contract-free.mjs +117 -0
  18. package/dist/contract-free.mjs.map +1 -0
  19. package/dist/control.d.mts +1 -1
  20. package/dist/control.d.mts.map +1 -1
  21. package/dist/control.mjs +67 -41
  22. package/dist/control.mjs.map +1 -1
  23. package/dist/{data-transform-CdtGUWp2.mjs → data-transform-D25tLeYU.mjs} +1 -1
  24. package/dist/{data-transform-CdtGUWp2.mjs.map → data-transform-D25tLeYU.mjs.map} +1 -1
  25. package/dist/{data-transform-bmOKkygi.d.mts → data-transform-DGOqcLrf.d.mts} +2 -2
  26. package/dist/{data-transform-bmOKkygi.d.mts.map → data-transform-DGOqcLrf.d.mts.map} +1 -1
  27. package/dist/data-transform.d.mts +1 -1
  28. package/dist/data-transform.mjs +1 -1
  29. package/dist/ddl-77SyXgFt.mjs +30 -0
  30. package/dist/ddl-77SyXgFt.mjs.map +1 -0
  31. package/dist/ddl.d.mts +2 -0
  32. package/dist/ddl.mjs +2 -0
  33. package/dist/{default-normalizer-CRscvhS5.mjs → default-normalizer-DyyCHQWs.mjs} +1 -1
  34. package/dist/{default-normalizer-CRscvhS5.mjs.map → default-normalizer-DyyCHQWs.mjs.map} +1 -1
  35. package/dist/default-normalizer.mjs +1 -1
  36. package/dist/descriptor-meta-DKmj-IMN.mjs +14 -0
  37. package/dist/descriptor-meta-DKmj-IMN.mjs.map +1 -0
  38. package/dist/{descriptor-meta-DLA2xV6B.mjs → descriptor-meta-runtime-My8_s4cs.mjs} +82 -78
  39. package/dist/descriptor-meta-runtime-My8_s4cs.mjs.map +1 -0
  40. package/dist/{enum-planning-Dz0Ye3Lb.mjs → enum-planning-DTMrPLkN.mjs} +0 -0
  41. package/dist/enum-planning-DTMrPLkN.mjs.map +1 -0
  42. package/dist/enum-planning.d.mts +14 -8
  43. package/dist/enum-planning.d.mts.map +1 -1
  44. package/dist/enum-planning.mjs +2 -2
  45. package/dist/{errors--zafB5_n.mjs → errors-CUk87ByX.mjs} +1 -1
  46. package/dist/{errors--zafB5_n.mjs.map → errors-CUk87ByX.mjs.map} +1 -1
  47. package/dist/errors.d.mts.map +1 -1
  48. package/dist/errors.mjs +1 -1
  49. package/dist/{issue-planner-ByQhUzS4.mjs → issue-planner-B0A7RFN2.mjs} +130 -28
  50. package/dist/issue-planner-B0A7RFN2.mjs.map +1 -0
  51. package/dist/issue-planner.d.mts +1 -1
  52. package/dist/issue-planner.d.mts.map +1 -1
  53. package/dist/issue-planner.mjs +1 -1
  54. package/dist/migration.d.mts +7 -8
  55. package/dist/migration.d.mts.map +1 -1
  56. package/dist/migration.mjs +5 -4
  57. package/dist/migration.mjs.map +1 -1
  58. package/dist/{native-type-normalizer-ClNPq__-.mjs → native-type-normalizer-Bc9XJzWC.mjs} +1 -1
  59. package/dist/{native-type-normalizer-ClNPq__-.mjs.map → native-type-normalizer-Bc9XJzWC.mjs.map} +1 -1
  60. package/dist/native-type-normalizer.mjs +1 -1
  61. package/dist/nodes-779hmCfL.d.mts +40 -0
  62. package/dist/nodes-779hmCfL.d.mts.map +1 -0
  63. package/dist/nodes-DZk2JZG3.mjs +47 -0
  64. package/dist/nodes-DZk2JZG3.mjs.map +1 -0
  65. package/dist/op-factory-call-Clp7Zr1z.mjs +1307 -0
  66. package/dist/op-factory-call-Clp7Zr1z.mjs.map +1 -0
  67. package/dist/{op-factory-call-Drccm_JD.d.mts → op-factory-call-DMA86_2D.d.mts} +39 -14
  68. package/dist/op-factory-call-DMA86_2D.d.mts.map +1 -0
  69. package/dist/op-factory-call.d.mts +2 -2
  70. package/dist/op-factory-call.mjs +2 -2
  71. package/dist/pack.d.mts +13 -12
  72. package/dist/pack.d.mts.map +1 -1
  73. package/dist/pack.mjs +1 -1
  74. package/dist/planner-DID7RZCQ.mjs +344 -0
  75. package/dist/planner-DID7RZCQ.mjs.map +1 -0
  76. package/dist/{planner-ddl-builders-BxRCSn_b.mjs → planner-ddl-builders-Cw2n2llW.mjs} +7 -30
  77. package/dist/planner-ddl-builders-Cw2n2llW.mjs.map +1 -0
  78. package/dist/planner-ddl-builders.d.mts +6 -7
  79. package/dist/planner-ddl-builders.d.mts.map +1 -1
  80. package/dist/planner-ddl-builders.mjs +2 -2
  81. package/dist/{planner-identity-values-ojX-6cPV.mjs → planner-identity-values-BIpa5p2I.mjs} +1 -1
  82. package/dist/{planner-identity-values-ojX-6cPV.mjs.map → planner-identity-values-BIpa5p2I.mjs.map} +1 -1
  83. package/dist/planner-identity-values.mjs +1 -1
  84. package/dist/{planner-produced-postgres-migration-p-VKkCia.d.mts → planner-produced-postgres-migration-B4EDvLdz.d.mts} +5 -4
  85. package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +1 -0
  86. package/dist/{planner-produced-postgres-migration-N1yqYg20.mjs → planner-produced-postgres-migration-B8gZBPOR.mjs} +8 -6
  87. package/dist/planner-produced-postgres-migration-B8gZBPOR.mjs.map +1 -0
  88. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  89. package/dist/planner-produced-postgres-migration.mjs +1 -1
  90. package/dist/{planner-schema-lookup-BGyukuzG.mjs → planner-schema-lookup-CiVaAQP-.mjs} +1 -1
  91. package/dist/{planner-schema-lookup-BGyukuzG.mjs.map → planner-schema-lookup-CiVaAQP-.mjs.map} +1 -1
  92. package/dist/planner-schema-lookup.mjs +1 -1
  93. package/dist/{planner-sql-checks-D3H-xOO1.mjs → planner-sql-checks-DRD5E8A1.mjs} +41 -30
  94. package/dist/planner-sql-checks-DRD5E8A1.mjs.map +1 -0
  95. package/dist/planner-sql-checks.d.mts.map +1 -1
  96. package/dist/planner-sql-checks.mjs +1 -1
  97. package/dist/{planner-target-details-CIj61DUj.d.mts → planner-target-details-CIY6tLeo.d.mts} +2 -2
  98. package/dist/planner-target-details-CIY6tLeo.d.mts.map +1 -0
  99. package/dist/planner-target-details.d.mts +2 -2
  100. package/dist/planner-type-resolution-836DExFN.mjs +20 -0
  101. package/dist/planner-type-resolution-836DExFN.mjs.map +1 -0
  102. package/dist/planner.d.mts +7 -3
  103. package/dist/planner.d.mts.map +1 -1
  104. package/dist/planner.mjs +1 -1
  105. package/dist/{postgres-contract-serializer-YJvjKrmo.mjs → postgres-contract-serializer-DCg7YaP3.mjs} +40 -24
  106. package/dist/postgres-contract-serializer-DCg7YaP3.mjs.map +1 -0
  107. package/dist/{postgres-enum-type-CNhPTDhy.d.mts → postgres-enum-type-BVn63a89.d.mts} +4 -1
  108. package/dist/postgres-enum-type-BVn63a89.d.mts.map +1 -0
  109. package/dist/{postgres-enum-type-DS-KLVRH.mjs → postgres-enum-type-DPKqCBem.mjs} +2 -1
  110. package/dist/postgres-enum-type-DPKqCBem.mjs.map +1 -0
  111. package/dist/{postgres-migration-uADmx0dW.mjs → postgres-migration-BCQEjFHK.mjs} +23 -3
  112. package/dist/postgres-migration-BCQEjFHK.mjs.map +1 -0
  113. package/dist/{postgres-migration-Fd4fQkBw.d.mts → postgres-migration-DZ_gLUOW.d.mts} +25 -3
  114. package/dist/postgres-migration-DZ_gLUOW.d.mts.map +1 -0
  115. package/dist/{postgres-schema-Bm7vjlOv.mjs → postgres-schema-BVTA2QH7.mjs} +41 -15
  116. package/dist/postgres-schema-BVTA2QH7.mjs.map +1 -0
  117. package/dist/{render-ops-BC2PtCkj.mjs → render-ops-BpjstrKQ.mjs} +4 -3
  118. package/dist/{render-ops-BC2PtCkj.mjs.map → render-ops-BpjstrKQ.mjs.map} +1 -1
  119. package/dist/render-ops.d.mts +3 -2
  120. package/dist/render-ops.d.mts.map +1 -1
  121. package/dist/render-ops.mjs +1 -1
  122. package/dist/{render-typescript-CPk7hhWH.mjs → render-typescript-KMgosran.mjs} +5 -2
  123. package/dist/render-typescript-KMgosran.mjs.map +1 -0
  124. package/dist/render-typescript.mjs +1 -1
  125. package/dist/runtime.d.mts.map +1 -1
  126. package/dist/runtime.mjs +3 -3
  127. package/dist/runtime.mjs.map +1 -1
  128. package/dist/{shared-ByhSooBS.d.mts → shared-DarONYBZ.d.mts} +5 -5
  129. package/dist/{shared-ByhSooBS.d.mts.map → shared-DarONYBZ.d.mts.map} +1 -1
  130. package/dist/{sql-utils-B_ruBD-M.mjs → sql-utils-DcfMz4MQ.mjs} +1 -1
  131. package/dist/{sql-utils-B_ruBD-M.mjs.map → sql-utils-DcfMz4MQ.mjs.map} +1 -1
  132. package/dist/sql-utils.mjs +1 -1
  133. package/dist/{types-D-XIpzHA.d.mts → types-BDKkx8MA.d.mts} +1 -1
  134. package/dist/types-BDKkx8MA.d.mts.map +1 -0
  135. package/dist/types.d.mts +18 -11
  136. package/dist/types.d.mts.map +1 -1
  137. package/dist/types.mjs +2 -2
  138. package/package.json +21 -20
  139. package/src/contract-free/columns.ts +49 -0
  140. package/src/contract-free/control-bootstrap.ts +55 -0
  141. package/src/contract-free/ddl.ts +37 -0
  142. package/src/core/ast/table-source.ts +23 -0
  143. package/src/core/authoring.ts +1 -1
  144. package/src/core/codec-ids.ts +1 -0
  145. package/src/core/codecs.ts +44 -0
  146. package/src/core/ddl/nodes.ts +72 -0
  147. package/src/core/descriptor-meta-runtime.ts +28 -0
  148. package/src/core/descriptor-meta.ts +3 -6
  149. package/src/core/migrations/control-policy.ts +234 -0
  150. package/src/core/migrations/enum-planning.ts +33 -29
  151. package/src/core/migrations/issue-planner.ts +81 -13
  152. package/src/core/migrations/op-factory-call.ts +289 -46
  153. package/src/core/migrations/operations/constraints.ts +79 -10
  154. package/src/core/migrations/operations/dependencies.ts +0 -17
  155. package/src/core/migrations/operations/shared.ts +3 -3
  156. package/src/core/migrations/operations/tables.ts +1 -39
  157. package/src/core/migrations/planner-ddl-builders.ts +7 -48
  158. package/src/core/migrations/planner-produced-postgres-migration.ts +11 -6
  159. package/src/core/migrations/planner-sql-checks.ts +9 -9
  160. package/src/core/migrations/planner-strategies.ts +149 -11
  161. package/src/core/migrations/planner-target-details.ts +2 -1
  162. package/src/core/migrations/planner.ts +66 -8
  163. package/src/core/migrations/postgres-migration.ts +41 -0
  164. package/src/core/migrations/render-ops.ts +7 -2
  165. package/src/core/migrations/render-typescript.ts +5 -1
  166. package/src/core/migrations/runner.ts +78 -50
  167. package/src/core/postgres-contract-serializer.ts +66 -46
  168. package/src/core/postgres-enum-type.ts +4 -0
  169. package/src/core/postgres-schema.ts +56 -19
  170. package/src/exports/contract-free.ts +7 -0
  171. package/src/exports/control.ts +15 -24
  172. package/src/exports/ddl.ts +7 -0
  173. package/src/exports/enum-planning.ts +0 -1
  174. package/src/exports/migration.ts +11 -2
  175. package/src/exports/op-factory-call.ts +2 -0
  176. package/src/exports/planner-ddl-builders.ts +0 -1
  177. package/src/exports/runtime.ts +2 -2
  178. package/dist/codec-ids-C5qzBqus.mjs.map +0 -1
  179. package/dist/codec-ids-D9fJ4HP5.d.mts.map +0 -1
  180. package/dist/codec-types-CRlHq7Cz.d.mts.map +0 -1
  181. package/dist/codecs-Dud5KDNk.d.mts.map +0 -1
  182. package/dist/descriptor-meta-DLA2xV6B.mjs.map +0 -1
  183. package/dist/enum-planning-Dz0Ye3Lb.mjs.map +0 -1
  184. package/dist/issue-planner-ByQhUzS4.mjs.map +0 -1
  185. package/dist/op-factory-call-B0WNg30h.mjs +0 -625
  186. package/dist/op-factory-call-B0WNg30h.mjs.map +0 -1
  187. package/dist/op-factory-call-Drccm_JD.d.mts.map +0 -1
  188. package/dist/planner-ClF0y0YR.mjs +0 -177
  189. package/dist/planner-ClF0y0YR.mjs.map +0 -1
  190. package/dist/planner-ddl-builders-BxRCSn_b.mjs.map +0 -1
  191. package/dist/planner-produced-postgres-migration-N1yqYg20.mjs.map +0 -1
  192. package/dist/planner-produced-postgres-migration-p-VKkCia.d.mts.map +0 -1
  193. package/dist/planner-sql-checks-D3H-xOO1.mjs.map +0 -1
  194. package/dist/planner-target-details-CIj61DUj.d.mts.map +0 -1
  195. package/dist/postgres-contract-serializer-YJvjKrmo.mjs.map +0 -1
  196. package/dist/postgres-enum-type-CNhPTDhy.d.mts.map +0 -1
  197. package/dist/postgres-enum-type-DS-KLVRH.mjs.map +0 -1
  198. package/dist/postgres-migration-Fd4fQkBw.d.mts.map +0 -1
  199. package/dist/postgres-migration-uADmx0dW.mjs.map +0 -1
  200. package/dist/postgres-schema-Bm7vjlOv.mjs.map +0 -1
  201. package/dist/render-typescript-CPk7hhWH.mjs.map +0 -1
  202. package/dist/statement-builders-vImtdfmM.mjs +0 -131
  203. package/dist/statement-builders-vImtdfmM.mjs.map +0 -1
  204. package/dist/statement-builders.d.mts +0 -51
  205. package/dist/statement-builders.d.mts.map +0 -1
  206. package/dist/statement-builders.mjs +0 -2
  207. package/dist/tables-Dcb2q9zV.mjs +0 -516
  208. package/dist/tables-Dcb2q9zV.mjs.map +0 -1
  209. package/dist/types-D-XIpzHA.d.mts.map +0 -1
  210. package/src/core/migrations/statement-builders.ts +0 -183
  211. package/src/exports/statement-builders.ts +0 -8
@@ -25,10 +25,13 @@ import type {
25
25
  StorageTable,
26
26
  StorageTypeInstance,
27
27
  } from '@prisma-next/sql-contract/types';
28
+ import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
29
+ import * as contractFree from '@prisma-next/sql-relational-core/contract-free';
28
30
  import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
29
31
  import type { Result } from '@prisma-next/utils/result';
30
32
  import { notOk, ok } from '@prisma-next/utils/result';
31
33
  import { PostgresEnumType } from '../postgres-enum-type';
34
+ import { isPostgresSchema } from '../postgres-schema';
32
35
  import {
33
36
  AddColumnCall,
34
37
  AddForeignKeyCall,
@@ -39,6 +42,7 @@ import {
39
42
  CreateIndexCall,
40
43
  CreateSchemaCall,
41
44
  CreateTableCall,
45
+ DropCheckConstraintCall,
42
46
  DropColumnCall,
43
47
  DropConstraintCall,
44
48
  DropDefaultCall,
@@ -46,6 +50,7 @@ import {
46
50
  DropNotNullCall,
47
51
  DropTableCall,
48
52
  type PostgresOpFactoryCall,
53
+ postgresDefaultToDdlColumnDefault,
49
54
  SetDefaultCall,
50
55
  SetNotNullCall,
51
56
  } from './op-factory-call';
@@ -73,8 +78,7 @@ function locateNamespaceTypeInStorage(
73
78
  typeName: string,
74
79
  ): unknown {
75
80
  const ns = storage.namespaces[namespaceId];
76
- if (!ns || !('enum' in ns) || ns.enum == null) return undefined;
77
- return (ns.enum as Record<string, unknown>)[typeName];
81
+ return isPostgresSchema(ns) ? ns.entries.type[typeName] : undefined;
78
82
  }
79
83
 
80
84
  // ============================================================================
@@ -118,6 +122,11 @@ const ISSUE_KIND_ORDER: Record<string, number> = {
118
122
  unique_constraint_mismatch: 51,
119
123
  index_mismatch: 52,
120
124
  foreign_key_mismatch: 60,
125
+
126
+ // Check constraints
127
+ check_missing: 53,
128
+ check_mismatch: 54,
129
+ check_removed: 55,
121
130
  };
122
131
 
123
132
  function issueOrder(issue: SchemaIssue): number {
@@ -191,16 +200,26 @@ function toColumnSpec(
191
200
  ): ColumnSpec {
192
201
  return {
193
202
  name,
194
- typeSql: buildColumnTypeSql(
195
- column,
196
- codecHooks as Map<string, CodecControlHooks>,
197
- storageTypes as Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
198
- ),
203
+ typeSql: buildColumnTypeSql(column, codecHooks, storageTypes),
199
204
  defaultSql: buildColumnDefaultSql(column.default, column),
200
205
  nullable: column.nullable,
201
206
  };
202
207
  }
203
208
 
209
+ function toDdlColumn(
210
+ name: string,
211
+ column: StorageColumn,
212
+ codecHooks: ReadonlyMap<string, CodecControlHooks>,
213
+ storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>,
214
+ ): DdlColumn {
215
+ const typeSql = buildColumnTypeSql(column, codecHooks, storageTypes);
216
+ const ddlDefault = postgresDefaultToDdlColumnDefault(column.default);
217
+ return contractFree.col(name, typeSql, {
218
+ ...(!column.nullable ? { notNull: true } : {}),
219
+ ...(ddlDefault ? { default: ddlDefault } : {}),
220
+ });
221
+ }
222
+
204
223
  function mapIssueToCall(
205
224
  issue: SchemaIssue,
206
225
  ctx: StrategyContext,
@@ -245,14 +264,18 @@ function mapIssueToCall(
245
264
  );
246
265
  }
247
266
  const schemaForTable = tableSchema(issue);
248
- const columns: ColumnSpec[] = Object.entries(contractTable.columns).map(([name, column]) =>
249
- toColumnSpec(name, column, codecHooks, storageTypes),
267
+ const ddlColumns: DdlColumn[] = Object.entries(contractTable.columns).map(([name, column]) =>
268
+ toDdlColumn(name, column, codecHooks, storageTypes),
250
269
  );
251
- const primaryKey = contractTable.primaryKey
252
- ? { columns: contractTable.primaryKey.columns }
270
+ const ddlConstraints: DdlTableConstraint[] | undefined = contractTable.primaryKey
271
+ ? [
272
+ contractFree.primaryKey(contractTable.primaryKey.columns, {
273
+ ...(contractTable.primaryKey.name ? { name: contractTable.primaryKey.name } : {}),
274
+ }),
275
+ ]
253
276
  : undefined;
254
277
  const calls: PostgresOpFactoryCall[] = [
255
- new CreateTableCall(schemaForTable, issue.table, columns, primaryKey),
278
+ new CreateTableCall(schemaForTable, issue.table, ddlColumns, ddlConstraints),
256
279
  ];
257
280
  for (const index of contractTable.indexes) {
258
281
  const indexName = index.name ?? `${issue.table}_${index.columns.join('_')}_idx`;
@@ -555,6 +578,48 @@ function mapIssueToCall(
555
578
  ),
556
579
  );
557
580
 
581
+ case 'check_missing': {
582
+ if (!issue.table || !issue.indexOrConstraint)
583
+ return notOk(
584
+ issueConflict('unsupportedOperation', 'Check missing issue has no table/constraint name'),
585
+ );
586
+ // check_missing is normally consumed by checkConstraintPlanCallStrategy.
587
+ // This case handles any that arrive here (e.g. in tests that invoke
588
+ // mapIssueToCall directly or skip the strategy).
589
+ return notOk(
590
+ issueConflict(
591
+ 'unsupportedOperation',
592
+ `Check constraint "${issue.indexOrConstraint}" missing on "${issue.table}" — handled by checkConstraintPlanCallStrategy`,
593
+ ),
594
+ );
595
+ }
596
+
597
+ case 'check_mismatch': {
598
+ if (!issue.table || !issue.indexOrConstraint)
599
+ return notOk(
600
+ issueConflict(
601
+ 'unsupportedOperation',
602
+ 'Check mismatch issue has no table/constraint name',
603
+ ),
604
+ );
605
+ return notOk(
606
+ issueConflict(
607
+ 'unsupportedOperation',
608
+ `Check constraint "${issue.indexOrConstraint}" values mismatch on "${issue.table}" — handled by checkConstraintPlanCallStrategy`,
609
+ ),
610
+ );
611
+ }
612
+
613
+ case 'check_removed': {
614
+ if (!issue.table || !issue.indexOrConstraint)
615
+ return notOk(
616
+ issueConflict('unsupportedOperation', 'Check removed issue has no table/constraint name'),
617
+ );
618
+ return ok([
619
+ new DropCheckConstraintCall(tableSchema(issue), issue.table, issue.indexOrConstraint),
620
+ ]);
621
+ }
622
+
558
623
  case 'foreign_key_mismatch':
559
624
  if (!issue.table)
560
625
  return notOk(issueConflict('foreignKeyConflict', 'Foreign key issue has no table name'));
@@ -601,7 +666,7 @@ function mapIssueToCall(
601
666
  case 'type_missing': {
602
667
  if (!issue.typeName)
603
668
  return notOk(issueConflict('unsupportedOperation', 'Type missing issue has no typeName'));
604
- // Codec aliases live in storage.types; enum types live in namespace.enum.
669
+ // Codec aliases live in storage.types; enum types live in namespace.entries.type.
605
670
  // Check types first; fall back to the namespace-keyed enum slot using the
606
671
  // issue's namespace coordinate (populated by the verifier for enum-related
607
672
  // issues per the BaseSchemaIssue.namespaceId contract).
@@ -687,9 +752,12 @@ function classifyCall(call: PostgresOpFactoryCall): CallCategory {
687
752
  case 'dropTable':
688
753
  case 'dropColumn':
689
754
  case 'dropConstraint':
755
+ case 'dropCheckConstraint':
690
756
  case 'dropIndex':
691
757
  case 'dropDefault':
692
758
  return 'drop';
759
+ case 'addCheckConstraint':
760
+ return 'unique'; // after uniques, before indexes
693
761
  case 'createTable':
694
762
  return 'table';
695
763
  case 'addColumn':
@@ -22,11 +22,23 @@
22
22
 
23
23
  import { errorUnfilledPlaceholder } from '@prisma-next/errors/migration';
24
24
  import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
25
+ import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
25
26
  import type {
26
27
  OpFactoryCall as FrameworkOpFactoryCall,
27
28
  MigrationOperationClass,
28
29
  } from '@prisma-next/framework-components/control';
30
+ import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
31
+ import type {
32
+ AnyDdlColumnDefault,
33
+ DdlColumn,
34
+ DdlTableConstraint,
35
+ } from '@prisma-next/sql-relational-core/ast';
36
+ import { FunctionColumnDefault, LiteralColumnDefault } from '@prisma-next/sql-relational-core/ast';
29
37
  import { type ImportRequirement, jsonToTsSource, TsExpression } from '@prisma-next/ts-render';
38
+ import { blindCast } from '@prisma-next/utils/casts';
39
+ import * as contractFreeDdl from '../../contract-free/ddl';
40
+ import { escapeLiteral, quoteIdentifier } from '../sql-utils';
41
+ import type { PostgresColumnDefault } from '../types';
30
42
  import {
31
43
  addColumn,
32
44
  alterColumnType,
@@ -36,26 +48,47 @@ import {
36
48
  setDefault,
37
49
  setNotNull,
38
50
  } from './operations/columns';
39
- import { addForeignKey, addPrimaryKey, addUnique, dropConstraint } from './operations/constraints';
40
- import { createExtension, createSchema } from './operations/dependencies';
51
+ import {
52
+ addCheckConstraint,
53
+ addForeignKey,
54
+ addPrimaryKey,
55
+ addUnique,
56
+ dropCheckConstraint,
57
+ dropConstraint,
58
+ } from './operations/constraints';
59
+ import { createExtension } from './operations/dependencies';
41
60
  import { addEnumValues, createEnumType, dropEnumType, renameType } from './operations/enums';
42
61
  import { createIndex, dropIndex } from './operations/indexes';
43
62
  import type { ColumnSpec, ForeignKeySpec } from './operations/shared';
44
- import { createTable, dropTable } from './operations/tables';
63
+ import { step, targetDetails } from './operations/shared';
64
+ import { dropTable } from './operations/tables';
65
+ import { toRegclassLiteral } from './planner-sql-checks';
45
66
  import type { PostgresPlanTargetDetails } from './planner-target-details';
46
67
 
47
68
  type Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
48
69
 
49
- const TARGET_MIGRATION_MODULE = '@prisma-next/postgres/migration';
70
+ // Single module specifier emitted in user-edited `migration.ts` imports. The
71
+ // Postgres migration facade re-exports both the `*Call` factory names
72
+ // (createTable / addColumn / …) and the contract-free DDL builders
73
+ // (col / lit / fn / primaryKey / foreignKey / unique) from
74
+ // sql-relational-core/contract-free. We emit imports against the facade,
75
+ // not against the underlying sql-relational-core subpath, because user
76
+ // projects depend on `@prisma-next/postgres` (a runtime dep of every
77
+ // init-scaffolded project) — they do not depend on the internal
78
+ // `@prisma-next/sql-relational-core` package, so an emitted
79
+ // `import … from '@prisma-next/sql-relational-core/contract-free'` fails
80
+ // ESM resolution at runtime in user migrations even though pnpm has the
81
+ // transitive package on disk.
82
+ const POSTGRES_MIGRATION_FACADE = '@prisma-next/postgres/migration';
50
83
 
51
84
  abstract class PostgresOpFactoryCallNode extends TsExpression implements FrameworkOpFactoryCall {
52
85
  abstract readonly factoryName: string;
53
86
  abstract readonly operationClass: MigrationOperationClass;
54
87
  abstract readonly label: string;
55
- abstract toOp(): Op;
88
+ abstract toOp(lowerer?: Lowerer): Op;
56
89
 
57
90
  importRequirements(): readonly ImportRequirement[] {
58
- return [{ moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: this.factoryName }];
91
+ return [{ moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: this.factoryName }];
59
92
  }
60
93
 
61
94
  protected freeze(): void {
@@ -67,8 +100,93 @@ abstract class PostgresOpFactoryCallNode extends TsExpression implements Framewo
67
100
  // Table
68
101
  // ============================================================================
69
102
 
70
- export interface CreateTablePrimaryKey {
71
- readonly columns: readonly string[];
103
+ export function postgresDefaultToDdlColumnDefault(
104
+ columnDefault: PostgresColumnDefault | undefined,
105
+ ): DdlColumn['default'] {
106
+ if (!columnDefault) return undefined;
107
+ switch (columnDefault.kind) {
108
+ case 'literal':
109
+ return new LiteralColumnDefault(columnDefault.value);
110
+ case 'function':
111
+ if (columnDefault.expression === 'autoincrement()') return undefined;
112
+ return new FunctionColumnDefault(columnDefault.expression);
113
+ case 'sequence':
114
+ return new FunctionColumnDefault(
115
+ `nextval('${escapeLiteral(quoteIdentifier(columnDefault.name))}'::regclass)`,
116
+ );
117
+ default: {
118
+ const exhaustive: never = columnDefault;
119
+ throw new Error(
120
+ `postgresDefaultToDdlColumnDefault: unhandled kind "${blindCast<{ kind: string }, 'exhaustiveness: surface the unhandled default kind'>(exhaustive).kind}"`,
121
+ );
122
+ }
123
+ }
124
+ }
125
+
126
+ // ---------------------------------------------------------------------------
127
+ // TypeScript rendering helpers for DdlColumn / DdlTableConstraint
128
+ // ---------------------------------------------------------------------------
129
+
130
+ function renderDdlColumnDefault(def: AnyDdlColumnDefault | undefined): string {
131
+ if (!def) return '';
132
+ if (def.kind === 'literal') {
133
+ return `lit(${jsonToTsSource(def.value)})`;
134
+ }
135
+ return `fn(${jsonToTsSource(def.expression)})`;
136
+ }
137
+
138
+ function renderDdlColumnAsTsCall(col: DdlColumn): string {
139
+ const opts: string[] = [];
140
+ if (col.notNull) opts.push('notNull: true');
141
+ if (col.primaryKey) opts.push('primaryKey: true');
142
+ if (col.default) opts.push(`default: ${renderDdlColumnDefault(col.default)}`);
143
+ const optsStr = opts.length > 0 ? `, { ${opts.join(', ')} }` : '';
144
+ return `col(${jsonToTsSource(col.name)}, ${jsonToTsSource(col.type)}${optsStr})`;
145
+ }
146
+
147
+ function renderDdlConstraintAsTsCall(constraint: DdlTableConstraint): string {
148
+ switch (constraint.kind) {
149
+ case 'primary-key': {
150
+ const nameOpt = constraint.name ? `, { name: ${jsonToTsSource(constraint.name)} }` : '';
151
+ return `primaryKey(${jsonToTsSource(constraint.columns)}${nameOpt})`;
152
+ }
153
+ case 'foreign-key': {
154
+ const opts: string[] = [];
155
+ if (constraint.name) opts.push(`name: ${jsonToTsSource(constraint.name)}`);
156
+ if (constraint.onDelete) opts.push(`onDelete: ${jsonToTsSource(constraint.onDelete)}`);
157
+ if (constraint.onUpdate) opts.push(`onUpdate: ${jsonToTsSource(constraint.onUpdate)}`);
158
+ const optsStr = opts.length > 0 ? `, { ${opts.join(', ')} }` : '';
159
+ return `foreignKey(${jsonToTsSource(constraint.columns)}, ${jsonToTsSource(constraint.refTable)}, ${jsonToTsSource(constraint.refColumns)}${optsStr})`;
160
+ }
161
+ case 'unique': {
162
+ const nameOpt = constraint.name ? `, { name: ${jsonToTsSource(constraint.name)} }` : '';
163
+ return `unique(${jsonToTsSource(constraint.columns)}${nameOpt})`;
164
+ }
165
+ }
166
+ }
167
+
168
+ function needsColOrConstraintImport(columns: readonly DdlColumn[]): boolean {
169
+ return columns.length > 0;
170
+ }
171
+
172
+ function constraintImportSymbols(constraints: readonly DdlTableConstraint[] | undefined): string[] {
173
+ if (!constraints || constraints.length === 0) return [];
174
+ const symbols = new Set<string>();
175
+ for (const c of constraints) {
176
+ if (c.kind === 'primary-key') symbols.add('primaryKey');
177
+ else if (c.kind === 'foreign-key') symbols.add('foreignKey');
178
+ else if (c.kind === 'unique') symbols.add('unique');
179
+ }
180
+ return [...symbols];
181
+ }
182
+
183
+ function defaultImportSymbols(columns: readonly DdlColumn[]): string[] {
184
+ const symbols = new Set<string>();
185
+ for (const col of columns) {
186
+ if (col.default?.kind === 'literal') symbols.add('lit');
187
+ else if (col.default?.kind === 'function') symbols.add('fn');
188
+ }
189
+ return [...symbols];
72
190
  }
73
191
 
74
192
  export class CreateTableCall extends PostgresOpFactoryCallNode {
@@ -76,37 +194,91 @@ export class CreateTableCall extends PostgresOpFactoryCallNode {
76
194
  readonly operationClass = 'additive' as const;
77
195
  readonly schemaName: string;
78
196
  readonly tableName: string;
79
- readonly columns: readonly ColumnSpec[];
80
- readonly primaryKey: CreateTablePrimaryKey | undefined;
197
+ readonly columns: readonly DdlColumn[];
198
+ readonly constraints: readonly DdlTableConstraint[] | undefined;
81
199
  readonly label: string;
82
200
 
83
201
  constructor(
84
202
  schemaName: string,
85
203
  tableName: string,
86
- columns: readonly ColumnSpec[],
87
- primaryKey?: CreateTablePrimaryKey,
204
+ columns: readonly DdlColumn[],
205
+ constraints?: readonly DdlTableConstraint[],
88
206
  ) {
89
207
  super();
90
208
  this.schemaName = schemaName;
91
209
  this.tableName = tableName;
92
- this.columns = columns;
93
- this.primaryKey = primaryKey;
210
+ this.columns = Object.freeze([...columns]);
211
+ this.constraints = constraints ? Object.freeze([...constraints]) : undefined;
94
212
  this.label = `Create table "${tableName}"`;
95
213
  this.freeze();
96
214
  }
97
215
 
98
- toOp(): Op {
99
- return createTable(this.schemaName, this.tableName, this.columns, this.primaryKey);
216
+ toOp(lowerer?: Lowerer): Op {
217
+ if (lowerer === undefined) {
218
+ throw new Error(
219
+ `CreateTableCall.toOp: a DDL lowerer is required on the Postgres planner path (table "${this.tableName}"). Pass the control adapter to createPostgresMigrationPlanner.`,
220
+ );
221
+ }
222
+ const ddlNode = contractFreeDdl.createTable({
223
+ ...(this.schemaName !== UNBOUND_NAMESPACE_ID ? { schema: this.schemaName } : {}),
224
+ table: this.tableName,
225
+ columns: this.columns,
226
+ ...(this.constraints ? { constraints: this.constraints } : {}),
227
+ });
228
+ const { sql } = lowerer.lower(ddlNode, { contract: {} });
229
+ const schemaName = this.schemaName;
230
+ const tableName = this.tableName;
231
+ return {
232
+ id: `table.${tableName}`,
233
+ label: `Create table "${tableName}"`,
234
+ summary: `Creates table "${tableName}"`,
235
+ operationClass: 'additive',
236
+ target: targetDetails('table', tableName, schemaName),
237
+ precheck: [
238
+ step(
239
+ `ensure table "${tableName}" does not exist`,
240
+ `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NULL`,
241
+ ),
242
+ ],
243
+ execute: [step(`create table "${tableName}"`, sql)],
244
+ postcheck: [
245
+ step(
246
+ `verify table "${tableName}" exists`,
247
+ `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NOT NULL`,
248
+ ),
249
+ ],
250
+ };
100
251
  }
101
252
 
102
253
  renderTypeScript(): string {
103
- const args = [
104
- jsonToTsSource(this.schemaName),
105
- jsonToTsSource(this.tableName),
106
- jsonToTsSource(this.columns),
107
- ];
108
- if (this.primaryKey) args.push(jsonToTsSource(this.primaryKey));
109
- return `createTable(${args.join(', ')})`;
254
+ const columnsList = this.columns.map(renderDdlColumnAsTsCall).join(', ');
255
+ const constraintsList = this.constraints
256
+ ? this.constraints.map(renderDdlConstraintAsTsCall).join(', ')
257
+ : undefined;
258
+
259
+ const opts: string[] = [];
260
+ if (this.schemaName !== UNBOUND_NAMESPACE_ID) {
261
+ opts.push(`schema: ${jsonToTsSource(this.schemaName)}`);
262
+ }
263
+ opts.push(`table: ${jsonToTsSource(this.tableName)}`);
264
+ opts.push(`columns: [${columnsList}]`);
265
+ if (constraintsList) opts.push(`constraints: [${constraintsList}]`);
266
+
267
+ return `this.createTable({ ${opts.join(', ')} })`;
268
+ }
269
+
270
+ override importRequirements(): readonly ImportRequirement[] {
271
+ const req: ImportRequirement[] = [];
272
+ if (needsColOrConstraintImport(this.columns)) {
273
+ req.push({ moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: 'col' });
274
+ for (const sym of defaultImportSymbols(this.columns)) {
275
+ req.push({ moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: sym });
276
+ }
277
+ }
278
+ for (const sym of constraintImportSymbols(this.constraints)) {
279
+ req.push({ moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: sym });
280
+ }
281
+ return req;
110
282
  }
111
283
  }
112
284
 
@@ -495,6 +667,74 @@ export class DropConstraintCall extends PostgresOpFactoryCallNode {
495
667
  }
496
668
  }
497
669
 
670
+ export class AddCheckConstraintCall extends PostgresOpFactoryCallNode {
671
+ readonly factoryName = 'addCheckConstraint' as const;
672
+ readonly operationClass = 'additive' as const;
673
+ readonly schemaName: string;
674
+ readonly tableName: string;
675
+ readonly constraintName: string;
676
+ readonly column: string;
677
+ readonly values: readonly string[];
678
+ readonly label: string;
679
+
680
+ constructor(
681
+ schemaName: string,
682
+ tableName: string,
683
+ constraintName: string,
684
+ column: string,
685
+ values: readonly string[],
686
+ ) {
687
+ super();
688
+ this.schemaName = schemaName;
689
+ this.tableName = tableName;
690
+ this.constraintName = constraintName;
691
+ this.column = column;
692
+ this.values = values;
693
+ this.label = `Add check constraint "${constraintName}" on "${tableName}"."${column}"`;
694
+ this.freeze();
695
+ }
696
+
697
+ toOp(): Op {
698
+ return addCheckConstraint(
699
+ this.schemaName,
700
+ this.tableName,
701
+ this.constraintName,
702
+ this.column,
703
+ this.values,
704
+ );
705
+ }
706
+
707
+ renderTypeScript(): string {
708
+ return `addCheckConstraint(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.constraintName)}, ${jsonToTsSource(this.column)}, ${jsonToTsSource(this.values)})`;
709
+ }
710
+ }
711
+
712
+ export class DropCheckConstraintCall extends PostgresOpFactoryCallNode {
713
+ readonly factoryName = 'dropCheckConstraint' as const;
714
+ readonly operationClass = 'destructive' as const;
715
+ readonly schemaName: string;
716
+ readonly tableName: string;
717
+ readonly constraintName: string;
718
+ readonly label: string;
719
+
720
+ constructor(schemaName: string, tableName: string, constraintName: string) {
721
+ super();
722
+ this.schemaName = schemaName;
723
+ this.tableName = tableName;
724
+ this.constraintName = constraintName;
725
+ this.label = `Drop check constraint "${constraintName}" on "${tableName}"`;
726
+ this.freeze();
727
+ }
728
+
729
+ toOp(): Op {
730
+ return dropCheckConstraint(this.schemaName, this.tableName, this.constraintName);
731
+ }
732
+
733
+ renderTypeScript(): string {
734
+ return `dropCheckConstraint(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.constraintName)})`;
735
+ }
736
+ }
737
+
498
738
  // ============================================================================
499
739
  // Indexes
500
740
  // ============================================================================
@@ -776,12 +1016,32 @@ export class CreateSchemaCall extends PostgresOpFactoryCallNode {
776
1016
  this.freeze();
777
1017
  }
778
1018
 
779
- toOp(): Op {
780
- return createSchema(this.schemaName);
1019
+ toOp(lowerer?: Lowerer): Op {
1020
+ if (lowerer === undefined) {
1021
+ throw new Error(
1022
+ `CreateSchemaCall.toOp: a DDL lowerer is required on the Postgres planner path (schema "${this.schemaName}"). Pass the control adapter to createPostgresMigrationPlanner.`,
1023
+ );
1024
+ }
1025
+ const ddlNode = contractFreeDdl.createSchema({ schema: this.schemaName, ifNotExists: true });
1026
+ const { sql } = lowerer.lower(ddlNode, { contract: {} });
1027
+ const schemaName = this.schemaName;
1028
+ return {
1029
+ id: `schema.${schemaName}`,
1030
+ label: `Create schema "${schemaName}"`,
1031
+ operationClass: 'additive',
1032
+ target: { id: 'postgres' },
1033
+ precheck: [],
1034
+ execute: [step(`Create schema "${schemaName}"`, sql)],
1035
+ postcheck: [],
1036
+ };
781
1037
  }
782
1038
 
783
1039
  renderTypeScript(): string {
784
- return `createSchema(${jsonToTsSource(this.schemaName)})`;
1040
+ return `this.createSchema({ schema: ${jsonToTsSource(this.schemaName)} })`;
1041
+ }
1042
+
1043
+ override importRequirements(): readonly ImportRequirement[] {
1044
+ return [];
785
1045
  }
786
1046
  }
787
1047
 
@@ -832,7 +1092,7 @@ export class DataTransformCall extends PostgresOpFactoryCallNode {
832
1092
 
833
1093
  override importRequirements(): readonly ImportRequirement[] {
834
1094
  return [
835
- { moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: 'placeholder' },
1095
+ { moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: 'placeholder' },
836
1096
  {
837
1097
  moduleSpecifier: './end-contract.json',
838
1098
  symbol: 'endContract',
@@ -856,6 +1116,8 @@ export type PostgresOpFactoryCall =
856
1116
  | AddPrimaryKeyCall
857
1117
  | AddForeignKeyCall
858
1118
  | AddUniqueCall
1119
+ | AddCheckConstraintCall
1120
+ | DropCheckConstraintCall
859
1121
  | CreateIndexCall
860
1122
  | DropIndexCall
861
1123
  | DropConstraintCall
@@ -867,22 +1129,3 @@ export type PostgresOpFactoryCall =
867
1129
  | CreateExtensionCall
868
1130
  | CreateSchemaCall
869
1131
  | DataTransformCall;
870
-
871
- /**
872
- * Stable identity key for reconciliation-level dedup.
873
- *
874
- * Two calls whose runtime ops would share the same `id` return the same
875
- * key, so a `Set<string>` can collapse them before they're emitted. The
876
- * current implementation delegates to `toOp().id`, which is the
877
- * authoritative identity; isolating dedup behind this helper lets a future
878
- * pass replace it with an allocation-free computation directly from the
879
- * call's fields without touching call sites.
880
- *
881
- * `DataTransformCall` intentionally has no sensible identity today — it
882
- * throws `PN-MIG-2001` on `toOp()`. Reconciliation never produces one; the
883
- * helper is unspecified for that variant and only meant for
884
- * reconciliation-emitted calls.
885
- */
886
- export function identityKeyFor(call: PostgresOpFactoryCall): string {
887
- return call.toOp().id;
888
- }