@prisma-next/target-postgres 0.13.0-dev.3 → 0.13.0-dev.30

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 (175) 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 +17 -2
  16. package/dist/contract-free.d.mts.map +1 -1
  17. package/dist/contract-free.mjs +3 -3
  18. package/dist/control.d.mts.map +1 -1
  19. package/dist/control.mjs +21 -27
  20. package/dist/control.mjs.map +1 -1
  21. package/dist/{data-transform-D25tLeYU.mjs → data-transform-BOWpliq8.mjs} +9 -17
  22. package/dist/data-transform-BOWpliq8.mjs.map +1 -0
  23. package/dist/{data-transform-DGOqcLrf.d.mts → data-transform-DDgWdB5o.d.mts} +2 -2
  24. package/dist/data-transform-DDgWdB5o.d.mts.map +1 -0
  25. package/dist/data-transform.d.mts +1 -1
  26. package/dist/data-transform.mjs +1 -1
  27. package/dist/{ddl-77SyXgFt.mjs → ddl-DY2R_Yqz.mjs} +18 -3
  28. package/dist/ddl-DY2R_Yqz.mjs.map +1 -0
  29. package/dist/ddl.d.mts +2 -2
  30. package/dist/ddl.mjs +2 -2
  31. package/dist/{descriptor-meta-DKmj-IMN.mjs → descriptor-meta-BKma_hQ5.mjs} +2 -2
  32. package/dist/{descriptor-meta-DKmj-IMN.mjs.map → descriptor-meta-BKma_hQ5.mjs.map} +1 -1
  33. package/dist/descriptor-meta-runtime-e5f2tscJ.mjs +131 -0
  34. package/dist/descriptor-meta-runtime-e5f2tscJ.mjs.map +1 -0
  35. package/dist/{issue-planner-Br0pt1Ea.mjs → issue-planner-DsjB7xDj.mjs} +48 -252
  36. package/dist/issue-planner-DsjB7xDj.mjs.map +1 -0
  37. package/dist/issue-planner.d.mts +8 -11
  38. package/dist/issue-planner.d.mts.map +1 -1
  39. package/dist/issue-planner.mjs +1 -1
  40. package/dist/migration.d.mts +4 -15
  41. package/dist/migration.d.mts.map +1 -1
  42. package/dist/migration.mjs +4 -4
  43. package/dist/{nodes-DZk2JZG3.mjs → nodes-Bbhs2rwj.mjs} +31 -2
  44. package/dist/nodes-Bbhs2rwj.mjs.map +1 -0
  45. package/dist/{nodes-779hmCfL.d.mts → nodes-pLeLgdis.d.mts} +30 -3
  46. package/dist/nodes-pLeLgdis.d.mts.map +1 -0
  47. package/dist/{op-factory-call-DMA86_2D.d.mts → op-factory-call-CdtMyrlU.d.mts} +12 -56
  48. package/dist/op-factory-call-CdtMyrlU.d.mts.map +1 -0
  49. package/dist/{op-factory-call-D2aAUhmS.mjs → op-factory-call-CjR846f7.mjs} +70 -198
  50. package/dist/op-factory-call-CjR846f7.mjs.map +1 -0
  51. package/dist/op-factory-call.d.mts +2 -2
  52. package/dist/op-factory-call.mjs +2 -2
  53. package/dist/pack.d.mts +36 -15
  54. package/dist/pack.d.mts.map +1 -1
  55. package/dist/pack.mjs +1 -1
  56. package/dist/{planner-CAYPJObw.mjs → planner-_FOL4I21.mjs} +25 -45
  57. package/dist/planner-_FOL4I21.mjs.map +1 -0
  58. package/dist/{planner-ddl-builders-Cw2n2llW.mjs → planner-ddl-builders-B2wOwLqI.mjs} +2 -2
  59. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +1 -0
  60. package/dist/planner-ddl-builders.d.mts +4 -4
  61. package/dist/planner-ddl-builders.d.mts.map +1 -1
  62. package/dist/planner-ddl-builders.mjs +1 -1
  63. package/dist/{planner-identity-values-BIpa5p2I.mjs → planner-identity-values-CJPha2Sz.mjs} +3 -9
  64. package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -0
  65. package/dist/planner-identity-values.d.mts +1 -1
  66. package/dist/planner-identity-values.d.mts.map +1 -1
  67. package/dist/planner-identity-values.mjs +1 -1
  68. package/dist/{planner-produced-postgres-migration-NSEhWL0L.mjs → planner-produced-postgres-migration-BmCpyWLJ.mjs} +6 -4
  69. package/dist/planner-produced-postgres-migration-BmCpyWLJ.mjs.map +1 -0
  70. package/dist/{planner-produced-postgres-migration-B4EDvLdz.d.mts → planner-produced-postgres-migration-wLhnJMMA.d.mts} +5 -6
  71. package/dist/planner-produced-postgres-migration-wLhnJMMA.d.mts.map +1 -0
  72. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  73. package/dist/planner-produced-postgres-migration.mjs +1 -1
  74. package/dist/{planner-sql-checks-DAdhnI2c.mjs → planner-sql-checks-CJJtPfDH.mjs} +3 -3
  75. package/dist/planner-sql-checks-CJJtPfDH.mjs.map +1 -0
  76. package/dist/planner-sql-checks.d.mts +2 -2
  77. package/dist/planner-sql-checks.d.mts.map +1 -1
  78. package/dist/planner-sql-checks.mjs +1 -1
  79. package/dist/{planner-type-resolution-836DExFN.mjs → planner-type-resolution-Bt2f_q-F.mjs} +1 -6
  80. package/dist/planner-type-resolution-Bt2f_q-F.mjs.map +1 -0
  81. package/dist/planner.d.mts +4 -4
  82. package/dist/planner.d.mts.map +1 -1
  83. package/dist/planner.mjs +1 -1
  84. package/dist/{postgres-contract-serializer-DYTyXjPf.mjs → postgres-contract-serializer-CyAe8ZFv.mjs} +27 -37
  85. package/dist/postgres-contract-serializer-CyAe8ZFv.mjs.map +1 -0
  86. package/dist/{postgres-migration-DZ_gLUOW.d.mts → postgres-migration-DLXL0GBf.d.mts} +10 -5
  87. package/dist/postgres-migration-DLXL0GBf.d.mts.map +1 -0
  88. package/dist/{postgres-migration-COore9Mz.mjs → postgres-migration-dG-J0aI8.mjs} +7 -3
  89. package/dist/postgres-migration-dG-J0aI8.mjs.map +1 -0
  90. package/dist/{postgres-schema-BuxCxbvB.mjs → postgres-schema-CTKYiTHu.mjs} +30 -13
  91. package/dist/postgres-schema-CTKYiTHu.mjs.map +1 -0
  92. package/dist/{render-ops-BpjstrKQ.mjs → render-ops-BREh1kHe.mjs} +10 -5
  93. package/dist/render-ops-BREh1kHe.mjs.map +1 -0
  94. package/dist/render-ops.d.mts +2 -2
  95. package/dist/render-ops.d.mts.map +1 -1
  96. package/dist/render-ops.mjs +1 -1
  97. package/dist/runtime.d.mts.map +1 -1
  98. package/dist/runtime.mjs +2 -2
  99. package/dist/{shared-DarONYBZ.d.mts → shared-jcsbXxiW.d.mts} +2 -20
  100. package/dist/shared-jcsbXxiW.d.mts.map +1 -0
  101. package/dist/types.d.mts +8 -13
  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/ddl.ts +28 -1
  106. package/src/core/authoring.ts +43 -44
  107. package/src/core/codec-helpers.ts +0 -17
  108. package/src/core/codec-ids.ts +1 -1
  109. package/src/core/codec-type-map.ts +2 -2
  110. package/src/core/codecs.ts +43 -48
  111. package/src/core/ddl/nodes.ts +59 -1
  112. package/src/core/migrations/control-policy.ts +17 -47
  113. package/src/core/migrations/issue-planner.ts +34 -70
  114. package/src/core/migrations/op-factory-call.ts +89 -142
  115. package/src/core/migrations/operations/data-transform.ts +15 -18
  116. package/src/core/migrations/planner-ddl-builders.ts +3 -4
  117. package/src/core/migrations/planner-identity-values.ts +4 -28
  118. package/src/core/migrations/planner-produced-postgres-migration.ts +15 -7
  119. package/src/core/migrations/planner-recipes.ts +2 -6
  120. package/src/core/migrations/planner-sql-checks.ts +2 -6
  121. package/src/core/migrations/planner-strategies.ts +51 -376
  122. package/src/core/migrations/planner-type-resolution.ts +2 -20
  123. package/src/core/migrations/planner.ts +6 -6
  124. package/src/core/migrations/postgres-migration.ts +19 -4
  125. package/src/core/migrations/render-ops.ts +26 -13
  126. package/src/core/migrations/runner.ts +26 -20
  127. package/src/core/postgres-contract-serializer.ts +32 -54
  128. package/src/core/postgres-enum-type-schema.ts +17 -0
  129. package/src/core/postgres-schema.ts +56 -34
  130. package/src/exports/codecs.ts +2 -2
  131. package/src/exports/contract-free.ts +1 -1
  132. package/src/exports/control.ts +0 -22
  133. package/src/exports/ddl.ts +4 -0
  134. package/src/exports/migration.ts +0 -7
  135. package/src/exports/op-factory-call.ts +0 -4
  136. package/src/exports/types.ts +0 -1
  137. package/dist/codec-ids-B1vOchLE.d.mts.map +0 -1
  138. package/dist/codec-ids-CTikp1if.mjs.map +0 -1
  139. package/dist/codecs-CBpEv4s5.d.mts.map +0 -1
  140. package/dist/data-transform-D25tLeYU.mjs.map +0 -1
  141. package/dist/data-transform-DGOqcLrf.d.mts.map +0 -1
  142. package/dist/ddl-77SyXgFt.mjs.map +0 -1
  143. package/dist/descriptor-meta-runtime-My8_s4cs.mjs +0 -130
  144. package/dist/descriptor-meta-runtime-My8_s4cs.mjs.map +0 -1
  145. package/dist/enum-planning-BCyvlFHk.mjs +0 -0
  146. package/dist/enum-planning-BCyvlFHk.mjs.map +0 -1
  147. package/dist/enum-planning.d.mts +0 -86
  148. package/dist/enum-planning.d.mts.map +0 -1
  149. package/dist/enum-planning.mjs +0 -2
  150. package/dist/issue-planner-Br0pt1Ea.mjs.map +0 -1
  151. package/dist/nodes-779hmCfL.d.mts.map +0 -1
  152. package/dist/nodes-DZk2JZG3.mjs.map +0 -1
  153. package/dist/op-factory-call-D2aAUhmS.mjs.map +0 -1
  154. package/dist/op-factory-call-DMA86_2D.d.mts.map +0 -1
  155. package/dist/planner-CAYPJObw.mjs.map +0 -1
  156. package/dist/planner-ddl-builders-Cw2n2llW.mjs.map +0 -1
  157. package/dist/planner-identity-values-BIpa5p2I.mjs.map +0 -1
  158. package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +0 -1
  159. package/dist/planner-produced-postgres-migration-NSEhWL0L.mjs.map +0 -1
  160. package/dist/planner-sql-checks-DAdhnI2c.mjs.map +0 -1
  161. package/dist/planner-type-resolution-836DExFN.mjs.map +0 -1
  162. package/dist/postgres-contract-serializer-DYTyXjPf.mjs.map +0 -1
  163. package/dist/postgres-enum-type-BVn63a89.d.mts +0 -72
  164. package/dist/postgres-enum-type-BVn63a89.d.mts.map +0 -1
  165. package/dist/postgres-enum-type-DPKqCBem.mjs +0 -62
  166. package/dist/postgres-enum-type-DPKqCBem.mjs.map +0 -1
  167. package/dist/postgres-migration-COore9Mz.mjs.map +0 -1
  168. package/dist/postgres-migration-DZ_gLUOW.d.mts.map +0 -1
  169. package/dist/postgres-schema-BuxCxbvB.mjs.map +0 -1
  170. package/dist/render-ops-BpjstrKQ.mjs.map +0 -1
  171. package/dist/shared-DarONYBZ.d.mts.map +0 -1
  172. package/src/core/migrations/enum-planning.ts +0 -213
  173. package/src/core/migrations/operations/enums.ts +0 -114
  174. package/src/core/postgres-enum-type.ts +0 -89
  175. package/src/exports/enum-planning.ts +0 -11
@@ -8,7 +8,7 @@
8
8
  * through `mapIssueToCall` for the default case.
9
9
  */
10
10
 
11
- import type { Contract } from '@prisma-next/contract/types';
11
+ import type { Contract, JsonValue } from '@prisma-next/contract/types';
12
12
  import type {
13
13
  CodecControlHooks,
14
14
  MigrationOperationPolicy,
@@ -19,26 +19,24 @@ import { arraysEqual } from '@prisma-next/family-sql/schema-verify';
19
19
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
20
20
  import type { SchemaIssue } from '@prisma-next/framework-components/control';
21
21
  import type {
22
- PostgresEnumStorageEntry,
23
22
  SqlStorage,
24
23
  StorageColumn,
25
24
  StorageTable,
26
25
  StorageTypeInstance,
27
26
  } from '@prisma-next/sql-contract/types';
28
- import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
27
+ import type { CodecRef, DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
29
28
  import * as contractFree from '@prisma-next/sql-relational-core/contract-free';
30
29
  import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
30
+ import { blindCast } from '@prisma-next/utils/casts';
31
+ import { ifDefined } from '@prisma-next/utils/defined';
31
32
  import type { Result } from '@prisma-next/utils/result';
32
33
  import { notOk, ok } from '@prisma-next/utils/result';
33
- import { PostgresEnumType } from '../postgres-enum-type';
34
- import { isPostgresSchema } from '../postgres-schema';
35
34
  import {
36
35
  AddColumnCall,
37
36
  AddForeignKeyCall,
38
37
  AddPrimaryKeyCall,
39
38
  AddUniqueCall,
40
39
  AlterColumnTypeCall,
41
- CreateEnumTypeCall,
42
40
  CreateIndexCall,
43
41
  CreateSchemaCall,
44
42
  CreateTableCall,
@@ -54,7 +52,7 @@ import {
54
52
  SetDefaultCall,
55
53
  SetNotNullCall,
56
54
  } from './op-factory-call';
57
- import type { ColumnSpec, ForeignKeySpec } from './operations/shared';
55
+ import type { ForeignKeySpec } from './operations/shared';
58
56
  import { buildColumnDefaultSql, buildColumnTypeSql } from './planner-ddl-builders';
59
57
  import { buildExpectedFormatType } from './planner-sql-checks';
60
58
  import {
@@ -65,22 +63,10 @@ import {
65
63
  type StrategyContext,
66
64
  tableAt,
67
65
  } from './planner-strategies';
66
+ import { resolveColumnTypeMetadata } from './planner-type-resolution';
68
67
 
69
68
  export type { CallMigrationStrategy, StrategyContext };
70
69
 
71
- /**
72
- * Finds a type entry by explicit namespace coordinate. Reads the named
73
- * namespace's `enum` slot directly — never scans other namespaces.
74
- */
75
- function locateNamespaceTypeInStorage(
76
- storage: SqlStorage,
77
- namespaceId: string,
78
- typeName: string,
79
- ): unknown {
80
- const ns = storage.namespaces[namespaceId];
81
- return isPostgresSchema(ns) ? ns.entries.type[typeName] : undefined;
82
- }
83
-
84
70
  // ============================================================================
85
71
  // Issue kind ordering (dependency order)
86
72
  // ============================================================================
@@ -165,7 +151,7 @@ export interface IssuePlannerOptions {
165
151
  readonly fromContract: Contract<SqlStorage> | null;
166
152
  readonly schemaName: string;
167
153
  readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;
168
- readonly storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>;
154
+ readonly storageTypes: Readonly<Record<string, StorageTypeInstance>>;
169
155
  /**
170
156
  * Current database schema IR. Strategies read this to detect whether a
171
157
  * structure already exists (e.g. `buildSchemaLookupMap` for shared-temp-
@@ -192,31 +178,35 @@ export interface IssuePlannerValue {
192
178
  readonly calls: readonly PostgresOpFactoryCall[];
193
179
  }
194
180
 
195
- function toColumnSpec(
196
- name: string,
197
- column: StorageColumn,
198
- codecHooks: ReadonlyMap<string, CodecControlHooks>,
199
- storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>,
200
- ): ColumnSpec {
201
- return {
202
- name,
203
- typeSql: buildColumnTypeSql(column, codecHooks, storageTypes),
204
- defaultSql: buildColumnDefaultSql(column.default, column),
205
- nullable: column.nullable,
206
- };
207
- }
208
-
209
181
  function toDdlColumn(
210
182
  name: string,
211
183
  column: StorageColumn,
212
184
  codecHooks: ReadonlyMap<string, CodecControlHooks>,
213
- storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>,
185
+ storageTypes: Readonly<Record<string, StorageTypeInstance>>,
214
186
  ): DdlColumn {
215
187
  const typeSql = buildColumnTypeSql(column, codecHooks, storageTypes);
216
188
  const ddlDefault = postgresDefaultToDdlColumnDefault(column.default);
189
+ const resolved = resolveColumnTypeMetadata(
190
+ column,
191
+ storageTypes as Record<string, StorageTypeInstance>,
192
+ );
193
+ const codecRef: CodecRef | undefined = resolved.codecId
194
+ ? {
195
+ codecId: resolved.codecId,
196
+ ...(resolved.typeParams !== undefined
197
+ ? {
198
+ typeParams: blindCast<
199
+ JsonValue,
200
+ 'resolved.typeParams is JsonValue-shaped storage metadata; the narrowed (non-undefined) value lands in CodecRef.typeParams which is JsonValue'
201
+ >(resolved.typeParams),
202
+ }
203
+ : {}),
204
+ }
205
+ : undefined;
217
206
  return contractFree.col(name, typeSql, {
218
207
  ...(!column.nullable ? { notNull: true } : {}),
219
- ...(ddlDefault ? { default: ddlDefault } : {}),
208
+ ...ifDefined('default', ddlDefault),
209
+ ...ifDefined('codecRef', codecRef),
220
210
  });
221
211
  }
222
212
 
@@ -342,7 +332,7 @@ function mapIssueToCall(
342
332
  new AddColumnCall(
343
333
  tableSchema(issue),
344
334
  issue.table,
345
- toColumnSpec(issue.column, column, codecHooks, storageTypes),
335
+ toDdlColumn(issue.column, column, codecHooks, storageTypes),
346
336
  ),
347
337
  ]);
348
338
  }
@@ -475,10 +465,7 @@ function mapIssueToCall(
475
465
  ),
476
466
  );
477
467
  const hooksMap = codecHooks as Map<string, CodecControlHooks>;
478
- const typesMap = storageTypes as Record<
479
- string,
480
- StorageTypeInstance | PostgresEnumStorageEntry
481
- >;
468
+ const typesMap = storageTypes as Record<string, StorageTypeInstance>;
482
469
  const qualifiedTargetType = buildColumnTypeSql(column, hooksMap, typesMap, false);
483
470
  const formatTypeExpected = buildExpectedFormatType(column, hooksMap, typesMap);
484
471
  return ok([
@@ -666,14 +653,7 @@ function mapIssueToCall(
666
653
  case 'type_missing': {
667
654
  if (!issue.typeName)
668
655
  return notOk(issueConflict('unsupportedOperation', 'Type missing issue has no typeName'));
669
- // Codec aliases live in storage.types; enum types live in namespace.entries.type.
670
- // Check types first; fall back to the namespace-keyed enum slot using the
671
- // issue's namespace coordinate (populated by the verifier for enum-related
672
- // issues per the BaseSchemaIssue.namespaceId contract).
673
- const namespaceId = resolveNamespaceIdForIssue(issue);
674
- const typeInstance: unknown =
675
- ctx.toContract.storage.types?.[issue.typeName] ??
676
- locateNamespaceTypeInStorage(ctx.toContract.storage, namespaceId, issue.typeName);
656
+ const typeInstance = ctx.toContract.storage.types?.[issue.typeName];
677
657
  if (!typeInstance) {
678
658
  return notOk(
679
659
  issueConflict(
@@ -682,22 +662,10 @@ function mapIssueToCall(
682
662
  ),
683
663
  );
684
664
  }
685
- if (typeInstance instanceof PostgresEnumType) {
686
- const ddlSchema = resolveDdlSchemaForNamespace(ctx, namespaceId);
687
- return ok([
688
- new CreateEnumTypeCall(
689
- ddlSchema,
690
- issue.typeName,
691
- typeInstance.values,
692
- typeInstance.nativeType,
693
- ),
694
- ]);
695
- }
696
- const codecInstance = typeInstance as StorageTypeInstance;
697
665
  return notOk(
698
666
  issueConflict(
699
667
  'unsupportedOperation',
700
- `Type "${issue.typeName}" uses codec "${codecInstance.codecId}" — only enum types are supported`,
668
+ `Type "${issue.typeName}" uses codec "${typeInstance.codecId}" — only value-set types are supported`,
701
669
  ),
702
670
  );
703
671
  }
@@ -744,10 +712,6 @@ function classifyCall(call: PostgresOpFactoryCall): CallCategory {
744
712
  switch (call.factoryName) {
745
713
  case 'createExtension':
746
714
  case 'createSchema':
747
- case 'createEnumType':
748
- case 'addEnumValues':
749
- case 'dropEnumType':
750
- case 'renameType':
751
715
  return 'dep';
752
716
  case 'dropTable':
753
717
  case 'dropColumn':
@@ -971,10 +935,10 @@ export function planIssues(
971
935
  return notOk(conflicts);
972
936
  }
973
937
 
974
- // Recipe strategies (`nativeEnumPlanCallStrategy`,
975
- // `notNullBackfillCallStrategy`, etc.) emit a cohesive sequence that must
938
+ // Recipe strategies (`notNullBackfillCallStrategy`,
939
+ // `nullableTighteningCallStrategy`, etc.) emit a cohesive sequence that must
976
940
  // stay contiguous. They are inserted at a single pattern slot. Non-recipe
977
- // pattern strategies (`dependencyInstallCallStrategy`,
941
+ // pattern strategies (`checkConstraintPlanCallStrategy`,
978
942
  // `storageTypePlanCallStrategy`, `notNullAddColumnCallStrategy`) produce
979
943
  // individually classifiable calls that slot into DDL buckets alongside
980
944
  // default-mapped calls.
@@ -22,7 +22,7 @@
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
+ import type { ExecuteRequestLowerer, Lowerer } from '@prisma-next/family-sql/control-adapter';
26
26
  import type {
27
27
  OpFactoryCall as FrameworkOpFactoryCall,
28
28
  MigrationOperationClass,
@@ -36,11 +36,11 @@ import type {
36
36
  import { FunctionColumnDefault, LiteralColumnDefault } from '@prisma-next/sql-relational-core/ast';
37
37
  import { type ImportRequirement, jsonToTsSource, TsExpression } from '@prisma-next/ts-render';
38
38
  import { blindCast } from '@prisma-next/utils/casts';
39
+ import { ifDefined } from '@prisma-next/utils/defined';
39
40
  import * as contractFreeDdl from '../../contract-free/ddl';
40
41
  import { escapeLiteral, quoteIdentifier } from '../sql-utils';
41
42
  import type { PostgresColumnDefault } from '../types';
42
43
  import {
43
- addColumn,
44
44
  alterColumnType,
45
45
  dropColumn,
46
46
  dropDefault,
@@ -57,12 +57,11 @@ import {
57
57
  dropConstraint,
58
58
  } from './operations/constraints';
59
59
  import { createExtension } from './operations/dependencies';
60
- import { addEnumValues, createEnumType, dropEnumType, renameType } from './operations/enums';
61
60
  import { createIndex, dropIndex } from './operations/indexes';
62
- import type { ColumnSpec, ForeignKeySpec } from './operations/shared';
61
+ import type { ForeignKeySpec } from './operations/shared';
63
62
  import { step, targetDetails } from './operations/shared';
64
63
  import { dropTable } from './operations/tables';
65
- import { toRegclassLiteral } from './planner-sql-checks';
64
+ import { columnExistsCheck, toRegclassLiteral } from './planner-sql-checks';
66
65
  import type { PostgresPlanTargetDetails } from './planner-target-details';
67
66
 
68
67
  type Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
@@ -81,11 +80,15 @@ type Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
81
80
  // transitive package on disk.
82
81
  const POSTGRES_MIGRATION_FACADE = '@prisma-next/postgres/migration';
83
82
 
83
+ function boundSchema(schemaName: string): string | undefined {
84
+ return schemaName === UNBOUND_NAMESPACE_ID ? undefined : schemaName;
85
+ }
86
+
84
87
  abstract class PostgresOpFactoryCallNode extends TsExpression implements FrameworkOpFactoryCall {
85
88
  abstract readonly factoryName: string;
86
89
  abstract readonly operationClass: MigrationOperationClass;
87
90
  abstract readonly label: string;
88
- abstract toOp(lowerer?: Lowerer): Op;
91
+ abstract toOp(lowerer?: Lowerer): Op | Promise<Op>;
89
92
 
90
93
  importRequirements(): readonly ImportRequirement[] {
91
94
  return [{ moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: this.factoryName }];
@@ -213,19 +216,19 @@ export class CreateTableCall extends PostgresOpFactoryCallNode {
213
216
  this.freeze();
214
217
  }
215
218
 
216
- toOp(lowerer?: Lowerer): Op {
219
+ async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
217
220
  if (lowerer === undefined) {
218
221
  throw new Error(
219
222
  `CreateTableCall.toOp: a DDL lowerer is required on the Postgres planner path (table "${this.tableName}"). Pass the control adapter to createPostgresMigrationPlanner.`,
220
223
  );
221
224
  }
222
225
  const ddlNode = contractFreeDdl.createTable({
223
- ...(this.schemaName !== UNBOUND_NAMESPACE_ID ? { schema: this.schemaName } : {}),
226
+ ...ifDefined('schema', boundSchema(this.schemaName)),
224
227
  table: this.tableName,
225
228
  columns: this.columns,
226
- ...(this.constraints ? { constraints: this.constraints } : {}),
229
+ ...ifDefined('constraints', this.constraints),
227
230
  });
228
- const { sql } = lowerer.lower(ddlNode, { contract: {} });
231
+ const statement = await lowerer.lowerToExecuteRequest(ddlNode);
229
232
  const schemaName = this.schemaName;
230
233
  const tableName = this.tableName;
231
234
  return {
@@ -240,7 +243,13 @@ export class CreateTableCall extends PostgresOpFactoryCallNode {
240
243
  `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NULL`,
241
244
  ),
242
245
  ],
243
- execute: [step(`create table "${tableName}"`, sql)],
246
+ execute: [
247
+ {
248
+ description: `create table "${tableName}"`,
249
+ sql: statement.sql,
250
+ params: statement.params ?? [],
251
+ },
252
+ ],
244
253
  postcheck: [
245
254
  step(
246
255
  `verify table "${tableName}" exists`,
@@ -315,10 +324,10 @@ export class AddColumnCall extends PostgresOpFactoryCallNode {
315
324
  readonly operationClass = 'additive' as const;
316
325
  readonly schemaName: string;
317
326
  readonly tableName: string;
318
- readonly column: ColumnSpec;
327
+ readonly column: DdlColumn;
319
328
  readonly label: string;
320
329
 
321
- constructor(schemaName: string, tableName: string, column: ColumnSpec) {
330
+ constructor(schemaName: string, tableName: string, column: DdlColumn) {
322
331
  super();
323
332
  this.schemaName = schemaName;
324
333
  this.tableName = tableName;
@@ -327,12 +336,65 @@ export class AddColumnCall extends PostgresOpFactoryCallNode {
327
336
  this.freeze();
328
337
  }
329
338
 
330
- toOp(): Op {
331
- return addColumn(this.schemaName, this.tableName, this.column);
339
+ async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
340
+ if (lowerer === undefined) {
341
+ throw new Error(
342
+ `AddColumnCall.toOp: a DDL lowerer is required on the Postgres planner path (column "${this.column.name}" on table "${this.tableName}"). Pass the control adapter to createPostgresMigrationPlanner.`,
343
+ );
344
+ }
345
+ const ddlNode = contractFreeDdl.alterTable({
346
+ ...ifDefined('schema', boundSchema(this.schemaName)),
347
+ table: this.tableName,
348
+ actions: [contractFreeDdl.addColumnAction(this.column)],
349
+ });
350
+ const statement = await lowerer.lowerToExecuteRequest(ddlNode);
351
+ const schemaName = this.schemaName;
352
+ const tableName = this.tableName;
353
+ const columnName = this.column.name;
354
+ return {
355
+ id: `column.${tableName}.${columnName}`,
356
+ label: `Add column "${columnName}" to "${tableName}"`,
357
+ operationClass: 'additive',
358
+ target: targetDetails('column', columnName, schemaName, tableName),
359
+ precheck: [
360
+ step(
361
+ `ensure column "${columnName}" is missing`,
362
+ columnExistsCheck({
363
+ schema: schemaName,
364
+ table: tableName,
365
+ column: columnName,
366
+ exists: false,
367
+ }),
368
+ ),
369
+ ],
370
+ execute: [step(`add column "${columnName}"`, statement.sql)],
371
+ postcheck: [
372
+ step(
373
+ `verify column "${columnName}" exists`,
374
+ columnExistsCheck({ schema: schemaName, table: tableName, column: columnName }),
375
+ ),
376
+ ],
377
+ };
332
378
  }
333
379
 
334
380
  renderTypeScript(): string {
335
- return `addColumn(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.column)})`;
381
+ const opts: string[] = [];
382
+ if (this.schemaName !== UNBOUND_NAMESPACE_ID) {
383
+ opts.push(`schema: ${jsonToTsSource(this.schemaName)}`);
384
+ }
385
+ opts.push(`table: ${jsonToTsSource(this.tableName)}`);
386
+ opts.push(`column: ${renderDdlColumnAsTsCall(this.column)}`);
387
+ return `this.addColumn({ ${opts.join(', ')} })`;
388
+ }
389
+
390
+ override importRequirements(): readonly ImportRequirement[] {
391
+ const req: ImportRequirement[] = [
392
+ { moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: 'col' },
393
+ ];
394
+ for (const sym of defaultImportSymbols([this.column])) {
395
+ req.push({ moduleSpecifier: POSTGRES_MIGRATION_FACADE, symbol: sym });
396
+ }
397
+ return req;
336
398
  }
337
399
  }
338
400
 
@@ -746,8 +808,8 @@ export class CreateIndexCall extends PostgresOpFactoryCallNode {
746
808
  readonly tableName: string;
747
809
  readonly indexName: string;
748
810
  readonly columns: readonly string[];
749
- // Named indexType (not typeName) to avoid collision with CreateEnumTypeCall.typeName,
750
- // which identifies a CREATE TYPE target and is read by `locationForCall` in issue-planner.ts.
811
+ // Named indexType (not typeName): `locationForCall` in issue-planner.ts reads
812
+ // a call's `typeName` as a CREATE TYPE target location, which an index is not.
751
813
  readonly indexType: string | undefined;
752
814
  readonly options: Record<string, unknown> | undefined;
753
815
  readonly label: string;
@@ -820,123 +882,6 @@ export class DropIndexCall extends PostgresOpFactoryCallNode {
820
882
  }
821
883
  }
822
884
 
823
- // ============================================================================
824
- // Enum types
825
- // ============================================================================
826
-
827
- export class CreateEnumTypeCall extends PostgresOpFactoryCallNode {
828
- readonly factoryName = 'createEnumType' as const;
829
- readonly operationClass = 'additive' as const;
830
- readonly schemaName: string;
831
- readonly typeName: string;
832
- readonly nativeType: string;
833
- readonly values: readonly string[];
834
- readonly label: string;
835
-
836
- constructor(
837
- schemaName: string,
838
- typeName: string,
839
- values: readonly string[],
840
- nativeType: string = typeName,
841
- ) {
842
- super();
843
- this.schemaName = schemaName;
844
- this.typeName = typeName;
845
- this.nativeType = nativeType;
846
- this.values = values;
847
- this.label = `Create enum type "${typeName}"`;
848
- this.freeze();
849
- }
850
-
851
- toOp(): Op {
852
- return createEnumType(this.schemaName, this.typeName, this.values, this.nativeType);
853
- }
854
-
855
- renderTypeScript(): string {
856
- const nativeArg =
857
- this.nativeType === this.typeName ? '' : `, ${jsonToTsSource(this.nativeType)}`;
858
- return `createEnumType(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.typeName)}, ${jsonToTsSource(this.values)}${nativeArg})`;
859
- }
860
- }
861
-
862
- export class AddEnumValuesCall extends PostgresOpFactoryCallNode {
863
- readonly factoryName = 'addEnumValues' as const;
864
- readonly operationClass = 'additive' as const;
865
- readonly schemaName: string;
866
- readonly typeName: string;
867
- readonly nativeType: string;
868
- readonly values: readonly string[];
869
- readonly label: string;
870
-
871
- constructor(schemaName: string, typeName: string, nativeType: string, values: readonly string[]) {
872
- super();
873
- this.schemaName = schemaName;
874
- this.typeName = typeName;
875
- this.nativeType = nativeType;
876
- this.values = values;
877
- this.label = `Add values to enum type "${typeName}": ${values.join(', ')}`;
878
- this.freeze();
879
- }
880
-
881
- toOp(): Op {
882
- return addEnumValues(this.schemaName, this.typeName, this.nativeType, this.values);
883
- }
884
-
885
- renderTypeScript(): string {
886
- return `addEnumValues(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.typeName)}, ${jsonToTsSource(this.nativeType)}, ${jsonToTsSource(this.values)})`;
887
- }
888
- }
889
-
890
- export class DropEnumTypeCall extends PostgresOpFactoryCallNode {
891
- readonly factoryName = 'dropEnumType' as const;
892
- readonly operationClass = 'destructive' as const;
893
- readonly schemaName: string;
894
- readonly typeName: string;
895
- readonly label: string;
896
-
897
- constructor(schemaName: string, typeName: string) {
898
- super();
899
- this.schemaName = schemaName;
900
- this.typeName = typeName;
901
- this.label = `Drop enum type "${typeName}"`;
902
- this.freeze();
903
- }
904
-
905
- toOp(): Op {
906
- return dropEnumType(this.schemaName, this.typeName);
907
- }
908
-
909
- renderTypeScript(): string {
910
- return `dropEnumType(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.typeName)})`;
911
- }
912
- }
913
-
914
- export class RenameTypeCall extends PostgresOpFactoryCallNode {
915
- readonly factoryName = 'renameType' as const;
916
- readonly operationClass = 'destructive' as const;
917
- readonly schemaName: string;
918
- readonly fromName: string;
919
- readonly toName: string;
920
- readonly label: string;
921
-
922
- constructor(schemaName: string, fromName: string, toName: string) {
923
- super();
924
- this.schemaName = schemaName;
925
- this.fromName = fromName;
926
- this.toName = toName;
927
- this.label = `Rename type "${fromName}" to "${toName}"`;
928
- this.freeze();
929
- }
930
-
931
- toOp(): Op {
932
- return renameType(this.schemaName, this.fromName, this.toName);
933
- }
934
-
935
- renderTypeScript(): string {
936
- return `renameType(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.fromName)}, ${jsonToTsSource(this.toName)})`;
937
- }
938
- }
939
-
940
885
  // ============================================================================
941
886
  // Raw SQL
942
887
  // ============================================================================
@@ -1016,14 +961,14 @@ export class CreateSchemaCall extends PostgresOpFactoryCallNode {
1016
961
  this.freeze();
1017
962
  }
1018
963
 
1019
- toOp(lowerer?: Lowerer): Op {
964
+ async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
1020
965
  if (lowerer === undefined) {
1021
966
  throw new Error(
1022
967
  `CreateSchemaCall.toOp: a DDL lowerer is required on the Postgres planner path (schema "${this.schemaName}"). Pass the control adapter to createPostgresMigrationPlanner.`,
1023
968
  );
1024
969
  }
1025
970
  const ddlNode = contractFreeDdl.createSchema({ schema: this.schemaName, ifNotExists: true });
1026
- const { sql } = lowerer.lower(ddlNode, { contract: {} });
971
+ const statement = await lowerer.lowerToExecuteRequest(ddlNode);
1027
972
  const schemaName = this.schemaName;
1028
973
  return {
1029
974
  id: `schema.${schemaName}`,
@@ -1031,7 +976,13 @@ export class CreateSchemaCall extends PostgresOpFactoryCallNode {
1031
976
  operationClass: 'additive',
1032
977
  target: { id: 'postgres' },
1033
978
  precheck: [],
1034
- execute: [step(`Create schema "${schemaName}"`, sql)],
979
+ execute: [
980
+ {
981
+ description: `Create schema "${schemaName}"`,
982
+ sql: statement.sql,
983
+ params: statement.params ?? [],
984
+ },
985
+ ],
1035
986
  postcheck: [],
1036
987
  };
1037
988
  }
@@ -1121,10 +1072,6 @@ export type PostgresOpFactoryCall =
1121
1072
  | CreateIndexCall
1122
1073
  | DropIndexCall
1123
1074
  | DropConstraintCall
1124
- | CreateEnumTypeCall
1125
- | AddEnumValuesCall
1126
- | DropEnumTypeCall
1127
- | RenameTypeCall
1128
1075
  | RawSqlCall
1129
1076
  | CreateExtensionCall
1130
1077
  | CreateSchemaCall
@@ -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,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 =