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

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-BLkL4fFG.mjs +528 -0
  2. package/dist/authoring-BLkL4fFG.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-BpmChlAK.mjs +1151 -0
  25. package/dist/control-policy-BpmChlAK.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 +901 -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-BovUVFVi.mjs} +77 -6
  35. package/dist/ddl-BovUVFVi.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-C1T4BXJ8.mjs +22 -0
  43. package/dist/descriptor-meta-C1T4BXJ8.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-RMwnSOnz.mjs +298 -0
  47. package/dist/diff-database-schema-RMwnSOnz.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-D_p5vxwt.mjs → op-factory-call-CI00nS4z.mjs} +300 -31
  71. package/dist/op-factory-call-CI00nS4z.mjs.map +1 -0
  72. package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-D6_7-7Vc.d.mts} +68 -15
  73. package/dist/op-factory-call-D6_7-7Vc.d.mts.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 +287 -3
  77. package/dist/pack.d.mts.map +1 -1
  78. package/dist/pack.mjs +1 -1
  79. package/dist/planner-CAHZN1Ez.mjs +422 -0
  80. package/dist/planner-CAHZN1Ez.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-QqHa2C2l.d.mts → planner-produced-postgres-migration-a-tjfKsA.d.mts} +4 -4
  91. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-a-tjfKsA.d.mts.map} +1 -1
  92. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-flkG4Y7n.mjs} +3 -3
  93. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-flkG4Y7n.mjs.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-C1-Kk3Eu.mjs} +2 -2
  97. package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-C1-Kk3Eu.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-DWLNQbdR.mjs} +45 -41
  110. package/dist/postgres-contract-view-DWLNQbdR.mjs.map +1 -0
  111. package/dist/postgres-database-schema-node-BVdOffjC.d.mts +221 -0
  112. package/dist/postgres-database-schema-node-BVdOffjC.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-C92swCzd.mjs} +53 -45
  116. package/dist/postgres-migration-C92swCzd.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-BmCboEa_.mjs +198 -0
  122. package/dist/postgres-role-schema-node-BmCboEa_.mjs.map +1 -0
  123. package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-COEca21H.mjs} +188 -10
  124. package/dist/postgres-schema-COEca21H.mjs.map +1 -0
  125. package/dist/postgres-schema-DsrtYp2v.d.mts +269 -0
  126. package/dist/postgres-schema-DsrtYp2v.d.mts.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-ZkKxt2Fm.mjs +22 -0
  134. package/dist/resolve-ddl-schema-ZkKxt2Fm.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 +467 -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 +126 -44
  165. package/src/core/migrations/diff-database-schema.ts +253 -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 +386 -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 +59 -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 +34 -0
  196. package/src/core/psl-infer/infer-psl-contract.ts +1326 -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 +61 -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 +65 -0
  205. package/src/core/schema-ir/postgres-table-schema-node.ts +140 -0
  206. package/src/core/schema-ir/schema-node-kinds.ts +113 -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
@@ -3,9 +3,11 @@ import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control'
3
3
  import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
4
4
  import { Migration as SqlMigration } from '@prisma-next/family-sql/migration';
5
5
  import type { ControlStack } from '@prisma-next/framework-components/control';
6
+ import { MigrationContractViews } from '@prisma-next/migration-tools/migration';
6
7
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
7
8
  import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
8
9
  import { errorPostgresMigrationStackMissing } from '../errors';
10
+ import { PostgresContractView } from '../postgres-contract-view';
9
11
  import {
10
12
  AddCheckConstraintCall,
11
13
  AddColumnCall,
@@ -60,20 +62,31 @@ import type { PostgresPlanTargetDetails } from './planner-target-details';
60
62
  * is an antipattern in a migration. (The unbound/unspecified namespace concept
61
63
  * remains for SQLite, which has no schemas, and for Mongo's connection `db`.)
62
64
  */
63
- export abstract class PostgresMigration extends SqlMigration<
64
- PostgresPlanTargetDetails,
65
- 'postgres'
66
- > {
65
+ export abstract class PostgresMigration<
66
+ Start extends Contract<SqlStorage> = Contract<SqlStorage>,
67
+ End extends Contract<SqlStorage> = Contract<SqlStorage>,
68
+ > extends SqlMigration<PostgresPlanTargetDetails, 'postgres', Start, End> {
67
69
  readonly targetId = 'postgres' as const;
68
70
 
69
71
  /**
70
72
  * Materialized Postgres control adapter, created once per migration
71
73
  * instance from the injected stack. `undefined` only when the migration
72
- * was instantiated without a stack (test fixtures); `dataTransform`
73
- * throws in that case to surface the misuse.
74
+ * was instantiated without a stack (test fixtures); `controlAdapterFor`
75
+ * throws a PN-MIG-2007 in that case to surface the misuse.
74
76
  */
75
77
  protected readonly controlAdapter: SqlControlAdapter<'postgres'> | undefined;
76
78
 
79
+ #endView = new MigrationContractViews<PostgresContractView<End>>(
80
+ this,
81
+ 'PostgresMigration',
82
+ (json) => PostgresContractView.fromJson<End>(json),
83
+ );
84
+ #startView = new MigrationContractViews<PostgresContractView<Start>>(
85
+ this,
86
+ 'PostgresMigration',
87
+ (json) => PostgresContractView.fromJson<Start>(json),
88
+ );
89
+
77
90
  constructor(stack?: ControlStack<'sql', 'postgres'>) {
78
91
  super(stack);
79
92
  // The descriptor `create()` is typed as the wider `ControlAdapterInstance`;
@@ -84,6 +97,35 @@ export abstract class PostgresMigration extends SqlMigration<
84
97
  : undefined;
85
98
  }
86
99
 
100
+ /**
101
+ * Returns the materialized control adapter, or throws a PN-MIG-2007 naming
102
+ * `operation` when the migration was constructed without a `ControlStack`.
103
+ * Single home for the null-check that every DDL/DML method shares.
104
+ */
105
+ private controlAdapterFor(operation: string): SqlControlAdapter<'postgres'> {
106
+ if (!this.controlAdapter) {
107
+ throw errorPostgresMigrationStackMissing(operation);
108
+ }
109
+ return this.controlAdapter;
110
+ }
111
+
112
+ /**
113
+ * The typed, schema-qualified Postgres view over this migration's end-state
114
+ * contract — `this.endContract.namespace.<schema>.table.<name>`, etc. Throws
115
+ * if no `endContractJson` was provided.
116
+ */
117
+ get endContract(): PostgresContractView<End> {
118
+ return this.#endView.endContract;
119
+ }
120
+
121
+ /**
122
+ * The typed Postgres view over this migration's start-state contract, or
123
+ * `null` for a baseline migration (no `startContractJson`).
124
+ */
125
+ get startContract(): PostgresContractView<Start> | null {
126
+ return this.#startView.startContract;
127
+ }
128
+
87
129
  /**
88
130
  * Instance-method wrapper around the free `dataTransform` factory that
89
131
  * supplies the stored control adapter. Authors call this from inside
@@ -94,10 +136,7 @@ export abstract class PostgresMigration extends SqlMigration<
94
136
  name: string,
95
137
  options: DataTransformOptions,
96
138
  ): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
97
- if (!this.controlAdapter) {
98
- throw errorPostgresMigrationStackMissing();
99
- }
100
- return dataTransform(contract, name, options, this.controlAdapter);
139
+ return dataTransform(contract, name, options, this.controlAdapterFor('dataTransform'));
101
140
  }
102
141
 
103
142
  /**
@@ -112,15 +151,12 @@ export abstract class PostgresMigration extends SqlMigration<
112
151
  readonly columns: readonly DdlColumn[];
113
152
  readonly constraints?: readonly DdlTableConstraint[];
114
153
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
115
- if (!this.controlAdapter) {
116
- throw errorPostgresMigrationStackMissing();
117
- }
118
154
  return new CreateTableCall(
119
155
  options.schema,
120
156
  options.table,
121
157
  options.columns,
122
158
  options.constraints,
123
- ).toOp(this.controlAdapter);
159
+ ).toOp(this.controlAdapterFor('createTable'));
124
160
  }
125
161
 
126
162
  /**
@@ -132,10 +168,7 @@ export abstract class PostgresMigration extends SqlMigration<
132
168
  readonly schema: string;
133
169
  readonly ifNotExists?: boolean;
134
170
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
135
- if (!this.controlAdapter) {
136
- throw errorPostgresMigrationStackMissing();
137
- }
138
- return new CreateSchemaCall(options.schema).toOp(this.controlAdapter);
171
+ return new CreateSchemaCall(options.schema).toOp(this.controlAdapterFor('createSchema'));
139
172
  }
140
173
 
141
174
  protected addColumn(options: {
@@ -143,11 +176,8 @@ export abstract class PostgresMigration extends SqlMigration<
143
176
  readonly table: string;
144
177
  readonly column: DdlColumn;
145
178
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
146
- if (!this.controlAdapter) {
147
- throw errorPostgresMigrationStackMissing();
148
- }
149
179
  return new AddColumnCall(options.schema, options.table, options.column).toOp(
150
- this.controlAdapter,
180
+ this.controlAdapterFor('addColumn'),
151
181
  );
152
182
  }
153
183
 
@@ -157,15 +187,12 @@ export abstract class PostgresMigration extends SqlMigration<
157
187
  readonly constraint: string;
158
188
  readonly columns: readonly string[];
159
189
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
160
- if (!this.controlAdapter) {
161
- throw errorPostgresMigrationStackMissing();
162
- }
163
190
  return new AddPrimaryKeyCall(
164
191
  options.schema,
165
192
  options.table,
166
193
  options.constraint,
167
194
  options.columns,
168
- ).toOp(this.controlAdapter);
195
+ ).toOp(this.controlAdapterFor('addPrimaryKey'));
169
196
  }
170
197
 
171
198
  protected addUnique(options: {
@@ -174,15 +201,12 @@ export abstract class PostgresMigration extends SqlMigration<
174
201
  readonly constraint: string;
175
202
  readonly columns: readonly string[];
176
203
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
177
- if (!this.controlAdapter) {
178
- throw errorPostgresMigrationStackMissing();
179
- }
180
204
  return new AddUniqueCall(
181
205
  options.schema,
182
206
  options.table,
183
207
  options.constraint,
184
208
  options.columns,
185
- ).toOp(this.controlAdapter);
209
+ ).toOp(this.controlAdapterFor('addUnique'));
186
210
  }
187
211
 
188
212
  protected addForeignKey(options: {
@@ -190,11 +214,8 @@ export abstract class PostgresMigration extends SqlMigration<
190
214
  readonly table: string;
191
215
  readonly foreignKey: ForeignKeySpec;
192
216
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
193
- if (!this.controlAdapter) {
194
- throw errorPostgresMigrationStackMissing();
195
- }
196
217
  return new AddForeignKeyCall(options.schema, options.table, options.foreignKey).toOp(
197
- this.controlAdapter,
218
+ this.controlAdapterFor('addForeignKey'),
198
219
  );
199
220
  }
200
221
 
@@ -205,16 +226,13 @@ export abstract class PostgresMigration extends SqlMigration<
205
226
  readonly column: string;
206
227
  readonly values: readonly string[];
207
228
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
208
- if (!this.controlAdapter) {
209
- throw errorPostgresMigrationStackMissing();
210
- }
211
229
  return new AddCheckConstraintCall(
212
230
  options.schema,
213
231
  options.table,
214
232
  options.constraint,
215
233
  options.column,
216
234
  options.values,
217
- ).toOp(this.controlAdapter);
235
+ ).toOp(this.controlAdapterFor('addCheckConstraint'));
218
236
  }
219
237
 
220
238
  protected dropCheckConstraint(options: {
@@ -222,11 +240,8 @@ export abstract class PostgresMigration extends SqlMigration<
222
240
  readonly table: string;
223
241
  readonly constraint: string;
224
242
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
225
- if (!this.controlAdapter) {
226
- throw errorPostgresMigrationStackMissing();
227
- }
228
243
  return new DropCheckConstraintCall(options.schema, options.table, options.constraint).toOp(
229
- this.controlAdapter,
244
+ this.controlAdapterFor('dropCheckConstraint'),
230
245
  );
231
246
  }
232
247
 
@@ -236,25 +251,21 @@ export abstract class PostgresMigration extends SqlMigration<
236
251
  readonly constraint: string;
237
252
  readonly kind?: 'foreignKey' | 'unique' | 'primaryKey';
238
253
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
239
- if (!this.controlAdapter) {
240
- throw errorPostgresMigrationStackMissing();
241
- }
242
254
  return new DropConstraintCall(
243
255
  options.schema,
244
256
  options.table,
245
257
  options.constraint,
246
258
  options.kind ?? 'unique',
247
- ).toOp(this.controlAdapter);
259
+ ).toOp(this.controlAdapterFor('dropConstraint'));
248
260
  }
249
261
 
250
262
  protected dropTable(options: {
251
263
  readonly schema: string;
252
264
  readonly table: string;
253
265
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
254
- if (!this.controlAdapter) {
255
- throw errorPostgresMigrationStackMissing();
256
- }
257
- return new DropTableCall(options.schema, options.table).toOp(this.controlAdapter);
266
+ return new DropTableCall(options.schema, options.table).toOp(
267
+ this.controlAdapterFor('dropTable'),
268
+ );
258
269
  }
259
270
 
260
271
  protected dropColumn(options: {
@@ -262,11 +273,8 @@ export abstract class PostgresMigration extends SqlMigration<
262
273
  readonly table: string;
263
274
  readonly column: string;
264
275
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
265
- if (!this.controlAdapter) {
266
- throw errorPostgresMigrationStackMissing();
267
- }
268
276
  return new DropColumnCall(options.schema, options.table, options.column).toOp(
269
- this.controlAdapter,
277
+ this.controlAdapterFor('dropColumn'),
270
278
  );
271
279
  }
272
280
 
@@ -276,15 +284,12 @@ export abstract class PostgresMigration extends SqlMigration<
276
284
  readonly column: string;
277
285
  readonly options: AlterColumnTypeOptions;
278
286
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
279
- if (!this.controlAdapter) {
280
- throw errorPostgresMigrationStackMissing();
281
- }
282
287
  return new AlterColumnTypeCall(
283
288
  options.schema,
284
289
  options.table,
285
290
  options.column,
286
291
  options.options,
287
- ).toOp(this.controlAdapter);
292
+ ).toOp(this.controlAdapterFor('alterColumnType'));
288
293
  }
289
294
 
290
295
  protected setNotNull(options: {
@@ -292,11 +297,8 @@ export abstract class PostgresMigration extends SqlMigration<
292
297
  readonly table: string;
293
298
  readonly column: string;
294
299
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
295
- if (!this.controlAdapter) {
296
- throw errorPostgresMigrationStackMissing();
297
- }
298
300
  return new SetNotNullCall(options.schema, options.table, options.column).toOp(
299
- this.controlAdapter,
301
+ this.controlAdapterFor('setNotNull'),
300
302
  );
301
303
  }
302
304
 
@@ -305,11 +307,8 @@ export abstract class PostgresMigration extends SqlMigration<
305
307
  readonly table: string;
306
308
  readonly column: string;
307
309
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
308
- if (!this.controlAdapter) {
309
- throw errorPostgresMigrationStackMissing();
310
- }
311
310
  return new DropNotNullCall(options.schema, options.table, options.column).toOp(
312
- this.controlAdapter,
311
+ this.controlAdapterFor('dropNotNull'),
313
312
  );
314
313
  }
315
314
 
@@ -320,16 +319,13 @@ export abstract class PostgresMigration extends SqlMigration<
320
319
  readonly defaultSql: string;
321
320
  readonly operationClass?: 'additive' | 'widening';
322
321
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
323
- if (!this.controlAdapter) {
324
- throw errorPostgresMigrationStackMissing();
325
- }
326
322
  return new SetDefaultCall(
327
323
  options.schema,
328
324
  options.table,
329
325
  options.column,
330
326
  options.defaultSql,
331
327
  options.operationClass,
332
- ).toOp(this.controlAdapter);
328
+ ).toOp(this.controlAdapterFor('setDefault'));
333
329
  }
334
330
 
335
331
  protected dropDefault(options: {
@@ -337,11 +333,8 @@ export abstract class PostgresMigration extends SqlMigration<
337
333
  readonly table: string;
338
334
  readonly column: string;
339
335
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
340
- if (!this.controlAdapter) {
341
- throw errorPostgresMigrationStackMissing();
342
- }
343
336
  return new DropDefaultCall(options.schema, options.table, options.column).toOp(
344
- this.controlAdapter,
337
+ this.controlAdapterFor('dropDefault'),
345
338
  );
346
339
  }
347
340
 
@@ -352,16 +345,13 @@ export abstract class PostgresMigration extends SqlMigration<
352
345
  readonly columns: readonly string[];
353
346
  readonly extras?: CreateIndexExtras;
354
347
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
355
- if (!this.controlAdapter) {
356
- throw errorPostgresMigrationStackMissing();
357
- }
358
348
  return new CreateIndexCall(
359
349
  options.schema,
360
350
  options.table,
361
351
  options.index,
362
352
  options.columns,
363
353
  options.extras,
364
- ).toOp(this.controlAdapter);
354
+ ).toOp(this.controlAdapterFor('createIndex'));
365
355
  }
366
356
 
367
357
  protected dropIndex(options: {
@@ -369,11 +359,8 @@ export abstract class PostgresMigration extends SqlMigration<
369
359
  readonly table: string;
370
360
  readonly index: string;
371
361
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
372
- if (!this.controlAdapter) {
373
- throw errorPostgresMigrationStackMissing();
374
- }
375
362
  return new DropIndexCall(options.schema, options.table, options.index).toOp(
376
- this.controlAdapter,
363
+ this.controlAdapterFor('dropIndex'),
377
364
  );
378
365
  }
379
366
 
@@ -383,9 +370,6 @@ export abstract class PostgresMigration extends SqlMigration<
383
370
  readonly id: string;
384
371
  readonly label?: string;
385
372
  }): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
386
- if (!this.controlAdapter) {
387
- throw errorPostgresMigrationStackMissing();
388
- }
389
- return installExtension(options, this.controlAdapter);
373
+ return installExtension(options, this.controlAdapterFor('installExtension'));
390
374
  }
391
375
  }
@@ -45,15 +45,19 @@ export function renderCallsToTypeScript(
45
45
  calls: ReadonlyArray<OpFactoryCall>,
46
46
  meta: RenderMigrationMeta,
47
47
  ): string {
48
- const imports = buildImports(calls);
48
+ const imports = buildImports(calls, meta);
49
49
  const operationsBody = calls.map((c) => renderCall(c)).join(',\n');
50
+ const hasStart = meta.from !== null;
51
+ const startField = hasStart ? [' override readonly startContractJson = startContract;'] : [];
50
52
 
51
53
  return [
52
54
  shebangLineFor(detectScaffoldRuntime()),
53
55
  imports,
54
56
  '',
55
- 'export default class M extends Migration {',
56
- buildDescribeMethod(meta),
57
+ `export default class M extends Migration<${hasStart ? 'Start' : 'never'}, End> {`,
58
+ ...startField,
59
+ ' override readonly endContractJson = endContract;',
60
+ '',
57
61
  ' override get operations() {',
58
62
  ' return [',
59
63
  indent(operationsBody, 6),
@@ -70,8 +74,8 @@ function renderCall(call: OpFactoryCall): string {
70
74
  return call.renderTypeScript();
71
75
  }
72
76
 
73
- function buildImports(calls: ReadonlyArray<OpFactoryCall>): string {
74
- const requirements: ImportRequirement[] = [...BASE_IMPORTS];
77
+ function buildImports(calls: ReadonlyArray<OpFactoryCall>, meta: RenderMigrationMeta): string {
78
+ const requirements: ImportRequirement[] = [...BASE_IMPORTS, ...contractImports(meta)];
75
79
  for (const call of calls) {
76
80
  for (const req of call.importRequirements()) {
77
81
  requirements.push(req);
@@ -80,16 +84,39 @@ function buildImports(calls: ReadonlyArray<OpFactoryCall>): string {
80
84
  return renderImports(requirements);
81
85
  }
82
86
 
83
- function buildDescribeMethod(meta: RenderMigrationMeta): string {
84
- const lines: string[] = [];
85
- lines.push(' override describe() {');
86
- lines.push(' return {');
87
- lines.push(` from: ${JSON.stringify(meta.from)},`);
88
- lines.push(` to: ${JSON.stringify(meta.to)},`);
89
- lines.push(' };');
90
- lines.push(' }');
91
- lines.push('');
92
- return lines.join('\n');
87
+ /**
88
+ * The committed contract-JSON imports the scaffold reads its from/to identity
89
+ * from. `end-contract.json` is always present; `start-contract.json` is added
90
+ * only for a non-baseline migration (`meta.from !== null`). The matching
91
+ * `Contract` type imports (aliased `Start`/`End`) feed the
92
+ * `Migration<Start, End>` generics. Baseline emits `Migration<never, End>` with
93
+ * no start imports — `never` is the honest "no prior contract" Start.
94
+ */
95
+ function contractImports(meta: RenderMigrationMeta): readonly ImportRequirement[] {
96
+ const reqs: ImportRequirement[] = [
97
+ {
98
+ moduleSpecifier: './end-contract.json',
99
+ symbol: 'endContract',
100
+ kind: 'default',
101
+ attributes: { type: 'json' },
102
+ },
103
+ { moduleSpecifier: './end-contract', symbol: 'Contract', alias: 'End', typeOnly: true },
104
+ ];
105
+ if (meta.from !== null) {
106
+ reqs.push({
107
+ moduleSpecifier: './start-contract.json',
108
+ symbol: 'startContract',
109
+ kind: 'default',
110
+ attributes: { type: 'json' },
111
+ });
112
+ reqs.push({
113
+ moduleSpecifier: './start-contract',
114
+ symbol: 'Contract',
115
+ alias: 'Start',
116
+ typeOnly: true,
117
+ });
118
+ }
119
+ return reqs;
93
120
  }
94
121
 
95
122
  function indent(text: string, spaces: number): string {
@@ -0,0 +1,26 @@
1
+ import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
2
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
3
+ import { DEFAULT_NAMESPACE_ID } from '../namespace-ids';
4
+ import { isPostgresSchema } from '../postgres-schema';
5
+
6
+ /**
7
+ * Given the contract's storage and a namespace id, returns the live Postgres
8
+ * DDL schema name that namespace maps to. A named Postgres namespace dispatches
9
+ * to its `ddlSchemaName(storage)`; the unbound sentinel resolves to
10
+ * `DEFAULT_NAMESPACE_ID` (the search-path default for offline planning); a
11
+ * bare object payload (used by some tests) falls back to the namespace id
12
+ * itself.
13
+ */
14
+ export function resolveDdlSchemaForNamespaceStorage(
15
+ storage: SqlStorage,
16
+ namespaceId: string,
17
+ ): string {
18
+ if (namespaceId === UNBOUND_NAMESPACE_ID) {
19
+ return DEFAULT_NAMESPACE_ID;
20
+ }
21
+ const namespace = storage.namespaces[namespaceId];
22
+ if (namespace && isPostgresSchema(namespace)) {
23
+ return namespace.ddlSchemaName(storage);
24
+ }
25
+ return namespaceId;
26
+ }
@@ -12,7 +12,6 @@ import type {
12
12
  SqlMigrationRunnerSuccessValue,
13
13
  } from '@prisma-next/family-sql/control';
14
14
  import { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';
15
- import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
16
15
  import type { MigrationRunnerResult } from '@prisma-next/framework-components/control';
17
16
  import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
18
17
  import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
@@ -23,8 +22,6 @@ import { blindCast } from '@prisma-next/utils/casts';
23
22
  import { ifDefined } from '@prisma-next/utils/defined';
24
23
  import type { Result } from '@prisma-next/utils/result';
25
24
  import { notOk, ok, okVoid } from '@prisma-next/utils/result';
26
- import { parsePostgresDefault } from '../default-normalizer';
27
- import { normalizeSchemaNativeType } from '../native-type-normalizer';
28
25
  import type { PostgresPlanTargetDetails } from './planner-target-details';
29
26
 
30
27
  interface ApplyPlanSuccessValue {
@@ -124,30 +121,27 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
124
121
  applyValue = applyResult.value;
125
122
  }
126
123
 
127
- // Schema verification on app-space only extension spaces don't
128
- // own user-facing tables in the live schema, and `verifySqlSchema`
129
- // matches the destination contract against the database, which
130
- // would flag every app-space table as "extra" when called against
131
- // an extension contract.
124
+ // Verify the schema on app-space only: extension spaces don't own
125
+ // user-facing tables, so verifying the destination contract against the
126
+ // database would flag every app-space table as "extra". Delegates to the
127
+ // family `verifySchema` the same comparison the CLI verify runs.
132
128
  if (space === APP_SPACE_ID) {
133
- const schemaIR = await this.family.introspect({
129
+ const schemaNode = await this.family.introspect({
134
130
  driver,
135
131
  contract: options.destinationContract,
136
132
  });
137
- const schemaVerifyResult = verifySqlSchema({
133
+ const schemaVerifyResult = this.family.verifySchema({
138
134
  contract: options.destinationContract,
139
- schema: schemaIR,
135
+ schema: schemaNode,
140
136
  strict: options.strictVerification ?? true,
141
- context: options.context ?? {},
142
- typeMetadataRegistry: this.family.typeMetadataRegistry,
143
137
  frameworkComponents: options.frameworkComponents,
144
- normalizeDefault: parsePostgresDefault,
145
- normalizeNativeType: normalizeSchemaNativeType,
146
138
  });
147
139
  if (!schemaVerifyResult.ok) {
148
140
  return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {
149
141
  why: 'The resulting database schema does not satisfy the destination contract.',
150
- meta: { issues: schemaVerifyResult.schema.issues },
142
+ meta: {
143
+ issues: schemaVerifyResult.schema.issues,
144
+ },
151
145
  });
152
146
  }
153
147
  }
@@ -1,9 +1,13 @@
1
1
  import type { Contract } from '@prisma-next/contract/types';
2
- import type { SchemaIssue } from '@prisma-next/framework-components/control';
2
+ import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
3
3
  import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
4
4
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
5
- import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
5
+ import type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
6
+ import { DEFAULT_NAMESPACE_ID } from '../namespace-ids';
6
7
  import { isPostgresSchema } from '../postgres-schema';
8
+ import { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
9
+ import { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';
10
+ import type { SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';
7
11
 
8
12
  /**
9
13
  * Resolves the live-database schema name for a given namespace
@@ -23,32 +27,36 @@ function resolveDdlSchemaName(storage: SqlStorage, namespaceId: string): string
23
27
  }
24
28
 
25
29
  /**
26
- * Reads the introspected list of schema names from the Postgres-flavoured
27
- * annotations slot on the schema IR. Defaults to the always-present
28
- * `public` schema when introspection did not populate the slot a fresh
29
- * Postgres database always carries `public` (unless an operator dropped
30
- * it manually), so any verifier path that runs without an enriched
31
- * introspection still suppresses the redundant `CREATE SCHEMA "public"`.
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"`.
32
39
  *
33
40
  * Production introspection (`PostgresControlAdapter.introspect`) is the
34
- * authoritative source: it queries `pg_namespace` and writes every
35
- * non-system schema into `annotations.pg.existingSchemas`. Tests that
36
- * want to assert against a richer initial state pass the slot
37
- * explicitly via the schema IR.
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.
38
44
  */
39
- function existingSchemasFromSchema(schema: SqlSchemaIR): readonly string[] {
40
- const annotations = (schema as { annotations?: { pg?: { existingSchemas?: unknown } } })
41
- .annotations;
42
- const slot = annotations?.pg?.existingSchemas;
43
- if (Array.isArray(slot)) {
44
- return slot.filter((s): s is string => typeof s === 'string');
45
+ function existingSchemasFromSchema(schema: SqlSchemaIRNode): readonly string[] {
46
+ if (PostgresDatabaseSchemaNode.is(schema)) {
47
+ return schema.existingSchemas;
45
48
  }
46
- return ['public'];
49
+ return [DEFAULT_NAMESPACE_ID];
47
50
  }
48
51
 
49
52
  /**
50
- * Emits a `missing_schema` issue for every contract-declared Postgres
51
- * namespace whose live container does not yet exist.
53
+ * Emits a `postgres-namespace` `not-found` diff issue for every
54
+ * contract-declared Postgres namespace whose live container does not yet
55
+ * exist. The planner prepends these (node-typed, synthesized) to the
56
+ * relational diff issues so a multi-schema plan emits `CREATE SCHEMA`
57
+ * before the tables that need it — a planner-only concern (verify already
58
+ * rejects via the `not-found` table issues a missing schema already
59
+ * produces), so this is not part of the shared diff.
52
60
  *
53
61
  * A namespace's live container is the schema returned by its
54
62
  * polymorphic `ddlSchemaName(storage)` method — named schemas resolve
@@ -59,28 +67,36 @@ function existingSchemasFromSchema(schema: SqlSchemaIR): readonly string[] {
59
67
  * introspected list. `public` is suppressed implicitly because the
60
68
  * introspection (or its sensible default) always carries it.
61
69
  *
62
- * Each emitted issue stamps `namespaceId` with the contract namespace
63
- * coordinate so the downstream `mapIssueToCall` re-resolves the DDL
64
- * schema name through the same polymorphic path keeping the
65
- * coordinate, not the resolved name, as the issue's stable identity.
70
+ * Each emitted issue's path is `['database', ddlName]` an ancestor of
71
+ * every table path under that schema, so it must never be run through
72
+ * `coalesceSubtreeIssues` alongside the table diff (it would swallow the
73
+ * table-level `not-found` issues that drive `CREATE TABLE`); the planner
74
+ * adds these AFTER coalescing the relational issues, and they are not
75
+ * subject to sibling-space ownership scoping (mirrors the retired
76
+ * coordinate walk, which prepended namespace issues after that filter).
66
77
  */
67
78
  export function verifyPostgresNamespacePresence(input: {
68
79
  readonly contract: Contract<SqlStorage>;
69
- readonly schema: SqlSchemaIR;
70
- }): readonly SchemaIssue[] {
80
+ readonly schema: SqlSchemaIRNode;
81
+ }): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {
71
82
  const { contract, schema } = input;
72
83
  const existing = new Set(existingSchemasFromSchema(schema));
73
- const issues: SchemaIssue[] = [];
84
+ const issues: SchemaDiffIssue<SqlSchemaDiffNode>[] = [];
74
85
  const namespaceIds = Object.keys(contract.storage.namespaces).sort();
75
86
  for (const namespaceId of namespaceIds) {
76
87
  if (namespaceId === UNBOUND_NAMESPACE_ID) continue;
77
88
  const ddlName = resolveDdlSchemaName(contract.storage, namespaceId);
78
89
  if (ddlName === UNBOUND_NAMESPACE_ID) continue;
79
90
  if (existing.has(ddlName)) continue;
91
+ const namespace = new PostgresNamespaceSchemaNode({
92
+ schemaName: ddlName,
93
+ tables: {},
94
+ nativeEnumTypeNames: [],
95
+ });
80
96
  issues.push({
81
- kind: 'missing_schema',
82
- namespaceId,
83
- message: `Schema "${ddlName}" is missing from database`,
97
+ path: ['database', ddlName],
98
+ reason: 'not-found',
99
+ expected: namespace,
84
100
  });
85
101
  }
86
102
  return issues;
@@ -0,0 +1,3 @@
1
+ // Leaf module: authoring.ts and descriptor-meta.ts both need this and import each other.
2
+ /** Postgres's default schema; `postgresTargetDescriptorMeta.defaultNamespaceId` is this value. */
3
+ export const DEFAULT_NAMESPACE_ID = 'public' as const;