@prisma-next/target-postgres 0.14.0-dev.6 → 0.14.0-dev.60

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 (253) hide show
  1. package/dist/authoring-WkqG_MkU.mjs +419 -0
  2. package/dist/authoring-WkqG_MkU.mjs.map +1 -0
  3. package/dist/canonicalize-CAbXtVtB.d.mts +37 -0
  4. package/dist/canonicalize-CAbXtVtB.d.mts.map +1 -0
  5. package/dist/{codec-ids-CnXu9Qy3.d.mts → codec-ids-BzrFF-I4.d.mts} +3 -2
  6. package/dist/codec-ids-BzrFF-I4.d.mts.map +1 -0
  7. package/dist/{codec-ids-BvytN2P8.mjs → codec-ids-C_-Hj6bL.mjs} +3 -2
  8. package/dist/codec-ids-C_-Hj6bL.mjs.map +1 -0
  9. package/dist/codec-ids.d.mts +2 -2
  10. package/dist/codec-ids.mjs +2 -2
  11. package/dist/{codec-types-DHCkwPKE.d.mts → codec-types-BiIWziRO.d.mts} +3 -2
  12. package/dist/codec-types-BiIWziRO.d.mts.map +1 -0
  13. package/dist/codec-types.d.mts +1 -1
  14. package/dist/codecs-CkVQrZ4G.mjs +913 -0
  15. package/dist/codecs-CkVQrZ4G.mjs.map +1 -0
  16. package/dist/{codecs--0A5_4Bq.d.mts → codecs-Cm-nS4mQ.d.mts} +111 -4
  17. package/dist/codecs-Cm-nS4mQ.d.mts.map +1 -0
  18. package/dist/codecs.d.mts +2 -2
  19. package/dist/codecs.mjs +3 -757
  20. package/dist/codecs.mjs.map +1 -1
  21. package/dist/contract-free.d.mts +33 -3
  22. package/dist/contract-free.d.mts.map +1 -1
  23. package/dist/contract-free.mjs +4 -4
  24. package/dist/control-policy-Co_13Hxa.mjs +1128 -0
  25. package/dist/control-policy-Co_13Hxa.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 +900 -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-B-krEXY1.mjs} +77 -6
  35. package/dist/ddl-B-krEXY1.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-BOcKPaLE.mjs +22 -0
  43. package/dist/descriptor-meta-BOcKPaLE.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-BOsDnH64.mjs +266 -0
  47. package/dist/diff-database-schema-BOsDnH64.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/errors-DO-w0EUS.mjs +35 -0
  52. package/dist/errors-DO-w0EUS.mjs.map +1 -0
  53. package/dist/errors.d.mts +11 -9
  54. package/dist/errors.d.mts.map +1 -1
  55. package/dist/errors.mjs +1 -1
  56. package/dist/issue-planner.d.mts +35 -11
  57. package/dist/issue-planner.d.mts.map +1 -1
  58. package/dist/issue-planner.mjs +2 -2
  59. package/dist/migration.d.mts +5 -5
  60. package/dist/migration.d.mts.map +1 -1
  61. package/dist/migration.mjs +4 -4
  62. package/dist/namespace-ids-xtp_ZY86.mjs +7 -0
  63. package/dist/namespace-ids-xtp_ZY86.mjs.map +1 -0
  64. package/dist/native-type-normalizer.mjs +37 -1
  65. package/dist/native-type-normalizer.mjs.map +1 -0
  66. package/dist/nodes-B815pj_X.mjs +162 -0
  67. package/dist/nodes-B815pj_X.mjs.map +1 -0
  68. package/dist/nodes-BtQyZha6.d.mts +146 -0
  69. package/dist/nodes-BtQyZha6.d.mts.map +1 -0
  70. package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-D6_7-7Vc.d.mts} +68 -15
  71. package/dist/op-factory-call-D6_7-7Vc.d.mts.map +1 -0
  72. package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-DxNNKUeZ.mjs} +300 -31
  73. package/dist/op-factory-call-DxNNKUeZ.mjs.map +1 -0
  74. package/dist/op-factory-call.d.mts +2 -2
  75. package/dist/op-factory-call.mjs +2 -2
  76. package/dist/pack.d.mts +144 -3
  77. package/dist/pack.d.mts.map +1 -1
  78. package/dist/pack.mjs +1 -1
  79. package/dist/planner-CNrc1Odu.mjs +422 -0
  80. package/dist/planner-CNrc1Odu.mjs.map +1 -0
  81. package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-B8Nn6nHN.mjs} +12 -27
  82. package/dist/planner-ddl-builders-B8Nn6nHN.mjs.map +1 -0
  83. package/dist/planner-ddl-builders.d.mts +4 -6
  84. package/dist/planner-ddl-builders.d.mts.map +1 -1
  85. package/dist/planner-ddl-builders.mjs +2 -2
  86. package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -1
  87. package/dist/planner-identity-values.d.mts +8 -2
  88. package/dist/planner-identity-values.d.mts.map +1 -1
  89. package/dist/planner-identity-values.mjs +2 -2
  90. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-NI-oGKcw.mjs} +3 -3
  91. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-NI-oGKcw.mjs.map} +1 -1
  92. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-a-tjfKsA.d.mts} +4 -4
  93. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-a-tjfKsA.d.mts.map} +1 -1
  94. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  95. package/dist/planner-produced-postgres-migration.mjs +1 -1
  96. package/dist/{planner-sql-checks-jqUUGyQR.mjs → planner-sql-checks-AXoxB1Jl.mjs} +2 -2
  97. package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-AXoxB1Jl.mjs.map} +1 -1
  98. package/dist/planner-sql-checks.d.mts +2 -2
  99. package/dist/planner-sql-checks.d.mts.map +1 -1
  100. package/dist/planner-sql-checks.mjs +1 -1
  101. package/dist/{planner-target-details-CIY6tLeo.d.mts → planner-target-details-HkP4RrRO.d.mts} +2 -2
  102. package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -0
  103. package/dist/planner-target-details.d.mts +1 -1
  104. package/dist/planner.d.mts +72 -17
  105. package/dist/planner.d.mts.map +1 -1
  106. package/dist/planner.mjs +3 -2
  107. package/dist/postgres-contract-view-C9j5cqP0.d.mts +34 -0
  108. package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +1 -0
  109. package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-Dg-N7KA7.mjs} +45 -41
  110. package/dist/postgres-contract-view-Dg-N7KA7.mjs.map +1 -0
  111. package/dist/postgres-database-schema-node-CfdTY-Qs.d.mts +218 -0
  112. package/dist/postgres-database-schema-node-CfdTY-Qs.d.mts.map +1 -0
  113. package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-Bzzi0Asr.d.mts} +28 -9
  114. package/dist/postgres-migration-Bzzi0Asr.d.mts.map +1 -0
  115. package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-ChyRsWvE.mjs} +53 -45
  116. package/dist/postgres-migration-ChyRsWvE.mjs.map +1 -0
  117. package/dist/postgres-native-enum-xdiqmBf_.mjs +41 -0
  118. package/dist/postgres-native-enum-xdiqmBf_.mjs.map +1 -0
  119. package/dist/postgres-rls-policy--CSddvMR.d.mts +52 -0
  120. package/dist/postgres-rls-policy--CSddvMR.d.mts.map +1 -0
  121. package/dist/postgres-role-schema-node-BiSTCTNg.mjs +195 -0
  122. package/dist/postgres-role-schema-node-BiSTCTNg.mjs.map +1 -0
  123. package/dist/postgres-schema-CU4gF6QZ.d.mts +257 -0
  124. package/dist/postgres-schema-CU4gF6QZ.d.mts.map +1 -0
  125. package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-DTLA_aRi.mjs} +171 -10
  126. package/dist/postgres-schema-DTLA_aRi.mjs.map +1 -0
  127. package/dist/postgres-table-schema-node-9FCtCUz2.mjs +153 -0
  128. package/dist/postgres-table-schema-node-9FCtCUz2.mjs.map +1 -0
  129. package/dist/render-ops.d.mts +1 -1
  130. package/dist/{render-typescript-KMgosran.mjs → render-typescript-7yqILcwr.mjs} +45 -16
  131. package/dist/render-typescript-7yqILcwr.mjs.map +1 -0
  132. package/dist/render-typescript.mjs +1 -1
  133. package/dist/resolve-ddl-schema-Ca88Tg6W.mjs +22 -0
  134. package/dist/resolve-ddl-schema-Ca88Tg6W.mjs.map +1 -0
  135. package/dist/rls-canonicalize.d.mts +20 -0
  136. package/dist/rls-canonicalize.d.mts.map +1 -0
  137. package/dist/rls-canonicalize.mjs +2 -0
  138. package/dist/runtime.d.mts +6 -8
  139. package/dist/runtime.d.mts.map +1 -1
  140. package/dist/runtime.mjs +3 -3
  141. package/dist/runtime.mjs.map +1 -1
  142. package/dist/schema-ir-annotations.d.mts +15 -0
  143. package/dist/schema-ir-annotations.d.mts.map +1 -0
  144. package/dist/schema-ir-annotations.mjs +2 -0
  145. package/dist/types.d.mts +4 -140
  146. package/dist/types.mjs +5 -2
  147. package/dist/wire-name-rHHtr1h0.mjs +75 -0
  148. package/dist/wire-name-rHHtr1h0.mjs.map +1 -0
  149. package/package.json +23 -17
  150. package/src/contract-free/checks.ts +73 -0
  151. package/src/contract-free/ddl.ts +71 -1
  152. package/src/core/authoring.ts +356 -2
  153. package/src/core/codec-ids.ts +1 -0
  154. package/src/core/codec-type-map.ts +2 -0
  155. package/src/core/codecs.ts +180 -1
  156. package/src/core/ddl/nodes.ts +141 -2
  157. package/src/core/default-normalizer.ts +122 -2
  158. package/src/core/descriptor-meta.ts +10 -1
  159. package/src/core/entity-kinds.ts +41 -0
  160. package/src/core/errors.ts +14 -12
  161. package/src/core/migrations/bound-schema.ts +10 -0
  162. package/src/core/migrations/column-ddl-rendering.ts +117 -0
  163. package/src/core/migrations/contract-to-postgres-database-schema-node.ts +160 -0
  164. package/src/core/migrations/control-policy.ts +99 -46
  165. package/src/core/migrations/diff-database-schema.ts +217 -0
  166. package/src/core/migrations/issue-planner.ts +692 -652
  167. package/src/core/migrations/op-factory-call.ts +189 -21
  168. package/src/core/migrations/operations/columns.ts +24 -12
  169. package/src/core/migrations/operations/constraints.ts +1 -1
  170. package/src/core/migrations/operations/data-transform.ts +6 -0
  171. package/src/core/migrations/operations/dependencies.ts +2 -1
  172. package/src/core/migrations/operations/rls.ts +187 -0
  173. package/src/core/migrations/operations/shared.ts +0 -30
  174. package/src/core/migrations/planner-ddl-builders.ts +20 -58
  175. package/src/core/migrations/planner-identity-values.ts +1 -1
  176. package/src/core/migrations/planner-recipes.ts +31 -13
  177. package/src/core/migrations/planner-sql-checks.ts +1 -1
  178. package/src/core/migrations/planner-strategies.ts +248 -216
  179. package/src/core/migrations/planner-target-details.ts +3 -1
  180. package/src/core/migrations/planner.ts +381 -59
  181. package/src/core/migrations/postgres-migration.ts +70 -86
  182. package/src/core/migrations/render-typescript.ts +42 -15
  183. package/src/core/migrations/resolve-ddl-schema.ts +26 -0
  184. package/src/core/migrations/runner.ts +10 -16
  185. package/src/core/migrations/verify-postgres-namespaces.ts +47 -31
  186. package/src/core/namespace-ids.ts +3 -0
  187. package/src/core/postgres-contract-serializer.ts +46 -71
  188. package/src/core/postgres-contract-view.ts +48 -0
  189. package/src/core/postgres-native-enum.ts +51 -0
  190. package/src/core/postgres-rls-enablement.ts +34 -0
  191. package/src/core/postgres-rls-policy.ts +64 -0
  192. package/src/core/postgres-role.ts +37 -0
  193. package/src/core/postgres-schema-verifier.ts +10 -7
  194. package/src/core/postgres-schema.ts +64 -15
  195. package/src/core/postgres-validators.ts +33 -0
  196. package/src/core/psl-infer/infer-psl-contract.ts +1325 -0
  197. package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
  198. package/src/core/psl-infer/postgres-type-map.ts +128 -0
  199. package/src/core/rls/canonicalize.ts +48 -0
  200. package/src/core/rls/wire-name.ts +33 -0
  201. package/src/core/schema-ir/postgres-database-schema-node.ts +60 -0
  202. package/src/core/schema-ir/postgres-namespace-schema-node.ts +79 -0
  203. package/src/core/schema-ir/postgres-policy-schema-node.ts +90 -0
  204. package/src/core/schema-ir/postgres-role-schema-node.ts +63 -0
  205. package/src/core/schema-ir/postgres-table-schema-node.ts +140 -0
  206. package/src/core/schema-ir/schema-node-kinds.ts +106 -0
  207. package/src/exports/codecs.ts +3 -0
  208. package/src/exports/contract-free.ts +11 -1
  209. package/src/exports/control.ts +27 -33
  210. package/src/exports/ddl.ts +6 -0
  211. package/src/exports/diff-database-schema.ts +7 -0
  212. package/src/exports/issue-planner.ts +1 -1
  213. package/src/exports/migration.ts +1 -0
  214. package/src/exports/op-factory-call.ts +1 -0
  215. package/src/exports/planner-ddl-builders.ts +0 -2
  216. package/src/exports/planner-identity-values.ts +4 -1
  217. package/src/exports/planner.ts +1 -0
  218. package/src/exports/rls-canonicalize.ts +7 -0
  219. package/src/exports/runtime.ts +1 -0
  220. package/src/exports/schema-ir-annotations.ts +1 -0
  221. package/src/exports/types.ts +34 -0
  222. package/dist/codec-ids-BvytN2P8.mjs.map +0 -1
  223. package/dist/codec-ids-CnXu9Qy3.d.mts.map +0 -1
  224. package/dist/codec-types-DHCkwPKE.d.mts.map +0 -1
  225. package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
  226. package/dist/ddl-QDyOSeLc.mjs.map +0 -1
  227. package/dist/default-normalizer-DyyCHQWs.mjs +0 -131
  228. package/dist/default-normalizer-DyyCHQWs.mjs.map +0 -1
  229. package/dist/descriptor-meta-CpGygXpI.mjs +0 -140
  230. package/dist/descriptor-meta-CpGygXpI.mjs.map +0 -1
  231. package/dist/errors-CUk87ByX.mjs +0 -33
  232. package/dist/errors-CUk87ByX.mjs.map +0 -1
  233. package/dist/issue-planner-DL6g3CmE.mjs +0 -824
  234. package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
  235. package/dist/native-type-normalizer-Bc9XJzWC.mjs +0 -38
  236. package/dist/native-type-normalizer-Bc9XJzWC.mjs.map +0 -1
  237. package/dist/nodes-Bbhs2rwj.mjs +0 -76
  238. package/dist/nodes-Bbhs2rwj.mjs.map +0 -1
  239. package/dist/nodes-pLeLgdis.d.mts +0 -67
  240. package/dist/nodes-pLeLgdis.d.mts.map +0 -1
  241. package/dist/op-factory-call-D_p5vxwt.mjs.map +0 -1
  242. package/dist/op-factory-call-DmQEc3XV.d.mts.map +0 -1
  243. package/dist/planner-Bs_baQax.mjs +0 -324
  244. package/dist/planner-Bs_baQax.mjs.map +0 -1
  245. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +0 -1
  246. package/dist/planner-target-details-CIY6tLeo.d.mts.map +0 -1
  247. package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +0 -1
  248. package/dist/postgres-migration-B5jKrXv3.mjs.map +0 -1
  249. package/dist/postgres-migration-Y4YBJqkS.d.mts.map +0 -1
  250. package/dist/postgres-schema-COGZ1ark.mjs.map +0 -1
  251. package/dist/render-typescript-KMgosran.mjs.map +0 -1
  252. package/dist/types.d.mts.map +0 -1
  253. package/src/core/postgres-enum-type-schema.ts +0 -17
@@ -0,0 +1,217 @@
1
+ import type { Contract, ControlPolicy } from '@prisma-next/contract/types';
2
+ import type { SqlSchemaDiffResult } from '@prisma-next/family-sql/control';
3
+ import { buildNativeTypeExpander } from '@prisma-next/family-sql/control';
4
+ import { classifyDiffSubjectGranularity } from '@prisma-next/family-sql/diff';
5
+ import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
6
+ import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
7
+ import { diffSchemas } from '@prisma-next/framework-components/control';
8
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
9
+ import type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
10
+ import { blindCast } from '@prisma-next/utils/casts';
11
+ import { ifDefined } from '@prisma-next/utils/defined';
12
+ import type { PostgresContract } from '../postgres-schema';
13
+ import { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
14
+ import { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';
15
+ import {
16
+ postgresDiffSubjectGranularity,
17
+ type SqlSchemaDiffNode,
18
+ } from '../schema-ir/schema-node-kinds';
19
+ import { contractToPostgresDatabaseSchemaNode } from './contract-to-postgres-database-schema-node';
20
+ import { resolvePostgresNodeIssueControlPolicySubject } from './control-policy';
21
+
22
+ function ownedSchemaNames(expected: PostgresDatabaseSchemaNode): ReadonlySet<string> {
23
+ const policyNamespaces = Object.values(expected.namespaces).flatMap((ns) =>
24
+ Object.values(ns.tables).flatMap((t) => t.policies.map((p) => p.namespaceId)),
25
+ );
26
+ return new Set([...policyNamespaces, ...expected.existingSchemas]);
27
+ }
28
+
29
+ /**
30
+ * Drops contract namespaces that declare no tables from the verdict-diff
31
+ * expected tree and the relational owned-schema set. The legacy relational
32
+ * walk skipped a table-less namespace (e.g. an enums-only schema) before
33
+ * pairing, so neither its DDL schema's absence nor that schema's live
34
+ * relational contents ever reached the verdict — the pruned tree
35
+ * reproduces that. The prune loses no expected policies: policies attach
36
+ * to tables, so a table-less namespace carries none (the projection
37
+ * throws on a policy referencing an absent table). Live policies in a
38
+ * pruned schema remain governed via the full owned set (see
39
+ * {@link diffPostgresSchema}).
40
+ */
41
+ function pruneTableLessNamespaces(
42
+ expected: PostgresDatabaseSchemaNode,
43
+ ): PostgresDatabaseSchemaNode {
44
+ const namespaces = Object.fromEntries(
45
+ Object.entries(expected.namespaces).filter(([, ns]) => Object.keys(ns.tables).length > 0),
46
+ );
47
+ return new PostgresDatabaseSchemaNode({
48
+ namespaces,
49
+ roles: [...expected.roles],
50
+ existingSchemas: expected.existingSchemas.filter((s) => namespaces[s] !== undefined),
51
+ pgVersion: expected.pgVersion,
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Resolves a verdict-diff issue's subject table's declared control policy
57
+ * directly from the contract, by delegating to the same node-typed resolver
58
+ * ({@link resolvePostgresNodeIssueControlPolicySubject}) the planner uses to
59
+ * gate DDL calls. `undefined` when the issue resolves to no contract table.
60
+ */
61
+ function resolveControlPolicy(
62
+ issue: SchemaDiffIssue,
63
+ contract: Contract<SqlStorage>,
64
+ ): ControlPolicy | undefined {
65
+ const nodeIssue = blindCast<
66
+ SchemaDiffIssue<SqlSchemaDiffNode>,
67
+ 'every node in a Postgres schema diff tree is a SqlSchemaDiffNode'
68
+ >(issue);
69
+ return resolvePostgresNodeIssueControlPolicySubject(nodeIssue, contract)
70
+ ?.explicitNodeControlPolicy;
71
+ }
72
+
73
+ /**
74
+ * The Postgres full-tree node diff for the family verify verdict: derive
75
+ * the expected tree (resolved leaf values, expander threaded, FK schemas
76
+ * resolved, table-less namespaces pruned), run the generic
77
+ * differ over the trees as derived, and scope out `not-expected` findings under namespaces the
78
+ * contract does not own. Ownership is role-aware, mirroring the legacy
79
+ * decomposition: relational extras check the PRUNED owned set (the legacy
80
+ * per-namespace walk never visited a table-less namespace, so its live
81
+ * relational contents are invisible), while `structural` extras (RLS
82
+ * policies) check the FULL owned set (the legacy policy diff governed
83
+ * every contract schema regardless of tables — RLS governance does not
84
+ * shrink because a namespace declares no tables). The codec `verifyType`
85
+ * hooks run once per contract namespace with tables against that
86
+ * namespace's paired actual node (the hooks read namespace-scoped state
87
+ * such as `nativeEnumTypeNames`).
88
+ */
89
+ export function diffPostgresSchema(input: {
90
+ readonly contract: Contract<SqlStorage>;
91
+ readonly schema: SqlSchemaIRNode;
92
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
93
+ }): SqlSchemaDiffResult {
94
+ const postgresContract = blindCast<
95
+ PostgresContract,
96
+ 'diffPostgresSchema is only called with a postgres contract'
97
+ >(input.contract);
98
+ PostgresDatabaseSchemaNode.assert(input.schema);
99
+ const actual = input.schema;
100
+ const expandNativeType = buildNativeTypeExpander(input.frameworkComponents);
101
+ const fullExpected = contractToPostgresDatabaseSchemaNode(postgresContract, {
102
+ annotationNamespace: 'pg',
103
+ ...ifDefined('expandNativeType', expandNativeType),
104
+ });
105
+ const expected = pruneTableLessNamespaces(fullExpected);
106
+ const relationalOwned = ownedSchemaNames(expected);
107
+ const structuralOwned = ownedSchemaNames(fullExpected);
108
+ const issues = diffSchemas(expected, actual).filter((issue) => {
109
+ if (issue.reason !== 'not-expected') return true;
110
+ const namespaceSegment = issue.path[1];
111
+ if (namespaceSegment === undefined) return true;
112
+ const granularity = classifyDiffSubjectGranularity(issue, postgresDiffSubjectGranularity);
113
+ const owned = granularity === 'structural' ? structuralOwned : relationalOwned;
114
+ return owned.has(namespaceSegment);
115
+ });
116
+ const namespacePairs = Object.values(expected.namespaces).map((ns) => ({
117
+ actual: actual.namespaces[ns.schemaName],
118
+ }));
119
+ return {
120
+ issues,
121
+ resolveControlPolicy: (issue) => resolveControlPolicy(issue, postgresContract),
122
+ namespacePairs,
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Adds an empty namespace node to the actual tree for every expected namespace
128
+ * absent from it. The relational plan diff pairs on namespace: a contract
129
+ * namespace whose live schema does not exist yet must surface each of its
130
+ * tables as `not-found` (→ `CREATE TABLE`), NOT as a single namespace
131
+ * `not-found` that subtree-coalescing would collapse (leaving `CREATE SCHEMA`
132
+ * with no tables). Padding makes the namespaces pair, so only table/column/
133
+ * policy drift surfaces; `CREATE SCHEMA` comes separately from the synthesized
134
+ * namespace-presence stitch (`verifyPostgresNamespacePresence`), never from the
135
+ * tree diff — matching the retired per-namespace-paired relational walk, which
136
+ * paired a missing schema against an empty namespace node.
137
+ */
138
+ function padActualNamespaces(
139
+ expected: PostgresDatabaseSchemaNode,
140
+ actual: PostgresDatabaseSchemaNode,
141
+ ): PostgresDatabaseSchemaNode {
142
+ const namespaces: Record<string, PostgresNamespaceSchemaNode> = { ...actual.namespaces };
143
+ let padded = false;
144
+ for (const schemaName of Object.keys(expected.namespaces)) {
145
+ if (namespaces[schemaName] === undefined) {
146
+ namespaces[schemaName] = new PostgresNamespaceSchemaNode({
147
+ schemaName,
148
+ tables: {},
149
+ nativeEnumTypeNames: [],
150
+ });
151
+ padded = true;
152
+ }
153
+ }
154
+ if (!padded) return actual;
155
+ return new PostgresDatabaseSchemaNode({
156
+ namespaces,
157
+ roles: [...actual.roles],
158
+ existingSchemas: [...actual.existingSchemas],
159
+ pgVersion: actual.pgVersion,
160
+ });
161
+ }
162
+
163
+ export interface PostgresPlanDiff {
164
+ /** The desired ("end") tree — resolved leaf values (incl. `codecRef`) on every column, table-less namespaces pruned. */
165
+ readonly expected: PostgresDatabaseSchemaNode;
166
+ /** The live ("start") tree, padded with empty namespaces so a missing schema's tables pair. */
167
+ readonly actual: PostgresDatabaseSchemaNode;
168
+ /** The one node diff over the two trees: relational + policy drift, role-aware ownership filtered. */
169
+ readonly issues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[];
170
+ }
171
+
172
+ /**
173
+ * The Postgres planner's diff input: the SAME tree-building
174
+ * `diffPostgresSchema` uses (expander threaded, FK schemas resolved,
175
+ * table-less namespaces pruned, role-aware ownership filter) plus actual
176
+ * namespace padding (so a missing
177
+ * schema's tables surface as `not-found` instead of a swallowed namespace
178
+ * `not-found`). One differ drives both verify and plan; this is the
179
+ * plan-side derivation. The single issue list covers tables / columns /
180
+ * constraints / indexes / defaults AND policies — the caller splits it
181
+ * (relational → `mapNodeIssueToCall`; policy → RLS ops) and stitches in
182
+ * `CREATE SCHEMA` separately.
183
+ */
184
+ export function buildPostgresPlanDiff(input: {
185
+ readonly contract: Contract<SqlStorage>;
186
+ readonly actualSchema: SqlSchemaIRNode;
187
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
188
+ }): PostgresPlanDiff {
189
+ const postgresContract = blindCast<
190
+ PostgresContract,
191
+ 'buildPostgresPlanDiff is only called with a postgres contract'
192
+ >(input.contract);
193
+ PostgresDatabaseSchemaNode.assert(input.actualSchema);
194
+ const actual = input.actualSchema;
195
+ const expandNativeType = buildNativeTypeExpander(input.frameworkComponents);
196
+ const projectionOptions = {
197
+ annotationNamespace: 'pg',
198
+ ...ifDefined('expandNativeType', expandNativeType),
199
+ };
200
+ const fullExpected = contractToPostgresDatabaseSchemaNode(postgresContract, projectionOptions);
201
+ const expected = pruneTableLessNamespaces(fullExpected);
202
+ const paddedActual = padActualNamespaces(expected, actual);
203
+ const relationalOwned = ownedSchemaNames(expected);
204
+ const structuralOwned = ownedSchemaNames(fullExpected);
205
+ const issues = blindCast<
206
+ readonly SchemaDiffIssue<SqlSchemaDiffNode>[],
207
+ 'both trees are PostgresDatabaseSchemaNodes, so every diff-issue node is a SqlSchemaDiffNode'
208
+ >(diffSchemas(expected, paddedActual)).filter((issue) => {
209
+ if (issue.reason !== 'not-expected') return true;
210
+ const namespaceSegment = issue.path[1];
211
+ if (namespaceSegment === undefined) return true;
212
+ const granularity = classifyDiffSubjectGranularity(issue, postgresDiffSubjectGranularity);
213
+ const owned = granularity === 'structural' ? structuralOwned : relationalOwned;
214
+ return owned.has(namespaceSegment);
215
+ });
216
+ return { expected, actual: paddedActual, issues };
217
+ }