@prisma-next/target-postgres 0.13.0-dev.28 → 0.13.0-dev.29

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 (128) hide show
  1. package/dist/{codec-ids-C_-Hj6bL.mjs → codec-ids-BvytN2P8.mjs} +2 -3
  2. package/dist/codec-ids-BvytN2P8.mjs.map +1 -0
  3. package/dist/{codec-ids-BzrFF-I4.d.mts → codec-ids-CnXu9Qy3.d.mts} +2 -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-B0WT0obB.d.mts → codec-types-DHCkwPKE.d.mts} +2 -3
  8. package/dist/codec-types-DHCkwPKE.d.mts.map +1 -0
  9. package/dist/codec-types.d.mts +1 -1
  10. package/dist/{codecs-CX56Smsj.d.mts → codecs--0A5_4Bq.d.mts} +3 -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 +2 -38
  14. package/dist/codecs.mjs.map +1 -1
  15. package/dist/contract-free.mjs +1 -1
  16. package/dist/control.d.mts.map +1 -1
  17. package/dist/control.mjs +7 -10
  18. package/dist/control.mjs.map +1 -1
  19. package/dist/{descriptor-meta-C7O6XHfh.mjs → descriptor-meta-BKma_hQ5.mjs} +2 -2
  20. package/dist/{descriptor-meta-C7O6XHfh.mjs.map → descriptor-meta-BKma_hQ5.mjs.map} +1 -1
  21. package/dist/{descriptor-meta-runtime-BToWdas9.mjs → descriptor-meta-runtime-e5f2tscJ.mjs} +2 -39
  22. package/dist/descriptor-meta-runtime-e5f2tscJ.mjs.map +1 -0
  23. package/dist/{issue-planner-CK-XWGB0.mjs → issue-planner-DsjB7xDj.mjs} +17 -227
  24. package/dist/issue-planner-DsjB7xDj.mjs.map +1 -0
  25. package/dist/issue-planner.d.mts +8 -11
  26. package/dist/issue-planner.d.mts.map +1 -1
  27. package/dist/issue-planner.mjs +1 -1
  28. package/dist/migration.d.mts +1 -11
  29. package/dist/migration.d.mts.map +1 -1
  30. package/dist/migration.mjs +3 -3
  31. package/dist/{op-factory-call-DxjpXw-A.d.mts → op-factory-call-CdtMyrlU.d.mts} +3 -48
  32. package/dist/{op-factory-call-DxjpXw-A.d.mts.map → op-factory-call-CdtMyrlU.d.mts.map} +1 -1
  33. package/dist/{op-factory-call-CHvtj70z.mjs → op-factory-call-CjR846f7.mjs} +4 -159
  34. package/dist/op-factory-call-CjR846f7.mjs.map +1 -0
  35. package/dist/op-factory-call.d.mts +2 -2
  36. package/dist/op-factory-call.mjs +2 -2
  37. package/dist/pack.d.mts +2 -18
  38. package/dist/pack.d.mts.map +1 -1
  39. package/dist/pack.mjs +1 -1
  40. package/dist/{planner-4FbY_95H.mjs → planner-_FOL4I21.mjs} +9 -41
  41. package/dist/planner-_FOL4I21.mjs.map +1 -0
  42. package/dist/{planner-ddl-builders-Cw2n2llW.mjs → planner-ddl-builders-B2wOwLqI.mjs} +2 -2
  43. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +1 -0
  44. package/dist/planner-ddl-builders.d.mts +4 -4
  45. package/dist/planner-ddl-builders.d.mts.map +1 -1
  46. package/dist/planner-ddl-builders.mjs +1 -1
  47. package/dist/{planner-identity-values-BIpa5p2I.mjs → planner-identity-values-CJPha2Sz.mjs} +3 -9
  48. package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -0
  49. package/dist/planner-identity-values.d.mts +1 -1
  50. package/dist/planner-identity-values.d.mts.map +1 -1
  51. package/dist/planner-identity-values.mjs +1 -1
  52. package/dist/{planner-produced-postgres-migration-qfkCkGVe.mjs → planner-produced-postgres-migration-BmCpyWLJ.mjs} +2 -2
  53. package/dist/{planner-produced-postgres-migration-qfkCkGVe.mjs.map → planner-produced-postgres-migration-BmCpyWLJ.mjs.map} +1 -1
  54. package/dist/planner-produced-postgres-migration.mjs +1 -1
  55. package/dist/{planner-sql-checks-BLgdXLsA.mjs → planner-sql-checks-CJJtPfDH.mjs} +3 -3
  56. package/dist/planner-sql-checks-CJJtPfDH.mjs.map +1 -0
  57. package/dist/planner-sql-checks.d.mts +2 -2
  58. package/dist/planner-sql-checks.d.mts.map +1 -1
  59. package/dist/planner-sql-checks.mjs +1 -1
  60. package/dist/{planner-type-resolution-836DExFN.mjs → planner-type-resolution-Bt2f_q-F.mjs} +1 -6
  61. package/dist/planner-type-resolution-Bt2f_q-F.mjs.map +1 -0
  62. package/dist/planner.d.mts.map +1 -1
  63. package/dist/planner.mjs +1 -1
  64. package/dist/{postgres-contract-serializer-CTxVcCVW.mjs → postgres-contract-serializer-CyAe8ZFv.mjs} +12 -29
  65. package/dist/postgres-contract-serializer-CyAe8ZFv.mjs.map +1 -0
  66. package/dist/{postgres-migration-DF5ApLqQ.mjs → postgres-migration-dG-J0aI8.mjs} +2 -2
  67. package/dist/{postgres-migration-DF5ApLqQ.mjs.map → postgres-migration-dG-J0aI8.mjs.map} +1 -1
  68. package/dist/{postgres-schema-C7c9rhGk.mjs → postgres-schema-CTKYiTHu.mjs} +7 -21
  69. package/dist/postgres-schema-CTKYiTHu.mjs.map +1 -0
  70. package/dist/runtime.d.mts +0 -2
  71. package/dist/runtime.d.mts.map +1 -1
  72. package/dist/runtime.mjs +2 -2
  73. package/dist/types.d.mts +5 -25
  74. package/dist/types.d.mts.map +1 -1
  75. package/dist/types.mjs +2 -4
  76. package/package.json +17 -18
  77. package/src/core/authoring.ts +1 -44
  78. package/src/core/codec-helpers.ts +0 -17
  79. package/src/core/codec-ids.ts +0 -1
  80. package/src/core/codec-type-map.ts +0 -2
  81. package/src/core/codecs.ts +0 -49
  82. package/src/core/migrations/control-policy.ts +3 -45
  83. package/src/core/migrations/issue-planner.ts +9 -52
  84. package/src/core/migrations/op-factory-call.ts +2 -124
  85. package/src/core/migrations/planner-ddl-builders.ts +3 -4
  86. package/src/core/migrations/planner-identity-values.ts +4 -28
  87. package/src/core/migrations/planner-recipes.ts +2 -6
  88. package/src/core/migrations/planner-sql-checks.ts +2 -6
  89. package/src/core/migrations/planner-strategies.ts +13 -353
  90. package/src/core/migrations/planner-type-resolution.ts +2 -20
  91. package/src/core/migrations/planner.ts +0 -2
  92. package/src/core/migrations/runner.ts +0 -4
  93. package/src/core/postgres-contract-serializer.ts +9 -67
  94. package/src/core/postgres-schema.ts +6 -37
  95. package/src/exports/codecs.ts +0 -2
  96. package/src/exports/control.ts +0 -15
  97. package/src/exports/migration.ts +0 -6
  98. package/src/exports/op-factory-call.ts +0 -4
  99. package/src/exports/types.ts +0 -2
  100. package/dist/codec-ids-BzrFF-I4.d.mts.map +0 -1
  101. package/dist/codec-ids-C_-Hj6bL.mjs.map +0 -1
  102. package/dist/codec-types-B0WT0obB.d.mts.map +0 -1
  103. package/dist/codecs-CX56Smsj.d.mts.map +0 -1
  104. package/dist/descriptor-meta-runtime-BToWdas9.mjs.map +0 -1
  105. package/dist/enum-planning-D8z4FH7y.mjs +0 -129
  106. package/dist/enum-planning-D8z4FH7y.mjs.map +0 -1
  107. package/dist/enum-planning.d.mts +0 -92
  108. package/dist/enum-planning.d.mts.map +0 -1
  109. package/dist/enum-planning.mjs +0 -2
  110. package/dist/issue-planner-CK-XWGB0.mjs.map +0 -1
  111. package/dist/op-factory-call-CHvtj70z.mjs.map +0 -1
  112. package/dist/planner-4FbY_95H.mjs.map +0 -1
  113. package/dist/planner-ddl-builders-Cw2n2llW.mjs.map +0 -1
  114. package/dist/planner-identity-values-BIpa5p2I.mjs.map +0 -1
  115. package/dist/planner-sql-checks-BLgdXLsA.mjs.map +0 -1
  116. package/dist/planner-type-resolution-836DExFN.mjs.map +0 -1
  117. package/dist/postgres-contract-serializer-CTxVcCVW.mjs.map +0 -1
  118. package/dist/postgres-enum-type-BVn63a89.d.mts +0 -72
  119. package/dist/postgres-enum-type-BVn63a89.d.mts.map +0 -1
  120. package/dist/postgres-enum-type-DPKqCBem.mjs +0 -62
  121. package/dist/postgres-enum-type-DPKqCBem.mjs.map +0 -1
  122. package/dist/postgres-enum-type-schema-DZBTtvBF.mjs +0 -20
  123. package/dist/postgres-enum-type-schema-DZBTtvBF.mjs.map +0 -1
  124. package/dist/postgres-schema-C7c9rhGk.mjs.map +0 -1
  125. package/src/core/migrations/enum-planning.ts +0 -217
  126. package/src/core/migrations/operations/enums.ts +0 -114
  127. package/src/core/postgres-enum-type.ts +0 -89
  128. package/src/exports/enum-planning.ts +0 -10
@@ -11,7 +11,7 @@
11
11
  * two journeys differ only in `policy.allowedOperationClasses`:
12
12
  *
13
13
  * - When `'data'` is in the policy, data-safe strategies (NOT NULL backfill,
14
- * nullability tightening, unsafe type changes, enum shrink/rebuild) emit
14
+ * nullability tightening, unsafe type changes) emit
15
15
  * `DataTransformCall` placeholders that the user fills in.
16
16
  * - When `'data'` is excluded, those strategies short-circuit so the
17
17
  * downstream walk-schema strategies (codec-hook type ops and temp-default
@@ -29,8 +29,6 @@ import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-comp
29
29
  import type { SchemaIssue } from '@prisma-next/framework-components/control';
30
30
  import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
31
31
  import {
32
- isPostgresEnumStorageEntry,
33
- type PostgresEnumStorageEntry,
34
32
  type SqlStorage,
35
33
  StorageTable,
36
34
  type StorageTypeInstance,
@@ -41,26 +39,16 @@ import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
41
39
  import { blindCast } from '@prisma-next/utils/casts';
42
40
  import { ifDefined } from '@prisma-next/utils/defined';
43
41
  import type { JsonValue } from '@prisma-next/utils/json';
44
- import { PostgresEnumType } from '../postgres-enum-type';
45
42
  import { isPostgresSchema } from '../postgres-schema';
46
- import {
47
- determineEnumDiff,
48
- readExistingEnumValues,
49
- resolveDdlSchemaForNamespaceStorage,
50
- } from './enum-planning';
51
43
  import {
52
44
  AddCheckConstraintCall,
53
45
  AddColumnCall,
54
- AddEnumValuesCall,
55
46
  AlterColumnTypeCall,
56
- CreateEnumTypeCall,
57
47
  DataTransformCall,
58
48
  DropCheckConstraintCall,
59
- DropEnumTypeCall,
60
49
  type PostgresOpFactoryCall,
61
50
  postgresDefaultToDdlColumnDefault,
62
51
  RawSqlCall,
63
- RenameTypeCall,
64
52
  SetNotNullCall,
65
53
  } from './op-factory-call';
66
54
  import { buildAddColumnSql, buildColumnTypeSql } from './planner-ddl-builders';
@@ -80,8 +68,6 @@ import {
80
68
  import { buildTargetDetails, type PostgresPlanTargetDetails } from './planner-target-details';
81
69
  import { resolveColumnTypeMetadata } from './planner-type-resolution';
82
70
 
83
- const REBUILD_SUFFIX = '__prisma_next_new';
84
-
85
71
  /**
86
72
  * Look up a storage table by its explicit namespace coordinate. Returns
87
73
  * `undefined` when the namespace has no table by that name (or no such
@@ -133,63 +119,6 @@ export function resolveDdlSchemaForNamespace(ctx: StrategyContext, namespaceId:
133
119
  return namespaceId;
134
120
  }
135
121
 
136
- /** Default Postgres enum landing namespace — where contract-level (`types:`)
137
- * enums are placed by the authoring builder when no explicit namespace is
138
- * given. Mirrors `POSTGRES_ENUM_NAMESPACE_ID` in the contract-ts builder. */
139
- const DEFAULT_ENUM_NAMESPACE_ID = 'public';
140
-
141
- function namespaceHasEnum(storage: SqlStorage, namespaceId: string, typeName: string): boolean {
142
- const ns = storage.namespaces[namespaceId];
143
- if (!isPostgresSchema(ns)) return false;
144
- return ns.type[typeName] !== undefined;
145
- }
146
-
147
- /**
148
- * Resolves which namespace's enum a column's bare `typeRef` binds to.
149
- *
150
- * Columns carry a bare (non-namespace-qualified) `typeRef`; the enum it names
151
- * may live in a different namespace than the column's own (the authoring
152
- * builder places contract-level `types:` enums in the default `public`
153
- * namespace while a model's table may sit in the unbound namespace). The
154
- * binding rule: an enum declared in the column's *own* namespace shadows
155
- * everything; otherwise the column references the ambient enum — the sole
156
- * namespace that defines `typeName`, preferring the default `public`
157
- * namespace when several do. Returns `undefined` when no namespace defines it.
158
- */
159
- function resolveColumnEnumNamespace(
160
- storage: SqlStorage,
161
- columnNamespaceId: string,
162
- typeName: string,
163
- ): string | undefined {
164
- if (namespaceHasEnum(storage, columnNamespaceId, typeName)) return columnNamespaceId;
165
- const owners = Object.keys(storage.namespaces).filter((nsId) =>
166
- namespaceHasEnum(storage, nsId, typeName),
167
- );
168
- if (owners.length === 1) return owners[0];
169
- if (owners.includes(DEFAULT_ENUM_NAMESPACE_ID)) return DEFAULT_ENUM_NAMESPACE_ID;
170
- return owners[0];
171
- }
172
-
173
- /**
174
- * Finds a type entry by explicit namespace coordinate. Namespace types (e.g.
175
- * Postgres enums) live under `storage.namespaces[nsId].entries.type`. Returns the
176
- * entry from the named namespace only — never scans other namespaces, so two
177
- * namespaces that hold an enum with the same name resolve independently.
178
- */
179
- function locateNamespaceType(
180
- storage: SqlStorage,
181
- namespaceId: string,
182
- typeName: string,
183
- ): PostgresEnumStorageEntry | undefined {
184
- const ns = storage.namespaces[namespaceId];
185
- const raw = ns?.entries['type']?.[typeName];
186
- if (raw === undefined) return undefined;
187
- return blindCast<
188
- PostgresEnumStorageEntry,
189
- 'postgres type slot carries PostgresEnumStorageEntry at the postgres target layer'
190
- >(raw);
191
- }
192
-
193
122
  // ============================================================================
194
123
  // Strategy types
195
124
  // ============================================================================
@@ -208,7 +137,7 @@ export interface StrategyContext {
208
137
  readonly fromContract: Contract<SqlStorage> | null;
209
138
  readonly schemaName: string;
210
139
  readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;
211
- readonly storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>;
140
+ readonly storageTypes: Readonly<Record<string, StorageTypeInstance>>;
212
141
  readonly schema: SqlSchemaIR;
213
142
  readonly policy: MigrationOperationPolicy;
214
143
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
@@ -229,12 +158,9 @@ export type CallMigrationStrategy = (
229
158
  /**
230
159
  * `true` for strategies that emit cohesive sequential recipes whose
231
160
  * calls must stay contiguous and in the returned order — e.g.
232
- * `nativeEnumPlanCallStrategy` (createEnumTypealterColumnType
233
- * dropEnumType renameType, optionally prefixed by a
234
- * `DataTransformCall` placeholder), `notNullBackfillCallStrategy`
235
- * (addColumn → dataTransform → setNotNull). Defaults to `false`,
236
- * which lets `planIssues` hoist individual calls into their DDL
237
- * sequencing bucket.
161
+ * `notNullBackfillCallStrategy` (addColumndataTransform setNotNull).
162
+ * Defaults to `false`, which lets `planIssues` hoist individual calls
163
+ * into their DDL sequencing bucket.
238
164
  */
239
165
  recipe?: boolean;
240
166
  }
@@ -251,10 +177,7 @@ function buildColumnSpec(
251
177
  if (!storageCol)
252
178
  throw new Error(`Column "${table}"."${column}" not found in destination contract`);
253
179
  const mutableHooks = ctx.codecHooks as Map<string, CodecControlHooks>;
254
- const mutableTypes = ctx.storageTypes as Record<
255
- string,
256
- StorageTypeInstance | PostgresEnumStorageEntry
257
- >;
180
+ const mutableTypes = ctx.storageTypes as Record<string, StorageTypeInstance>;
258
181
  const typeSql = buildColumnTypeSql(storageCol, mutableHooks, mutableTypes);
259
182
  const ddlDefault = postgresDefaultToDdlColumnDefault(storageCol.default);
260
183
  const resolved = resolveColumnTypeMetadata(storageCol, mutableTypes);
@@ -289,10 +212,7 @@ function buildAlterTypeOptions(
289
212
  const col = tableAt(ctx.toContract.storage, namespaceId, table)?.columns[column];
290
213
  if (!col) throw new Error(`Column "${table}"."${column}" not found in destination contract`);
291
214
  const mutableHooks = ctx.codecHooks as Map<string, CodecControlHooks>;
292
- const mutableTypes = ctx.storageTypes as Record<
293
- string,
294
- StorageTypeInstance | PostgresEnumStorageEntry
295
- >;
215
+ const mutableTypes = ctx.storageTypes as Record<string, StorageTypeInstance>;
296
216
  const qualifiedTargetType = buildColumnTypeSql(col, mutableHooks, mutableTypes, false);
297
217
  const formatTypeExpected = buildExpectedFormatType(col, mutableHooks, mutableTypes);
298
218
  return {
@@ -435,246 +355,6 @@ export const nullableTighteningCallStrategy: CallMigrationStrategy = (issues, ct
435
355
  };
436
356
  };
437
357
 
438
- function enumRebuildCallRecipe(
439
- namespaceId: string,
440
- typeName: string,
441
- ctx: StrategyContext,
442
- ): readonly PostgresOpFactoryCall[] {
443
- const toType = locateNamespaceType(ctx.toContract.storage, namespaceId, typeName);
444
- if (!toType) return [];
445
- const isEnum = isPostgresEnumStorageEntry(toType);
446
- const nativeType = toType.nativeType;
447
- const desiredValues: readonly string[] = isEnum
448
- ? toType.values
449
- : (((toType as StorageTypeInstance).typeParams['values'] ?? []) as readonly string[]);
450
- const tempName = `${nativeType}${REBUILD_SUFFIX}`;
451
- // Type DDL targets the enum's real schema — the unbound coordinate resolves
452
- // to the introspected `current_schema()`, never the `__unbound__` sentinel.
453
- const ddlSchema = resolveDdlSchemaForNamespaceStorage(
454
- ctx.toContract.storage,
455
- namespaceId,
456
- ctx.schema,
457
- );
458
-
459
- // Migrate every column whose `typeRef` binds to *this* enum. The column's
460
- // bare `typeRef` resolves to an enum namespace (own-namespace shadows;
461
- // otherwise the ambient/default `public` enum), so a column in the unbound
462
- // namespace correctly binds to a `public`-namespace enum, while two
463
- // same-named enums in distinct namespaces keep their columns disjoint.
464
- const columnRefs: { namespaceId: string; table: string; column: string }[] = [];
465
- for (const [nsId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {
466
- for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
467
- for (const [columnName, column] of Object.entries(table.columns)) {
468
- if (
469
- column.typeRef === typeName &&
470
- resolveColumnEnumNamespace(ctx.toContract.storage, nsId, typeName) === namespaceId
471
- ) {
472
- columnRefs.push({ namespaceId: nsId, table: tableName, column: columnName });
473
- }
474
- }
475
- }
476
- }
477
-
478
- return [
479
- new CreateEnumTypeCall(ddlSchema, tempName, desiredValues),
480
- ...columnRefs.map((ref) => {
481
- const using = `${ref.column}::text::${tempName}`;
482
- return new AlterColumnTypeCall(
483
- resolveDdlSchemaForNamespace(ctx, ref.namespaceId),
484
- ref.table,
485
- ref.column,
486
- {
487
- qualifiedTargetType: tempName,
488
- formatTypeExpected: tempName,
489
- rawTargetTypeForLabel: tempName,
490
- using,
491
- },
492
- );
493
- }),
494
- new DropEnumTypeCall(ddlSchema, nativeType),
495
- new RenameTypeCall(ddlSchema, tempName, nativeType),
496
- ];
497
- }
498
-
499
- // ============================================================================
500
- // Native enum planner strategy
501
- // ============================================================================
502
-
503
- /**
504
- * Single planner strategy for `PostgresEnumType` instances. Walks
505
- * `toContract.storage.types` directly (no codec-hook dispatch) and
506
- * resolves existing values via `readExistingEnumValues`, the same
507
- * Postgres bridging adapter the verifier uses.
508
- *
509
- * Per-enum dispatch:
510
- *
511
- * - No existing type → `CreateEnumTypeCall` with the contract's desired
512
- * values.
513
- * - Diff is `unchanged` → no calls emitted (consumes the matching
514
- * `enum_values_changed` issue if present).
515
- * - Diff is `add_values` → `AddEnumValuesCall` with the new labels.
516
- * - Diff is `rebuild` → the create-temp / migrate-columns /
517
- * drop-original / rename rebuild recipe. When
518
- * `policy.allowedOperationClasses` includes `'data'` and the rebuild
519
- * removes labels (`removedValues.length > 0`), prepend a
520
- * `DataTransformCall` placeholder so the user can author the value
521
- * remap before the destructive recipe runs. Without `'data'` in the
522
- * policy (`db update` / `db init`), the rebuild's PG `USING ::text`
523
- * cast surfaces any value-removal data loss as a runtime error rather
524
- * than silent loss.
525
- *
526
- * Returns `recipe: true` only when a rebuild recipe was emitted (its
527
- * `createEnumType(temp) → alterColumnType → dropEnumType(orig) →
528
- * renameType` sequence mixes `dep`-class and `alter`-class calls that
529
- * would mis-order if the planner hoisted them into its DDL sequencing
530
- * buckets). For the create-only and add-values paths the strategy
531
- * returns `recipe: false` so the planner hoists `CreateEnumTypeCall`
532
- * into the `dep` bucket — i.e. `CREATE TYPE` runs before any
533
- * `CreateTableCall` that references the new enum.
534
- */
535
- /**
536
- * Separator character for compound enum map keys (`namespaceId\u0000typeName`).
537
- * NUL (`\u0000`) is invalid in both Postgres identifiers and TypeScript symbol
538
- * names so it cannot appear in either component — unambiguous separator.
539
- */
540
- const COMPOUND_KEY_SEP = '\u0000';
541
-
542
- /** Builds the compound map key for a namespace-qualified enum entry. */
543
- function enumCompoundKey(namespaceId: string, typeName: string): string {
544
- return `${namespaceId}${COMPOUND_KEY_SEP}${typeName}`;
545
- }
546
-
547
- export const nativeEnumPlanCallStrategy: CallMigrationStrategy = (issues, ctx) => {
548
- const enumTypes = collectPostgresEnumTypes(ctx.toContract.storage);
549
- if (enumTypes.size === 0) return { kind: 'no_match' };
550
-
551
- const dataAllowed = ctx.policy.allowedOperationClasses.includes('data');
552
-
553
- const calls: PostgresOpFactoryCall[] = [];
554
- const handledKeys = new Set<string>();
555
- const introducedKeys = new Set<string>();
556
- const rebuiltKeys = new Set<string>();
557
- let emittedRebuildRecipe = false;
558
-
559
- for (const [key, enumType] of enumTypes) {
560
- const sepIdx = key.indexOf(COMPOUND_KEY_SEP);
561
- const enumNamespaceId = key.slice(0, sepIdx);
562
- const typeName = key.slice(sepIdx + 1);
563
-
564
- const desired = enumType.values;
565
- // The enum's live schema: for the unbound coordinate this resolves to the
566
- // introspected `current_schema()` (e.g. `public`), never the `__unbound__`
567
- // DDL-emit sentinel — so both the existing-values lookup key and the
568
- // emitted `CREATE TYPE` / `ALTER TYPE` target the real schema the type
569
- // lives in. Named namespaces resolve to their own DDL schema.
570
- const ddlSchema = resolveDdlSchemaForNamespaceStorage(
571
- ctx.toContract.storage,
572
- enumNamespaceId,
573
- ctx.schema,
574
- );
575
- const existing = readExistingEnumValues(ctx.schema, ddlSchema, enumType.nativeType);
576
- if (!existing) {
577
- calls.push(new CreateEnumTypeCall(ddlSchema, typeName, desired, enumType.nativeType));
578
- handledKeys.add(key);
579
- introducedKeys.add(key);
580
- continue;
581
- }
582
- const diff = determineEnumDiff(existing, desired);
583
- if (diff.kind === 'unchanged') {
584
- handledKeys.add(key);
585
- continue;
586
- }
587
- if (diff.kind === 'add_values') {
588
- calls.push(new AddEnumValuesCall(ddlSchema, typeName, enumType.nativeType, diff.values));
589
- handledKeys.add(key);
590
- continue;
591
- }
592
- if (dataAllowed && diff.removedValues.length > 0) {
593
- calls.push(
594
- new DataTransformCall(
595
- `migrate-${typeName}-values`,
596
- `migrate-${typeName}-values:check`,
597
- `migrate-${typeName}-values:run`,
598
- ),
599
- );
600
- }
601
- calls.push(...enumRebuildCallRecipe(enumNamespaceId, typeName, ctx));
602
- emittedRebuildRecipe = true;
603
- handledKeys.add(key);
604
- rebuiltKeys.add(key);
605
- }
606
-
607
- // The strategy emits a single `recipe` flag for the entire pass,
608
- // which routes every emitted call to either the contiguous recipe
609
- // slot (rebuild path) or the `dep` bucket (introduce / add-values
610
- // path). A plan that needs both shapes simultaneously cannot be
611
- // expressed today — the introduced `CreateEnumTypeCall` would land
612
- // in the recipe slot and any `CreateTableCall` referencing the new
613
- // enum would fail at runtime with a confusing `type "X" does not
614
- // exist` error. Surface the unrepresentable case here as a
615
- // planner-time error so the failure mode is loud, not silent.
616
- if (introducedKeys.size > 0 && rebuiltKeys.size > 0) {
617
- const introducedDisplay = [...introducedKeys]
618
- .sort()
619
- .map((k) => k.replace(COMPOUND_KEY_SEP, '.'))
620
- .join(', ');
621
- const rebuiltDisplay = [...rebuiltKeys]
622
- .sort()
623
- .map((k) => k.replace(COMPOUND_KEY_SEP, '.'))
624
- .join(', ');
625
- throw new Error(
626
- `nativeEnumPlanCallStrategy: cannot emit both a brand-new enum and a rebuild on a different enum in the same plan; the single recipe flag cannot route them to different buckets. Introduced: [${introducedDisplay}]; rebuilt: [${rebuiltDisplay}]. Split the strategy or grow the \`match\` return type before this case lands.`,
627
- );
628
- }
629
-
630
- const remaining = issues.filter(
631
- (issue) =>
632
- !(
633
- (issue.kind === 'type_missing' || issue.kind === 'enum_values_changed') &&
634
- issue.typeName &&
635
- handledKeys.has(enumCompoundKey(resolveNamespaceIdForIssue(issue), issue.typeName))
636
- ),
637
- );
638
-
639
- if (calls.length === 0 && remaining.length === issues.length) {
640
- return { kind: 'no_match' };
641
- }
642
- // `recipe: true` is required for the rebuild path — its
643
- // `createEnumType(temp) → alterColumnType → dropEnumType(orig) →
644
- // renameType` mixes `dep`-class and `alter`-class calls that would
645
- // mis-order if the planner hoisted them into its DDL sequencing
646
- // buckets. For the type_missing / add_values paths we want the
647
- // opposite: hoisted into the `dep` bucket so a brand-new
648
- // `CreateEnumTypeCall` runs *before* the `CreateTableCall` that
649
- // references it. The two cases never co-occur in the same plan
650
- // (introducing a new enum type and rebuilding an existing one in
651
- // one shot would require both buckets — a shape today's interface
652
- // does not surface; if that combination ever needs to land we'd
653
- // split this strategy or grow the `match` return type).
654
- return { kind: 'match', issues: remaining, calls, recipe: emittedRebuildRecipe };
655
- };
656
-
657
- /**
658
- * Collects every `PostgresEnumType` instance across all declared namespaces,
659
- * returning a compound-keyed map (`${namespaceId}\u0000${typeName}`). Two
660
- * namespaces that declare an enum with the same name produce two distinct
661
- * entries — no name collision, no last-write-wins.
662
- *
663
- * Entries within each namespace are sorted by name for deterministic ordering.
664
- */
665
- function collectPostgresEnumTypes(storage: SqlStorage): ReadonlyMap<string, PostgresEnumType> {
666
- const result = new Map<string, PostgresEnumType>();
667
- for (const [nsId, ns] of Object.entries(storage.namespaces)) {
668
- if (!isPostgresSchema(ns)) continue;
669
- for (const [name, instance] of Object.entries(ns.type).sort(([a], [b]) => a.localeCompare(b))) {
670
- if (instance instanceof PostgresEnumType) {
671
- result.set(enumCompoundKey(nsId, name), instance);
672
- }
673
- }
674
- }
675
- return result;
676
- }
677
-
678
358
  /**
679
359
  * Collects every check constraint from a table in the contract storage.
680
360
  * Returns an empty array when the table has no checks or the table is absent.
@@ -723,8 +403,6 @@ function checkValueSetsEqual(a: readonly string[], b: readonly string[]): boolea
723
403
  * be altered in place).
724
404
  *
725
405
  * Consumes `check_missing`, `check_removed`, and `check_mismatch` issues.
726
- * Does not touch the native enum path (`nativeEnumPlanCallStrategy` is
727
- * unchanged).
728
406
  */
729
407
  export const checkConstraintPlanCallStrategy: CallMigrationStrategy = (issues, ctx) => {
730
408
  const calls: PostgresOpFactoryCall[] = [];
@@ -803,10 +481,9 @@ export const checkConstraintPlanCallStrategy: CallMigrationStrategy = (issues, c
803
481
  };
804
482
 
805
483
  /**
806
- * Dispatches non-enum codec-typed storage types through their codec's
484
+ * Dispatches codec-typed storage types through their codec's
807
485
  * `planTypeOperations` hook (the authoritative source for codec-driven DDL
808
- * such as custom type creation). Enum dispatch lives in
809
- * `nativeEnumPlanCallStrategy` and no longer relies on codec hooks.
486
+ * such as custom type creation).
810
487
  */
811
488
  export const storageTypePlanCallStrategy: CallMigrationStrategy = (issues, ctx) => {
812
489
  const storageTypes = ctx.toContract.storage.types ?? {};
@@ -818,10 +495,6 @@ export const storageTypePlanCallStrategy: CallMigrationStrategy = (issues, ctx)
818
495
  for (const [typeName, typeInstance] of Object.entries(storageTypes).sort(([a], [b]) =>
819
496
  a.localeCompare(b),
820
497
  )) {
821
- // Enums walk natively in `nativeEnumPlanCallStrategy`; codec-hook
822
- // dispatch here is reserved for genuinely codec-typed entries
823
- // (decimal, varchar, pgvector, …).
824
- if (isPostgresEnumStorageEntry(typeInstance)) continue;
825
498
  const codecInstance = typeInstance as StorageTypeInstance;
826
499
  const hook = ctx.codecHooks.get(codecInstance.codecId);
827
500
  if (!hook?.planTypeOperations) continue;
@@ -889,10 +562,7 @@ export const notNullAddColumnCallStrategy: CallMigrationStrategy = (issues, ctx)
889
562
  const schemaLookups = buildSchemaLookupMap(ctx.schema);
890
563
 
891
564
  const mutableCodecHooks = ctx.codecHooks as Map<string, CodecControlHooks>;
892
- const mutableStorageTypes = ctx.storageTypes as Record<
893
- string,
894
- StorageTypeInstance | PostgresEnumType
895
- >;
565
+ const mutableStorageTypes = ctx.storageTypes as Record<string, StorageTypeInstance>;
896
566
 
897
567
  for (const issue of issues) {
898
568
  if (issue.kind !== 'missing_column' || !issue.table || !issue.column) continue;
@@ -1048,8 +718,7 @@ function canUseSharedTemporaryDefaultStrategy(options: {
1048
718
  *
1049
719
  * - When `'data'` is allowed (`migration plan`), the data-safe strategies
1050
720
  * (`notNullBackfillCallStrategy`, `typeChangeCallStrategy`,
1051
- * `nullableTighteningCallStrategy`) and the enum walk
1052
- * (`nativeEnumPlanCallStrategy`) consume their matching issues and emit
721
+ * `nullableTighteningCallStrategy`) consume their matching issues and emit
1053
722
  * `DataTransformCall` placeholders or recipe ops.
1054
723
  *
1055
724
  * - When `'data'` is not allowed (`db update` / `db init`), the
@@ -1057,23 +726,14 @@ function canUseSharedTemporaryDefaultStrategy(options: {
1057
726
  * the issue for the downstream walk-schema strategies
1058
727
  * (`storageTypePlanCallStrategy`, `notNullAddColumnCallStrategy`) or the
1059
728
  * `mapIssueToCall` default to handle with direct DDL.
1060
- * `nativeEnumPlanCallStrategy` runs in both modes; under `db update` /
1061
- * `db init` it emits the rebuild recipe without the data-transform
1062
- * placeholder so value-removal data loss surfaces as a runtime cast
1063
- * error rather than silent loss.
1064
729
  *
1065
- * Enum dispatch is unified into a single strategy: the
1066
- * `nativeEnumPlanCallStrategy` decides per-emission whether to emit a
1067
- * rebuild recipe (`recipe: true`, contiguous slot) or hoist the call
1068
- * into the `dep` bucket (`recipe: false`, so a brand-new
1069
- * `CreateEnumTypeCall` runs before any `CreateTableCall` referencing
1070
- * it). Codec-typed entries continue through `storageTypePlanCallStrategy`.
730
+ * Codec-typed storage type entries are dispatched through
731
+ * `storageTypePlanCallStrategy`.
1071
732
  */
1072
733
  export const postgresPlannerStrategies: readonly CallMigrationStrategy[] = [
1073
734
  notNullBackfillCallStrategy,
1074
735
  typeChangeCallStrategy,
1075
736
  nullableTighteningCallStrategy,
1076
- nativeEnumPlanCallStrategy,
1077
737
  checkConstraintPlanCallStrategy,
1078
738
  storageTypePlanCallStrategy,
1079
739
  notNullAddColumnCallStrategy,
@@ -1,9 +1,4 @@
1
- import {
2
- isPostgresEnumStorageEntry,
3
- type PostgresEnumStorageEntry,
4
- type StorageColumn,
5
- type StorageTypeInstance,
6
- } from '@prisma-next/sql-contract/types';
1
+ import type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';
7
2
 
8
3
  export type ResolvedColumnTypeMetadata = Pick<
9
4
  StorageColumn,
@@ -12,7 +7,7 @@ export type ResolvedColumnTypeMetadata = Pick<
12
7
 
13
8
  export function resolveColumnTypeMetadata(
14
9
  column: StorageColumn,
15
- storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>,
10
+ storageTypes: Readonly<Record<string, StorageTypeInstance>>,
16
11
  ): ResolvedColumnTypeMetadata {
17
12
  if (!column.typeRef) {
18
13
  return column;
@@ -23,19 +18,6 @@ export function resolveColumnTypeMetadata(
23
18
  return column;
24
19
  }
25
20
 
26
- if (isPostgresEnumStorageEntry(referencedType)) {
27
- // Enum types are referenced by name (`quoteIdentifier(nativeType)`),
28
- // not via parameterised codec expansion. The structural shape
29
- // carries `codecId` as an enumerable property (mirroring the
30
- // codec-typed view); `typeParams` is intentionally omitted here so
31
- // `expandParameterizedTypeSql` does not try to look up a
32
- // (deliberately absent) `expandNativeType` hook for `pg/enum@*`.
33
- return {
34
- codecId: referencedType.codecId,
35
- nativeType: referencedType.nativeType,
36
- };
37
- }
38
-
39
21
  return {
40
22
  codecId: referencedType.codecId,
41
23
  nativeType: referencedType.nativeType,
@@ -31,7 +31,6 @@ import {
31
31
  resolvePostgresIssueControlPolicySubject,
32
32
  resolvePostgresIssueCreationFactoryName,
33
33
  } from './control-policy';
34
- import { createResolveExistingEnumValues } from './enum-planning';
35
34
  import { planIssues } from './issue-planner';
36
35
  import type { PostgresOpFactoryCall } from './op-factory-call';
37
36
  import { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';
@@ -268,7 +267,6 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
268
267
  frameworkComponents: options.frameworkComponents,
269
268
  normalizeDefault: parsePostgresDefault,
270
269
  normalizeNativeType: normalizeSchemaNativeType,
271
- resolveExistingEnumValues: createResolveExistingEnumValues(options.contract.storage),
272
270
  };
273
271
  const verifyResult = verifySqlSchema(verifyOptions);
274
272
  // Schema presence is a Postgres-specific concern (no equivalent in
@@ -25,7 +25,6 @@ import type { Result } from '@prisma-next/utils/result';
25
25
  import { notOk, ok, okVoid } from '@prisma-next/utils/result';
26
26
  import { parsePostgresDefault } from '../default-normalizer';
27
27
  import { normalizeSchemaNativeType } from '../native-type-normalizer';
28
- import { createResolveExistingEnumValues } from './enum-planning';
29
28
  import type { PostgresPlanTargetDetails } from './planner-target-details';
30
29
 
31
30
  interface ApplyPlanSuccessValue {
@@ -144,9 +143,6 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
144
143
  frameworkComponents: options.frameworkComponents,
145
144
  normalizeDefault: parsePostgresDefault,
146
145
  normalizeNativeType: normalizeSchemaNativeType,
147
- resolveExistingEnumValues: createResolveExistingEnumValues(
148
- options.destinationContract.storage,
149
- ),
150
146
  });
151
147
  if (!schemaVerifyResult.ok) {
152
148
  return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {