@prisma-next/target-postgres 0.16.0-dev.24 → 0.16.0-dev.26

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 (99) hide show
  1. package/dist/{authoring-BCzcFRay.mjs → authoring-DnO1B0N9.mjs} +7 -14
  2. package/dist/authoring-DnO1B0N9.mjs.map +1 -0
  3. package/dist/canonicalize-C7zKHw8m.mjs +59 -0
  4. package/dist/canonicalize-C7zKHw8m.mjs.map +1 -0
  5. package/dist/{canonicalize-D1F4vUnP.d.mts → canonicalize-CQlxSR4D.d.mts} +3 -18
  6. package/dist/canonicalize-CQlxSR4D.d.mts.map +1 -0
  7. package/dist/contract-free.d.mts +1 -1
  8. package/dist/contract-free.d.mts.map +1 -1
  9. package/dist/contract-free.mjs +1 -1
  10. package/dist/{control-policy-B-_34g05.mjs → control-policy-DEwdS3oK.mjs} +23 -24
  11. package/dist/control-policy-DEwdS3oK.mjs.map +1 -0
  12. package/dist/control.mjs +10 -7
  13. package/dist/control.mjs.map +1 -1
  14. package/dist/{ddl-DYEob9xQ.mjs → ddl-BQC6u-L9.mjs} +27 -3
  15. package/dist/{ddl-DYEob9xQ.mjs.map → ddl-BQC6u-L9.mjs.map} +1 -1
  16. package/dist/ddl.d.mts +3 -3
  17. package/dist/ddl.mjs +2 -2
  18. package/dist/{descriptor-meta-D_0ZKcj-.mjs → descriptor-meta-DGlJurgA.mjs} +2 -2
  19. package/dist/{descriptor-meta-D_0ZKcj-.mjs.map → descriptor-meta-DGlJurgA.mjs.map} +1 -1
  20. package/dist/{diff-database-schema-C9H09OD3.mjs → diff-database-schema-qRPwuYBH.mjs} +22 -12
  21. package/dist/diff-database-schema-qRPwuYBH.mjs.map +1 -0
  22. package/dist/diff-database-schema.mjs +1 -1
  23. package/dist/errors.d.mts +4 -2
  24. package/dist/errors.d.mts.map +1 -1
  25. package/dist/errors.mjs +2 -2
  26. package/dist/issue-planner.d.mts +2 -2
  27. package/dist/issue-planner.d.mts.map +1 -1
  28. package/dist/issue-planner.mjs +1 -1
  29. package/dist/migration.d.mts +2 -2
  30. package/dist/migration.mjs +2 -2
  31. package/dist/{nodes-DJC5B8Id.mjs → nodes-04EILM-z.mjs} +65 -2
  32. package/dist/nodes-04EILM-z.mjs.map +1 -0
  33. package/dist/{nodes-CQzM2hR0.d.mts → nodes-DjCsN-uv.d.mts} +69 -4
  34. package/dist/nodes-DjCsN-uv.d.mts.map +1 -0
  35. package/dist/{op-factory-call-DT7kdjVP.d.mts → op-factory-call-0TB5XNij.d.mts} +46 -8
  36. package/dist/op-factory-call-0TB5XNij.d.mts.map +1 -0
  37. package/dist/{op-factory-call-BVYLIojV.mjs → op-factory-call-CIaPDDUc.mjs} +104 -27
  38. package/dist/op-factory-call-CIaPDDUc.mjs.map +1 -0
  39. package/dist/op-factory-call.d.mts +2 -2
  40. package/dist/op-factory-call.mjs +2 -2
  41. package/dist/pack.d.mts.map +1 -1
  42. package/dist/pack.mjs +1 -1
  43. package/dist/{planner-4sj5cJCY.mjs → planner-BhnkIJX-.mjs} +117 -9
  44. package/dist/planner-BhnkIJX-.mjs.map +1 -0
  45. package/dist/{planner-produced-postgres-migration-CcQPDWmX.mjs → planner-produced-postgres-migration-BE3EJIRK.mjs} +2 -2
  46. package/dist/{planner-produced-postgres-migration-CcQPDWmX.mjs.map → planner-produced-postgres-migration-BE3EJIRK.mjs.map} +1 -1
  47. package/dist/{planner-produced-postgres-migration-8QP8eMph.d.mts → planner-produced-postgres-migration-CRAHl6ak.d.mts} +2 -2
  48. package/dist/planner-produced-postgres-migration-CRAHl6ak.d.mts.map +1 -0
  49. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  50. package/dist/planner-produced-postgres-migration.mjs +1 -1
  51. package/dist/{planner-schema-lookup-CiVaAQP-.mjs → planner-schema-lookup-D3Y_OL-C.mjs} +3 -3
  52. package/dist/planner-schema-lookup-D3Y_OL-C.mjs.map +1 -0
  53. package/dist/planner-schema-lookup.mjs +1 -1
  54. package/dist/planner.d.mts +21 -1
  55. package/dist/planner.d.mts.map +1 -1
  56. package/dist/planner.mjs +2 -2
  57. package/dist/{postgres-contract-view-B8yXVWYe.mjs → postgres-contract-view-BeIEyZfD.mjs} +2 -2
  58. package/dist/{postgres-contract-view-B8yXVWYe.mjs.map → postgres-contract-view-BeIEyZfD.mjs.map} +1 -1
  59. package/dist/{postgres-migration-GIOABsAa.mjs → postgres-migration--BzvpA92.mjs} +7 -4
  60. package/dist/postgres-migration--BzvpA92.mjs.map +1 -0
  61. package/dist/{postgres-migration-DLIvzHjX.d.mts → postgres-migration-BXelnqHO.d.mts} +15 -10
  62. package/dist/postgres-migration-BXelnqHO.d.mts.map +1 -0
  63. package/dist/rls-canonicalize.d.mts +2 -26
  64. package/dist/rls-canonicalize.mjs +2 -2
  65. package/dist/runtime.mjs +1 -1
  66. package/package.json +20 -20
  67. package/src/contract-free/ddl.ts +47 -0
  68. package/src/core/authoring.ts +10 -22
  69. package/src/core/ddl/nodes.ts +104 -0
  70. package/src/core/migrations/contract-to-postgres-database-schema-node.ts +24 -13
  71. package/src/core/migrations/issue-planner.ts +40 -13
  72. package/src/core/migrations/op-factory-call.ts +100 -9
  73. package/src/core/migrations/operations/indexes.ts +80 -35
  74. package/src/core/migrations/planner-schema-lookup.ts +2 -2
  75. package/src/core/migrations/planner.ts +155 -5
  76. package/src/core/migrations/postgres-migration.ts +26 -8
  77. package/src/core/psl-infer/infer-psl-contract.ts +8 -1
  78. package/src/core/rls/canonicalize.ts +4 -21
  79. package/src/exports/ddl.ts +4 -0
  80. package/src/exports/errors.ts +1 -1
  81. package/src/exports/op-factory-call.ts +1 -0
  82. package/src/exports/rls-canonicalize.ts +0 -6
  83. package/dist/authoring-BCzcFRay.mjs.map +0 -1
  84. package/dist/canonicalize-D1F4vUnP.d.mts.map +0 -1
  85. package/dist/control-policy-B-_34g05.mjs.map +0 -1
  86. package/dist/diff-database-schema-C9H09OD3.mjs.map +0 -1
  87. package/dist/nodes-CQzM2hR0.d.mts.map +0 -1
  88. package/dist/nodes-DJC5B8Id.mjs.map +0 -1
  89. package/dist/op-factory-call-BVYLIojV.mjs.map +0 -1
  90. package/dist/op-factory-call-DT7kdjVP.d.mts.map +0 -1
  91. package/dist/planner-4sj5cJCY.mjs.map +0 -1
  92. package/dist/planner-produced-postgres-migration-8QP8eMph.d.mts.map +0 -1
  93. package/dist/planner-schema-lookup-CiVaAQP-.mjs.map +0 -1
  94. package/dist/postgres-migration-DLIvzHjX.d.mts.map +0 -1
  95. package/dist/postgres-migration-GIOABsAa.mjs.map +0 -1
  96. package/dist/rls-canonicalize.d.mts.map +0 -1
  97. package/dist/wire-name-DbQ9-2RC.mjs +0 -104
  98. package/dist/wire-name-DbQ9-2RC.mjs.map +0 -1
  99. package/src/core/rls/wire-name.ts +0 -33
@@ -1,16 +1,17 @@
1
1
  import { t as DEFAULT_NAMESPACE_ID } from "./namespace-ids-xtp_ZY86.mjs";
2
2
  import { g as PostgresRlsPolicy, r as isPostgresSchema } from "./postgres-schema-CTplQZDK.mjs";
3
- import { n as parseRlsPolicyWireName } from "./wire-name-DbQ9-2RC.mjs";
4
3
  import { i as PostgresDatabaseSchemaNode, n as PostgresPolicySchemaNode, r as PostgresNamespaceSchemaNode } from "./postgres-role-schema-node-bg32e7I-.mjs";
5
4
  import { t as resolveDdlSchemaForNamespaceStorage } from "./resolve-ddl-schema-BAsJEKW8.mjs";
6
- import { t as buildPostgresPlanDiff } from "./diff-database-schema-C9H09OD3.mjs";
7
- import { a as resolvePostgresNodeIssueCreationFactoryName, c as issueSchemaName, d as postgresNodeStorageCoordinate, i as resolvePostgresNodeIssueControlPolicySubject, l as planIssues, n as resolveNamespaceIdForDdlSchema, o as coalesceSubtreeIssues, r as resolvePostgresCallControlPolicySubject, s as issueNode, t as renderPostgresSuppression, u as postgresPlannerStrategies } from "./control-policy-B-_34g05.mjs";
8
- import { T as DropPostgresRlsPolicyCall, k as RenamePostgresRlsPolicyCall, p as CreatePostgresRlsPolicyCall } from "./op-factory-call-BVYLIojV.mjs";
9
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-CcQPDWmX.mjs";
5
+ import { t as buildPostgresPlanDiff } from "./diff-database-schema-qRPwuYBH.mjs";
6
+ import { a as resolvePostgresNodeIssueCreationFactoryName, c as issueSchemaName, d as postgresNodeStorageCoordinate, i as resolvePostgresNodeIssueControlPolicySubject, l as planIssues, n as resolveNamespaceIdForDdlSchema, o as coalesceSubtreeIssues, r as resolvePostgresCallControlPolicySubject, s as issueNode, t as renderPostgresSuppression, u as postgresPlannerStrategies } from "./control-policy-DEwdS3oK.mjs";
7
+ import { A as RenamePostgresRlsPolicyCall, T as DropPostgresRlsPolicyCall, k as RenameIndexCall, p as CreatePostgresRlsPolicyCall } from "./op-factory-call-CIaPDDUc.mjs";
8
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-BE3EJIRK.mjs";
10
9
  import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
11
10
  import { blindCast } from "@prisma-next/utils/casts";
12
11
  import { extractCodecControlHooks, partitionCallsByControlPolicy, partitionIssuesByControlPolicy, planFieldEventOperations, plannerFailure } from "@prisma-next/family-sql/control";
13
12
  import { ifDefined } from "@prisma-next/utils/defined";
13
+ import { parseWireName } from "@prisma-next/sql-schema-ir/naming";
14
+ import { SqlIndexIR } from "@prisma-next/sql-schema-ir/types";
14
15
  import { issueOutcome } from "@prisma-next/framework-components/control";
15
16
  //#region src/core/migrations/verify-postgres-namespaces.ts
16
17
  /**
@@ -150,11 +151,13 @@ var PostgresMigrationPlanner = class {
150
151
  contract: options.contract,
151
152
  schema: options.schema
152
153
  }), ...gated];
154
+ const indexRenames = this.pairIndexRenames(options, schemaIssues);
155
+ const plannableIssues = indexRenames.consumed.size === 0 ? schemaIssues : schemaIssues.filter((issue) => !indexRenames.consumed.has(issue));
153
156
  const codecHooks = extractCodecControlHooks(options.frameworkComponents);
154
157
  const storageTypes = options.contract.storage.types ?? {};
155
158
  const relationalSchema = relationalNamespaceNode(options.schema, schemaName);
156
159
  const issuePartition = partitionIssuesByControlPolicy({
157
- issues: schemaIssues,
160
+ issues: plannableIssues,
158
161
  contract: options.contract,
159
162
  resolveControlPolicySubject: (issue) => resolvePostgresNodeIssueControlPolicySubject(issue, options.contract),
160
163
  resolveCreationFactoryName: resolvePostgresNodeIssueCreationFactoryName
@@ -172,6 +175,12 @@ var PostgresMigrationPlanner = class {
172
175
  strategies: postgresPlannerStrategies
173
176
  });
174
177
  if (!result.ok) return plannerFailure(result.failure);
178
+ const indexRenamePartition = partitionCallsByControlPolicy({
179
+ calls: indexRenames.calls,
180
+ contract: options.contract,
181
+ resolveControlPolicySubject: (call) => resolvePostgresCallControlPolicySubject(call, options.contract),
182
+ resolveFactoryName: (call) => call.factoryName
183
+ });
175
184
  const schemaDiffPartition = partitionCallsByControlPolicy({
176
185
  calls: this.planPostgresSchemaDiff(options, policyDiffIssues),
177
186
  contract: options.contract,
@@ -190,11 +199,13 @@ var PostgresMigrationPlanner = class {
190
199
  });
191
200
  const calls = [
192
201
  ...result.value.calls,
202
+ ...indexRenamePartition.kept,
193
203
  ...schemaDiffPartition.kept,
194
204
  ...fieldEventPartition.kept
195
205
  ];
196
206
  const warnings = [
197
207
  ...issuePartition.suppressions,
208
+ ...indexRenamePartition.suppressions,
198
209
  ...schemaDiffPartition.suppressions,
199
210
  ...fieldEventPartition.suppressions
200
211
  ].map((record) => renderPostgresSuppression(record, options.contract));
@@ -208,6 +219,103 @@ var PostgresMigrationPlanner = class {
208
219
  });
209
220
  }
210
221
  /**
222
+ * Rename post-pass for indexes, per `(schema, table)`, widening-only,
223
+ * deterministic by sorted names — the same structure as the policy pass
224
+ * below (which stays untouched: policies pair by hash only).
225
+ *
226
+ * Phase 1 — hash pairing: extras whose live names parse as wire names,
227
+ * grouped by `(schema, table, hash)`; missing nodes iterated in sorted-name
228
+ * order consume the sorted-name-first candidate — a prefix-only rename.
229
+ *
230
+ * Phase 2 — content pairing: the remaining managed-missing nodes
231
+ * (`prefix` defined) against the remaining extras of any name shape,
232
+ * paired iff content-equal (columns ordered-strict both-defined-or-
233
+ * both-undefined, `unique`/`type` strict, `options` loose, bodies
234
+ * byte-equal) — exact→managed adoption convergence.
235
+ *
236
+ * Leftovers proceed as create/drop exactly as before; without the
237
+ * widening allowance the pass is skipped and pairing degrades to the
238
+ * additive half, like the policy pass.
239
+ */
240
+ pairIndexRenames(options, issues) {
241
+ const consumed = /* @__PURE__ */ new Set();
242
+ const calls = [];
243
+ if (!options.policy.allowedOperationClasses.includes("widening")) return {
244
+ calls,
245
+ consumed
246
+ };
247
+ const missing = [];
248
+ const extra = [];
249
+ for (const issue of issues) {
250
+ const node = issueNode(issue);
251
+ if (node === void 0 || !SqlIndexIR.is(node)) continue;
252
+ const ddlSchema = issue.path[1];
253
+ const tableName = issue.path[2];
254
+ if (ddlSchema === void 0 || tableName === void 0) continue;
255
+ if (issueOutcome(issue) === "not-found") missing.push({
256
+ issue,
257
+ node,
258
+ ddlSchema,
259
+ tableName
260
+ });
261
+ else if (issueOutcome(issue) === "not-expected") extra.push({
262
+ issue,
263
+ node,
264
+ ddlSchema,
265
+ tableName
266
+ });
267
+ }
268
+ if (missing.length === 0 || extra.length === 0) return {
269
+ calls,
270
+ consumed
271
+ };
272
+ const byName = (a, b) => a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0;
273
+ const emissionSchema = (ddlSchema) => resolveNamespaceIdForDdlSchema(options.contract, ddlSchema) === UNBOUND_NAMESPACE_ID ? UNBOUND_NAMESPACE_ID : ddlSchema;
274
+ const pairingKey = (finding, hash) => JSON.stringify([
275
+ finding.ddlSchema,
276
+ finding.tableName,
277
+ hash
278
+ ]);
279
+ const rename = (missingFinding, candidate) => {
280
+ consumed.add(missingFinding.issue);
281
+ consumed.add(candidate.issue);
282
+ calls.push(new RenameIndexCall(emissionSchema(missingFinding.ddlSchema), missingFinding.tableName, candidate.node.name, missingFinding.node.name));
283
+ };
284
+ const sortedMissing = [...missing].sort(byName);
285
+ const extrasByHash = /* @__PURE__ */ new Map();
286
+ for (const finding of extra) {
287
+ const parsed = parseWireName(finding.node.name);
288
+ if (parsed === void 0) continue;
289
+ const key = pairingKey(finding, parsed.hash);
290
+ const group = extrasByHash.get(key) ?? [];
291
+ group.push(finding);
292
+ extrasByHash.set(key, group);
293
+ }
294
+ for (const group of extrasByHash.values()) group.sort(byName);
295
+ for (const missingFinding of sortedMissing) {
296
+ const parsed = parseWireName(missingFinding.node.name);
297
+ if (parsed === void 0) continue;
298
+ const candidate = extrasByHash.get(pairingKey(missingFinding, parsed.hash))?.shift();
299
+ if (candidate === void 0) continue;
300
+ rename(missingFinding, candidate);
301
+ }
302
+ const sortedExtras = [...extra].sort(byName);
303
+ for (const missingFinding of sortedMissing) {
304
+ if (consumed.has(missingFinding.issue)) continue;
305
+ if (missingFinding.node.prefix === void 0) continue;
306
+ const candidate = sortedExtras.find((extraFinding) => !consumed.has(extraFinding.issue) && extraFinding.ddlSchema === missingFinding.ddlSchema && extraFinding.tableName === missingFinding.tableName && missingFinding.node.contentEquals(extraFinding.node, {
307
+ columnPresence: "matching",
308
+ bodies: "verbatim"
309
+ }));
310
+ if (candidate === void 0) continue;
311
+ rename(missingFinding, candidate);
312
+ }
313
+ return {
314
+ calls,
315
+ consumed
316
+ };
317
+ }
318
+ /**
211
319
  * Maps the RLS policy presence findings of the one combined tree diff
212
320
  * (`buildPostgresPlanDiff`, already ownership-filtered) into
213
321
  * `CREATE POLICY` / `DROP POLICY` / `ALTER POLICY … RENAME TO` ops. It
@@ -261,7 +369,7 @@ var PostgresMigrationPlanner = class {
261
369
  if (allowsWidening) {
262
370
  const extrasByGroup = /* @__PURE__ */ new Map();
263
371
  for (const finding of extra) {
264
- const parsed = parseRlsPolicyWireName(finding.node.name);
372
+ const parsed = parseWireName(finding.node.name);
265
373
  if (parsed === void 0) continue;
266
374
  const key = pairingKey(finding, parsed.hash);
267
375
  const group = extrasByGroup.get(key) ?? [];
@@ -271,7 +379,7 @@ var PostgresMigrationPlanner = class {
271
379
  for (const group of extrasByGroup.values()) group.sort((a, b) => a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0);
272
380
  const sortedMissing = [...missing].sort((a, b) => a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0);
273
381
  for (const missingFinding of sortedMissing) {
274
- const parsed = parseRlsPolicyWireName(missingFinding.node.name);
382
+ const parsed = parseWireName(missingFinding.node.name);
275
383
  if (parsed === void 0) continue;
276
384
  const candidate = extrasByGroup.get(pairingKey(missingFinding, parsed.hash))?.shift();
277
385
  if (candidate === void 0) continue;
@@ -387,4 +495,4 @@ function policyNodeToContractPolicy(node) {
387
495
  //#endregion
388
496
  export { createPostgresMigrationPlanner as t };
389
497
 
390
- //# sourceMappingURL=planner-4sj5cJCY.mjs.map
498
+ //# sourceMappingURL=planner-BhnkIJX-.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-BhnkIJX-.mjs","names":["#lowerer"],"sources":["../src/core/migrations/verify-postgres-namespaces.ts","../src/core/migrations/planner.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport type { SchemaDiffIssue } from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';\nimport { DEFAULT_NAMESPACE_ID } from '../namespace-ids';\nimport { isPostgresSchema } from '../postgres-schema';\nimport { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';\nimport { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';\nimport type { SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';\n\n/**\n * Resolves the live-database schema name for a given namespace\n * coordinate. Mirrors `resolveDdlSchemaForNamespace` in\n * `planner-strategies.ts` so the verifier's projection and the\n * planner's projection always agree — Postgres-aware namespaces (the\n * production path) dispatch to `ddlSchemaName(storage)`, and bare\n * object payloads (used by some tests) fall back to the coordinate\n * itself.\n */\nfunction resolveDdlSchemaName(storage: SqlStorage, namespaceId: string): string {\n const namespace = storage.namespaces[namespaceId];\n if (isPostgresSchema(namespace)) {\n return namespace.ddlSchemaName(storage);\n }\n return namespaceId;\n}\n\n/**\n * Reads the introspected list of schema names from the database-root schema\n * node. `existingSchemas` is database-level, so it lives on the\n * `PostgresDatabaseSchemaNode` root — not on the per-schema namespace nodes.\n *\n * Defaults to the always-present `public` schema when the node is not the\n * database root — a fresh Postgres database always carries `public` (unless an\n * operator dropped it manually), so any verifier path that runs without an\n * enriched introspection still suppresses the redundant `CREATE SCHEMA\n * \"public\"`.\n *\n * Production introspection (`PostgresControlAdapter.introspect`) is the\n * authoritative source: it queries `pg_namespace` and sets `existingSchemas`\n * on the returned root. Tests that want to assert against a richer initial\n * state construct a `PostgresDatabaseSchemaNode` explicitly.\n */\nfunction existingSchemasFromSchema(schema: SqlSchemaIRNode): readonly string[] {\n if (PostgresDatabaseSchemaNode.is(schema)) {\n return schema.existingSchemas;\n }\n return [DEFAULT_NAMESPACE_ID];\n}\n\n/**\n * Emits a `postgres-namespace` `not-found` diff issue for every\n * contract-declared Postgres namespace whose live container does not yet\n * exist. The planner prepends these (node-typed, synthesized) to the\n * relational diff issues so a multi-schema plan emits `CREATE SCHEMA`\n * before the tables that need it — a planner-only concern (verify already\n * rejects via the `not-found` table issues a missing schema already\n * produces), so this is not part of the shared diff.\n *\n * A namespace's live container is the schema returned by its\n * polymorphic `ddlSchemaName(storage)` method — named schemas resolve\n * to their own id; the unbound singleton returns `UNBOUND_NAMESPACE_ID`\n * and is skipped explicitly (late-bound namespaces have no fixed DDL\n * schema). Issues are emitted only when the resolved name is a real,\n * creatable schema (not the unbound sentinel) and is missing from the\n * introspected list. `public` is suppressed implicitly because the\n * introspection (or its sensible default) always carries it.\n *\n * Each emitted issue's path is `['database', ddlName]` — an ancestor of\n * every table path under that schema, so it must never be run through\n * `coalesceSubtreeIssues` alongside the table diff (it would swallow the\n * table-level `not-found` issues that drive `CREATE TABLE`); the planner\n * adds these AFTER coalescing the relational issues, and they are not\n * subject to sibling-space ownership scoping (mirrors the retired\n * coordinate walk, which prepended namespace issues after that filter).\n */\nexport function verifyPostgresNamespacePresence(input: {\n readonly contract: Contract<SqlStorage>;\n readonly schema: SqlSchemaIRNode;\n}): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {\n const { contract, schema } = input;\n const existing = new Set(existingSchemasFromSchema(schema));\n const issues: SchemaDiffIssue<SqlSchemaDiffNode>[] = [];\n const namespaceIds = Object.keys(contract.storage.namespaces).sort();\n for (const namespaceId of namespaceIds) {\n if (namespaceId === UNBOUND_NAMESPACE_ID) continue;\n const ddlName = resolveDdlSchemaName(contract.storage, namespaceId);\n if (ddlName === UNBOUND_NAMESPACE_ID) continue;\n if (existing.has(ddlName)) continue;\n const namespace = new PostgresNamespaceSchemaNode({\n schemaName: ddlName,\n tables: {},\n });\n issues.push({\n path: ['database', ddlName],\n expected: namespace,\n });\n }\n return issues;\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlMigrationPlannerPlanOptions,\n SqlPlannerConflict,\n SqlPlannerFailureResult,\n} from '@prisma-next/family-sql/control';\nimport {\n extractCodecControlHooks,\n partitionCallsByControlPolicy,\n partitionIssuesByControlPolicy,\n planFieldEventOperations,\n plannerFailure,\n} from '@prisma-next/family-sql/control';\nimport type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n MigrationPlanner,\n MigrationPlanWithAuthoringSurface,\n MigrationScaffoldContext,\n SchemaDiffIssue,\n SchemaOwnership,\n} from '@prisma-next/framework-components/control';\nimport { issueOutcome } from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { parseWireName } from '@prisma-next/sql-schema-ir/naming';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\nimport { SqlIndexIR } from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { PostgresRlsPolicy } from '../postgres-rls-policy';\nimport { postgresNodeStorageCoordinate } from '../schema-ir/node-storage-coordinate';\nimport { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';\nimport { PostgresPolicySchemaNode } from '../schema-ir/postgres-policy-schema-node';\nimport type { SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';\nimport {\n renderPostgresSuppression,\n resolveNamespaceIdForDdlSchema,\n resolvePostgresCallControlPolicySubject,\n resolvePostgresNodeIssueControlPolicySubject,\n resolvePostgresNodeIssueCreationFactoryName,\n} from './control-policy';\nimport { buildPostgresPlanDiff } from './diff-database-schema';\nimport { coalesceSubtreeIssues, issueNode, issueSchemaName, planIssues } from './issue-planner';\nimport type { PostgresOpFactoryCall } from './op-factory-call';\nimport {\n CreatePostgresRlsPolicyCall,\n DropPostgresRlsPolicyCall,\n RenameIndexCall,\n RenamePostgresRlsPolicyCall,\n} from './op-factory-call';\nimport { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';\nimport { postgresPlannerStrategies } from './planner-strategies';\nimport { resolveDdlSchemaForNamespaceStorage } from './resolve-ddl-schema';\nimport { verifyPostgresNamespacePresence } from './verify-postgres-namespaces';\n\ntype PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {\n readonly frameworkComponents: infer T;\n}\n ? T\n : ReadonlyArray<unknown>;\n\ntype PlannerOptionsWithComponents = SqlMigrationPlannerPlanOptions & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\nexport function createPostgresMigrationPlanner(\n lowerer: ExecuteRequestLowerer,\n): PostgresMigrationPlanner {\n return new PostgresMigrationPlanner(lowerer);\n}\n\n/**\n * Result of `PostgresMigrationPlanner.plan()`. A discriminated union whose\n * success variant carries a `TypeScriptRenderablePostgresMigration` — a\n * migration object that both the CLI (via `renderTypeScript()`) and the\n * SQL-typed callers (via `operations`, `describe()`, etc.) consume\n * uniformly.\n */\nexport type PostgresPlanResult =\n | {\n readonly kind: 'success';\n readonly plan: TypeScriptRenderablePostgresMigration;\n readonly warnings?: readonly SqlPlannerConflict[];\n }\n | SqlPlannerFailureResult;\n\n/**\n * Postgres migration planner — a thin wrapper over `planIssues`.\n *\n * `plan()` diffs the target contract against the live schema via the one\n * differ (`buildPostgresPlanDiff`, producing node-typed `SchemaDiffIssue[]`)\n * and delegates to `planIssues` with the unified `postgresPlannerStrategies`\n * list: NOT-NULL backfill, type-change, nullable-tightening, codec-hook\n * storage types, component-declared dependency installs, and\n * shared-temp-default / empty-table-guarded NOT-NULL add-column. The same\n * strategy list runs for `migration plan`, `db update`, and `db init`;\n * behavior diverges purely on `policy.allowedOperationClasses` (the\n * data-safe strategies short-circuit when `'data'` is excluded). The issue\n * planner applies operation-class policy gates and emits a single\n * `PostgresOpFactoryCall[]` that drives both the runtime-ops view (via\n * `renderOps`) and the `renderTypeScript()` authoring surface. RLS policy\n * drift (the structural half of the same one-differ tree) is handled\n * separately via `planPostgresSchemaDiff`.\n */\nexport class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {\n readonly #lowerer: ExecuteRequestLowerer | undefined;\n\n constructor(lowerer?: ExecuteRequestLowerer) {\n this.#lowerer = lowerer;\n }\n\n plan(options: {\n readonly contract: unknown;\n readonly schema: unknown;\n readonly policy: MigrationOperationPolicy;\n /**\n * The \"from\" contract (state the planner assumes the database starts\n * at), or `null` for reconciliation flows. Only `migration plan` ever\n * supplies a non-null value; `db update` / `db init` reconcile against\n * the live schema and pass `null`. When present alongside the\n * `'data'` operation class, strategies that need from/to column-shape\n * comparisons (unsafe type change, nullability tightening) activate.\n *\n * Typed as the framework `Contract | null` to satisfy the\n * `MigrationPlanner` interface contract; `planSql` narrows to the SQL\n * shape via `SqlMigrationPlannerPlanOptions`. Used to populate\n * `describe().from` on the produced plan as\n * `fromContract?.storage.storageHash ?? null`.\n */\n readonly fromContract: Contract | null;\n readonly schemaName?: string;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n /**\n * Contract space this plan applies to. Stamped onto the produced\n * {@link TypeScriptRenderablePostgresMigration.spaceId} so the runner keys\n * the marker row by the right space.\n */\n readonly spaceId: string;\n /**\n * Ownership oracle over the contract-space composition — see\n * {@link SqlMigrationPlannerPlanOptions.ownership}.\n */\n readonly ownership?: SchemaOwnership;\n /**\n * POSIX-relative path from the migration package dir to\n * `migrations/snapshots` — see\n * {@link SqlMigrationPlannerPlanOptions.snapshotsImportPath}.\n */\n readonly snapshotsImportPath: string;\n }): PostgresPlanResult {\n return this.planSql(options as SqlMigrationPlannerPlanOptions);\n }\n\n emptyMigration(\n context: MigrationScaffoldContext,\n spaceId: string,\n ): MigrationPlanWithAuthoringSurface {\n return new TypeScriptRenderablePostgresMigration(\n [],\n {\n from: context.fromHash,\n to: context.toHash,\n },\n spaceId,\n context.snapshotsImportPath,\n this.#lowerer,\n );\n }\n\n private planSql(options: SqlMigrationPlannerPlanOptions): PostgresPlanResult {\n const schemaName =\n options.schemaName ??\n Object.keys(options.contract.storage.namespaces).find((id) => id !== UNBOUND_NAMESPACE_ID) ??\n UNBOUND_NAMESPACE_ID;\n const policyResult = this.ensureAdditivePolicy(options.policy);\n if (policyResult) {\n return policyResult;\n }\n\n // The one combined tree diff drives the whole plan: relational findings\n // become structural DDL via `planIssues`, policy findings become RLS ops\n // via `planPostgresSchemaDiff`. Verify runs its own full-tree node diff\n // (`diffSchema`) over the same schema and rejects on a\n // surviving failure.\n PostgresDatabaseSchemaNode.assert(options.schema);\n const { issues: rawIssues } = buildPostgresPlanDiff({\n contract: options.contract,\n actualSchema: options.schema,\n frameworkComponents: options.frameworkComponents,\n });\n const policyDiffIssues = rawIssues.filter((issue) => isPolicyDiffIssue(issue));\n // Role diff issues resolve to the `external` control policy (see\n // `resolvePostgresNodeIssueControlPolicySubject`'s role branch), so the\n // control-policy partition below suppresses them to zero ops on its own,\n // before `mapNodeIssueToCall` ever sees them — no separate exclusion\n // needed here.\n const relationalDiffIssues = rawIssues.filter((issue) => !isPolicyDiffIssue(issue));\n\n // The generic differ is total and un-gated: strict-mode extras filtering\n // (dropping `not-expected` findings outside strict mode, mirroring the\n // retired coordinate walk's `if (strict) { ...extra_* } }` guards),\n // subtree coalescing (a missing/extra table also emits an issue for\n // every child under it — redundant once the table-level Create/Drop call\n // already accounts for the whole subtree), and ownership are all post-diff\n // planner steps.\n //\n // Ownership: a live extra is only this plan's to drop when no contract\n // space owns it. The differ ran against THIS space's contract, so a table\n // a sibling space owns surfaces here as `not-expected`; the planner asks\n // the ownership oracle (the passive aggregate) whether any space declares\n // it and, if so, leaves it alone — it is a sibling's table, not an orphan.\n // A table no space owns stays a genuine extra to drop under a destructive\n // policy. Ownership lives in the aggregate; the planner only asks. Absent\n // oracle (single-space, none handed) keeps every extra. Coalescing MUST\n // run before this so a sibling-owned table's child issues have already\n // collapsed into the one table-level issue that carries the table name.\n const strict =\n options.policy.allowedOperationClasses.includes('widening') ||\n options.policy.allowedOperationClasses.includes('destructive');\n const coalesced = coalesceSubtreeIssues(relationalDiffIssues);\n const owned = retainUnownedExtras(coalesced, options.ownership, options.contract);\n const gated = strict ? owned : owned.filter((issue) => issueOutcome(issue) !== 'not-expected');\n\n // Namespace presence (`CREATE SCHEMA`) is a planner-only op-generation\n // concern stitched in here rather than inside the shared diff — verify\n // never needs it (a missing schema already surfaces as a `not-found`\n // table in the relational findings). These synthesized issues are added\n // AFTER coalescing/scoping (never coalesced against the table diff —\n // their path is an ancestor of every table path under that schema, so\n // running them through the same coalesce would swallow the table-level\n // `not-found` issues that drive `CREATE TABLE`) and are NOT subject to\n // sibling-space scoping, matching the retired coordinate walk exactly.\n const namespaceIssues = verifyPostgresNamespacePresence({\n contract: options.contract,\n schema: options.schema,\n });\n const schemaIssues = [...namespaceIssues, ...gated];\n\n // Index rename post-pass (the policy pass's structure, generalized): a\n // `not-found` and a `not-expected` index that are one rename collapse\n // into a single widening `ALTER INDEX … RENAME TO` before the per-issue\n // mapping turns them into create + drop. Consumed issues never reach\n // `planIssues`; the rename calls go through the same call-side\n // control-policy partition the policy ops use.\n const indexRenames = this.pairIndexRenames(options, schemaIssues);\n const plannableIssues =\n indexRenames.consumed.size === 0\n ? schemaIssues\n : schemaIssues.filter((issue) => !indexRenames.consumed.has(issue));\n\n const codecHooks = extractCodecControlHooks(options.frameworkComponents);\n const storageTypes = options.contract.storage.types ?? {};\n // The strategy layer reads the live schema by bare table name for existence\n // checks (shared-temp-default safety, FK/unique probes), so it takes one\n // per-schema namespace node — never the whole tree root, and never a flat\n // merge of every namespace (which would collide same-named tables across\n // schemas). Probing more than one namespace at once is future work.\n const relationalSchema = relationalNamespaceNode(options.schema, schemaName);\n\n // Input-side control-policy partition. `external` / `observed` subjects\n // — and non-creation issues for `tolerated` subjects — are dropped from\n // the planner's input entirely; the planner never observes them, never\n // diffs them, never generates DDL for them. Suppression warnings are\n // built directly from the suppressed partition (one per subject), so the\n // user-visible message survives even when the planner would have failed\n // to model the subject's live shape.\n const issuePartition = partitionIssuesByControlPolicy({\n issues: plannableIssues,\n contract: options.contract,\n resolveControlPolicySubject: (issue) =>\n resolvePostgresNodeIssueControlPolicySubject(issue, options.contract),\n resolveCreationFactoryName: resolvePostgresNodeIssueCreationFactoryName,\n });\n\n const result = planIssues({\n issues: issuePartition.plannable,\n toContract: options.contract,\n // `fromContract` is only supplied by `migration plan`. It is `null` for\n // `db update` / `db init`, which means data-safety strategies needing\n // from/to comparisons (unsafe type change, nullable tightening) are\n // inapplicable there — reconciliation falls through to\n // `mapNodeIssueToCall`'s direct destructive handlers.\n fromContract: options.fromContract,\n schemaName,\n codecHooks,\n storageTypes,\n ...ifDefined('schema', relationalSchema),\n policy: options.policy,\n frameworkComponents: options.frameworkComponents,\n strategies: postgresPlannerStrategies,\n });\n\n if (!result.ok) {\n return plannerFailure(result.failure);\n }\n\n const indexRenamePartition = partitionCallsByControlPolicy({\n calls: indexRenames.calls,\n contract: options.contract,\n resolveControlPolicySubject: (call) =>\n resolvePostgresCallControlPolicySubject(call, options.contract),\n resolveFactoryName: (call) => call.factoryName,\n });\n\n const schemaDiffCalls = this.planPostgresSchemaDiff(options, policyDiffIssues);\n const schemaDiffPartition = partitionCallsByControlPolicy({\n calls: schemaDiffCalls,\n contract: options.contract,\n resolveControlPolicySubject: (call) =>\n resolvePostgresCallControlPolicySubject(call, options.contract),\n resolveFactoryName: (call) => call.factoryName,\n });\n\n // Inline `onFieldEvent`-emitted ops after structural DDL. The fixed\n // ordering is `structural → added → dropped → altered`, with\n // within-group sorting by `(tableName, fieldName)` so re-emits are\n // byte-stable. The hook fires only at the application emitter —\n // extension-space planning never reaches this helper.\n const fieldEventOps = planFieldEventOperations({\n priorContract: options.fromContract,\n newContract: options.contract,\n codecHooks,\n });\n // Codec hook ops are target-agnostic `OpFactoryCall`; Postgres planning\n // lifts them at this integration boundary (see field-event-planner JSDoc).\n const fieldEventPostgresCalls = blindCast<\n readonly PostgresOpFactoryCall[],\n 'Codec hook ops conform to PostgresOpFactoryCall at the app emitter boundary'\n >(fieldEventOps);\n const fieldEventPartition = partitionCallsByControlPolicy({\n calls: fieldEventPostgresCalls,\n contract: options.contract,\n resolveControlPolicySubject: (call) =>\n resolvePostgresCallControlPolicySubject(call, options.contract),\n resolveFactoryName: (call) => call.factoryName,\n });\n const calls = [\n ...result.value.calls,\n ...indexRenamePartition.kept,\n ...schemaDiffPartition.kept,\n ...fieldEventPartition.kept,\n ];\n const warnings: SqlPlannerConflict[] = [\n ...issuePartition.suppressions,\n ...indexRenamePartition.suppressions,\n ...schemaDiffPartition.suppressions,\n ...fieldEventPartition.suppressions,\n ].map((record) => renderPostgresSuppression(record, options.contract));\n\n return Object.freeze({\n kind: 'success' as const,\n plan: new TypeScriptRenderablePostgresMigration(\n calls,\n {\n from: options.fromContract?.storage.storageHash ?? null,\n to: options.contract.storage.storageHash,\n },\n options.spaceId,\n options.snapshotsImportPath,\n this.#lowerer,\n ),\n ...(warnings.length > 0 ? { warnings: Object.freeze(warnings) } : {}),\n });\n }\n\n /**\n * Rename post-pass for indexes, per `(schema, table)`, widening-only,\n * deterministic by sorted names — the same structure as the policy pass\n * below (which stays untouched: policies pair by hash only).\n *\n * Phase 1 — hash pairing: extras whose live names parse as wire names,\n * grouped by `(schema, table, hash)`; missing nodes iterated in sorted-name\n * order consume the sorted-name-first candidate — a prefix-only rename.\n *\n * Phase 2 — content pairing: the remaining managed-missing nodes\n * (`prefix` defined) against the remaining extras of any name shape,\n * paired iff content-equal (columns ordered-strict both-defined-or-\n * both-undefined, `unique`/`type` strict, `options` loose, bodies\n * byte-equal) — exact→managed adoption convergence.\n *\n * Leftovers proceed as create/drop exactly as before; without the\n * widening allowance the pass is skipped and pairing degrades to the\n * additive half, like the policy pass.\n */\n private pairIndexRenames(\n options: PlannerOptionsWithComponents,\n issues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],\n ): {\n readonly calls: readonly RenameIndexCall[];\n readonly consumed: ReadonlySet<SchemaDiffIssue<SqlSchemaDiffNode>>;\n } {\n const consumed = new Set<SchemaDiffIssue<SqlSchemaDiffNode>>();\n const calls: RenameIndexCall[] = [];\n if (!options.policy.allowedOperationClasses.includes('widening')) {\n return { calls, consumed };\n }\n\n interface IndexFinding {\n readonly issue: SchemaDiffIssue<SqlSchemaDiffNode>;\n readonly node: SqlIndexIR;\n readonly ddlSchema: string;\n readonly tableName: string;\n }\n const missing: IndexFinding[] = [];\n const extra: IndexFinding[] = [];\n for (const issue of issues) {\n const node = issueNode(issue);\n if (node === undefined || !SqlIndexIR.is(node)) continue;\n const ddlSchema = issue.path[1];\n const tableName = issue.path[2];\n if (ddlSchema === undefined || tableName === undefined) continue;\n if (issueOutcome(issue) === 'not-found') {\n missing.push({ issue, node, ddlSchema, tableName });\n } else if (issueOutcome(issue) === 'not-expected') {\n extra.push({ issue, node, ddlSchema, tableName });\n }\n }\n if (missing.length === 0 || extra.length === 0) {\n return { calls, consumed };\n }\n\n const byName = (a: IndexFinding, b: IndexFinding): number =>\n a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0;\n // DDL emission must stay unqualified for the unbound namespace, exactly\n // like the per-issue mapping's `emissionSchemaName`.\n const emissionSchema = (ddlSchema: string): string =>\n resolveNamespaceIdForDdlSchema(options.contract, ddlSchema) === UNBOUND_NAMESPACE_ID\n ? UNBOUND_NAMESPACE_ID\n : ddlSchema;\n const pairingKey = (finding: IndexFinding, hash: string): string =>\n JSON.stringify([finding.ddlSchema, finding.tableName, hash]);\n const rename = (missingFinding: IndexFinding, candidate: IndexFinding): void => {\n consumed.add(missingFinding.issue);\n consumed.add(candidate.issue);\n calls.push(\n new RenameIndexCall(\n emissionSchema(missingFinding.ddlSchema),\n missingFinding.tableName,\n candidate.node.name,\n missingFinding.node.name,\n ),\n );\n };\n\n const sortedMissing = [...missing].sort(byName);\n\n const extrasByHash = new Map<string, IndexFinding[]>();\n for (const finding of extra) {\n const parsed = parseWireName(finding.node.name);\n if (parsed === undefined) continue;\n const key = pairingKey(finding, parsed.hash);\n const group = extrasByHash.get(key) ?? [];\n group.push(finding);\n extrasByHash.set(key, group);\n }\n for (const group of extrasByHash.values()) {\n group.sort(byName);\n }\n for (const missingFinding of sortedMissing) {\n const parsed = parseWireName(missingFinding.node.name);\n if (parsed === undefined) continue;\n const candidate = extrasByHash.get(pairingKey(missingFinding, parsed.hash))?.shift();\n if (candidate === undefined) continue;\n rename(missingFinding, candidate);\n }\n\n const sortedExtras = [...extra].sort(byName);\n for (const missingFinding of sortedMissing) {\n if (consumed.has(missingFinding.issue)) continue;\n if (missingFinding.node.prefix === undefined) continue;\n const candidate = sortedExtras.find(\n (extraFinding) =>\n !consumed.has(extraFinding.issue) &&\n extraFinding.ddlSchema === missingFinding.ddlSchema &&\n extraFinding.tableName === missingFinding.tableName &&\n missingFinding.node.contentEquals(extraFinding.node, {\n columnPresence: 'matching',\n bodies: 'verbatim',\n }),\n );\n if (candidate === undefined) continue;\n rename(missingFinding, candidate);\n }\n\n return { calls, consumed };\n }\n\n /**\n * Maps the RLS policy presence findings of the one combined tree diff\n * (`buildPostgresPlanDiff`, already ownership-filtered) into\n * `CREATE POLICY` / `DROP POLICY` / `ALTER POLICY … RENAME TO` ops. It\n * does not re-diff — it consumes exactly the policy-node subset of the\n * shared diff's issues. Enablement is NOT decided here: `ENABLE`/`DISABLE\n * ROW LEVEL SECURITY` derive from the table's marker-driven `rlsEnabled`\n * attribute diff on the relational side.\n *\n * Rename post-pass: a `not-found` and a `not-expected` policy on the SAME\n * table whose wire-name content hashes match but prefixes differ are one\n * prefix-only rename, collapsed into a single non-destructive\n * `RenamePostgresRlsPolicyCall`. Multi-candidate hash groups pair\n * deterministically by sorted wire name; leftovers proceed as\n * create/drop. Unparseable wire names never pair.\n *\n * The pairing runs only when the policy allows `widening` (rename's\n * class). Without it (db-init's additive-only set), pairing degrades\n * deliberately to the additive half: the new name is CREATEd and the old\n * policy survives live until a widening/destructive-allowed plan runs —\n * emitting an ungated widening rename would only fail at the runner's\n * class re-enforcement.\n */\n private planPostgresSchemaDiff(\n options: PlannerOptionsWithComponents,\n filteredDiffIssues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],\n ): readonly PostgresOpFactoryCall[] {\n const allowsDestructive = options.policy.allowedOperationClasses.includes('destructive');\n const allowsWidening = options.policy.allowedOperationClasses.includes('widening');\n\n interface PolicyFinding {\n readonly node: PostgresPolicySchemaNode;\n readonly schemaForTable: string;\n }\n const missing: PolicyFinding[] = [];\n const extra: PolicyFinding[] = [];\n\n for (const issue of filteredDiffIssues) {\n // 'not-equal' is unreachable for content-addressed policies: the wire name\n // encodes the body hash, so two policies sharing a local key (same name)\n // are always equal and isEqualTo never returns false.\n if (issueOutcome(issue) === 'not-found') {\n const expected = issue.expected;\n PostgresPolicySchemaNode.assert(expected);\n // expected.namespaceId is the DDL schema name (resolved during projection);\n // this re-resolution is a no-op as long as PostgresSchema.ddlSchemaName() returns this.id.\n missing.push({\n node: expected,\n schemaForTable: resolveDdlSchemaForNamespaceStorage(\n options.contract.storage,\n expected.namespaceId,\n ),\n });\n } else if (issueOutcome(issue) === 'not-expected') {\n const actual = issue.actual;\n PostgresPolicySchemaNode.assert(actual);\n extra.push({\n node: actual,\n schemaForTable: resolveDdlSchemaForNamespaceStorage(\n options.contract.storage,\n actual.namespaceId,\n ),\n });\n }\n }\n\n const calls: PostgresOpFactoryCall[] = [];\n const renamedExtras = new Set<PolicyFinding>();\n const renamedMissing = new Set<PolicyFinding>();\n const pairingKey = (finding: PolicyFinding, hash: string): string =>\n JSON.stringify([finding.schemaForTable, finding.node.tableName, hash]);\n\n if (allowsWidening) {\n const extrasByGroup = new Map<string, PolicyFinding[]>();\n for (const finding of extra) {\n const parsed = parseWireName(finding.node.name);\n if (parsed === undefined) continue;\n const key = pairingKey(finding, parsed.hash);\n const group = extrasByGroup.get(key) ?? [];\n group.push(finding);\n extrasByGroup.set(key, group);\n }\n for (const group of extrasByGroup.values()) {\n group.sort((a, b) => (a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0));\n }\n\n const sortedMissing = [...missing].sort((a, b) =>\n a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0,\n );\n for (const missingFinding of sortedMissing) {\n const parsed = parseWireName(missingFinding.node.name);\n if (parsed === undefined) continue;\n const candidates = extrasByGroup.get(pairingKey(missingFinding, parsed.hash));\n const candidate = candidates?.shift();\n if (candidate === undefined) continue;\n // Same name would never surface as missing+extra (the differ pairs by\n // name), so a matched candidate always differs in prefix only.\n renamedExtras.add(candidate);\n renamedMissing.add(missingFinding);\n calls.push(\n new RenamePostgresRlsPolicyCall(\n missingFinding.schemaForTable,\n missingFinding.node.tableName,\n candidate.node.name,\n missingFinding.node.name,\n ),\n );\n }\n }\n\n for (const finding of missing) {\n if (renamedMissing.has(finding)) continue;\n calls.push(\n new CreatePostgresRlsPolicyCall(\n finding.schemaForTable,\n finding.node.tableName,\n policyNodeToContractPolicy(finding.node),\n ),\n );\n }\n if (allowsDestructive) {\n for (const finding of extra) {\n if (renamedExtras.has(finding)) continue;\n calls.push(\n new DropPostgresRlsPolicyCall(\n finding.schemaForTable,\n finding.node.tableName,\n finding.node.name,\n ),\n );\n }\n }\n\n return calls;\n }\n\n private ensureAdditivePolicy(policy: MigrationOperationPolicy) {\n if (!policy.allowedOperationClasses.includes('additive')) {\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: 'Migration planner requires additive operations be allowed',\n why: 'The planner requires the \"additive\" operation class to be allowed in the policy.',\n },\n ]);\n }\n return null;\n }\n}\n\n/**\n * A diff issue whose node is an RLS policy — the structural half of the one\n * combined tree diff, routed to `planPostgresSchemaDiff` instead of\n * `planIssues`.\n */\nfunction isPolicyDiffIssue(issue: SchemaDiffIssue<SqlSchemaDiffNode>): boolean {\n const node = issue.expected ?? issue.actual;\n return node !== undefined && PostgresPolicySchemaNode.is(node);\n}\n\n/**\n * Drops a `not-expected` issue when it is a whole extra storage entity (a table\n * or a native enum) that some space in the composition owns. Each such node\n * yields its own storage coordinate (see {@link postgresNodeStorageCoordinate}),\n * so `declaresEntity` answers over the whole composition on one uniform\n * coordinate: a positive answer means a sibling owns this entity here — leave\n * it; a negative answer means a genuine orphan — drop it. A node with no storage\n * coordinate (a namespace, or a deeper column/constraint drift on an owned\n * table) is this space's own and is always kept. No oracle ⇒ keep everything.\n */\nfunction retainUnownedExtras(\n issues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],\n ownership: SchemaOwnership | undefined,\n contract: Contract<SqlStorage>,\n): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {\n if (ownership === undefined) return issues;\n return issues.filter((issue) => {\n if (issueOutcome(issue) !== 'not-expected') return true;\n const node = issueNode(issue);\n if (node === undefined) return true;\n const coordinate = postgresNodeStorageCoordinate(node);\n if (coordinate === undefined) return true;\n const ddlSchemaName = issueSchemaName(issue);\n if (ddlSchemaName === undefined) return true;\n const namespaceId = resolveNamespaceIdForDdlSchema(contract, ddlSchemaName);\n return !ownership.declaresEntity({ namespaceId, ...coordinate });\n });\n}\n\n/**\n * Returns the one namespace node the relational strategy layer probes for\n * live-table existence and reads codec-hook context off — the namespace\n * matching the planner's resolved schema name, or the first namespace when\n * none matches. `undefined` when the tree has no namespaces, so the strategy\n * context uses its empty-schema default.\n *\n * The relational strategies key tables by bare name, so they can only probe one\n * namespace at a time; probing across every namespace at once is future work.\n *\n * Returns the real `PostgresNamespaceSchemaNode` reference rather than a\n * projection: `storageTypePlanCallStrategy` hands this same value to codec\n * `planTypeOperations` hooks as `schema`, and hooks read the Postgres-specific\n * `nativeEnums` field off it (via `PostgresNamespaceSchemaNode.is`) to decide\n * whether a native enum type already exists — a projection that only copies\n * `tables` would silently drop that signal. `StrategyContext.schema`'s\n * declared type (`SqlSchemaIR`, shared with SQLite's flat shape) doesn't\n * capture this, so the return is `blindCast` the same way `namespaceSchemaNodes`\n * in the family's relational walk already treats a namespace node as a\n * structurally-`SqlSchemaIR`-shaped value.\n */\nfunction relationalNamespaceNode(\n schema: PostgresDatabaseSchemaNode,\n schemaName: string,\n): SqlSchemaIR | undefined {\n const namespaceNodes = Object.values(schema.namespaces);\n const namespaceNode =\n namespaceNodes.find((node) => node.schemaName === schemaName) ?? namespaceNodes[0];\n if (namespaceNode === undefined) return undefined;\n return blindCast<\n SqlSchemaIR,\n 'PostgresNamespaceSchemaNode carries tables (+ nativeEnums, read by codec hooks via PostgresNamespaceSchemaNode.is) structurally compatible with the SqlSchemaIR shape the strategy layer declares'\n >(namespaceNode);\n}\n\n/**\n * Rebuilds the `PostgresRlsPolicy` contract entity `CreatePostgresRlsPolicyCall`\n * carries (its `renderTypeScript`/`createRlsPolicy` paths serialize the whole\n * entity, `namespaceId` included). This reconstructs rather than looking the\n * original up in the contract on purpose: the diff node's `namespaceId` is the\n * *resolved DDL schema* (set when the expected tree was built), which is the\n * value the emitted op must carry; the contract-stored entity holds the raw,\n * pre-resolution coordinate, so a lookup would change the migration output.\n */\nfunction policyNodeToContractPolicy(node: PostgresPolicySchemaNode): PostgresRlsPolicy {\n return new PostgresRlsPolicy({\n name: node.name,\n prefix: node.prefix,\n tableName: node.tableName,\n namespaceId: node.namespaceId,\n operation: node.operation,\n roles: [...node.roles],\n ...ifDefined('using', node.using),\n ...ifDefined('withCheck', node.withCheck),\n permissive: node.permissive,\n });\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { t as PostgresMigration } from "./postgres-migration-GIOABsAa.mjs";
1
+ import { t as PostgresMigration } from "./postgres-migration--BzvpA92.mjs";
2
2
  import { t as renderOps } from "./render-ops-TcY9XEkz.mjs";
3
3
  import { t as renderCallsToTypeScript } from "./render-typescript-Ta7_6CGf.mjs";
4
4
  //#region src/core/migrations/planner-produced-postgres-migration.ts
@@ -43,4 +43,4 @@ var TypeScriptRenderablePostgresMigration = class extends PostgresMigration {
43
43
  //#endregion
44
44
  export { TypeScriptRenderablePostgresMigration as t };
45
45
 
46
- //# sourceMappingURL=planner-produced-postgres-migration-CcQPDWmX.mjs.map
46
+ //# sourceMappingURL=planner-produced-postgres-migration-BE3EJIRK.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"planner-produced-postgres-migration-CcQPDWmX.mjs","names":["#calls","#meta","#spaceId","#snapshotsImportPath","#lowerer","#operationsCache"],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"sourcesContent":["/**\n * Planner-produced Postgres migration.\n *\n * Returned by `PostgresMigrationPlanner.plan(...)` and `emptyMigration(...)`.\n * Holds the migration IR (`PostgresOpFactoryCall[]`) alongside\n * `MigrationMeta` and exposes both the runtime-ops view (`get operations`)\n * and the TypeScript authoring view (`renderTypeScript()`). Satisfies\n * `MigrationPlanWithAuthoringSurface` so the CLI can uniformly serialize any\n * planner result back to `migration.ts`.\n *\n * Extends the family-level `SqlMigration` alias rather than the target-local\n * migration base directly — mirrors Mongo's `PlannerProducedMongoMigration`\n * shape and keeps CLI wiring one step removed from target internals.\n *\n * Placeholder-bearing plans: `renderTypeScript()` always succeeds and embeds\n * `() => placeholder(\"slot\")` at each stub. `operations`, in contrast, is\n * _not safe to enumerate_ on a stub-bearing plan — `DataTransformCall.toOp()`\n * throws `MIGRATION.UNFILLED_PLACEHOLDER` because a planner-stubbed closure cannot be lowered\n * to a runtime op. Callers that know a plan may carry stubs must render to\n * `migration.ts`, let the user fill the slots, and re-load the edited\n * migration before enumerating ops. The walk-schema planner does not emit\n * `DataTransformCall`s today, so this asymmetry is invisible until the\n * issue-planner integration lands in Phase 2.\n */\n\nimport type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';\nimport type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';\nimport type {\n MigrationPlanWithAuthoringSurface,\n OpFactoryCall,\n} from '@prisma-next/framework-components/control';\nimport type { MigrationMeta } from '@prisma-next/migration-tools/migration';\nimport type { PostgresPlanTargetDetails } from './planner-target-details';\nimport { PostgresMigration } from './postgres-migration';\nimport { renderOps } from './render-ops';\nimport { renderCallsToTypeScript } from './render-typescript';\n\nexport class TypeScriptRenderablePostgresMigration\n extends PostgresMigration\n implements MigrationPlanWithAuthoringSurface\n{\n readonly #calls: readonly OpFactoryCall[];\n readonly #meta: MigrationMeta;\n readonly #spaceId: string;\n readonly #snapshotsImportPath: string;\n readonly #lowerer: ExecuteRequestLowerer | undefined;\n #operationsCache:\n | readonly (\n | SqlMigrationPlanOperation<PostgresPlanTargetDetails>\n | Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>>\n )[]\n | undefined;\n\n constructor(\n calls: readonly OpFactoryCall[],\n meta: MigrationMeta,\n spaceId: string,\n snapshotsImportPath: string,\n lowerer?: ExecuteRequestLowerer,\n ) {\n super();\n this.#calls = calls;\n this.#meta = meta;\n this.#spaceId = spaceId;\n this.#snapshotsImportPath = snapshotsImportPath;\n this.#lowerer = lowerer;\n }\n\n override get operations(): readonly (\n | SqlMigrationPlanOperation<PostgresPlanTargetDetails>\n | Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>>\n )[] {\n this.#operationsCache ??= renderOps(this.#calls, this.#lowerer);\n return this.#operationsCache;\n }\n\n override describe(): MigrationMeta {\n return this.#meta;\n }\n\n /**\n * Contract space this planner-produced plan applies to. Threaded\n * from the planner options so the runner keys the marker row by\n * the right space when executing the plan.\n */\n get spaceId(): string {\n return this.#spaceId;\n }\n\n renderTypeScript(): string {\n return renderCallsToTypeScript(this.#calls, {\n from: this.#meta.from,\n to: this.#meta.to,\n snapshotsImportPath: this.#snapshotsImportPath,\n });\n }\n}\n"],"mappings":";;;;AAqCA,IAAa,wCAAb,cACU,kBAEV;CACE;CACA;CACA;CACA;CACA;CACA;CAOA,YACE,OACA,MACA,SACA,qBACA,SACA;EACA,MAAM;EACN,KAAKA,SAAS;EACd,KAAKC,QAAQ;EACb,KAAKC,WAAW;EAChB,KAAKC,uBAAuB;EAC5B,KAAKC,WAAW;CAClB;CAEA,IAAa,aAGT;EACF,KAAKC,qBAAqB,UAAU,KAAKL,QAAQ,KAAKI,QAAQ;EAC9D,OAAO,KAAKC;CACd;CAEA,WAAmC;EACjC,OAAO,KAAKJ;CACd;;;;;;CAOA,IAAI,UAAkB;EACpB,OAAO,KAAKC;CACd;CAEA,mBAA2B;EACzB,OAAO,wBAAwB,KAAKF,QAAQ;GAC1C,MAAM,KAAKC,MAAM;GACjB,IAAI,KAAKA,MAAM;GACf,qBAAqB,KAAKE;EAC5B,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"planner-produced-postgres-migration-BE3EJIRK.mjs","names":["#calls","#meta","#spaceId","#snapshotsImportPath","#lowerer","#operationsCache"],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"sourcesContent":["/**\n * Planner-produced Postgres migration.\n *\n * Returned by `PostgresMigrationPlanner.plan(...)` and `emptyMigration(...)`.\n * Holds the migration IR (`PostgresOpFactoryCall[]`) alongside\n * `MigrationMeta` and exposes both the runtime-ops view (`get operations`)\n * and the TypeScript authoring view (`renderTypeScript()`). Satisfies\n * `MigrationPlanWithAuthoringSurface` so the CLI can uniformly serialize any\n * planner result back to `migration.ts`.\n *\n * Extends the family-level `SqlMigration` alias rather than the target-local\n * migration base directly — mirrors Mongo's `PlannerProducedMongoMigration`\n * shape and keeps CLI wiring one step removed from target internals.\n *\n * Placeholder-bearing plans: `renderTypeScript()` always succeeds and embeds\n * `() => placeholder(\"slot\")` at each stub. `operations`, in contrast, is\n * _not safe to enumerate_ on a stub-bearing plan — `DataTransformCall.toOp()`\n * throws `MIGRATION.UNFILLED_PLACEHOLDER` because a planner-stubbed closure cannot be lowered\n * to a runtime op. Callers that know a plan may carry stubs must render to\n * `migration.ts`, let the user fill the slots, and re-load the edited\n * migration before enumerating ops. The walk-schema planner does not emit\n * `DataTransformCall`s today, so this asymmetry is invisible until the\n * issue-planner integration lands in Phase 2.\n */\n\nimport type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';\nimport type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';\nimport type {\n MigrationPlanWithAuthoringSurface,\n OpFactoryCall,\n} from '@prisma-next/framework-components/control';\nimport type { MigrationMeta } from '@prisma-next/migration-tools/migration';\nimport type { PostgresPlanTargetDetails } from './planner-target-details';\nimport { PostgresMigration } from './postgres-migration';\nimport { renderOps } from './render-ops';\nimport { renderCallsToTypeScript } from './render-typescript';\n\nexport class TypeScriptRenderablePostgresMigration\n extends PostgresMigration\n implements MigrationPlanWithAuthoringSurface\n{\n readonly #calls: readonly OpFactoryCall[];\n readonly #meta: MigrationMeta;\n readonly #spaceId: string;\n readonly #snapshotsImportPath: string;\n readonly #lowerer: ExecuteRequestLowerer | undefined;\n #operationsCache:\n | readonly (\n | SqlMigrationPlanOperation<PostgresPlanTargetDetails>\n | Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>>\n )[]\n | undefined;\n\n constructor(\n calls: readonly OpFactoryCall[],\n meta: MigrationMeta,\n spaceId: string,\n snapshotsImportPath: string,\n lowerer?: ExecuteRequestLowerer,\n ) {\n super();\n this.#calls = calls;\n this.#meta = meta;\n this.#spaceId = spaceId;\n this.#snapshotsImportPath = snapshotsImportPath;\n this.#lowerer = lowerer;\n }\n\n override get operations(): readonly (\n | SqlMigrationPlanOperation<PostgresPlanTargetDetails>\n | Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>>\n )[] {\n this.#operationsCache ??= renderOps(this.#calls, this.#lowerer);\n return this.#operationsCache;\n }\n\n override describe(): MigrationMeta {\n return this.#meta;\n }\n\n /**\n * Contract space this planner-produced plan applies to. Threaded\n * from the planner options so the runner keys the marker row by\n * the right space when executing the plan.\n */\n get spaceId(): string {\n return this.#spaceId;\n }\n\n renderTypeScript(): string {\n return renderCallsToTypeScript(this.#calls, {\n from: this.#meta.from,\n to: this.#meta.to,\n snapshotsImportPath: this.#snapshotsImportPath,\n });\n }\n}\n"],"mappings":";;;;AAqCA,IAAa,wCAAb,cACU,kBAEV;CACE;CACA;CACA;CACA;CACA;CACA;CAOA,YACE,OACA,MACA,SACA,qBACA,SACA;EACA,MAAM;EACN,KAAKA,SAAS;EACd,KAAKC,QAAQ;EACb,KAAKC,WAAW;EAChB,KAAKC,uBAAuB;EAC5B,KAAKC,WAAW;CAClB;CAEA,IAAa,aAGT;EACF,KAAKC,qBAAqB,UAAU,KAAKL,QAAQ,KAAKI,QAAQ;EAC9D,OAAO,KAAKC;CACd;CAEA,WAAmC;EACjC,OAAO,KAAKJ;CACd;;;;;;CAOA,IAAI,UAAkB;EACpB,OAAO,KAAKC;CACd;CAEA,mBAA2B;EACzB,OAAO,wBAAwB,KAAKF,QAAQ;GAC1C,MAAM,KAAKC,MAAM;GACjB,IAAI,KAAKA,MAAM;GACf,qBAAqB,KAAKE;EAC5B,CAAC;CACH;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { t as PostgresPlanTargetDetails } from "./planner-target-details-HkP4RrRO.mjs";
2
- import { t as PostgresMigration } from "./postgres-migration-DLIvzHjX.mjs";
2
+ import { t as PostgresMigration } from "./postgres-migration-BXelnqHO.mjs";
3
3
  import { SqlMigrationPlanOperation } from "@prisma-next/family-sql/control";
4
4
  import { MigrationPlanWithAuthoringSurface, OpFactoryCall } from "@prisma-next/framework-components/control";
5
5
  import { MigrationMeta } from "@prisma-next/migration-tools/migration";
@@ -20,4 +20,4 @@ declare class TypeScriptRenderablePostgresMigration extends PostgresMigration im
20
20
  }
21
21
  //#endregion
22
22
  export { TypeScriptRenderablePostgresMigration as t };
23
- //# sourceMappingURL=planner-produced-postgres-migration-8QP8eMph.d.mts.map
23
+ //# sourceMappingURL=planner-produced-postgres-migration-CRAHl6ak.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-produced-postgres-migration-CRAHl6ak.d.mts","names":[],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"mappings":";;;;;;;cAqCa,8CACH,6BACG;;cAeT,gBAAgB,iBAChB,MAAM,eACN,iBACA,6BACA,UAAU;MAUC,wBACT,0BAA0B,6BAC1B,QAAQ,0BAA0B;EAM7B,YAAY;;;;;;MASjB;EAIJ"}
@@ -1,2 +1,2 @@
1
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-8QP8eMph.mjs";
1
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-CRAHl6ak.mjs";
2
2
  export { TypeScriptRenderablePostgresMigration };
@@ -1,2 +1,2 @@
1
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-CcQPDWmX.mjs";
1
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-BE3EJIRK.mjs";
2
2
  export { TypeScriptRenderablePostgresMigration };
@@ -7,8 +7,8 @@ function buildSchemaLookupMap(schema) {
7
7
  }
8
8
  function buildSchemaTableLookup(table) {
9
9
  const uniqueKeys = new Set(table.uniques.map((u) => u.columns.join(",")));
10
- const indexKeys = new Set(table.indexes.map((i) => i.columns.join(",")));
11
- const uniqueIndexKeys = new Set(table.indexes.filter((i) => i.unique).map((i) => i.columns.join(",")));
10
+ const indexKeys = new Set(table.indexes.map((i) => (i.columns ?? []).join(",")));
11
+ const uniqueIndexKeys = new Set(table.indexes.filter((i) => i.unique).map((i) => (i.columns ?? []).join(",")));
12
12
  const fkKeys = /* @__PURE__ */ new Set();
13
13
  for (const fk of table.foreignKeys) {
14
14
  fkKeys.add(JSON.stringify([
@@ -54,4 +54,4 @@ function hasForeignKey(lookup, fk) {
54
54
  //#endregion
55
55
  export { hasUniqueConstraint as i, hasForeignKey as n, hasIndex as r, buildSchemaLookupMap as t };
56
56
 
57
- //# sourceMappingURL=planner-schema-lookup-CiVaAQP-.mjs.map
57
+ //# sourceMappingURL=planner-schema-lookup-D3Y_OL-C.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-schema-lookup-D3Y_OL-C.mjs","names":[],"sources":["../src/core/migrations/planner-schema-lookup.ts"],"sourcesContent":["import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { ForeignKey } from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\n\n/**\n * Pre-computed lookup sets for a schema table's constraints.\n * Converts O(n*m) linear scans to O(1) Set lookups per constraint check.\n */\nexport interface SchemaTableLookup {\n readonly uniqueKeys: Set<string>;\n readonly indexKeys: Set<string>;\n readonly uniqueIndexKeys: Set<string>;\n readonly fkKeys: Set<string>;\n}\n\nexport function buildSchemaLookupMap(schema: SqlSchemaIR): ReadonlyMap<string, SchemaTableLookup> {\n const map = new Map<string, SchemaTableLookup>();\n for (const [tableName, table] of Object.entries(schema.tables)) {\n map.set(tableName, buildSchemaTableLookup(table));\n }\n return map;\n}\n\nfunction buildSchemaTableLookup(table: SqlSchemaIR['tables'][string]): SchemaTableLookup {\n const uniqueKeys = new Set(table.uniques.map((u) => u.columns.join(',')));\n const indexKeys = new Set(table.indexes.map((i) => (i.columns ?? []).join(',')));\n const uniqueIndexKeys = new Set(\n table.indexes.filter((i) => i.unique).map((i) => (i.columns ?? []).join(',')),\n );\n const fkKeys = new Set<string>();\n for (const fk of table.foreignKeys) {\n // Keys are JSON-encoded tuples so identifiers containing any character\n // (including the column-list comma or pipe characters) cannot collide\n // across structurally-distinct FKs. Unqualified keys are 3-tuples\n // (cols, table, refCols); qualified keys are 4-tuples\n // (cols, schema, table, refCols) — the arity difference makes the two\n // key shapes fundamentally non-collidable.\n fkKeys.add(JSON.stringify([fk.columns, fk.referencedTable, fk.referencedColumns]));\n if (fk.referencedSchema !== undefined) {\n fkKeys.add(\n JSON.stringify([fk.columns, fk.referencedSchema, fk.referencedTable, fk.referencedColumns]),\n );\n }\n }\n return { uniqueKeys, indexKeys, uniqueIndexKeys, fkKeys };\n}\n\nexport function hasUniqueConstraint(\n lookup: SchemaTableLookup,\n columns: readonly string[],\n): boolean {\n const key = columns.join(',');\n return lookup.uniqueKeys.has(key) || lookup.uniqueIndexKeys.has(key);\n}\n\nexport function hasIndex(lookup: SchemaTableLookup, columns: readonly string[]): boolean {\n const key = columns.join(',');\n return lookup.indexKeys.has(key) || lookup.uniqueKeys.has(key);\n}\n\nexport function hasForeignKey(lookup: SchemaTableLookup, fk: ForeignKey): boolean {\n // Mirror the encoding produced by buildSchemaTableLookup exactly:\n // unqualified 3-tuple for unbound-namespace FKs, qualified 4-tuple for\n // bound-namespace FKs.\n if (fk.target.namespaceId === UNBOUND_NAMESPACE_ID) {\n return lookup.fkKeys.has(\n JSON.stringify([fk.source.columns, fk.target.tableName, fk.target.columns]),\n );\n }\n return lookup.fkKeys.has(\n JSON.stringify([\n fk.source.columns,\n fk.target.namespaceId,\n fk.target.tableName,\n fk.target.columns,\n ]),\n );\n}\n"],"mappings":";;AAeA,SAAgB,qBAAqB,QAA6D;CAChG,MAAM,sBAAM,IAAI,IAA+B;CAC/C,KAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,OAAO,MAAM,GAC3D,IAAI,IAAI,WAAW,uBAAuB,KAAK,CAAC;CAElD,OAAO;AACT;AAEA,SAAS,uBAAuB,OAAyD;CACvF,MAAM,aAAa,IAAI,IAAI,MAAM,QAAQ,KAAK,MAAM,EAAE,QAAQ,KAAK,GAAG,CAAC,CAAC;CACxE,MAAM,YAAY,IAAI,IAAI,MAAM,QAAQ,KAAK,OAAO,EAAE,WAAW,CAAC,EAAA,CAAG,KAAK,GAAG,CAAC,CAAC;CAC/E,MAAM,kBAAkB,IAAI,IAC1B,MAAM,QAAQ,QAAQ,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK,OAAO,EAAE,WAAW,CAAC,EAAA,CAAG,KAAK,GAAG,CAAC,CAC9E;CACA,MAAM,yBAAS,IAAI,IAAY;CAC/B,KAAK,MAAM,MAAM,MAAM,aAAa;EAOlC,OAAO,IAAI,KAAK,UAAU;GAAC,GAAG;GAAS,GAAG;GAAiB,GAAG;EAAiB,CAAC,CAAC;EACjF,IAAI,GAAG,qBAAqB,KAAA,GAC1B,OAAO,IACL,KAAK,UAAU;GAAC,GAAG;GAAS,GAAG;GAAkB,GAAG;GAAiB,GAAG;EAAiB,CAAC,CAC5F;CAEJ;CACA,OAAO;EAAE;EAAY;EAAW;EAAiB;CAAO;AAC1D;AAEA,SAAgB,oBACd,QACA,SACS;CACT,MAAM,MAAM,QAAQ,KAAK,GAAG;CAC5B,OAAO,OAAO,WAAW,IAAI,GAAG,KAAK,OAAO,gBAAgB,IAAI,GAAG;AACrE;AAEA,SAAgB,SAAS,QAA2B,SAAqC;CACvF,MAAM,MAAM,QAAQ,KAAK,GAAG;CAC5B,OAAO,OAAO,UAAU,IAAI,GAAG,KAAK,OAAO,WAAW,IAAI,GAAG;AAC/D;AAEA,SAAgB,cAAc,QAA2B,IAAyB;CAIhF,IAAI,GAAG,OAAO,gBAAgB,sBAC5B,OAAO,OAAO,OAAO,IACnB,KAAK,UAAU;EAAC,GAAG,OAAO;EAAS,GAAG,OAAO;EAAW,GAAG,OAAO;CAAO,CAAC,CAC5E;CAEF,OAAO,OAAO,OAAO,IACnB,KAAK,UAAU;EACb,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;CACZ,CAAC,CACH;AACF"}
@@ -1,2 +1,2 @@
1
- import { i as hasUniqueConstraint, n as hasForeignKey, r as hasIndex, t as buildSchemaLookupMap } from "./planner-schema-lookup-CiVaAQP-.mjs";
1
+ import { i as hasUniqueConstraint, n as hasForeignKey, r as hasIndex, t as buildSchemaLookupMap } from "./planner-schema-lookup-D3Y_OL-C.mjs";
2
2
  export { buildSchemaLookupMap, hasForeignKey, hasIndex, hasUniqueConstraint };
@@ -1,6 +1,6 @@
1
1
  import { t as PostgresDatabaseSchemaNode } from "./postgres-database-schema-node-DMXsIwAb.mjs";
2
2
  import { t as PostgresContract } from "./postgres-schema-FdKRwe7X.mjs";
3
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-8QP8eMph.mjs";
3
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-CRAHl6ak.mjs";
4
4
  import { ContractToSchemaIROptions, MigrationOperationPolicy, SqlPlannerConflict, SqlPlannerFailureResult } from "@prisma-next/family-sql/control";
5
5
  import { MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationScaffoldContext, SchemaOwnership } from "@prisma-next/framework-components/control";
6
6
  import { Contract } from "@prisma-next/contract/types";
@@ -105,6 +105,26 @@ declare class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postg
105
105
  }): PostgresPlanResult;
106
106
  emptyMigration(context: MigrationScaffoldContext, spaceId: string): MigrationPlanWithAuthoringSurface;
107
107
  private planSql;
108
+ /**
109
+ * Rename post-pass for indexes, per `(schema, table)`, widening-only,
110
+ * deterministic by sorted names — the same structure as the policy pass
111
+ * below (which stays untouched: policies pair by hash only).
112
+ *
113
+ * Phase 1 — hash pairing: extras whose live names parse as wire names,
114
+ * grouped by `(schema, table, hash)`; missing nodes iterated in sorted-name
115
+ * order consume the sorted-name-first candidate — a prefix-only rename.
116
+ *
117
+ * Phase 2 — content pairing: the remaining managed-missing nodes
118
+ * (`prefix` defined) against the remaining extras of any name shape,
119
+ * paired iff content-equal (columns ordered-strict both-defined-or-
120
+ * both-undefined, `unique`/`type` strict, `options` loose, bodies
121
+ * byte-equal) — exact→managed adoption convergence.
122
+ *
123
+ * Leftovers proceed as create/drop exactly as before; without the
124
+ * widening allowance the pass is skipped and pairing degrades to the
125
+ * additive half, like the policy pass.
126
+ */
127
+ private pairIndexRenames;
108
128
  /**
109
129
  * Maps the RLS policy presence findings of the one combined tree diff
110
130
  * (`buildPostgresPlanDiff`, already ownership-filtered) into
@@ -1 +1 @@
1
- {"version":3,"file":"planner.d.mts","names":[],"sources":["../src/core/migrations/contract-to-postgres-database-schema-node.ts","../src/core/migrations/planner.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8FgB,qCACd,UAAU,yBACV,SAAS,4BACR;;;iBChCa,+BACd,SAAS,wBACR;;;;;;;;KAWS;WAEG;WACA,MAAM;WACN,oBAAoB;IAE/B;;;;;;;;;;;;;;;;;;;cAoBS,oCAAoC;;cAGnC,UAAU;EAItB,KAAK;aACM;aACA;aACA,QAAQ;;;;;;;;;;;;;;;aAeR,cAAc;aACd;aACA,qBAAqB,cAAc;;;;;;aAMnC;;;;;aAKA,YAAY;;;;;;aAMZ;MACP;EAIJ,eACE,SAAS,0BACT,kBACC;UAaK;;;;;;;;;;;;;;;;;;;;;;;;UAiMA;UAiHA"}
1
+ {"version":3,"file":"planner.d.mts","names":[],"sources":["../src/core/migrations/contract-to-postgres-database-schema-node.ts","../src/core/migrations/planner.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8FgB,qCACd,UAAU,yBACV,SAAS,4BACR;;;iBC9Ba,+BACd,SAAS,wBACR;;;;;;;;KAWS;WAEG;WACA,MAAM;WACN,oBAAoB;IAE/B;;;;;;;;;;;;;;;;;;;cAoBS,oCAAoC;;cAGnC,UAAU;EAItB,KAAK;aACM;aACA;aACA,QAAQ;;;;;;;;;;;;;;;aAeR,cAAc;aACd;aACA,qBAAqB,cAAc;;;;;;aAMnC;;;;;aAKA,YAAY;;;;;;aAMZ;MACP;EAIJ,eACE,SAAS,0BACT,kBACC;UAaK;;;;;;;;;;;;;;;;;;;;UAuNA;;;;;;;;;;;;;;;;;;;;;;;;UA8HA;UAiHA"}
package/dist/planner.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { r as contractToPostgresDatabaseSchemaNode } from "./diff-database-schema-C9H09OD3.mjs";
2
- import { t as createPostgresMigrationPlanner } from "./planner-4sj5cJCY.mjs";
1
+ import { r as contractToPostgresDatabaseSchemaNode } from "./diff-database-schema-qRPwuYBH.mjs";
2
+ import { t as createPostgresMigrationPlanner } from "./planner-BhnkIJX-.mjs";
3
3
  export { contractToPostgresDatabaseSchemaNode, createPostgresMigrationPlanner };
@@ -1,6 +1,6 @@
1
1
  import { b as PG_TEXT_CODEC_ID, h as PG_INT_CODEC_ID } from "./codec-ids-D3G8K0YM.mjs";
2
2
  import { a as nativeEnumEntityKind, c as roleEntityKind, o as policyEntityKind, s as rlsEnablementEntityKind, t as PostgresSchema } from "./postgres-schema-CTplQZDK.mjs";
3
- import { t as postgresAuthoringEntityTypes } from "./authoring-BCzcFRay.mjs";
3
+ import { t as postgresAuthoringEntityTypes } from "./authoring-DnO1B0N9.mjs";
4
4
  import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
5
5
  import { blindCast } from "@prisma-next/utils/casts";
6
6
  import { buildSqlSchemaQualifiedView } from "@prisma-next/sql-contract/contract-view";
@@ -108,4 +108,4 @@ const PostgresContractView = {
108
108
  //#endregion
109
109
  export { PostgresContractSerializer as n, PostgresContractView as t };
110
110
 
111
- //# sourceMappingURL=postgres-contract-view-B8yXVWYe.mjs.map
111
+ //# sourceMappingURL=postgres-contract-view-BeIEyZfD.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-contract-view-B8yXVWYe.mjs","names":[],"sources":["../src/core/postgres-contract-serializer.ts","../src/core/postgres-contract-view.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n SqlContractSerializerBase,\n type SqlEntityHydrationFactory,\n} from '@prisma-next/family-sql/ir';\nimport {\n type AuthoringEntityContext,\n type AuthoringEntityTypeFactoryOutput,\n type AuthoringEntityTypeNamespace,\n isAuthoringEntityTypeDescriptor,\n} from '@prisma-next/framework-components/authoring';\nimport {\n type AnyEntityKindDescriptor,\n type Namespace,\n UNBOUND_NAMESPACE_ID,\n} from '@prisma-next/framework-components/ir';\nimport type { SqlNamespaceInput, SqlStorage } from '@prisma-next/sql-contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { JsonObject } from '@prisma-next/utils/json';\nimport { postgresAuthoringEntityTypes } from './authoring';\nimport { PG_INT_CODEC_ID, PG_TEXT_CODEC_ID } from './codec-ids';\nimport {\n nativeEnumEntityKind,\n policyEntityKind,\n rlsEnablementEntityKind,\n roleEntityKind,\n} from './entity-kinds';\nimport { PostgresSchema } from './postgres-schema';\n\nconst POSTGRES_AUTHORING_CTX: AuthoringEntityContext = {\n family: 'sql',\n target: 'postgres',\n enumInferenceCodecs: { text: PG_TEXT_CODEC_ID, int: PG_INT_CODEC_ID },\n};\n\nfunction isAuthoringEntityTypeFactoryOutput(\n output: unknown,\n): output is AuthoringEntityTypeFactoryOutput<unknown, unknown> {\n return (\n typeof output === 'object' &&\n output !== null &&\n 'factory' in output &&\n typeof output.factory === 'function'\n );\n}\n\n/**\n * Walks a pack's entity-type namespace tree and emits hydration factories\n * keyed by the descriptor's `discriminator`. Used for `storage.types`\n * (codec-triple hydration). Namespace entries hydration dispatches by\n * entries key, not discriminator — handled by `hydrateNamespaceEntities`.\n */\nfunction collectStorageTypesHydrators(\n namespace: AuthoringEntityTypeNamespace,\n): ReadonlyMap<string, SqlEntityHydrationFactory> {\n const registry = new Map<string, SqlEntityHydrationFactory>();\n const walk = (node: AuthoringEntityTypeNamespace): void => {\n for (const value of Object.values(node)) {\n if (isAuthoringEntityTypeDescriptor(value)) {\n if (isAuthoringEntityTypeFactoryOutput(value.output)) {\n const { factory } = value.output;\n registry.set(value.discriminator, (raw) => factory(raw, POSTGRES_AUTHORING_CTX));\n }\n continue;\n }\n if (typeof value === 'object' && value !== null) {\n walk(value);\n }\n }\n };\n walk(namespace);\n return registry;\n}\n\nexport class PostgresContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {\n constructor(extraPackEntityKinds: readonly AnyEntityKindDescriptor[] = []) {\n const storageTypesHydrators = collectStorageTypesHydrators(postgresAuthoringEntityTypes);\n super(storageTypesHydrators, [\n policyEntityKind,\n roleEntityKind,\n rlsEnablementEntityKind,\n nativeEnumEntityKind,\n ...extraPackEntityKinds,\n ]);\n }\n\n protected override hydrateSqlNamespaceEntry(\n nsId: string,\n raw: Record<string, unknown>,\n ): Namespace | SqlNamespaceInput {\n const hydrated = blindCast<\n SqlNamespaceInput,\n 'raw is always plain JSON, so super.hydrateSqlNamespaceEntry returns SqlNamespaceInput'\n >(super.hydrateSqlNamespaceEntry(nsId, raw));\n const { id, entries } = hydrated;\n\n const allSlotsEmpty = Object.values(entries).every(\n (slot) => slot === undefined || Object.keys(slot).length === 0,\n );\n if (id === UNBOUND_NAMESPACE_ID && allSlotsEmpty) {\n return PostgresSchema.unbound;\n }\n const valueSetSlot = entries['valueSet'];\n const hasValueSets = valueSetSlot !== undefined && Object.keys(valueSetSlot).length > 0;\n return new PostgresSchema({\n id,\n entries: {\n ...entries,\n table: entries['table'] ?? {},\n ...(hasValueSets ? { valueSet: valueSetSlot } : {}),\n },\n });\n }\n\n override serializeContract(contract: Contract<SqlStorage>): JsonObject {\n const { storage, ...rest } = contract;\n const namespacesJson: Record<string, JsonObject> = {};\n // Each namespace serializes to its id, its schema-kind tag, and the\n // base's generic entries walk — every enumerable kind on\n // `PostgresSchema.entries`, including `native_enum`.\n for (const [nsId, ns] of Object.entries(storage.namespaces)) {\n const isUnboundSlot = ns.id === UNBOUND_NAMESPACE_ID;\n namespacesJson[nsId] = {\n id: ns.id,\n kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',\n entries: this.serializeNamespaceEntries(ns.entries),\n };\n }\n const storageOut: Record<string, unknown> = {\n storageHash: String(storage.storageHash),\n namespaces: namespacesJson,\n };\n if (storage.types !== undefined) {\n const typesOut: Record<string, JsonObject> = {};\n for (const [name, entry] of Object.entries(storage.types)) {\n typesOut[name] = this.serializeJsonObject(entry);\n }\n storageOut['types'] = typesOut;\n }\n return blindCast<\n JsonObject,\n 'contract minus storage plus a JSON-shaped storageOut is a JsonObject'\n >({\n ...rest,\n storage: storageOut,\n });\n }\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport {\n buildSqlSchemaQualifiedView,\n type SqlSchemaQualifiedView,\n} from '@prisma-next/sql-contract/contract-view';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { PostgresContractSerializer } from './postgres-contract-serializer';\n\n/**\n * A schema-qualified Postgres contract view: the deserialized contract\n * intersected with a single `namespace` member holding every schema by id. It is\n * substitutable for `Contract` (carries `storage`, `domain`, …) and reaches each\n * schema's entities through `view.namespace.<schema>`:\n *\n * ```ts\n * const view = PostgresContractView.fromJson<Contract>(contractJson);\n * view.namespace.public.table.users // typed table leaf in the public schema\n * view.namespace.auth.table.users // the auth schema's own users table\n * view.namespace.public.entries.policy.X // pack-contributed kind (RLS / #771 path)\n * view.namespace.__unbound__.table.X // default schema, keyed by its raw id\n * view.storage // the full contract is still present\n * ```\n *\n * This mirrors the runtime `db.enums.<ns>` keying exactly (the default schema\n * keeps its literal `__unbound__` id). Schema names are NOT promoted to the\n * contract root, so there is no collision with contract envelope fields — a\n * schema named `storage` is `view.namespace.storage`, while `view.storage`\n * stays the contract's `storage`.\n */\nexport type PostgresContractView<TContract extends Contract<SqlStorage> = Contract<SqlStorage>> =\n SqlSchemaQualifiedView<TContract>;\n\nexport const PostgresContractView = {\n /** Wrap an already-deserialized Postgres contract in a schema-qualified view. */\n from<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n ): PostgresContractView<TContract> {\n return buildSqlSchemaQualifiedView(contract);\n },\n\n /** Deserialize a Postgres contract JSON envelope and wrap it in a view. */\n fromJson<TContract extends Contract<SqlStorage> = Contract<SqlStorage>>(\n json: unknown,\n ): PostgresContractView<TContract> {\n const contract = new PostgresContractSerializer().deserializeContract<TContract>(json);\n return buildSqlSchemaQualifiedView(contract);\n },\n};\n"],"mappings":";;;;;;;;;AA6BA,MAAM,yBAAiD;CACrD,QAAQ;CACR,QAAQ;CACR,qBAAqB;EAAE,MAAM;EAAkB,KAAK;CAAgB;AACtE;AAEA,SAAS,mCACP,QAC8D;CAC9D,OACE,OAAO,WAAW,YAClB,WAAW,QACX,aAAa,UACb,OAAO,OAAO,YAAY;AAE9B;;;;;;;AAQA,SAAS,6BACP,WACgD;CAChD,MAAM,2BAAW,IAAI,IAAuC;CAC5D,MAAM,QAAQ,SAA6C;EACzD,KAAK,MAAM,SAAS,OAAO,OAAO,IAAI,GAAG;GACvC,IAAI,gCAAgC,KAAK,GAAG;IAC1C,IAAI,mCAAmC,MAAM,MAAM,GAAG;KACpD,MAAM,EAAE,YAAY,MAAM;KAC1B,SAAS,IAAI,MAAM,gBAAgB,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;IACjF;IACA;GACF;GACA,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,KAAK,KAAK;EAEd;CACF;CACA,KAAK,SAAS;CACd,OAAO;AACT;AAEA,IAAa,6BAAb,cAAgD,0BAAgD;CAC9F,YAAY,uBAA2D,CAAC,GAAG;EACzE,MAAM,wBAAwB,6BAA6B,4BAA4B;EACvF,MAAM,uBAAuB;GAC3B;GACA;GACA;GACA;GACA,GAAG;EACL,CAAC;CACH;CAEA,yBACE,MACA,KAC+B;EAK/B,MAAM,EAAE,IAAI,YAJK,UAGf,MAAM,yBAAyB,MAAM,GAAG,CACX;EAE/B,MAAM,gBAAgB,OAAO,OAAO,OAAO,CAAC,CAAC,OAC1C,SAAS,SAAS,KAAA,KAAa,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,CAC/D;EACA,IAAI,OAAO,wBAAwB,eACjC,OAAO,eAAe;EAExB,MAAM,eAAe,QAAQ;EAC7B,MAAM,eAAe,iBAAiB,KAAA,KAAa,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS;EACtF,OAAO,IAAI,eAAe;GACxB;GACA,SAAS;IACP,GAAG;IACH,OAAO,QAAQ,YAAY,CAAC;IAC5B,GAAI,eAAe,EAAE,UAAU,aAAa,IAAI,CAAC;GACnD;EACF,CAAC;CACH;CAEA,kBAA2B,UAA4C;EACrE,MAAM,EAAE,SAAS,GAAG,SAAS;EAC7B,MAAM,iBAA6C,CAAC;EAIpD,KAAK,MAAM,CAAC,MAAM,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAAG;GAC3D,MAAM,gBAAgB,GAAG,OAAO;GAChC,eAAe,QAAQ;IACrB,IAAI,GAAG;IACP,MAAM,gBAAgB,4BAA4B;IAClD,SAAS,KAAK,0BAA0B,GAAG,OAAO;GACpD;EACF;EACA,MAAM,aAAsC;GAC1C,aAAa,OAAO,QAAQ,WAAW;GACvC,YAAY;EACd;EACA,IAAI,QAAQ,UAAU,KAAA,GAAW;GAC/B,MAAM,WAAuC,CAAC;GAC9C,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,QAAQ,KAAK,GACtD,SAAS,QAAQ,KAAK,oBAAoB,KAAK;GAEjD,WAAW,WAAW;EACxB;EACA,OAAO,UAGL;GACA,GAAG;GACH,SAAS;EACX,CAAC;CACH;AACF;;;ACnHA,MAAa,uBAAuB;;CAElC,KACE,UACiC;EACjC,OAAO,4BAA4B,QAAQ;CAC7C;;CAGA,SACE,MACiC;EAEjC,OAAO,4BADU,IAAI,2BAA2B,CAAC,CAAC,oBAA+B,IACvC,CAAC;CAC7C;AACF"}
1
+ {"version":3,"file":"postgres-contract-view-BeIEyZfD.mjs","names":[],"sources":["../src/core/postgres-contract-serializer.ts","../src/core/postgres-contract-view.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n SqlContractSerializerBase,\n type SqlEntityHydrationFactory,\n} from '@prisma-next/family-sql/ir';\nimport {\n type AuthoringEntityContext,\n type AuthoringEntityTypeFactoryOutput,\n type AuthoringEntityTypeNamespace,\n isAuthoringEntityTypeDescriptor,\n} from '@prisma-next/framework-components/authoring';\nimport {\n type AnyEntityKindDescriptor,\n type Namespace,\n UNBOUND_NAMESPACE_ID,\n} from '@prisma-next/framework-components/ir';\nimport type { SqlNamespaceInput, SqlStorage } from '@prisma-next/sql-contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { JsonObject } from '@prisma-next/utils/json';\nimport { postgresAuthoringEntityTypes } from './authoring';\nimport { PG_INT_CODEC_ID, PG_TEXT_CODEC_ID } from './codec-ids';\nimport {\n nativeEnumEntityKind,\n policyEntityKind,\n rlsEnablementEntityKind,\n roleEntityKind,\n} from './entity-kinds';\nimport { PostgresSchema } from './postgres-schema';\n\nconst POSTGRES_AUTHORING_CTX: AuthoringEntityContext = {\n family: 'sql',\n target: 'postgres',\n enumInferenceCodecs: { text: PG_TEXT_CODEC_ID, int: PG_INT_CODEC_ID },\n};\n\nfunction isAuthoringEntityTypeFactoryOutput(\n output: unknown,\n): output is AuthoringEntityTypeFactoryOutput<unknown, unknown> {\n return (\n typeof output === 'object' &&\n output !== null &&\n 'factory' in output &&\n typeof output.factory === 'function'\n );\n}\n\n/**\n * Walks a pack's entity-type namespace tree and emits hydration factories\n * keyed by the descriptor's `discriminator`. Used for `storage.types`\n * (codec-triple hydration). Namespace entries hydration dispatches by\n * entries key, not discriminator — handled by `hydrateNamespaceEntities`.\n */\nfunction collectStorageTypesHydrators(\n namespace: AuthoringEntityTypeNamespace,\n): ReadonlyMap<string, SqlEntityHydrationFactory> {\n const registry = new Map<string, SqlEntityHydrationFactory>();\n const walk = (node: AuthoringEntityTypeNamespace): void => {\n for (const value of Object.values(node)) {\n if (isAuthoringEntityTypeDescriptor(value)) {\n if (isAuthoringEntityTypeFactoryOutput(value.output)) {\n const { factory } = value.output;\n registry.set(value.discriminator, (raw) => factory(raw, POSTGRES_AUTHORING_CTX));\n }\n continue;\n }\n if (typeof value === 'object' && value !== null) {\n walk(value);\n }\n }\n };\n walk(namespace);\n return registry;\n}\n\nexport class PostgresContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {\n constructor(extraPackEntityKinds: readonly AnyEntityKindDescriptor[] = []) {\n const storageTypesHydrators = collectStorageTypesHydrators(postgresAuthoringEntityTypes);\n super(storageTypesHydrators, [\n policyEntityKind,\n roleEntityKind,\n rlsEnablementEntityKind,\n nativeEnumEntityKind,\n ...extraPackEntityKinds,\n ]);\n }\n\n protected override hydrateSqlNamespaceEntry(\n nsId: string,\n raw: Record<string, unknown>,\n ): Namespace | SqlNamespaceInput {\n const hydrated = blindCast<\n SqlNamespaceInput,\n 'raw is always plain JSON, so super.hydrateSqlNamespaceEntry returns SqlNamespaceInput'\n >(super.hydrateSqlNamespaceEntry(nsId, raw));\n const { id, entries } = hydrated;\n\n const allSlotsEmpty = Object.values(entries).every(\n (slot) => slot === undefined || Object.keys(slot).length === 0,\n );\n if (id === UNBOUND_NAMESPACE_ID && allSlotsEmpty) {\n return PostgresSchema.unbound;\n }\n const valueSetSlot = entries['valueSet'];\n const hasValueSets = valueSetSlot !== undefined && Object.keys(valueSetSlot).length > 0;\n return new PostgresSchema({\n id,\n entries: {\n ...entries,\n table: entries['table'] ?? {},\n ...(hasValueSets ? { valueSet: valueSetSlot } : {}),\n },\n });\n }\n\n override serializeContract(contract: Contract<SqlStorage>): JsonObject {\n const { storage, ...rest } = contract;\n const namespacesJson: Record<string, JsonObject> = {};\n // Each namespace serializes to its id, its schema-kind tag, and the\n // base's generic entries walk — every enumerable kind on\n // `PostgresSchema.entries`, including `native_enum`.\n for (const [nsId, ns] of Object.entries(storage.namespaces)) {\n const isUnboundSlot = ns.id === UNBOUND_NAMESPACE_ID;\n namespacesJson[nsId] = {\n id: ns.id,\n kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',\n entries: this.serializeNamespaceEntries(ns.entries),\n };\n }\n const storageOut: Record<string, unknown> = {\n storageHash: String(storage.storageHash),\n namespaces: namespacesJson,\n };\n if (storage.types !== undefined) {\n const typesOut: Record<string, JsonObject> = {};\n for (const [name, entry] of Object.entries(storage.types)) {\n typesOut[name] = this.serializeJsonObject(entry);\n }\n storageOut['types'] = typesOut;\n }\n return blindCast<\n JsonObject,\n 'contract minus storage plus a JSON-shaped storageOut is a JsonObject'\n >({\n ...rest,\n storage: storageOut,\n });\n }\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport {\n buildSqlSchemaQualifiedView,\n type SqlSchemaQualifiedView,\n} from '@prisma-next/sql-contract/contract-view';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { PostgresContractSerializer } from './postgres-contract-serializer';\n\n/**\n * A schema-qualified Postgres contract view: the deserialized contract\n * intersected with a single `namespace` member holding every schema by id. It is\n * substitutable for `Contract` (carries `storage`, `domain`, …) and reaches each\n * schema's entities through `view.namespace.<schema>`:\n *\n * ```ts\n * const view = PostgresContractView.fromJson<Contract>(contractJson);\n * view.namespace.public.table.users // typed table leaf in the public schema\n * view.namespace.auth.table.users // the auth schema's own users table\n * view.namespace.public.entries.policy.X // pack-contributed kind (RLS / #771 path)\n * view.namespace.__unbound__.table.X // default schema, keyed by its raw id\n * view.storage // the full contract is still present\n * ```\n *\n * This mirrors the runtime `db.enums.<ns>` keying exactly (the default schema\n * keeps its literal `__unbound__` id). Schema names are NOT promoted to the\n * contract root, so there is no collision with contract envelope fields — a\n * schema named `storage` is `view.namespace.storage`, while `view.storage`\n * stays the contract's `storage`.\n */\nexport type PostgresContractView<TContract extends Contract<SqlStorage> = Contract<SqlStorage>> =\n SqlSchemaQualifiedView<TContract>;\n\nexport const PostgresContractView = {\n /** Wrap an already-deserialized Postgres contract in a schema-qualified view. */\n from<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n ): PostgresContractView<TContract> {\n return buildSqlSchemaQualifiedView(contract);\n },\n\n /** Deserialize a Postgres contract JSON envelope and wrap it in a view. */\n fromJson<TContract extends Contract<SqlStorage> = Contract<SqlStorage>>(\n json: unknown,\n ): PostgresContractView<TContract> {\n const contract = new PostgresContractSerializer().deserializeContract<TContract>(json);\n return buildSqlSchemaQualifiedView(contract);\n },\n};\n"],"mappings":";;;;;;;;;AA6BA,MAAM,yBAAiD;CACrD,QAAQ;CACR,QAAQ;CACR,qBAAqB;EAAE,MAAM;EAAkB,KAAK;CAAgB;AACtE;AAEA,SAAS,mCACP,QAC8D;CAC9D,OACE,OAAO,WAAW,YAClB,WAAW,QACX,aAAa,UACb,OAAO,OAAO,YAAY;AAE9B;;;;;;;AAQA,SAAS,6BACP,WACgD;CAChD,MAAM,2BAAW,IAAI,IAAuC;CAC5D,MAAM,QAAQ,SAA6C;EACzD,KAAK,MAAM,SAAS,OAAO,OAAO,IAAI,GAAG;GACvC,IAAI,gCAAgC,KAAK,GAAG;IAC1C,IAAI,mCAAmC,MAAM,MAAM,GAAG;KACpD,MAAM,EAAE,YAAY,MAAM;KAC1B,SAAS,IAAI,MAAM,gBAAgB,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;IACjF;IACA;GACF;GACA,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,KAAK,KAAK;EAEd;CACF;CACA,KAAK,SAAS;CACd,OAAO;AACT;AAEA,IAAa,6BAAb,cAAgD,0BAAgD;CAC9F,YAAY,uBAA2D,CAAC,GAAG;EACzE,MAAM,wBAAwB,6BAA6B,4BAA4B;EACvF,MAAM,uBAAuB;GAC3B;GACA;GACA;GACA;GACA,GAAG;EACL,CAAC;CACH;CAEA,yBACE,MACA,KAC+B;EAK/B,MAAM,EAAE,IAAI,YAJK,UAGf,MAAM,yBAAyB,MAAM,GAAG,CACX;EAE/B,MAAM,gBAAgB,OAAO,OAAO,OAAO,CAAC,CAAC,OAC1C,SAAS,SAAS,KAAA,KAAa,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,CAC/D;EACA,IAAI,OAAO,wBAAwB,eACjC,OAAO,eAAe;EAExB,MAAM,eAAe,QAAQ;EAC7B,MAAM,eAAe,iBAAiB,KAAA,KAAa,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS;EACtF,OAAO,IAAI,eAAe;GACxB;GACA,SAAS;IACP,GAAG;IACH,OAAO,QAAQ,YAAY,CAAC;IAC5B,GAAI,eAAe,EAAE,UAAU,aAAa,IAAI,CAAC;GACnD;EACF,CAAC;CACH;CAEA,kBAA2B,UAA4C;EACrE,MAAM,EAAE,SAAS,GAAG,SAAS;EAC7B,MAAM,iBAA6C,CAAC;EAIpD,KAAK,MAAM,CAAC,MAAM,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAAG;GAC3D,MAAM,gBAAgB,GAAG,OAAO;GAChC,eAAe,QAAQ;IACrB,IAAI,GAAG;IACP,MAAM,gBAAgB,4BAA4B;IAClD,SAAS,KAAK,0BAA0B,GAAG,OAAO;GACpD;EACF;EACA,MAAM,aAAsC;GAC1C,aAAa,OAAO,QAAQ,WAAW;GACvC,YAAY;EACd;EACA,IAAI,QAAQ,UAAU,KAAA,GAAW;GAC/B,MAAM,WAAuC,CAAC;GAC9C,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,QAAQ,KAAK,GACtD,SAAS,QAAQ,KAAK,oBAAoB,KAAK;GAEjD,WAAW,WAAW;EACxB;EACA,OAAO,UAGL;GACA,GAAG;GACH,SAAS;EACX,CAAC;CACH;AACF;;;ACnHA,MAAa,uBAAuB;;CAElC,KACE,UACiC;EACjC,OAAO,4BAA4B,QAAQ;CAC7C;;CAGA,SACE,MACiC;EAEjC,OAAO,4BADU,IAAI,2BAA2B,CAAC,CAAC,oBAA+B,IACvC,CAAC;CAC7C;AACF"}
@@ -1,7 +1,7 @@
1
1
  import { t as errorPostgresMigrationStackMissing } from "./errors-DBSNx7EJ.mjs";
2
2
  import { g as PostgresRlsPolicy } from "./postgres-schema-CTplQZDK.mjs";
3
- import { A as SetDefaultCall, C as DropNativeEnumTypeCall, D as EnableRowLevelSecurityCall, E as DropTableCall, F as installExtension, S as DropIndexCall, T as DropPostgresRlsPolicyCall, _ as DisableRowLevelSecurityCall, b as DropConstraintCall, c as AddUniqueCall, d as CreateIndexCall, f as CreateNativeEnumTypeCall, h as CreateTableCall, i as AddNativeEnumValueCall, j as SetNotNullCall, k as RenamePostgresRlsPolicyCall, l as AlterColumnTypeCall, m as CreateSchemaCall, n as AddColumnCall, p as CreatePostgresRlsPolicyCall, r as AddForeignKeyCall, s as AddPrimaryKeyCall, t as AddCheckConstraintCall, v as DropCheckConstraintCall, w as DropNotNullCall, x as DropDefaultCall, y as DropColumnCall } from "./op-factory-call-BVYLIojV.mjs";
4
- import { t as PostgresContractView } from "./postgres-contract-view-B8yXVWYe.mjs";
3
+ import { A as RenamePostgresRlsPolicyCall, C as DropNativeEnumTypeCall, D as EnableRowLevelSecurityCall, E as DropTableCall, I as installExtension, M as SetNotNullCall, S as DropIndexCall, T as DropPostgresRlsPolicyCall, _ as DisableRowLevelSecurityCall, b as DropConstraintCall, c as AddUniqueCall, d as CreateIndexCall, f as CreateNativeEnumTypeCall, h as CreateTableCall, i as AddNativeEnumValueCall, j as SetDefaultCall, k as RenameIndexCall, l as AlterColumnTypeCall, m as CreateSchemaCall, n as AddColumnCall, p as CreatePostgresRlsPolicyCall, r as AddForeignKeyCall, s as AddPrimaryKeyCall, t as AddCheckConstraintCall, v as DropCheckConstraintCall, w as DropNotNullCall, x as DropDefaultCall, y as DropColumnCall } from "./op-factory-call-CIaPDDUc.mjs";
4
+ import { t as PostgresContractView } from "./postgres-contract-view-BeIEyZfD.mjs";
5
5
  import { t as dataTransform } from "./data-transform-BOWpliq8.mjs";
6
6
  import { Migration } from "@prisma-next/family-sql/migration";
7
7
  import { MigrationContractViews } from "@prisma-next/migration-tools/migration";
@@ -164,7 +164,10 @@ var PostgresMigration = class extends Migration {
164
164
  return new DropDefaultCall(options.schema, options.table, options.column).toOp(this.controlAdapterFor("dropDefault"));
165
165
  }
166
166
  createIndex(options) {
167
- return new CreateIndexCall(options.schema, options.table, options.index, options.columns, options.extras).toOp(this.controlAdapterFor("createIndex"));
167
+ return new CreateIndexCall(options.schema, options.table, options.index, options.columns !== void 0 ? { columns: options.columns } : { expression: options.expression }, options.extras).toOp(this.controlAdapterFor("createIndex"));
168
+ }
169
+ renameIndex(options) {
170
+ return new RenameIndexCall(options.schema, options.table, options.from, options.to).toOp(this.controlAdapterFor("renameIndex"));
168
171
  }
169
172
  dropIndex(options) {
170
173
  return new DropIndexCall(options.schema, options.table, options.index).toOp(this.controlAdapterFor("dropIndex"));
@@ -191,4 +194,4 @@ var PostgresMigration = class extends Migration {
191
194
  //#endregion
192
195
  export { PostgresMigration as t };
193
196
 
194
- //# sourceMappingURL=postgres-migration-GIOABsAa.mjs.map
197
+ //# sourceMappingURL=postgres-migration--BzvpA92.mjs.map