@prisma-next/target-postgres 0.14.0-dev.5 → 0.14.0-dev.50

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 (238) hide show
  1. package/dist/authoring-DzHOdWTl.mjs +364 -0
  2. package/dist/authoring-DzHOdWTl.mjs.map +1 -0
  3. package/dist/canonicalize-Bn3BM1Cn.mjs +46 -0
  4. package/dist/canonicalize-Bn3BM1Cn.mjs.map +1 -0
  5. package/dist/canonicalize-CAbXtVtB.d.mts +37 -0
  6. package/dist/canonicalize-CAbXtVtB.d.mts.map +1 -0
  7. package/dist/{codec-ids-CnXu9Qy3.d.mts → codec-ids-BzrFF-I4.d.mts} +3 -2
  8. package/dist/codec-ids-BzrFF-I4.d.mts.map +1 -0
  9. package/dist/{codec-ids-BvytN2P8.mjs → codec-ids-C_-Hj6bL.mjs} +3 -2
  10. package/dist/codec-ids-C_-Hj6bL.mjs.map +1 -0
  11. package/dist/codec-ids.d.mts +2 -2
  12. package/dist/codec-ids.mjs +2 -2
  13. package/dist/{codec-types-DHCkwPKE.d.mts → codec-types-BDVmvKAW.d.mts} +3 -2
  14. package/dist/codec-types-BDVmvKAW.d.mts.map +1 -0
  15. package/dist/codec-types.d.mts +1 -1
  16. package/dist/{codecs--0A5_4Bq.d.mts → codecs-Dk2sxGLv.d.mts} +77 -4
  17. package/dist/codecs-Dk2sxGLv.d.mts.map +1 -0
  18. package/dist/codecs.d.mts +1 -1
  19. package/dist/codecs.mjs +117 -2
  20. package/dist/codecs.mjs.map +1 -1
  21. package/dist/contract-free.d.mts +8 -3
  22. package/dist/contract-free.d.mts.map +1 -1
  23. package/dist/contract-free.mjs +4 -4
  24. package/dist/control-policy-DUFgy9jO.mjs +1103 -0
  25. package/dist/control-policy-DUFgy9jO.mjs.map +1 -0
  26. package/dist/control.d.mts +2 -2
  27. package/dist/control.d.mts.map +1 -1
  28. package/dist/control.mjs +757 -35
  29. package/dist/control.mjs.map +1 -1
  30. package/dist/data-transform-BOWpliq8.mjs.map +1 -1
  31. package/dist/{data-transform-DDgWdB5o.d.mts → data-transform-DPzwBMhW.d.mts} +3 -3
  32. package/dist/{data-transform-DDgWdB5o.d.mts.map → data-transform-DPzwBMhW.d.mts.map} +1 -1
  33. package/dist/data-transform.d.mts +1 -1
  34. package/dist/{ddl-QDyOSeLc.mjs → ddl-ujxH2A7r.mjs} +63 -6
  35. package/dist/ddl-ujxH2A7r.mjs.map +1 -0
  36. package/dist/ddl.d.mts +3 -2
  37. package/dist/ddl.mjs +2 -2
  38. package/dist/default-normalizer.d.mts +1 -1
  39. package/dist/default-normalizer.d.mts.map +1 -1
  40. package/dist/default-normalizer.mjs +247 -1
  41. package/dist/default-normalizer.mjs.map +1 -0
  42. package/dist/descriptor-meta-CuGDsrG4.mjs +19 -0
  43. package/dist/descriptor-meta-CuGDsrG4.mjs.map +1 -0
  44. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs +12 -0
  45. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs.map +1 -0
  46. package/dist/diff-database-schema-BmSmWcaY.mjs +313 -0
  47. package/dist/diff-database-schema-BmSmWcaY.mjs.map +1 -0
  48. package/dist/diff-database-schema.d.mts +46 -0
  49. package/dist/diff-database-schema.d.mts.map +1 -0
  50. package/dist/diff-database-schema.mjs +2 -0
  51. package/dist/issue-planner.d.mts +35 -11
  52. package/dist/issue-planner.d.mts.map +1 -1
  53. package/dist/issue-planner.mjs +2 -2
  54. package/dist/migration.d.mts +5 -5
  55. package/dist/migration.d.mts.map +1 -1
  56. package/dist/migration.mjs +4 -4
  57. package/dist/namespace-ids-xtp_ZY86.mjs +7 -0
  58. package/dist/namespace-ids-xtp_ZY86.mjs.map +1 -0
  59. package/dist/native-type-normalizer.mjs +37 -1
  60. package/dist/native-type-normalizer.mjs.map +1 -0
  61. package/dist/nodes-CSkPX3rI.d.mts +120 -0
  62. package/dist/nodes-CSkPX3rI.d.mts.map +1 -0
  63. package/dist/{nodes-Bbhs2rwj.mjs → nodes-Dh__NS58.mjs} +56 -2
  64. package/dist/nodes-Dh__NS58.mjs.map +1 -0
  65. package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-BKRnMgrB.mjs} +205 -31
  66. package/dist/op-factory-call-BKRnMgrB.mjs.map +1 -0
  67. package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-Dt-Jx5JS.d.mts} +46 -15
  68. package/dist/op-factory-call-Dt-Jx5JS.d.mts.map +1 -0
  69. package/dist/op-factory-call.d.mts +2 -2
  70. package/dist/op-factory-call.mjs +2 -2
  71. package/dist/pack.d.mts +115 -3
  72. package/dist/pack.d.mts.map +1 -1
  73. package/dist/pack.mjs +1 -1
  74. package/dist/planner-BMBRPzsv.mjs +367 -0
  75. package/dist/planner-BMBRPzsv.mjs.map +1 -0
  76. package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-B8Nn6nHN.mjs} +12 -27
  77. package/dist/planner-ddl-builders-B8Nn6nHN.mjs.map +1 -0
  78. package/dist/planner-ddl-builders.d.mts +4 -6
  79. package/dist/planner-ddl-builders.d.mts.map +1 -1
  80. package/dist/planner-ddl-builders.mjs +2 -2
  81. package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -1
  82. package/dist/planner-identity-values.d.mts +8 -2
  83. package/dist/planner-identity-values.d.mts.map +1 -1
  84. package/dist/planner-identity-values.mjs +2 -2
  85. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-C0a7I1-e.d.mts} +4 -4
  86. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-C0a7I1-e.d.mts.map} +1 -1
  87. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-Dp6IO_gj.mjs} +3 -3
  88. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-Dp6IO_gj.mjs.map} +1 -1
  89. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  90. package/dist/planner-produced-postgres-migration.mjs +1 -1
  91. package/dist/{planner-sql-checks-jqUUGyQR.mjs → planner-sql-checks-Cze3vMfe.mjs} +2 -2
  92. package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-Cze3vMfe.mjs.map} +1 -1
  93. package/dist/planner-sql-checks.d.mts +2 -2
  94. package/dist/planner-sql-checks.d.mts.map +1 -1
  95. package/dist/planner-sql-checks.mjs +1 -1
  96. package/dist/{planner-target-details-CIY6tLeo.d.mts → planner-target-details-HkP4RrRO.d.mts} +2 -2
  97. package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -0
  98. package/dist/planner-target-details.d.mts +1 -1
  99. package/dist/planner.d.mts +55 -17
  100. package/dist/planner.d.mts.map +1 -1
  101. package/dist/planner.mjs +3 -2
  102. package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-3xfUgjnC.mjs} +44 -41
  103. package/dist/postgres-contract-view-3xfUgjnC.mjs.map +1 -0
  104. package/dist/postgres-contract-view-C9j5cqP0.d.mts +34 -0
  105. package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +1 -0
  106. package/dist/postgres-database-schema-node-C9bTuMrd.d.mts +190 -0
  107. package/dist/postgres-database-schema-node-C9bTuMrd.d.mts.map +1 -0
  108. package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-D0jwzYDT.mjs} +21 -2
  109. package/dist/postgres-migration-D0jwzYDT.mjs.map +1 -0
  110. package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-DFaxuRyI.d.mts} +20 -7
  111. package/dist/postgres-migration-DFaxuRyI.d.mts.map +1 -0
  112. package/dist/postgres-native-enum-xdiqmBf_.mjs +41 -0
  113. package/dist/postgres-native-enum-xdiqmBf_.mjs.map +1 -0
  114. package/dist/postgres-rls-policy--CSddvMR.d.mts +52 -0
  115. package/dist/postgres-rls-policy--CSddvMR.d.mts.map +1 -0
  116. package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-CajYAwny.mjs} +135 -7
  117. package/dist/postgres-schema-CajYAwny.mjs.map +1 -0
  118. package/dist/postgres-schema-DqnhQRvR.d.mts +226 -0
  119. package/dist/postgres-schema-DqnhQRvR.d.mts.map +1 -0
  120. package/dist/postgres-table-schema-node-BgaSrxYN.mjs +249 -0
  121. package/dist/postgres-table-schema-node-BgaSrxYN.mjs.map +1 -0
  122. package/dist/render-ops.d.mts +1 -1
  123. package/dist/{render-typescript-KMgosran.mjs → render-typescript-7yqILcwr.mjs} +45 -16
  124. package/dist/render-typescript-7yqILcwr.mjs.map +1 -0
  125. package/dist/render-typescript.mjs +1 -1
  126. package/dist/resolve-ddl-schema-Bv1ZvjX8.mjs +22 -0
  127. package/dist/resolve-ddl-schema-Bv1ZvjX8.mjs.map +1 -0
  128. package/dist/rls-canonicalize.d.mts +2 -0
  129. package/dist/rls-canonicalize.mjs +2 -0
  130. package/dist/runtime.d.mts +6 -8
  131. package/dist/runtime.d.mts.map +1 -1
  132. package/dist/runtime.mjs +3 -3
  133. package/dist/runtime.mjs.map +1 -1
  134. package/dist/schema-ir-annotations.d.mts +15 -0
  135. package/dist/schema-ir-annotations.d.mts.map +1 -0
  136. package/dist/schema-ir-annotations.mjs +2 -0
  137. package/dist/schema-node-kinds-ClScchhi.mjs +76 -0
  138. package/dist/schema-node-kinds-ClScchhi.mjs.map +1 -0
  139. package/dist/types.d.mts +4 -140
  140. package/dist/types.mjs +3 -2
  141. package/package.json +23 -17
  142. package/src/contract-free/checks.ts +73 -0
  143. package/src/contract-free/ddl.ts +45 -1
  144. package/src/core/authoring.ts +287 -2
  145. package/src/core/codec-ids.ts +1 -0
  146. package/src/core/codec-type-map.ts +2 -0
  147. package/src/core/codecs.ts +141 -1
  148. package/src/core/ddl/nodes.ts +94 -2
  149. package/src/core/default-normalizer.ts +122 -2
  150. package/src/core/descriptor-meta.ts +6 -1
  151. package/src/core/entity-kinds.ts +30 -0
  152. package/src/core/migrations/bound-schema.ts +10 -0
  153. package/src/core/migrations/column-ddl-rendering.ts +117 -0
  154. package/src/core/migrations/contract-to-postgres-database-schema-node.ts +149 -0
  155. package/src/core/migrations/control-policy.ts +70 -47
  156. package/src/core/migrations/diff-database-schema.ts +280 -0
  157. package/src/core/migrations/issue-planner.ts +647 -652
  158. package/src/core/migrations/op-factory-call.ts +109 -21
  159. package/src/core/migrations/operations/columns.ts +24 -12
  160. package/src/core/migrations/operations/constraints.ts +1 -1
  161. package/src/core/migrations/operations/data-transform.ts +6 -0
  162. package/src/core/migrations/operations/dependencies.ts +2 -1
  163. package/src/core/migrations/operations/rls.ts +106 -0
  164. package/src/core/migrations/operations/shared.ts +0 -30
  165. package/src/core/migrations/planner-ddl-builders.ts +20 -58
  166. package/src/core/migrations/planner-identity-values.ts +1 -1
  167. package/src/core/migrations/planner-recipes.ts +31 -13
  168. package/src/core/migrations/planner-sql-checks.ts +1 -1
  169. package/src/core/migrations/planner-strategies.ts +248 -216
  170. package/src/core/migrations/planner-target-details.ts +3 -1
  171. package/src/core/migrations/planner.ts +297 -59
  172. package/src/core/migrations/postgres-migration.ts +34 -4
  173. package/src/core/migrations/render-typescript.ts +42 -15
  174. package/src/core/migrations/resolve-ddl-schema.ts +26 -0
  175. package/src/core/migrations/runner.ts +10 -16
  176. package/src/core/migrations/verify-postgres-namespaces.ts +47 -30
  177. package/src/core/namespace-ids.ts +3 -0
  178. package/src/core/postgres-contract-serializer.ts +41 -71
  179. package/src/core/postgres-contract-view.ts +48 -0
  180. package/src/core/postgres-native-enum.ts +51 -0
  181. package/src/core/postgres-rls-policy.ts +64 -0
  182. package/src/core/postgres-role.ts +37 -0
  183. package/src/core/postgres-schema-verifier.ts +10 -7
  184. package/src/core/postgres-schema.ts +62 -14
  185. package/src/core/postgres-validators.ts +27 -0
  186. package/src/core/psl-infer/infer-psl-contract.ts +1068 -0
  187. package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
  188. package/src/core/psl-infer/postgres-type-map.ts +157 -0
  189. package/src/core/rls/canonicalize.ts +48 -0
  190. package/src/core/schema-ir/postgres-database-schema-node.ts +60 -0
  191. package/src/core/schema-ir/postgres-namespace-schema-node.ts +60 -0
  192. package/src/core/schema-ir/postgres-policy-schema-node.ts +90 -0
  193. package/src/core/schema-ir/postgres-role-schema-node.ts +63 -0
  194. package/src/core/schema-ir/postgres-table-schema-node.ts +118 -0
  195. package/src/core/schema-ir/schema-node-kinds.ts +106 -0
  196. package/src/exports/contract-free.ts +7 -1
  197. package/src/exports/control.ts +27 -33
  198. package/src/exports/ddl.ts +4 -0
  199. package/src/exports/diff-database-schema.ts +7 -0
  200. package/src/exports/issue-planner.ts +1 -1
  201. package/src/exports/migration.ts +1 -0
  202. package/src/exports/op-factory-call.ts +1 -0
  203. package/src/exports/planner-ddl-builders.ts +0 -2
  204. package/src/exports/planner-identity-values.ts +4 -1
  205. package/src/exports/planner.ts +1 -0
  206. package/src/exports/rls-canonicalize.ts +6 -0
  207. package/src/exports/runtime.ts +1 -0
  208. package/src/exports/schema-ir-annotations.ts +1 -0
  209. package/src/exports/types.ts +28 -0
  210. package/dist/codec-ids-BvytN2P8.mjs.map +0 -1
  211. package/dist/codec-ids-CnXu9Qy3.d.mts.map +0 -1
  212. package/dist/codec-types-DHCkwPKE.d.mts.map +0 -1
  213. package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
  214. package/dist/ddl-QDyOSeLc.mjs.map +0 -1
  215. package/dist/default-normalizer-DyyCHQWs.mjs +0 -131
  216. package/dist/default-normalizer-DyyCHQWs.mjs.map +0 -1
  217. package/dist/descriptor-meta-CpGygXpI.mjs +0 -140
  218. package/dist/descriptor-meta-CpGygXpI.mjs.map +0 -1
  219. package/dist/issue-planner-DL6g3CmE.mjs +0 -824
  220. package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
  221. package/dist/native-type-normalizer-Bc9XJzWC.mjs +0 -38
  222. package/dist/native-type-normalizer-Bc9XJzWC.mjs.map +0 -1
  223. package/dist/nodes-Bbhs2rwj.mjs.map +0 -1
  224. package/dist/nodes-pLeLgdis.d.mts +0 -67
  225. package/dist/nodes-pLeLgdis.d.mts.map +0 -1
  226. package/dist/op-factory-call-D_p5vxwt.mjs.map +0 -1
  227. package/dist/op-factory-call-DmQEc3XV.d.mts.map +0 -1
  228. package/dist/planner-Bs_baQax.mjs +0 -324
  229. package/dist/planner-Bs_baQax.mjs.map +0 -1
  230. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +0 -1
  231. package/dist/planner-target-details-CIY6tLeo.d.mts.map +0 -1
  232. package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +0 -1
  233. package/dist/postgres-migration-B5jKrXv3.mjs.map +0 -1
  234. package/dist/postgres-migration-Y4YBJqkS.d.mts.map +0 -1
  235. package/dist/postgres-schema-COGZ1ark.mjs.map +0 -1
  236. package/dist/render-typescript-KMgosran.mjs.map +0 -1
  237. package/dist/types.d.mts.map +0 -1
  238. package/src/core/postgres-enum-type-schema.ts +0 -17
@@ -0,0 +1,367 @@
1
+ import { t as DEFAULT_NAMESPACE_ID } from "./namespace-ids-xtp_ZY86.mjs";
2
+ import { p as PostgresRlsPolicy, r as isPostgresSchema } from "./postgres-schema-CajYAwny.mjs";
3
+ import { t as PostgresSchemaNodeKind } from "./schema-node-kinds-ClScchhi.mjs";
4
+ import { a as PostgresDatabaseSchemaNode, i as PostgresNamespaceSchemaNode, r as PostgresPolicySchemaNode } from "./postgres-table-schema-node-BgaSrxYN.mjs";
5
+ import { t as resolveDdlSchemaForNamespaceStorage } from "./resolve-ddl-schema-Bv1ZvjX8.mjs";
6
+ import { t as buildPostgresPlanDiff } from "./diff-database-schema-BmSmWcaY.mjs";
7
+ import { C as EnableRowLevelSecurityCall, d as CreatePostgresRlsPolicyCall, x as DropPostgresRlsPolicyCall } from "./op-factory-call-BKRnMgrB.mjs";
8
+ import { a as resolvePostgresNodeIssueCreationFactoryName, c as issueSchemaName, d as postgresPlannerStrategies, i as resolvePostgresNodeIssueControlPolicySubject, l as issueTableName, n as resolveNamespaceIdForDdlSchema, o as coalesceSubtreeIssues, r as resolvePostgresCallControlPolicySubject, s as issueNode, t as formatPostgresControlPolicySubjectLabel, u as planIssues } from "./control-policy-DUFgy9jO.mjs";
9
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-Dp6IO_gj.mjs";
10
+ import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
11
+ import { blindCast } from "@prisma-next/utils/casts";
12
+ import { extractCodecControlHooks, partitionCallsByControlPolicy, partitionIssuesByControlPolicy, planFieldEventOperations, plannerFailure } from "@prisma-next/family-sql/control";
13
+ import { ifDefined } from "@prisma-next/utils/defined";
14
+ //#region src/core/migrations/verify-postgres-namespaces.ts
15
+ /**
16
+ * Resolves the live-database schema name for a given namespace
17
+ * coordinate. Mirrors `resolveDdlSchemaForNamespace` in
18
+ * `planner-strategies.ts` so the verifier's projection and the
19
+ * planner's projection always agree — Postgres-aware namespaces (the
20
+ * production path) dispatch to `ddlSchemaName(storage)`, and bare
21
+ * object payloads (used by some tests) fall back to the coordinate
22
+ * itself.
23
+ */
24
+ function resolveDdlSchemaName(storage, namespaceId) {
25
+ const namespace = storage.namespaces[namespaceId];
26
+ if (isPostgresSchema(namespace)) return namespace.ddlSchemaName(storage);
27
+ return namespaceId;
28
+ }
29
+ /**
30
+ * Reads the introspected list of schema names from the database-root schema
31
+ * node. `existingSchemas` is database-level, so it lives on the
32
+ * `PostgresDatabaseSchemaNode` root — not on the per-schema namespace nodes.
33
+ *
34
+ * Defaults to the always-present `public` schema when the node is not the
35
+ * database root — a fresh Postgres database always carries `public` (unless an
36
+ * operator dropped it manually), so any verifier path that runs without an
37
+ * enriched introspection still suppresses the redundant `CREATE SCHEMA
38
+ * "public"`.
39
+ *
40
+ * Production introspection (`PostgresControlAdapter.introspect`) is the
41
+ * authoritative source: it queries `pg_namespace` and sets `existingSchemas`
42
+ * on the returned root. Tests that want to assert against a richer initial
43
+ * state construct a `PostgresDatabaseSchemaNode` explicitly.
44
+ */
45
+ function existingSchemasFromSchema(schema) {
46
+ if (PostgresDatabaseSchemaNode.is(schema)) return schema.existingSchemas;
47
+ return [DEFAULT_NAMESPACE_ID];
48
+ }
49
+ /**
50
+ * Emits a `postgres-namespace` `not-found` diff issue for every
51
+ * contract-declared Postgres namespace whose live container does not yet
52
+ * exist. The planner prepends these (node-typed, synthesized) to the
53
+ * relational diff issues so a multi-schema plan emits `CREATE SCHEMA`
54
+ * before the tables that need it — a planner-only concern (verify already
55
+ * rejects via the `not-found` table issues a missing schema already
56
+ * produces), so this is not part of the shared diff.
57
+ *
58
+ * A namespace's live container is the schema returned by its
59
+ * polymorphic `ddlSchemaName(storage)` method — named schemas resolve
60
+ * to their own id; the unbound singleton returns `UNBOUND_NAMESPACE_ID`
61
+ * and is skipped explicitly (late-bound namespaces have no fixed DDL
62
+ * schema). Issues are emitted only when the resolved name is a real,
63
+ * creatable schema (not the unbound sentinel) and is missing from the
64
+ * introspected list. `public` is suppressed implicitly because the
65
+ * introspection (or its sensible default) always carries it.
66
+ *
67
+ * Each emitted issue's path is `['database', ddlName]` — an ancestor of
68
+ * every table path under that schema, so it must never be run through
69
+ * `coalesceSubtreeIssues` alongside the table diff (it would swallow the
70
+ * table-level `not-found` issues that drive `CREATE TABLE`); the planner
71
+ * adds these AFTER coalescing the relational issues, and they are not
72
+ * subject to sibling-space ownership scoping (mirrors the retired
73
+ * coordinate walk, which prepended namespace issues after that filter).
74
+ */
75
+ function verifyPostgresNamespacePresence(input) {
76
+ const { contract, schema } = input;
77
+ const existing = new Set(existingSchemasFromSchema(schema));
78
+ const issues = [];
79
+ const namespaceIds = Object.keys(contract.storage.namespaces).sort();
80
+ for (const namespaceId of namespaceIds) {
81
+ if (namespaceId === UNBOUND_NAMESPACE_ID) continue;
82
+ const ddlName = resolveDdlSchemaName(contract.storage, namespaceId);
83
+ if (ddlName === UNBOUND_NAMESPACE_ID) continue;
84
+ if (existing.has(ddlName)) continue;
85
+ const namespace = new PostgresNamespaceSchemaNode({
86
+ schemaName: ddlName,
87
+ tables: {},
88
+ nativeEnumTypeNames: []
89
+ });
90
+ issues.push({
91
+ path: ["database", ddlName],
92
+ reason: "not-found",
93
+ message: `Schema "${ddlName}" is missing from database`,
94
+ expected: namespace
95
+ });
96
+ }
97
+ return issues;
98
+ }
99
+ //#endregion
100
+ //#region src/core/migrations/planner.ts
101
+ function createPostgresMigrationPlanner(lowerer) {
102
+ return new PostgresMigrationPlanner(lowerer);
103
+ }
104
+ /**
105
+ * Postgres migration planner — a thin wrapper over `planIssues`.
106
+ *
107
+ * `plan()` diffs the target contract against the live schema via the one
108
+ * differ (`buildPostgresPlanDiff`, producing node-typed `SchemaDiffIssue[]`)
109
+ * and delegates to `planIssues` with the unified `postgresPlannerStrategies`
110
+ * list: NOT-NULL backfill, type-change, nullable-tightening, codec-hook
111
+ * storage types, component-declared dependency installs, and
112
+ * shared-temp-default / empty-table-guarded NOT-NULL add-column. The same
113
+ * strategy list runs for `migration plan`, `db update`, and `db init`;
114
+ * behavior diverges purely on `policy.allowedOperationClasses` (the
115
+ * data-safe strategies short-circuit when `'data'` is excluded). The issue
116
+ * planner applies operation-class policy gates and emits a single
117
+ * `PostgresOpFactoryCall[]` that drives both the runtime-ops view (via
118
+ * `renderOps`) and the `renderTypeScript()` authoring surface. RLS policy
119
+ * drift (the structural half of the same one-differ tree) is handled
120
+ * separately via `planPostgresSchemaDiff`.
121
+ */
122
+ var PostgresMigrationPlanner = class {
123
+ #lowerer;
124
+ constructor(lowerer) {
125
+ this.#lowerer = lowerer;
126
+ }
127
+ plan(options) {
128
+ return this.planSql(options);
129
+ }
130
+ emptyMigration(context, spaceId) {
131
+ return new TypeScriptRenderablePostgresMigration([], {
132
+ from: context.fromHash,
133
+ to: context.toHash
134
+ }, spaceId, this.#lowerer);
135
+ }
136
+ planSql(options) {
137
+ const schemaName = options.schemaName ?? Object.keys(options.contract.storage.namespaces).find((id) => id !== UNBOUND_NAMESPACE_ID) ?? UNBOUND_NAMESPACE_ID;
138
+ const policyResult = this.ensureAdditivePolicy(options.policy);
139
+ if (policyResult) return policyResult;
140
+ PostgresDatabaseSchemaNode.assert(options.schema);
141
+ const { issues: rawIssues } = buildPostgresPlanDiff({
142
+ contract: options.contract,
143
+ actualSchema: options.schema,
144
+ frameworkComponents: options.frameworkComponents
145
+ });
146
+ const policyDiffIssues = rawIssues.filter((issue) => isPolicyDiffIssue(issue));
147
+ const relationalDiffIssues = rawIssues.filter((issue) => !isPolicyDiffIssue(issue));
148
+ const strict = options.policy.allowedOperationClasses.includes("widening") || options.policy.allowedOperationClasses.includes("destructive");
149
+ const owned = retainUnownedExtras(coalesceSubtreeIssues(relationalDiffIssues), options.ownership, options.contract);
150
+ const gated = strict ? owned : owned.filter((issue) => issue.reason !== "not-expected");
151
+ const schemaIssues = [...verifyPostgresNamespacePresence({
152
+ contract: options.contract,
153
+ schema: options.schema
154
+ }), ...gated];
155
+ const codecHooks = extractCodecControlHooks(options.frameworkComponents);
156
+ const storageTypes = options.contract.storage.types ?? {};
157
+ const relationalSchema = relationalNamespaceNode(options.schema, schemaName);
158
+ const issuePartition = partitionIssuesByControlPolicy({
159
+ issues: schemaIssues,
160
+ contract: options.contract,
161
+ resolveControlPolicySubject: (issue) => resolvePostgresNodeIssueControlPolicySubject(issue, options.contract),
162
+ resolveCreationFactoryName: resolvePostgresNodeIssueCreationFactoryName,
163
+ formatSubjectLabel: (factoryName, subject) => formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract)
164
+ });
165
+ const result = planIssues({
166
+ issues: issuePartition.plannable,
167
+ toContract: options.contract,
168
+ fromContract: options.fromContract,
169
+ schemaName,
170
+ codecHooks,
171
+ storageTypes,
172
+ ...ifDefined("schema", relationalSchema),
173
+ policy: options.policy,
174
+ frameworkComponents: options.frameworkComponents,
175
+ strategies: postgresPlannerStrategies
176
+ });
177
+ if (!result.ok) return plannerFailure(result.failure);
178
+ const schemaDiffPartition = partitionCallsByControlPolicy({
179
+ calls: this.planPostgresSchemaDiff(options, policyDiffIssues),
180
+ contract: options.contract,
181
+ resolveControlPolicySubject: (call) => resolvePostgresCallControlPolicySubject(call, options.contract),
182
+ resolveFactoryName: (call) => call.factoryName,
183
+ formatSubjectLabel: (factoryName, subject) => formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract)
184
+ });
185
+ const fieldEventPartition = partitionCallsByControlPolicy({
186
+ calls: blindCast(planFieldEventOperations({
187
+ priorContract: options.fromContract,
188
+ newContract: options.contract,
189
+ codecHooks
190
+ })),
191
+ contract: options.contract,
192
+ resolveControlPolicySubject: (call) => resolvePostgresCallControlPolicySubject(call, options.contract),
193
+ resolveFactoryName: (call) => call.factoryName,
194
+ formatSubjectLabel: (factoryName, subject) => formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract)
195
+ });
196
+ const calls = [
197
+ ...result.value.calls,
198
+ ...schemaDiffPartition.kept,
199
+ ...fieldEventPartition.kept
200
+ ];
201
+ const warnings = [
202
+ ...issuePartition.warnings,
203
+ ...schemaDiffPartition.warnings,
204
+ ...fieldEventPartition.warnings
205
+ ];
206
+ return Object.freeze({
207
+ kind: "success",
208
+ plan: new TypeScriptRenderablePostgresMigration(calls, {
209
+ from: options.fromContract?.storage.storageHash ?? null,
210
+ to: options.contract.storage.storageHash
211
+ }, options.spaceId, this.#lowerer),
212
+ ...warnings.length > 0 ? { warnings: Object.freeze(warnings) } : {}
213
+ });
214
+ }
215
+ /**
216
+ * Maps the RLS policy presence findings of the one combined tree diff
217
+ * (`buildPostgresPlanDiff`, already ownership-filtered) into `ENABLE RLS`
218
+ * / `CREATE POLICY` / `DROP POLICY` ops. It does not re-diff — it consumes
219
+ * exactly the policy-node subset of the shared diff's issues.
220
+ */
221
+ planPostgresSchemaDiff(options, filteredDiffIssues) {
222
+ const allowsDestructive = options.policy.allowedOperationClasses.includes("destructive");
223
+ const calls = [];
224
+ const seenEnableTables = /* @__PURE__ */ new Set();
225
+ for (const issue of filteredDiffIssues) if (issue.reason === "not-found") {
226
+ const expected = issue.expected;
227
+ PostgresPolicySchemaNode.assert(expected);
228
+ const schemaForTable = resolveDdlSchemaForNamespaceStorage(options.contract.storage, expected.namespaceId);
229
+ const tableKey = `${schemaForTable}.${expected.tableName}`;
230
+ if (!seenEnableTables.has(tableKey)) {
231
+ seenEnableTables.add(tableKey);
232
+ calls.push(new EnableRowLevelSecurityCall(schemaForTable, expected.tableName));
233
+ }
234
+ calls.push(new CreatePostgresRlsPolicyCall(schemaForTable, expected.tableName, policyNodeToContractPolicy(expected)));
235
+ } else if (issue.reason === "not-expected" && allowsDestructive) {
236
+ const actual = issue.actual;
237
+ PostgresPolicySchemaNode.assert(actual);
238
+ const schemaForTable = resolveDdlSchemaForNamespaceStorage(options.contract.storage, actual.namespaceId);
239
+ calls.push(new DropPostgresRlsPolicyCall(schemaForTable, actual.tableName, actual.name));
240
+ }
241
+ return calls;
242
+ }
243
+ ensureAdditivePolicy(policy) {
244
+ if (!policy.allowedOperationClasses.includes("additive")) return plannerFailure([{
245
+ kind: "unsupportedOperation",
246
+ summary: "Migration planner requires additive operations be allowed",
247
+ why: "The planner requires the \"additive\" operation class to be allowed in the policy."
248
+ }]);
249
+ return null;
250
+ }
251
+ };
252
+ /**
253
+ * A diff issue whose node is an RLS policy — the structural half of the one
254
+ * combined tree diff, routed to `planPostgresSchemaDiff` instead of
255
+ * `planIssues`.
256
+ */
257
+ function isPolicyDiffIssue(issue) {
258
+ const node = issue.expected ?? issue.actual;
259
+ return node !== void 0 && PostgresPolicySchemaNode.is(node);
260
+ }
261
+ /**
262
+ * Drops a `not-expected` issue when it is a whole extra TABLE that some
263
+ * contract space owns, asking the ownership oracle per node.
264
+ *
265
+ * The consultation applies ONLY to table-level extras — a live table this
266
+ * space's contract lacks — identified by asking the issue's own node
267
+ * (`nodeKind === table`), never by counting path segments. `declaresEntity`
268
+ * answers over the whole composition (self included), keyed on the schema-IR
269
+ * entity coordinate so a genuine orphan in one namespace is never conflated
270
+ * with a same-named table a sibling space declares in another, or with a
271
+ * same-named non-table entity (an enum, an RLS policy) a sibling declares in
272
+ * the SAME namespace: a positive answer means another space owns THIS table
273
+ * in THIS namespace (a table this space owned would be in its expected tree,
274
+ * never an extra) — leave it. A negative answer means no space owns it — a
275
+ * genuine orphan to drop. `entityKind` is the literal `'table'` here: this
276
+ * function only ever asks about a node already confirmed to be
277
+ * `PostgresSchemaNodeKind.table` (checked just above), and the diff tree's
278
+ * `nodeKind` vocabulary (`'postgres-table'`) is distinct from the storage
279
+ * `entries` vocabulary `elementCoordinates` walks (`'table'`) — the literal
280
+ * is that storage-entries spelling, not the node kind.
281
+ *
282
+ * The issue path carries the *resolved DDL schema* (e.g. `public`), but a
283
+ * contract space's own declared namespace id can be the unbound sentinel
284
+ * (`__unbound__`) that resolves to that schema — the two spellings would
285
+ * never string-match. `resolveNamespaceIdForDdlSchema` recovers the raw
286
+ * namespace id THIS space's own contract would use for that DDL schema, so
287
+ * a table this space's own unbound namespace declares (and any sibling
288
+ * whose own unbound namespace resolves the same way) is compared on the
289
+ * same coordinate the aggregate's `elementCoordinates` walk yields.
290
+ *
291
+ * A DEEPER extra (an extra column/constraint on a table this space DOES own —
292
+ * only the child drifted, so the table is in the expected tree) is this
293
+ * space's own drift and is always kept for dropping; asking the oracle there
294
+ * would wrongly suppress it, because the owned table answers `true`. Shallower
295
+ * issues (namespace/root) are never ownership-scoped here. No oracle ⇒ every
296
+ * extra is kept (single-space plan).
297
+ */
298
+ function retainUnownedExtras(issues, ownership, contract) {
299
+ if (ownership === void 0) return issues;
300
+ return issues.filter((issue) => {
301
+ if (issue.reason !== "not-expected") return true;
302
+ const node = issueNode(issue);
303
+ if (node === void 0 || node.nodeKind !== PostgresSchemaNodeKind.table) return true;
304
+ const ddlSchemaName = issueSchemaName(issue);
305
+ const tableName = issueTableName(issue);
306
+ if (ddlSchemaName === void 0 || tableName === void 0) return true;
307
+ const namespaceId = resolveNamespaceIdForDdlSchema(contract, ddlSchemaName);
308
+ return !ownership.declaresEntity({
309
+ namespaceId,
310
+ entityKind: "table",
311
+ entityName: tableName
312
+ });
313
+ });
314
+ }
315
+ /**
316
+ * Returns the one namespace node the relational strategy layer probes for
317
+ * live-table existence and reads codec-hook context off — the namespace
318
+ * matching the planner's resolved schema name, or the first namespace when
319
+ * none matches. `undefined` when the tree has no namespaces, so the strategy
320
+ * context uses its empty-schema default.
321
+ *
322
+ * The relational strategies key tables by bare name, so they can only probe one
323
+ * namespace at a time; probing across every namespace at once is future work.
324
+ *
325
+ * Returns the real `PostgresNamespaceSchemaNode` reference rather than a
326
+ * projection: `storageTypePlanCallStrategy` hands this same value to codec
327
+ * `planTypeOperations` hooks as `schema`, and hooks read the Postgres-specific
328
+ * `nativeEnumTypeNames` field off it (via `PostgresNamespaceSchemaNode.is`) to
329
+ * decide whether a native enum type already exists — a projection that only
330
+ * copies `tables` would silently drop that signal. `StrategyContext.schema`'s
331
+ * declared type (`SqlSchemaIR`, shared with SQLite's flat shape) doesn't
332
+ * capture this, so the return is `blindCast` the same way `namespaceSchemaNodes`
333
+ * in the family's relational walk already treats a namespace node as a
334
+ * structurally-`SqlSchemaIR`-shaped value.
335
+ */
336
+ function relationalNamespaceNode(schema, schemaName) {
337
+ const namespaceNodes = Object.values(schema.namespaces);
338
+ const namespaceNode = namespaceNodes.find((node) => node.schemaName === schemaName) ?? namespaceNodes[0];
339
+ if (namespaceNode === void 0) return void 0;
340
+ return blindCast(namespaceNode);
341
+ }
342
+ /**
343
+ * Rebuilds the `PostgresRlsPolicy` contract entity `CreatePostgresRlsPolicyCall`
344
+ * carries (its `renderTypeScript`/`createRlsPolicy` paths serialize the whole
345
+ * entity, `namespaceId` included). This reconstructs rather than looking the
346
+ * original up in the contract on purpose: the diff node's `namespaceId` is the
347
+ * *resolved DDL schema* (set when the expected tree was built), which is the
348
+ * value the emitted op must carry; the contract-stored entity holds the raw,
349
+ * pre-resolution coordinate, so a lookup would change the migration output.
350
+ */
351
+ function policyNodeToContractPolicy(node) {
352
+ return new PostgresRlsPolicy({
353
+ name: node.name,
354
+ prefix: node.prefix,
355
+ tableName: node.tableName,
356
+ namespaceId: node.namespaceId,
357
+ operation: node.operation,
358
+ roles: [...node.roles],
359
+ ...ifDefined("using", node.using),
360
+ ...ifDefined("withCheck", node.withCheck),
361
+ permissive: node.permissive
362
+ });
363
+ }
364
+ //#endregion
365
+ export { createPostgresMigrationPlanner as t };
366
+
367
+ //# sourceMappingURL=planner-BMBRPzsv.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-BMBRPzsv.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 nativeEnumTypeNames: [],\n });\n issues.push({\n path: ['database', ddlName],\n reason: 'not-found',\n message: `Schema \"${ddlName}\" is missing from database`,\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 { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIR } 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 { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';\nimport { PostgresPolicySchemaNode } from '../schema-ir/postgres-policy-schema-node';\nimport { PostgresSchemaNodeKind, type SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';\nimport {\n formatPostgresControlPolicySubjectLabel,\n resolveNamespaceIdForDdlSchema,\n resolvePostgresCallControlPolicySubject,\n resolvePostgresNodeIssueControlPolicySubject,\n resolvePostgresNodeIssueCreationFactoryName,\n} from './control-policy';\nimport { buildPostgresPlanDiff } from './diff-database-schema';\nimport {\n coalesceSubtreeIssues,\n issueNode,\n issueSchemaName,\n issueTableName,\n planIssues,\n} from './issue-planner';\nimport type { PostgresOpFactoryCall } from './op-factory-call';\nimport {\n CreatePostgresRlsPolicyCall,\n DropPostgresRlsPolicyCall,\n EnableRowLevelSecurityCall,\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 }): 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 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 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) => issue.reason !== '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 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: schemaIssues,\n contract: options.contract,\n resolveControlPolicySubject: (issue) =>\n resolvePostgresNodeIssueControlPolicySubject(issue, options.contract),\n resolveCreationFactoryName: resolvePostgresNodeIssueCreationFactoryName,\n formatSubjectLabel: (factoryName, subject) =>\n formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),\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 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 formatSubjectLabel: (factoryName, subject) =>\n formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),\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 formatSubjectLabel: (factoryName, subject) =>\n formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),\n });\n const calls = [...result.value.calls, ...schemaDiffPartition.kept, ...fieldEventPartition.kept];\n const warnings: SqlPlannerConflict[] = [\n ...issuePartition.warnings,\n ...schemaDiffPartition.warnings,\n ...fieldEventPartition.warnings,\n ];\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 this.#lowerer,\n ),\n ...(warnings.length > 0 ? { warnings: Object.freeze(warnings) } : {}),\n });\n }\n\n /**\n * Maps the RLS policy presence findings of the one combined tree diff\n * (`buildPostgresPlanDiff`, already ownership-filtered) into `ENABLE RLS`\n * / `CREATE POLICY` / `DROP POLICY` ops. It does not re-diff — it consumes\n * exactly the policy-node subset of the shared diff's issues.\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 calls: PostgresOpFactoryCall[] = [];\n const seenEnableTables = new Set<string>();\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 (issue.reason === '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 const schemaForTable = resolveDdlSchemaForNamespaceStorage(\n options.contract.storage,\n expected.namespaceId,\n );\n const tableKey = `${schemaForTable}.${expected.tableName}`;\n if (!seenEnableTables.has(tableKey)) {\n seenEnableTables.add(tableKey);\n calls.push(new EnableRowLevelSecurityCall(schemaForTable, expected.tableName));\n }\n calls.push(\n new CreatePostgresRlsPolicyCall(\n schemaForTable,\n expected.tableName,\n policyNodeToContractPolicy(expected),\n ),\n );\n } else if (issue.reason === 'not-expected' && allowsDestructive) {\n const actual = issue.actual;\n PostgresPolicySchemaNode.assert(actual);\n const schemaForTable = resolveDdlSchemaForNamespaceStorage(\n options.contract.storage,\n actual.namespaceId,\n );\n calls.push(new DropPostgresRlsPolicyCall(schemaForTable, actual.tableName, actual.name));\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 TABLE that some\n * contract space owns, asking the ownership oracle per node.\n *\n * The consultation applies ONLY to table-level extras — a live table this\n * space's contract lacks — identified by asking the issue's own node\n * (`nodeKind === table`), never by counting path segments. `declaresEntity`\n * answers over the whole composition (self included), keyed on the schema-IR\n * entity coordinate so a genuine orphan in one namespace is never conflated\n * with a same-named table a sibling space declares in another, or with a\n * same-named non-table entity (an enum, an RLS policy) a sibling declares in\n * the SAME namespace: a positive answer means another space owns THIS table\n * in THIS namespace (a table this space owned would be in its expected tree,\n * never an extra) — leave it. A negative answer means no space owns it — a\n * genuine orphan to drop. `entityKind` is the literal `'table'` here: this\n * function only ever asks about a node already confirmed to be\n * `PostgresSchemaNodeKind.table` (checked just above), and the diff tree's\n * `nodeKind` vocabulary (`'postgres-table'`) is distinct from the storage\n * `entries` vocabulary `elementCoordinates` walks (`'table'`) — the literal\n * is that storage-entries spelling, not the node kind.\n *\n * The issue path carries the *resolved DDL schema* (e.g. `public`), but a\n * contract space's own declared namespace id can be the unbound sentinel\n * (`__unbound__`) that resolves to that schema — the two spellings would\n * never string-match. `resolveNamespaceIdForDdlSchema` recovers the raw\n * namespace id THIS space's own contract would use for that DDL schema, so\n * a table this space's own unbound namespace declares (and any sibling\n * whose own unbound namespace resolves the same way) is compared on the\n * same coordinate the aggregate's `elementCoordinates` walk yields.\n *\n * A DEEPER extra (an extra column/constraint on a table this space DOES own —\n * only the child drifted, so the table is in the expected tree) is this\n * space's own drift and is always kept for dropping; asking the oracle there\n * would wrongly suppress it, because the owned table answers `true`. Shallower\n * issues (namespace/root) are never ownership-scoped here. No oracle ⇒ every\n * extra is kept (single-space plan).\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 (issue.reason !== 'not-expected') return true;\n const node = issueNode(issue);\n if (node === undefined || node.nodeKind !== PostgresSchemaNodeKind.table) return true;\n const ddlSchemaName = issueSchemaName(issue);\n const tableName = issueTableName(issue);\n if (ddlSchemaName === undefined || tableName === undefined) return true;\n const namespaceId = resolveNamespaceIdForDdlSchema(contract, ddlSchemaName);\n return !ownership.declaresEntity({ namespaceId, entityKind: 'table', entityName: tableName });\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 * `nativeEnumTypeNames` field off it (via `PostgresNamespaceSchemaNode.is`) to\n * decide whether a native enum type already exists — a projection that only\n * copies `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 (+ nativeEnumTypeNames, 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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"}
@@ -2,19 +2,6 @@ import { i as quoteIdentifier, n as escapeLiteral } from "./sql-utils-DcfMz4MQ.m
2
2
  import { t as resolveColumnTypeMetadata } from "./planner-type-resolution-Bt2f_q-F.mjs";
3
3
  import { ifDefined } from "@prisma-next/utils/defined";
4
4
  //#region src/core/migrations/planner-ddl-builders.ts
5
- function buildCreateTableSql(qualifiedTableName, table, codecHooks, storageTypes = {}) {
6
- const columnDefinitions = Object.entries(table.columns).map(([columnName, column]) => {
7
- return [
8
- quoteIdentifier(columnName),
9
- buildColumnTypeSql(column, codecHooks, storageTypes),
10
- buildColumnDefaultSql(column.default, column),
11
- column.nullable ? "" : "NOT NULL"
12
- ].filter(Boolean).join(" ");
13
- });
14
- const constraintDefinitions = [];
15
- if (table.primaryKey) constraintDefinitions.push(`PRIMARY KEY (${table.primaryKey.columns.map(quoteIdentifier).join(", ")})`);
16
- return `CREATE TABLE ${qualifiedTableName} (\n ${[...columnDefinitions, ...constraintDefinitions].join(",\n ")}\n)`;
17
- }
18
5
  /**
19
6
  * Pattern for safe PostgreSQL type names.
20
7
  * Allows letters, digits, underscores, spaces (for "double precision", "character varying"),
@@ -50,10 +37,13 @@ function buildColumnTypeSql(column, codecHooks, storageTypes = {}, allowPseudoTy
50
37
  }
51
38
  }
52
39
  const expanded = expandParameterizedTypeSql(resolved, codecHooks);
53
- if (expanded !== null) return expanded;
54
- if (column.typeRef) return quoteIdentifier(resolved.nativeType);
40
+ if (expanded !== null) return column.many ? `${expanded}[]` : expanded;
41
+ if (column.typeRef) {
42
+ const base = quoteIdentifier(resolved.nativeType);
43
+ return column.many ? `${base}[]` : base;
44
+ }
55
45
  assertSafeNativeType(resolved.nativeType);
56
- return resolved.nativeType;
46
+ return column.many ? `${resolved.nativeType}[]` : resolved.nativeType;
57
47
  }
58
48
  function expandParameterizedTypeSql(column, codecHooks) {
59
49
  if (!column.typeParams || Object.keys(column.typeParams).length === 0) return null;
@@ -84,6 +74,7 @@ function buildColumnDefaultSql(columnDefault, column) {
84
74
  }
85
75
  function renderDefaultLiteral(value, column) {
86
76
  const isJsonColumn = column?.nativeType === "json" || column?.nativeType === "jsonb";
77
+ if (column?.many && Array.isArray(value)) return renderArrayLiteralDefault(value);
87
78
  if (value instanceof Date) return `'${escapeLiteral(value.toISOString())}'`;
88
79
  if (typeof value === "string") return `'${escapeLiteral(value)}'`;
89
80
  if (typeof value === "number" || typeof value === "boolean") return String(value);
@@ -92,17 +83,11 @@ function renderDefaultLiteral(value, column) {
92
83
  if (isJsonColumn) return `'${escapeLiteral(json)}'::${column.nativeType}`;
93
84
  return `'${escapeLiteral(json)}'`;
94
85
  }
95
- function buildAddColumnSql(qualifiedTableName, columnName, column, codecHooks, temporaryDefault, storageTypes = {}) {
96
- const typeSql = buildColumnTypeSql(column, codecHooks, storageTypes);
97
- const defaultSql = buildColumnDefaultSql(column.default, column) || (temporaryDefault ? `DEFAULT ${temporaryDefault}` : "");
98
- return [
99
- `ALTER TABLE ${qualifiedTableName}`,
100
- `ADD COLUMN ${quoteIdentifier(columnName)} ${typeSql}`,
101
- defaultSql,
102
- column.nullable ? "" : "NOT NULL"
103
- ].filter(Boolean).join(" ");
86
+ function renderArrayLiteralDefault(elements) {
87
+ if (elements.length === 0) return "'{}'";
88
+ return `ARRAY[${elements.map((el) => renderDefaultLiteral(el)).join(", ")}]`;
104
89
  }
105
90
  //#endregion
106
- export { renderDefaultLiteral as a, buildCreateTableSql as i, buildColumnDefaultSql as n, buildColumnTypeSql as r, buildAddColumnSql as t };
91
+ export { buildColumnTypeSql as n, renderDefaultLiteral as r, buildColumnDefaultSql as t };
107
92
 
108
- //# sourceMappingURL=planner-ddl-builders-B2wOwLqI.mjs.map
93
+ //# sourceMappingURL=planner-ddl-builders-B8Nn6nHN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-ddl-builders-B8Nn6nHN.mjs","names":[],"sources":["../src/core/migrations/planner-ddl-builders.ts"],"sourcesContent":["import type { CodecControlHooks } from '@prisma-next/family-sql/control';\nimport type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { escapeLiteral, quoteIdentifier } from '../sql-utils';\nimport type { PostgresColumnDefault } from '../types';\nimport { resolveColumnTypeMetadata } from './planner-type-resolution';\n\n/**\n * Pattern for safe PostgreSQL type names.\n * Allows letters, digits, underscores, spaces (for \"double precision\", \"character varying\"),\n * and trailing [] for array types.\n */\nconst SAFE_NATIVE_TYPE_PATTERN = /^[a-zA-Z][a-zA-Z0-9_ ]*(\\[\\])?$/;\n\nfunction assertSafeNativeType(nativeType: string): void {\n if (!SAFE_NATIVE_TYPE_PATTERN.test(nativeType)) {\n throw new Error(\n `Unsafe native type name in contract: \"${nativeType}\". ` +\n 'Native type names must match /^[a-zA-Z][a-zA-Z0-9_ ]*(\\\\[\\\\])?$/',\n );\n }\n}\n\n/**\n * Sanity check against accidental SQL injection from malformed contract files.\n * Rejects semicolons, SQL comment tokens, and dollar-quoting.\n * Not a comprehensive security boundary — the contract is developer-authored.\n */\nfunction assertSafeDefaultExpression(expression: string): void {\n if (expression.includes(';') || /--|\\/\\*|\\$\\$|\\bSELECT\\b/i.test(expression)) {\n throw new Error(\n `Unsafe default expression in contract: \"${expression}\". ` +\n 'Default expressions must not contain semicolons, SQL comment tokens, dollar-quoting, or subqueries.',\n );\n }\n}\n\n/**\n * Renders the SQL type for a column in DDL context.\n *\n * @param allowPseudoTypes - When true (default), autoincrement integer columns\n * produce SERIAL/BIGSERIAL/SMALLSERIAL pseudo-types. Set to false for contexts\n * like ALTER COLUMN TYPE where pseudo-types are invalid.\n */\nexport function buildColumnTypeSql(\n column: StorageColumn,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n storageTypes: Record<string, StorageTypeInstance> = {},\n allowPseudoTypes = true,\n): string {\n const resolved = resolveColumnTypeMetadata(column, storageTypes);\n\n if (allowPseudoTypes) {\n const columnDefault = column.default;\n if (columnDefault?.kind === 'function' && columnDefault.expression === 'autoincrement()') {\n if (resolved.nativeType === 'int4' || resolved.nativeType === 'integer') {\n return 'SERIAL';\n }\n if (resolved.nativeType === 'int8' || resolved.nativeType === 'bigint') {\n return 'BIGSERIAL';\n }\n if (resolved.nativeType === 'int2' || resolved.nativeType === 'smallint') {\n return 'SMALLSERIAL';\n }\n }\n }\n\n const expanded = expandParameterizedTypeSql(resolved, codecHooks);\n if (expanded !== null) {\n return column.many ? `${expanded}[]` : expanded;\n }\n\n if (column.typeRef) {\n const base = quoteIdentifier(resolved.nativeType);\n return column.many ? `${base}[]` : base;\n }\n\n assertSafeNativeType(resolved.nativeType);\n return column.many ? `${resolved.nativeType}[]` : resolved.nativeType;\n}\n\nfunction expandParameterizedTypeSql(\n column: Pick<StorageColumn, 'nativeType' | 'codecId' | 'typeParams'>,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n): string | null {\n if (!column.typeParams || Object.keys(column.typeParams).length === 0) {\n return null;\n }\n\n if (!column.codecId) {\n throw new Error(\n `Column declares typeParams for nativeType \"${column.nativeType}\" but has no codecId. ` +\n 'Ensure the column is associated with a codec.',\n );\n }\n\n const hooks = codecHooks.get(column.codecId);\n if (!hooks?.expandNativeType) {\n if (hooks?.planTypeOperations) {\n return null;\n }\n throw new Error(\n `Column declares typeParams for nativeType \"${column.nativeType}\" ` +\n `but no expandNativeType hook is registered for codecId \"${column.codecId}\". ` +\n 'Ensure the extension providing this codec is included in extensionPacks.',\n );\n }\n\n const expanded = hooks.expandNativeType({\n nativeType: column.nativeType,\n codecId: column.codecId,\n ...ifDefined('typeParams', column.typeParams),\n });\n\n return expanded !== column.nativeType ? expanded : null;\n}\n\n/** Autoincrement columns use SERIAL types, so this returns empty for them. */\nexport function buildColumnDefaultSql(\n columnDefault: PostgresColumnDefault | undefined,\n column?: Pick<StorageColumn, 'many' | 'nativeType'>,\n): string {\n if (!columnDefault) {\n return '';\n }\n\n switch (columnDefault.kind) {\n case 'literal':\n return `DEFAULT ${renderDefaultLiteral(columnDefault.value, column)}`;\n case 'function': {\n if (columnDefault.expression === 'autoincrement()') {\n return '';\n }\n assertSafeDefaultExpression(columnDefault.expression);\n return `DEFAULT (${columnDefault.expression})`;\n }\n case 'sequence':\n return `DEFAULT nextval('${escapeLiteral(quoteIdentifier(columnDefault.name))}'::regclass)`;\n }\n}\n\nexport function renderDefaultLiteral(\n value: unknown,\n column?: Pick<StorageColumn, 'many' | 'nativeType'>,\n): string {\n const isJsonColumn = column?.nativeType === 'json' || column?.nativeType === 'jsonb';\n\n if (column?.many && Array.isArray(value)) {\n return renderArrayLiteralDefault(value);\n }\n\n if (value instanceof Date) {\n return `'${escapeLiteral(value.toISOString())}'`;\n }\n if (typeof value === 'string') {\n return `'${escapeLiteral(value)}'`;\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (value === null) {\n return 'NULL';\n }\n const json = JSON.stringify(value);\n if (isJsonColumn) {\n return `'${escapeLiteral(json)}'::${column.nativeType}`;\n }\n return `'${escapeLiteral(json)}'`;\n}\n\nfunction renderArrayLiteralDefault(elements: unknown[]): string {\n if (elements.length === 0) {\n return \"'{}'\";\n }\n const rendered = elements.map((el) => renderDefaultLiteral(el)).join(', ');\n return `ARRAY[${rendered}]`;\n}\n"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
1
  import { t as PostgresColumnDefault } from "./types-BDKkx8MA.mjs";
2
+ import { StorageColumn, StorageTypeInstance } from "@prisma-next/sql-contract/types";
2
3
  import { CodecControlHooks } from "@prisma-next/family-sql/control";
3
- import { StorageColumn, StorageTable, StorageTypeInstance } from "@prisma-next/sql-contract/types";
4
4
 
5
5
  //#region src/core/migrations/planner-ddl-builders.d.ts
6
- declare function buildCreateTableSql(qualifiedTableName: string, table: StorageTable, codecHooks: ReadonlyMap<string, CodecControlHooks>, storageTypes?: Record<string, StorageTypeInstance>): string;
7
6
  /**
8
7
  * Renders the SQL type for a column in DDL context.
9
8
  *
@@ -13,9 +12,8 @@ declare function buildCreateTableSql(qualifiedTableName: string, table: StorageT
13
12
  */
14
13
  declare function buildColumnTypeSql(column: StorageColumn, codecHooks: ReadonlyMap<string, CodecControlHooks>, storageTypes?: Record<string, StorageTypeInstance>, allowPseudoTypes?: boolean): string;
15
14
  /** Autoincrement columns use SERIAL types, so this returns empty for them. */
16
- declare function buildColumnDefaultSql(columnDefault: PostgresColumnDefault | undefined, column?: StorageColumn): string;
17
- declare function renderDefaultLiteral(value: unknown, column?: StorageColumn): string;
18
- declare function buildAddColumnSql(qualifiedTableName: string, columnName: string, column: StorageColumn, codecHooks: ReadonlyMap<string, CodecControlHooks>, temporaryDefault?: string | null, storageTypes?: Record<string, StorageTypeInstance>): string;
15
+ declare function buildColumnDefaultSql(columnDefault: PostgresColumnDefault | undefined, column?: Pick<StorageColumn, 'many' | 'nativeType'>): string;
16
+ declare function renderDefaultLiteral(value: unknown, column?: Pick<StorageColumn, 'many' | 'nativeType'>): string;
19
17
  //#endregion
20
- export { buildAddColumnSql, buildColumnDefaultSql, buildColumnTypeSql, buildCreateTableSql, renderDefaultLiteral };
18
+ export { buildColumnDefaultSql, buildColumnTypeSql, renderDefaultLiteral };
21
19
  //# sourceMappingURL=planner-ddl-builders.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"planner-ddl-builders.d.mts","names":[],"sources":["../src/core/migrations/planner-ddl-builders.ts"],"mappings":";;;;;iBAWgB,mBAAA,CACd,kBAAA,UACA,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,WAAA,SAAoB,iBAAA,GAChC,YAAA,GAAc,MAAA,SAAe,mBAAA;;AAJ/B;;;;;;iBAkEgB,kBAAA,CACd,MAAA,EAAQ,aAAA,EACR,UAAA,EAAY,WAAA,SAAoB,iBAAA,GAChC,YAAA,GAAc,MAAA,SAAe,mBAAA,GAC7B,gBAAA;;iBAqEc,qBAAA,CACd,aAAA,EAAe,qBAAA,cACf,MAAA,GAAS,aAAa;AAAA,iBAqBR,oBAAA,CAAqB,KAAA,WAAgB,MAAA,GAAS,aAAa;AAAA,iBAsB3D,iBAAA,CACd,kBAAA,UACA,UAAA,UACA,MAAA,EAAQ,aAAA,EACR,UAAA,EAAY,WAAA,SAAoB,iBAAA,GAChC,gBAAA,kBACA,YAAA,GAAc,MAAA,SAAe,mBAAA"}
1
+ {"version":3,"file":"planner-ddl-builders.d.mts","names":[],"sources":["../src/core/migrations/planner-ddl-builders.ts"],"mappings":";;;;;;;AA4CA;;;;;iBAAgB,kBAAA,CACd,MAAA,EAAQ,aAAA,EACR,UAAA,EAAY,WAAA,SAAoB,iBAAA,GAChC,YAAA,GAAc,MAAA,SAAe,mBAAA,GAC7B,gBAAA;;iBAsEc,qBAAA,CACd,aAAA,EAAe,qBAAA,cACf,MAAA,GAAS,IAAA,CAAK,aAAA;AAAA,iBAqBA,oBAAA,CACd,KAAA,WACA,MAAA,GAAS,IAAI,CAAC,aAAA"}
@@ -1,2 +1,2 @@
1
- import { a as renderDefaultLiteral, i as buildCreateTableSql, n as buildColumnDefaultSql, r as buildColumnTypeSql, t as buildAddColumnSql } from "./planner-ddl-builders-B2wOwLqI.mjs";
2
- export { buildAddColumnSql, buildColumnDefaultSql, buildColumnTypeSql, buildCreateTableSql, renderDefaultLiteral };
1
+ import { n as buildColumnTypeSql, r as renderDefaultLiteral, t as buildColumnDefaultSql } from "./planner-ddl-builders-B8Nn6nHN.mjs";
2
+ export { buildColumnDefaultSql, buildColumnTypeSql, renderDefaultLiteral };
@@ -1 +1 @@
1
- {"version":3,"file":"planner-identity-values-CJPha2Sz.mjs","names":[],"sources":["../src/core/migrations/planner-identity-values.ts"],"sourcesContent":["import type { CodecControlHooks } from '@prisma-next/family-sql/control';\nimport type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\n/**\n * Resolves the identity value (monoid neutral element) as a SQL literal for a column's type.\n * Checks codec hooks first (extensions can provide type-specific identity values),\n * then falls back to the built-in map.\n */\nexport function resolveIdentityValue(\n column: StorageColumn,\n codecHooks: Map<string, CodecControlHooks>,\n storageTypes: Record<string, StorageTypeInstance> = {},\n): string | null {\n const referencedType = column.typeRef ? storageTypes[column.typeRef] : undefined;\n const codecId = referencedType?.codecId ?? column.codecId;\n const nativeType = referencedType?.nativeType ?? column.nativeType;\n const typeParams = referencedType?.typeParams ?? column.typeParams;\n\n if (codecId) {\n const hookDefault = codecHooks.get(codecId)?.resolveIdentityValue?.({\n nativeType,\n codecId,\n ...ifDefined('typeParams', typeParams),\n });\n if (hookDefault !== undefined) {\n return hookDefault;\n }\n }\n\n return buildBuiltinIdentityValue(nativeType, typeParams);\n}\n\n/**\n * Returns the built-in identity value (monoid neutral element) as a SQL literal for the given\n * PostgreSQL native type — e.g. 0 for integers, '' for text, false for booleans.\n *\n * This is the planner's fallback when no codec hook provides a type-specific identity value.\n *\n * Returns null for unrecognized types (for example enums and extension-owned types without a\n * hook), which causes the planner to fall back to the empty-table precheck.\n *\n * @internal Exported for testing only.\n */\nexport function buildBuiltinIdentityValue(\n nativeType: string,\n typeParams?: Record<string, unknown>,\n): string | null {\n const normalizedNativeType = normalizeIdentityValueNativeType(nativeType);\n\n if (normalizedNativeType.endsWith('[]')) {\n return \"'{}'\";\n }\n\n switch (normalizedNativeType) {\n case 'text':\n case 'character':\n case 'bpchar':\n case 'character varying':\n case 'varchar':\n return \"''\";\n\n case 'int2':\n case 'int4':\n case 'int8':\n case 'integer':\n case 'bigint':\n case 'smallint':\n case 'float4':\n case 'float8':\n case 'real':\n case 'double precision':\n case 'numeric':\n case 'decimal':\n return '0';\n\n case 'bool':\n case 'boolean':\n return 'false';\n\n case 'uuid':\n return \"'00000000-0000-0000-0000-000000000000'\";\n\n case 'json':\n return \"'{}'::json\";\n case 'jsonb':\n return \"'{}'::jsonb\";\n\n case 'date':\n case 'timestamp':\n case 'timestamptz':\n case 'timestamp with time zone':\n case 'timestamp without time zone':\n return \"'epoch'\";\n\n case 'time':\n case 'time without time zone':\n return \"'00:00:00'\";\n case 'timetz':\n case 'time with time zone':\n return \"'00:00:00+00'\";\n\n case 'interval':\n return \"'0'\";\n\n case 'bytea':\n return \"''::bytea\";\n case 'tsvector':\n return \"''::tsvector\";\n\n case 'bit':\n return buildBitIdentityValue(typeParams);\n case 'bit varying':\n case 'varbit':\n return \"B''\";\n\n default:\n return null;\n }\n}\n\nfunction normalizeIdentityValueNativeType(nativeType: string): string {\n return nativeType.trim().toLowerCase().replace(/\\s+/g, ' ');\n}\n\nfunction buildBitIdentityValue(typeParams?: Record<string, unknown>): string | null {\n const length = typeParams?.['length'];\n if (length === undefined) {\n return \"B'0'\";\n }\n if (typeof length !== 'number' || !Number.isInteger(length) || length <= 0) {\n return null;\n }\n return `B'${'0'.repeat(length)}'`;\n}\n"],"mappings":";;;;;;;AASA,SAAgB,qBACd,QACA,YACA,eAAoD,CAAC,GACtC;CACf,MAAM,iBAAiB,OAAO,UAAU,aAAa,OAAO,WAAW,KAAA;CACvE,MAAM,UAAU,gBAAgB,WAAW,OAAO;CAClD,MAAM,aAAa,gBAAgB,cAAc,OAAO;CACxD,MAAM,aAAa,gBAAgB,cAAc,OAAO;CAExD,IAAI,SAAS;EACX,MAAM,cAAc,WAAW,IAAI,OAAO,CAAC,EAAE,uBAAuB;GAClE;GACA;GACA,GAAG,UAAU,cAAc,UAAU;EACvC,CAAC;EACD,IAAI,gBAAgB,KAAA,GAClB,OAAO;CAEX;CAEA,OAAO,0BAA0B,YAAY,UAAU;AACzD;;;;;;;;;;;;AAaA,SAAgB,0BACd,YACA,YACe;CACf,MAAM,uBAAuB,iCAAiC,UAAU;CAExE,IAAI,qBAAqB,SAAS,IAAI,GACpC,OAAO;CAGT,QAAQ,sBAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EAET,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EAET,KAAK;EACL,KAAK,WACH,OAAO;EAET,KAAK,QACH,OAAO;EAET,KAAK,QACH,OAAO;EACT,KAAK,SACH,OAAO;EAET,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,+BACH,OAAO;EAET,KAAK;EACL,KAAK,0BACH,OAAO;EACT,KAAK;EACL,KAAK,uBACH,OAAO;EAET,KAAK,YACH,OAAO;EAET,KAAK,SACH,OAAO;EACT,KAAK,YACH,OAAO;EAET,KAAK,OACH,OAAO,sBAAsB,UAAU;EACzC,KAAK;EACL,KAAK,UACH,OAAO;EAET,SACE,OAAO;CACX;AACF;AAEA,SAAS,iCAAiC,YAA4B;CACpE,OAAO,WAAW,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,QAAQ,GAAG;AAC5D;AAEA,SAAS,sBAAsB,YAAqD;CAClF,MAAM,SAAS,aAAa;CAC5B,IAAI,WAAW,KAAA,GACb,OAAO;CAET,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GACvE,OAAO;CAET,OAAO,KAAK,IAAI,OAAO,MAAM,EAAE;AACjC"}
1
+ {"version":3,"file":"planner-identity-values-CJPha2Sz.mjs","names":[],"sources":["../src/core/migrations/planner-identity-values.ts"],"sourcesContent":["import type { CodecControlHooks } from '@prisma-next/family-sql/control';\nimport type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\n/**\n * Resolves the identity value (monoid neutral element) as a SQL literal for a column's type.\n * Checks codec hooks first (extensions can provide type-specific identity values),\n * then falls back to the built-in map.\n */\nexport function resolveIdentityValue(\n column: StorageColumn,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n storageTypes: Record<string, StorageTypeInstance> = {},\n): string | null {\n const referencedType = column.typeRef ? storageTypes[column.typeRef] : undefined;\n const codecId = referencedType?.codecId ?? column.codecId;\n const nativeType = referencedType?.nativeType ?? column.nativeType;\n const typeParams = referencedType?.typeParams ?? column.typeParams;\n\n if (codecId) {\n const hookDefault = codecHooks.get(codecId)?.resolveIdentityValue?.({\n nativeType,\n codecId,\n ...ifDefined('typeParams', typeParams),\n });\n if (hookDefault !== undefined) {\n return hookDefault;\n }\n }\n\n return buildBuiltinIdentityValue(nativeType, typeParams);\n}\n\n/**\n * Returns the built-in identity value (monoid neutral element) as a SQL literal for the given\n * PostgreSQL native type — e.g. 0 for integers, '' for text, false for booleans.\n *\n * This is the planner's fallback when no codec hook provides a type-specific identity value.\n *\n * Returns null for unrecognized types (for example enums and extension-owned types without a\n * hook), which causes the planner to fall back to the empty-table precheck.\n *\n * @internal Exported for testing only.\n */\nexport function buildBuiltinIdentityValue(\n nativeType: string,\n typeParams?: Record<string, unknown>,\n): string | null {\n const normalizedNativeType = normalizeIdentityValueNativeType(nativeType);\n\n if (normalizedNativeType.endsWith('[]')) {\n return \"'{}'\";\n }\n\n switch (normalizedNativeType) {\n case 'text':\n case 'character':\n case 'bpchar':\n case 'character varying':\n case 'varchar':\n return \"''\";\n\n case 'int2':\n case 'int4':\n case 'int8':\n case 'integer':\n case 'bigint':\n case 'smallint':\n case 'float4':\n case 'float8':\n case 'real':\n case 'double precision':\n case 'numeric':\n case 'decimal':\n return '0';\n\n case 'bool':\n case 'boolean':\n return 'false';\n\n case 'uuid':\n return \"'00000000-0000-0000-0000-000000000000'\";\n\n case 'json':\n return \"'{}'::json\";\n case 'jsonb':\n return \"'{}'::jsonb\";\n\n case 'date':\n case 'timestamp':\n case 'timestamptz':\n case 'timestamp with time zone':\n case 'timestamp without time zone':\n return \"'epoch'\";\n\n case 'time':\n case 'time without time zone':\n return \"'00:00:00'\";\n case 'timetz':\n case 'time with time zone':\n return \"'00:00:00+00'\";\n\n case 'interval':\n return \"'0'\";\n\n case 'bytea':\n return \"''::bytea\";\n case 'tsvector':\n return \"''::tsvector\";\n\n case 'bit':\n return buildBitIdentityValue(typeParams);\n case 'bit varying':\n case 'varbit':\n return \"B''\";\n\n default:\n return null;\n }\n}\n\nfunction normalizeIdentityValueNativeType(nativeType: string): string {\n return nativeType.trim().toLowerCase().replace(/\\s+/g, ' ');\n}\n\nfunction buildBitIdentityValue(typeParams?: Record<string, unknown>): string | null {\n const length = typeParams?.['length'];\n if (length === undefined) {\n return \"B'0'\";\n }\n if (typeof length !== 'number' || !Number.isInteger(length) || length <= 0) {\n return null;\n }\n return `B'${'0'.repeat(length)}'`;\n}\n"],"mappings":";;;;;;;AASA,SAAgB,qBACd,QACA,YACA,eAAoD,CAAC,GACtC;CACf,MAAM,iBAAiB,OAAO,UAAU,aAAa,OAAO,WAAW,KAAA;CACvE,MAAM,UAAU,gBAAgB,WAAW,OAAO;CAClD,MAAM,aAAa,gBAAgB,cAAc,OAAO;CACxD,MAAM,aAAa,gBAAgB,cAAc,OAAO;CAExD,IAAI,SAAS;EACX,MAAM,cAAc,WAAW,IAAI,OAAO,CAAC,EAAE,uBAAuB;GAClE;GACA;GACA,GAAG,UAAU,cAAc,UAAU;EACvC,CAAC;EACD,IAAI,gBAAgB,KAAA,GAClB,OAAO;CAEX;CAEA,OAAO,0BAA0B,YAAY,UAAU;AACzD;;;;;;;;;;;;AAaA,SAAgB,0BACd,YACA,YACe;CACf,MAAM,uBAAuB,iCAAiC,UAAU;CAExE,IAAI,qBAAqB,SAAS,IAAI,GACpC,OAAO;CAGT,QAAQ,sBAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EAET,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EAET,KAAK;EACL,KAAK,WACH,OAAO;EAET,KAAK,QACH,OAAO;EAET,KAAK,QACH,OAAO;EACT,KAAK,SACH,OAAO;EAET,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,+BACH,OAAO;EAET,KAAK;EACL,KAAK,0BACH,OAAO;EACT,KAAK;EACL,KAAK,uBACH,OAAO;EAET,KAAK,YACH,OAAO;EAET,KAAK,SACH,OAAO;EACT,KAAK,YACH,OAAO;EAET,KAAK,OACH,OAAO,sBAAsB,UAAU;EACzC,KAAK;EACL,KAAK,UACH,OAAO;EAET,SACE,OAAO;CACX;AACF;AAEA,SAAS,iCAAiC,YAA4B;CACpE,OAAO,WAAW,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,QAAQ,GAAG;AAC5D;AAEA,SAAS,sBAAsB,YAAqD;CAClF,MAAM,SAAS,aAAa;CAC5B,IAAI,WAAW,KAAA,GACb,OAAO;CAET,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GACvE,OAAO;CAET,OAAO,KAAK,IAAI,OAAO,MAAM,EAAE;AACjC"}
@@ -1,7 +1,13 @@
1
- import { CodecControlHooks } from "@prisma-next/family-sql/control";
2
1
  import { StorageColumn, StorageTypeInstance } from "@prisma-next/sql-contract/types";
2
+ import { CodecControlHooks } from "@prisma-next/family-sql/control";
3
3
 
4
4
  //#region src/core/migrations/planner-identity-values.d.ts
5
+ /**
6
+ * Resolves the identity value (monoid neutral element) as a SQL literal for a column's type.
7
+ * Checks codec hooks first (extensions can provide type-specific identity values),
8
+ * then falls back to the built-in map.
9
+ */
10
+ declare function resolveIdentityValue(column: StorageColumn, codecHooks: ReadonlyMap<string, CodecControlHooks>, storageTypes?: Record<string, StorageTypeInstance>): string | null;
5
11
  /**
6
12
  * Returns the built-in identity value (monoid neutral element) as a SQL literal for the given
7
13
  * PostgreSQL native type — e.g. 0 for integers, '' for text, false for booleans.
@@ -15,5 +21,5 @@ import { StorageColumn, StorageTypeInstance } from "@prisma-next/sql-contract/ty
15
21
  */
16
22
  declare function buildBuiltinIdentityValue(nativeType: string, typeParams?: Record<string, unknown>): string | null;
17
23
  //#endregion
18
- export { buildBuiltinIdentityValue };
24
+ export { buildBuiltinIdentityValue, resolveIdentityValue };
19
25
  //# sourceMappingURL=planner-identity-values.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"planner-identity-values.d.mts","names":[],"sources":["../src/core/migrations/planner-identity-values.ts"],"mappings":";;;;;;;;AA8CsC;;;;;;;iBAFtB,yBAAA,CACd,UAAA,UACA,UAAA,GAAa,MAAM"}
1
+ {"version":3,"file":"planner-identity-values.d.mts","names":[],"sources":["../src/core/migrations/planner-identity-values.ts"],"mappings":";;;;;;AASA;;;iBAAgB,oBAAA,CACd,MAAA,EAAQ,aAAA,EACR,UAAA,EAAY,WAAA,SAAoB,iBAAA,GAChC,YAAA,GAAc,MAAA,SAAe,mBAAA;;;;;;;;;;;;iBAgCf,yBAAA,CACd,UAAA,UACA,UAAA,GAAa,MAAM"}