@prisma-next/target-postgres 0.14.0-dev.9 → 0.14.0-dev.90

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 (266) hide show
  1. package/dist/authoring-BtsOWgI3.mjs +674 -0
  2. package/dist/authoring-BtsOWgI3.mjs.map +1 -0
  3. package/dist/canonicalize-D1F4vUnP.d.mts +48 -0
  4. package/dist/canonicalize-D1F4vUnP.d.mts.map +1 -0
  5. package/dist/{codec-ids-BvytN2P8.mjs → codec-ids-B10ZZHzw.mjs} +4 -2
  6. package/dist/codec-ids-B10ZZHzw.mjs.map +1 -0
  7. package/dist/{codec-ids-CnXu9Qy3.d.mts → codec-ids-CI144z7g.d.mts} +4 -2
  8. package/dist/codec-ids-CI144z7g.d.mts.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-CTfT4U4O.d.mts} +4 -2
  12. package/dist/codec-types-CTfT4U4O.d.mts.map +1 -0
  13. package/dist/codec-types.d.mts +1 -1
  14. package/dist/{codecs--0A5_4Bq.d.mts → codecs-D7W9O0Xx.d.mts} +134 -4
  15. package/dist/codecs-D7W9O0Xx.d.mts.map +1 -0
  16. package/dist/codecs-DRbb26Or.mjs +955 -0
  17. package/dist/codecs-DRbb26Or.mjs.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 +23 -7
  24. package/dist/contract-free.mjs.map +1 -1
  25. package/dist/control-policy-DtbkLLGv.mjs +1285 -0
  26. package/dist/control-policy-DtbkLLGv.mjs.map +1 -0
  27. package/dist/control.d.mts +2 -2
  28. package/dist/control.d.mts.map +1 -1
  29. package/dist/control.mjs +880 -36
  30. package/dist/control.mjs.map +1 -1
  31. package/dist/data-transform-BOWpliq8.mjs.map +1 -1
  32. package/dist/{data-transform-DDgWdB5o.d.mts → data-transform-DPzwBMhW.d.mts} +3 -3
  33. package/dist/{data-transform-DDgWdB5o.d.mts.map → data-transform-DPzwBMhW.d.mts.map} +1 -1
  34. package/dist/data-transform.d.mts +1 -1
  35. package/dist/{ddl-QDyOSeLc.mjs → ddl-GTTOvjx_.mjs} +128 -6
  36. package/dist/ddl-GTTOvjx_.mjs.map +1 -0
  37. package/dist/ddl.d.mts +3 -2
  38. package/dist/ddl.mjs +2 -2
  39. package/dist/default-normalizer.d.mts +1 -1
  40. package/dist/default-normalizer.d.mts.map +1 -1
  41. package/dist/default-normalizer.mjs +247 -1
  42. package/dist/default-normalizer.mjs.map +1 -0
  43. package/dist/descriptor-meta-CFQKLXl_.mjs +23 -0
  44. package/dist/descriptor-meta-CFQKLXl_.mjs.map +1 -0
  45. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs +12 -0
  46. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs.map +1 -0
  47. package/dist/diff-database-schema-GncqMuSI.mjs +305 -0
  48. package/dist/diff-database-schema-GncqMuSI.mjs.map +1 -0
  49. package/dist/diff-database-schema.d.mts +46 -0
  50. package/dist/diff-database-schema.d.mts.map +1 -0
  51. package/dist/diff-database-schema.mjs +2 -0
  52. package/dist/errors-DO-w0EUS.mjs +35 -0
  53. package/dist/errors-DO-w0EUS.mjs.map +1 -0
  54. package/dist/errors.d.mts +11 -9
  55. package/dist/errors.d.mts.map +1 -1
  56. package/dist/errors.mjs +1 -1
  57. package/dist/issue-planner.d.mts +35 -11
  58. package/dist/issue-planner.d.mts.map +1 -1
  59. package/dist/issue-planner.mjs +2 -2
  60. package/dist/migration.d.mts +5 -5
  61. package/dist/migration.d.mts.map +1 -1
  62. package/dist/migration.mjs +4 -4
  63. package/dist/namespace-ids-xtp_ZY86.mjs +7 -0
  64. package/dist/namespace-ids-xtp_ZY86.mjs.map +1 -0
  65. package/dist/native-type-normalizer.mjs +37 -1
  66. package/dist/native-type-normalizer.mjs.map +1 -0
  67. package/dist/nodes-DJC5B8Id.mjs +192 -0
  68. package/dist/nodes-DJC5B8Id.mjs.map +1 -0
  69. package/dist/nodes-Dv5eCSq9.d.mts +170 -0
  70. package/dist/nodes-Dv5eCSq9.d.mts.map +1 -0
  71. package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-Bn9zDx4_.d.mts} +114 -15
  72. package/dist/op-factory-call-Bn9zDx4_.d.mts.map +1 -0
  73. package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-C38NzvQD.mjs} +469 -32
  74. package/dist/op-factory-call-C38NzvQD.mjs.map +1 -0
  75. package/dist/op-factory-call.d.mts +2 -2
  76. package/dist/op-factory-call.mjs +2 -2
  77. package/dist/pack.d.mts +321 -3
  78. package/dist/pack.d.mts.map +1 -1
  79. package/dist/pack.mjs +1 -1
  80. package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-BKlmGDJl.mjs} +17 -28
  81. package/dist/planner-ddl-builders-BKlmGDJl.mjs.map +1 -0
  82. package/dist/planner-ddl-builders.d.mts +4 -6
  83. package/dist/planner-ddl-builders.d.mts.map +1 -1
  84. package/dist/planner-ddl-builders.mjs +2 -2
  85. package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -1
  86. package/dist/planner-identity-values.d.mts +8 -2
  87. package/dist/planner-identity-values.d.mts.map +1 -1
  88. package/dist/planner-identity-values.mjs +2 -2
  89. package/dist/planner-kql24i_F.mjs +390 -0
  90. package/dist/planner-kql24i_F.mjs.map +1 -0
  91. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-BEY1T0Xm.d.mts} +4 -4
  92. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-BEY1T0Xm.d.mts.map} +1 -1
  93. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-D7y-PEHK.mjs} +3 -3
  94. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-D7y-PEHK.mjs.map} +1 -1
  95. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  96. package/dist/planner-produced-postgres-migration.mjs +1 -1
  97. package/dist/{planner-sql-checks-jqUUGyQR.mjs → planner-sql-checks-zqNfs2XZ.mjs} +5 -5
  98. package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-zqNfs2XZ.mjs.map} +1 -1
  99. package/dist/planner-sql-checks.d.mts +2 -2
  100. package/dist/planner-sql-checks.d.mts.map +1 -1
  101. package/dist/planner-sql-checks.mjs +1 -1
  102. package/dist/{planner-target-details-CIY6tLeo.d.mts → planner-target-details-HkP4RrRO.d.mts} +2 -2
  103. package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -0
  104. package/dist/planner-target-details.d.mts +1 -1
  105. package/dist/planner.d.mts +72 -17
  106. package/dist/planner.d.mts.map +1 -1
  107. package/dist/planner.mjs +3 -2
  108. package/dist/postgres-contract-view-C9j5cqP0.d.mts +34 -0
  109. package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +1 -0
  110. package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-DM8sN1Ot.mjs} +45 -41
  111. package/dist/postgres-contract-view-DM8sN1Ot.mjs.map +1 -0
  112. package/dist/postgres-database-schema-node-CJv5bfbs.d.mts +262 -0
  113. package/dist/postgres-database-schema-node-CJv5bfbs.d.mts.map +1 -0
  114. package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-DbckK1su.d.mts} +58 -9
  115. package/dist/postgres-migration-DbckK1su.d.mts.map +1 -0
  116. package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-arMSWU9b.mjs} +78 -45
  117. package/dist/postgres-migration-arMSWU9b.mjs.map +1 -0
  118. package/dist/postgres-native-enum-BwVNf0Ku.mjs +45 -0
  119. package/dist/postgres-native-enum-BwVNf0Ku.mjs.map +1 -0
  120. package/dist/postgres-rls-policy--CSddvMR.d.mts +52 -0
  121. package/dist/postgres-rls-policy--CSddvMR.d.mts.map +1 -0
  122. package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs +190 -0
  123. package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs.map +1 -0
  124. package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-Cm4DtiGA.mjs} +200 -11
  125. package/dist/postgres-schema-Cm4DtiGA.mjs.map +1 -0
  126. package/dist/postgres-schema-DKq6s1P3.d.mts +269 -0
  127. package/dist/postgres-schema-DKq6s1P3.d.mts.map +1 -0
  128. package/dist/postgres-table-schema-node-D6LvInCe.mjs +216 -0
  129. package/dist/postgres-table-schema-node-D6LvInCe.mjs.map +1 -0
  130. package/dist/render-ops.d.mts +1 -1
  131. package/dist/{render-typescript-KMgosran.mjs → render-typescript-7yqILcwr.mjs} +45 -16
  132. package/dist/render-typescript-7yqILcwr.mjs.map +1 -0
  133. package/dist/render-typescript.mjs +1 -1
  134. package/dist/resolve-ddl-schema-XyBaaenM.mjs +22 -0
  135. package/dist/resolve-ddl-schema-XyBaaenM.mjs.map +1 -0
  136. package/dist/rls-canonicalize.d.mts +27 -0
  137. package/dist/rls-canonicalize.d.mts.map +1 -0
  138. package/dist/rls-canonicalize.mjs +2 -0
  139. package/dist/runtime.d.mts +6 -8
  140. package/dist/runtime.d.mts.map +1 -1
  141. package/dist/runtime.mjs +3 -3
  142. package/dist/runtime.mjs.map +1 -1
  143. package/dist/schema-ir-annotations.d.mts +15 -0
  144. package/dist/schema-ir-annotations.d.mts.map +1 -0
  145. package/dist/schema-ir-annotations.mjs +2 -0
  146. package/dist/{sql-utils-DcfMz4MQ.mjs → sql-utils-SU4FDvIV.mjs} +12 -3
  147. package/dist/{sql-utils-DcfMz4MQ.mjs.map → sql-utils-SU4FDvIV.mjs.map} +1 -1
  148. package/dist/sql-utils.d.mts +8 -1
  149. package/dist/sql-utils.d.mts.map +1 -1
  150. package/dist/sql-utils.mjs +2 -2
  151. package/dist/types.d.mts +4 -140
  152. package/dist/types.mjs +5 -2
  153. package/dist/wire-name-DbQ9-2RC.mjs +104 -0
  154. package/dist/wire-name-DbQ9-2RC.mjs.map +1 -0
  155. package/package.json +26 -20
  156. package/src/contract-free/checks.ts +153 -0
  157. package/src/contract-free/control-bootstrap.ts +20 -3
  158. package/src/contract-free/ddl.ts +98 -1
  159. package/src/core/authoring.ts +726 -2
  160. package/src/core/codec-helpers.ts +33 -7
  161. package/src/core/codec-ids.ts +2 -0
  162. package/src/core/codec-type-map.ts +4 -0
  163. package/src/core/codecs.ts +236 -12
  164. package/src/core/ddl/nodes.ts +185 -2
  165. package/src/core/default-normalizer.ts +122 -2
  166. package/src/core/descriptor-meta.ts +12 -1
  167. package/src/core/entity-kinds.ts +41 -0
  168. package/src/core/errors.ts +14 -12
  169. package/src/core/migrations/bound-schema.ts +10 -0
  170. package/src/core/migrations/column-ddl-rendering.ts +117 -0
  171. package/src/core/migrations/contract-to-postgres-database-schema-node.ts +189 -0
  172. package/src/core/migrations/control-policy.ts +217 -65
  173. package/src/core/migrations/diff-database-schema.ts +252 -0
  174. package/src/core/migrations/issue-planner.ts +817 -656
  175. package/src/core/migrations/op-factory-call.ts +383 -23
  176. package/src/core/migrations/operations/columns.ts +24 -12
  177. package/src/core/migrations/operations/constraints.ts +1 -1
  178. package/src/core/migrations/operations/data-transform.ts +6 -0
  179. package/src/core/migrations/operations/dependencies.ts +2 -1
  180. package/src/core/migrations/operations/native-enum-types.ts +62 -0
  181. package/src/core/migrations/operations/rls.ts +187 -0
  182. package/src/core/migrations/operations/shared.ts +0 -30
  183. package/src/core/migrations/planner-ddl-builders.ts +31 -59
  184. package/src/core/migrations/planner-identity-values.ts +1 -1
  185. package/src/core/migrations/planner-recipes.ts +31 -13
  186. package/src/core/migrations/planner-sql-checks.ts +1 -1
  187. package/src/core/migrations/planner-strategies.ts +248 -216
  188. package/src/core/migrations/planner-target-details.ts +3 -1
  189. package/src/core/migrations/planner.ts +357 -67
  190. package/src/core/migrations/postgres-migration.ts +118 -86
  191. package/src/core/migrations/render-typescript.ts +42 -15
  192. package/src/core/migrations/resolve-ddl-schema.ts +26 -0
  193. package/src/core/migrations/runner.ts +11 -16
  194. package/src/core/migrations/verify-postgres-namespaces.ts +46 -31
  195. package/src/core/namespace-ids.ts +3 -0
  196. package/src/core/postgres-contract-serializer.ts +46 -71
  197. package/src/core/postgres-contract-view.ts +48 -0
  198. package/src/core/postgres-native-enum.ts +61 -0
  199. package/src/core/postgres-rls-enablement.ts +34 -0
  200. package/src/core/postgres-rls-policy.ts +64 -0
  201. package/src/core/postgres-role.ts +59 -0
  202. package/src/core/postgres-schema-verifier.ts +10 -7
  203. package/src/core/postgres-schema.ts +85 -15
  204. package/src/core/postgres-validators.ts +34 -0
  205. package/src/core/psl-infer/infer-psl-contract.ts +1290 -0
  206. package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
  207. package/src/core/psl-infer/postgres-type-map.ts +129 -0
  208. package/src/core/rls/canonicalize.ts +65 -0
  209. package/src/core/rls/wire-name.ts +33 -0
  210. package/src/core/schema-ir/node-storage-coordinate.ts +26 -0
  211. package/src/core/schema-ir/postgres-database-schema-node.ts +61 -0
  212. package/src/core/schema-ir/postgres-namespace-schema-node.ts +70 -0
  213. package/src/core/schema-ir/postgres-native-enum-schema-node.ts +83 -0
  214. package/src/core/schema-ir/postgres-policy-schema-node.ts +90 -0
  215. package/src/core/schema-ir/postgres-role-schema-node.ts +65 -0
  216. package/src/core/schema-ir/postgres-table-schema-node.ts +140 -0
  217. package/src/core/schema-ir/schema-node-kinds.ts +122 -0
  218. package/src/core/sql-utils.ts +15 -2
  219. package/src/exports/codecs.ts +5 -0
  220. package/src/exports/contract-free.ts +11 -1
  221. package/src/exports/control.ts +27 -33
  222. package/src/exports/ddl.ts +8 -0
  223. package/src/exports/diff-database-schema.ts +7 -0
  224. package/src/exports/issue-planner.ts +1 -1
  225. package/src/exports/migration.ts +1 -0
  226. package/src/exports/op-factory-call.ts +4 -0
  227. package/src/exports/planner-ddl-builders.ts +0 -2
  228. package/src/exports/planner-identity-values.ts +4 -1
  229. package/src/exports/planner.ts +1 -0
  230. package/src/exports/rls-canonicalize.ts +12 -0
  231. package/src/exports/runtime.ts +1 -0
  232. package/src/exports/schema-ir-annotations.ts +1 -0
  233. package/src/exports/sql-utils.ts +1 -0
  234. package/src/exports/types.ts +37 -0
  235. package/dist/codec-ids-BvytN2P8.mjs.map +0 -1
  236. package/dist/codec-ids-CnXu9Qy3.d.mts.map +0 -1
  237. package/dist/codec-types-DHCkwPKE.d.mts.map +0 -1
  238. package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
  239. package/dist/ddl-QDyOSeLc.mjs.map +0 -1
  240. package/dist/default-normalizer-DyyCHQWs.mjs +0 -131
  241. package/dist/default-normalizer-DyyCHQWs.mjs.map +0 -1
  242. package/dist/descriptor-meta-CpGygXpI.mjs +0 -140
  243. package/dist/descriptor-meta-CpGygXpI.mjs.map +0 -1
  244. package/dist/errors-CUk87ByX.mjs +0 -33
  245. package/dist/errors-CUk87ByX.mjs.map +0 -1
  246. package/dist/issue-planner-DL6g3CmE.mjs +0 -824
  247. package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
  248. package/dist/native-type-normalizer-Bc9XJzWC.mjs +0 -38
  249. package/dist/native-type-normalizer-Bc9XJzWC.mjs.map +0 -1
  250. package/dist/nodes-Bbhs2rwj.mjs +0 -76
  251. package/dist/nodes-Bbhs2rwj.mjs.map +0 -1
  252. package/dist/nodes-pLeLgdis.d.mts +0 -67
  253. package/dist/nodes-pLeLgdis.d.mts.map +0 -1
  254. package/dist/op-factory-call-D_p5vxwt.mjs.map +0 -1
  255. package/dist/op-factory-call-DmQEc3XV.d.mts.map +0 -1
  256. package/dist/planner-Bs_baQax.mjs +0 -324
  257. package/dist/planner-Bs_baQax.mjs.map +0 -1
  258. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +0 -1
  259. package/dist/planner-target-details-CIY6tLeo.d.mts.map +0 -1
  260. package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +0 -1
  261. package/dist/postgres-migration-B5jKrXv3.mjs.map +0 -1
  262. package/dist/postgres-migration-Y4YBJqkS.d.mts.map +0 -1
  263. package/dist/postgres-schema-COGZ1ark.mjs.map +0 -1
  264. package/dist/render-typescript-KMgosran.mjs.map +0 -1
  265. package/dist/types.d.mts.map +0 -1
  266. package/src/core/postgres-enum-type-schema.ts +0 -17
package/dist/control.mjs CHANGED
@@ -1,18 +1,21 @@
1
- import { t as postgresTargetDescriptorMeta } from "./descriptor-meta-CpGygXpI.mjs";
2
- import { t as parsePostgresDefault } from "./default-normalizer-DyyCHQWs.mjs";
3
- import { t as normalizeSchemaNativeType } from "./native-type-normalizer-Bc9XJzWC.mjs";
4
- import { t as createPostgresMigrationPlanner } from "./planner-Bs_baQax.mjs";
5
- import { a as renderDefaultLiteral } from "./planner-ddl-builders-B2wOwLqI.mjs";
6
- import { t as PostgresContractSerializer } from "./postgres-contract-serializer-k3TAcPMY.mjs";
1
+ import { t as postgresTargetDescriptorMeta } from "./descriptor-meta-CFQKLXl_.mjs";
2
+ import { a as postgresDiffSubjectGranularity, i as postgresDiffSubjectEntityKind } from "./postgres-table-schema-node-D6LvInCe.mjs";
3
+ import { i as PostgresDatabaseSchemaNode } from "./postgres-role-schema-node-Cm-j0ZGM.mjs";
4
+ import { n as diffPostgresSchema, r as contractToPostgresDatabaseSchemaNode } from "./diff-database-schema-GncqMuSI.mjs";
5
+ import { r as renderDefaultLiteral } from "./planner-ddl-builders-BKlmGDJl.mjs";
6
+ import { n as PostgresContractSerializer } from "./postgres-contract-view-DM8sN1Ot.mjs";
7
+ import { t as createPostgresMigrationPlanner } from "./planner-kql24i_F.mjs";
8
+ import { UNBOUND_NAMESPACE_ID, coordinateKey, elementCoordinates } from "@prisma-next/framework-components/ir";
7
9
  import { blindCast } from "@prisma-next/utils/casts";
8
- import { contractToSchemaIR, extractCodecControlHooks, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
10
+ import { buildNativeTypeExpander, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
9
11
  import { ifDefined } from "@prisma-next/utils/defined";
10
- import { verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
11
- import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
12
- import { notOk, ok, okVoid } from "@prisma-next/utils/result";
12
+ import { SqlSchemaIR, SqlTableIR } from "@prisma-next/sql-schema-ir/types";
13
13
  import { APP_SPACE_ID } from "@prisma-next/framework-components/control";
14
- import { SqlQueryError } from "@prisma-next/sql-errors";
14
+ import { notOk, ok, okVoid } from "@prisma-next/utils/result";
15
15
  import { SqlSchemaVerifierBase } from "@prisma-next/family-sql/ir";
16
+ import { SqlQueryError } from "@prisma-next/sql-errors";
17
+ import { buildChildRelationField, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, toEnumMemberName, toEnumName, toFieldName, toModelName, toNamedTypeName } from "@prisma-next/family-sql/psl-infer";
18
+ import { UNSPECIFIED_PSL_NAMESPACE_ID, makePslNamespace, makePslNamespaceEntries } from "@prisma-next/framework-components/psl-ast";
16
19
  //#region src/core/migrations/runner.ts
17
20
  const LOCK_DOMAIN = "prisma_next.contract.marker";
18
21
  /**
@@ -74,19 +77,15 @@ var PostgresMigrationRunner = class {
74
77
  applyValue = applyResult.value;
75
78
  }
76
79
  if (space === APP_SPACE_ID) {
77
- const schemaIR = await this.family.introspect({
80
+ const schemaNode = await this.family.introspect({
78
81
  driver,
79
82
  contract: options.destinationContract
80
83
  });
81
- const schemaVerifyResult = verifySqlSchema({
84
+ const schemaVerifyResult = this.family.verifySchema({
82
85
  contract: options.destinationContract,
83
- schema: schemaIR,
86
+ schema: schemaNode,
84
87
  strict: options.strictVerification ?? true,
85
- context: options.context ?? {},
86
- typeMetadataRegistry: this.family.typeMetadataRegistry,
87
- frameworkComponents: options.frameworkComponents,
88
- normalizeDefault: parsePostgresDefault,
89
- normalizeNativeType: normalizeSchemaNativeType
88
+ frameworkComponents: options.frameworkComponents
90
89
  });
91
90
  if (!schemaVerifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", schemaVerifyResult.summary, {
92
91
  why: "The resulting database schema does not satisfy the destination contract.",
@@ -361,7 +360,8 @@ var PostgresMigrationRunner = class {
361
360
  to: edge.to,
362
361
  migrationName: edge.dirName,
363
362
  migrationHash: edge.migrationHash,
364
- operations: edgeOps
363
+ operations: edgeOps,
364
+ ...ifDefined("destinationContractJson", edge.destinationContractJson)
365
365
  }
366
366
  });
367
367
  }
@@ -387,10 +387,10 @@ var PostgresMigrationRunner = class {
387
387
  /**
388
388
  * Postgres target `SchemaVerifier` concretion. Plugs into the
389
389
  * SQL-shared verification surface; production verification today still
390
- * routes through the legacy `verifySqlSchema` entry point, which
391
- * carries options (codec hooks, normalizers, framework components)
392
- * that the framework-level `SchemaVerifyOptions` shape does not yet
393
- * surface.
390
+ * routes through the family verify verdict (`verifySqlSchemaByDiff` over
391
+ * `diffPostgresSchema`), which carries options (codec hooks,
392
+ * normalizers, framework components) that the framework-level
393
+ * `SchemaVerifyOptions` shape does not yet surface.
394
394
  *
395
395
  * The hooks return the empty list pending the call-site migration that
396
396
  * routes the existing verifier behaviour through the SPI — at that
@@ -408,18 +408,852 @@ var PostgresSchemaVerifier = class extends SqlSchemaVerifierBase {
408
408
  }
409
409
  };
410
410
  //#endregion
411
- //#region src/exports/control.ts
412
- function buildNativeTypeExpander(frameworkComponents) {
413
- if (!frameworkComponents) return;
414
- const codecHooks = extractCodecControlHooks(frameworkComponents);
415
- return (input) => {
416
- if (!input.typeParams) return input.nativeType;
417
- if (!input.codecId) return input.nativeType;
418
- const hooks = codecHooks.get(input.codecId);
419
- if (!hooks?.expandNativeType) return input.nativeType;
420
- return hooks.expandNativeType(input);
411
+ //#region src/core/psl-infer/postgres-default-mapping.ts
412
+ const POSTGRES_FUNCTION_ATTRIBUTES = { "gen_random_uuid()": "@default(dbgenerated(\"gen_random_uuid()\"))" };
413
+ function formatDbGeneratedAttribute(expression) {
414
+ return `@default(dbgenerated(${JSON.stringify(expression)}))`;
415
+ }
416
+ function createPostgresDefaultMapping() {
417
+ return {
418
+ functionAttributes: POSTGRES_FUNCTION_ATTRIBUTES,
419
+ fallbackFunctionAttribute: formatDbGeneratedAttribute
420
+ };
421
+ }
422
+ //#endregion
423
+ //#region src/core/psl-infer/postgres-type-map.ts
424
+ const POSTGRES_TO_PSL = {
425
+ text: "String",
426
+ bool: "Boolean",
427
+ boolean: "Boolean",
428
+ int4: "Int",
429
+ integer: "Int",
430
+ int8: "BigInt",
431
+ bigint: "BigInt",
432
+ float8: "Float",
433
+ "double precision": "Float",
434
+ numeric: "Decimal",
435
+ decimal: "Decimal",
436
+ timestamptz: "DateTime",
437
+ "timestamp with time zone": "DateTime",
438
+ jsonb: "Json",
439
+ bytea: "Bytes"
440
+ };
441
+ const PRESERVED_NATIVE_TYPES = {
442
+ "character varying": {
443
+ pslType: "String",
444
+ attributeName: "db.VarChar"
445
+ },
446
+ character: {
447
+ pslType: "String",
448
+ attributeName: "db.Char"
449
+ },
450
+ char: {
451
+ pslType: "String",
452
+ attributeName: "db.Char"
453
+ },
454
+ varchar: {
455
+ pslType: "String",
456
+ attributeName: "db.VarChar"
457
+ },
458
+ uuid: {
459
+ pslType: "String",
460
+ attributeName: "db.Uuid"
461
+ },
462
+ inet: {
463
+ pslType: "String",
464
+ attributeName: "db.Inet"
465
+ },
466
+ int2: {
467
+ pslType: "Int",
468
+ attributeName: "db.SmallInt"
469
+ },
470
+ smallint: {
471
+ pslType: "Int",
472
+ attributeName: "db.SmallInt"
473
+ },
474
+ float4: {
475
+ pslType: "Float",
476
+ attributeName: "db.Real"
477
+ },
478
+ real: {
479
+ pslType: "Float",
480
+ attributeName: "db.Real"
481
+ },
482
+ timestamp: {
483
+ pslType: "DateTime",
484
+ attributeName: "db.Timestamp"
485
+ },
486
+ "timestamp without time zone": {
487
+ pslType: "DateTime",
488
+ attributeName: "db.Timestamp"
489
+ },
490
+ date: {
491
+ pslType: "DateTime",
492
+ attributeName: "db.Date"
493
+ },
494
+ time: {
495
+ pslType: "DateTime",
496
+ attributeName: "db.Time"
497
+ },
498
+ "time without time zone": {
499
+ pslType: "DateTime",
500
+ attributeName: "db.Time"
501
+ },
502
+ timetz: {
503
+ pslType: "DateTime",
504
+ attributeName: "db.Timetz"
505
+ },
506
+ "time with time zone": {
507
+ pslType: "DateTime",
508
+ attributeName: "db.Timetz"
509
+ },
510
+ json: {
511
+ pslType: "Json",
512
+ attributeName: "db.Json"
513
+ }
514
+ };
515
+ const PARAMETERIZED_NATIVE_TYPES = {
516
+ "character varying": {
517
+ pslType: "String",
518
+ attributeName: "db.VarChar"
519
+ },
520
+ character: {
521
+ pslType: "String",
522
+ attributeName: "db.Char"
523
+ },
524
+ char: {
525
+ pslType: "String",
526
+ attributeName: "db.Char"
527
+ },
528
+ varchar: {
529
+ pslType: "String",
530
+ attributeName: "db.VarChar"
531
+ },
532
+ numeric: {
533
+ pslType: "Decimal",
534
+ attributeName: "db.Numeric"
535
+ },
536
+ timestamp: {
537
+ pslType: "DateTime",
538
+ attributeName: "db.Timestamp"
539
+ },
540
+ timestamptz: {
541
+ pslType: "DateTime",
542
+ attributeName: "db.Timestamptz"
543
+ },
544
+ time: {
545
+ pslType: "DateTime",
546
+ attributeName: "db.Time"
547
+ },
548
+ timetz: {
549
+ pslType: "DateTime",
550
+ attributeName: "db.Timetz"
551
+ }
552
+ };
553
+ const PARAMETERIZED_TYPE_PATTERN = /^(.+?)\((.+)\)$/;
554
+ function getOwnMappingValue(map, key) {
555
+ return Object.hasOwn(map, key) ? map[key] : void 0;
556
+ }
557
+ function getOwnRecordValue(map, key) {
558
+ return Object.hasOwn(map, key) ? map[key] : void 0;
559
+ }
560
+ function createNativeTypeAttribute(name, args) {
561
+ return args && args.length > 0 ? {
562
+ name,
563
+ args
564
+ } : { name };
565
+ }
566
+ function splitTypeParameterList(params) {
567
+ return params.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
568
+ }
569
+ function createPostgresTypeMap(enumTypeNames) {
570
+ return { resolve(nativeType) {
571
+ if (enumTypeNames?.has(nativeType)) return {
572
+ pslType: nativeType,
573
+ nativeType
574
+ };
575
+ const paramMatch = nativeType.match(PARAMETERIZED_TYPE_PATTERN);
576
+ if (paramMatch) {
577
+ const [, baseType = nativeType, params = ""] = paramMatch;
578
+ const template = getOwnRecordValue(PARAMETERIZED_NATIVE_TYPES, baseType);
579
+ if (template) return {
580
+ pslType: template.pslType,
581
+ nativeType,
582
+ typeParams: {
583
+ baseType,
584
+ params
585
+ },
586
+ nativeTypeAttribute: createNativeTypeAttribute(template.attributeName, splitTypeParameterList(params))
587
+ };
588
+ }
589
+ const preservedType = getOwnRecordValue(PRESERVED_NATIVE_TYPES, nativeType);
590
+ if (preservedType) return {
591
+ pslType: preservedType.pslType,
592
+ nativeType,
593
+ nativeTypeAttribute: createNativeTypeAttribute(preservedType.attributeName)
594
+ };
595
+ const pslType = getOwnMappingValue(POSTGRES_TO_PSL, nativeType);
596
+ if (pslType) return {
597
+ pslType,
598
+ nativeType
599
+ };
600
+ return {
601
+ unsupported: true,
602
+ nativeType
603
+ };
604
+ } };
605
+ }
606
+ //#endregion
607
+ //#region src/core/psl-infer/infer-psl-contract.ts
608
+ const SYNTHETIC_SPAN = {
609
+ start: {
610
+ offset: 0,
611
+ line: 1,
612
+ column: 1
613
+ },
614
+ end: {
615
+ offset: 0,
616
+ line: 1,
617
+ column: 1
618
+ }
619
+ };
620
+ const PSL_SCALAR_TYPE_NAMES = /* @__PURE__ */ new Set([
621
+ "String",
622
+ "Boolean",
623
+ "Int",
624
+ "BigInt",
625
+ "Float",
626
+ "Decimal",
627
+ "DateTime",
628
+ "Json",
629
+ "Bytes"
630
+ ]);
631
+ /**
632
+ * Coordinates every element a set of already-assembled contracts declare,
633
+ * mapped to the {@link SqlDescribedContractSpace} that owns it and keyed by
634
+ * the shared {@link coordinateKey} helper. `contract infer` uses this to omit
635
+ * database elements a stack extension pack's contract space already
636
+ * describes — reusing the same coordinate walk the contract-space aggregate
637
+ * and cross-space collision check use (`elementCoordinates`), rather than a
638
+ * bespoke per-entity-kind membership test — and, for a foreign key whose
639
+ * referenced table an entry owns, to resolve the qualified cross-space
640
+ * relation it describes.
641
+ */
642
+ function describedContractOwners(describedContracts) {
643
+ const owners = /* @__PURE__ */ new Map();
644
+ for (const entry of describedContracts) for (const coordinate of elementCoordinates(entry.contract.storage)) owners.set(coordinateKey(coordinate), entry);
645
+ return owners;
646
+ }
647
+ function resolveCrossSpaceTarget(owner, namespaceId, tableName) {
648
+ const domainNamespace = owner.contract.domain.namespaces[namespaceId];
649
+ if (domainNamespace === void 0) return;
650
+ for (const [modelName, model] of Object.entries(domainNamespace.models)) {
651
+ const storage = blindCast(model.storage);
652
+ if (storage.namespaceId !== namespaceId || storage.table !== tableName) continue;
653
+ const fieldNamesByColumn = /* @__PURE__ */ new Map();
654
+ for (const [fieldName, fieldStorage] of Object.entries(storage.fields)) fieldNamesByColumn.set(fieldStorage.column, { fieldName });
655
+ return {
656
+ spaceId: owner.spaceId,
657
+ namespaceId,
658
+ modelName,
659
+ fieldNamesByColumn
660
+ };
661
+ }
662
+ }
663
+ /**
664
+ * Classifies every foreign key on a surviving table into one of three cases.
665
+ * A foreign key that carries a `referencedSchema` is checked against the
666
+ * pack-owned coordinates first, so a pack-owned target wins even when a local
667
+ * table happens to share its bare name; only foreign keys with no owned
668
+ * coordinate fall through to the local/dangling distinction.
669
+ *
670
+ * - **Cross-space**: `referencedSchema` is set and a described contract owns
671
+ * the coordinate `(referencedSchema, 'table', referencedTable)`. The
672
+ * referenced table is absent from the tree (omitted because the pack
673
+ * describes it, or never introspected — `contract infer` walks a single
674
+ * namespace). Removed from `foreignKeys` (so `inferRelations` never falls
675
+ * back to a bare, unqualified table name for it) and replaced with a
676
+ * `RelationField` qualified with the owning pack's space id and namespace
677
+ * id. `owners` holds only pack-declared coordinates, so an app's own table
678
+ * (e.g. `public.users`) is never owned and cannot be captured here.
679
+ * - **Local**: not a pack-owned coordinate, and the referenced table survived
680
+ * introspection — left untouched, `inferRelations` handles it as before.
681
+ * - **Dangling**: not a pack-owned coordinate, and the referenced table is
682
+ * neither in the tree nor owned by any described contract. Removed from
683
+ * `foreignKeys`, keeping the scalar column, rather than emitting a relation
684
+ * to a model that was never defined.
685
+ *
686
+ * A pack that owns the referenced coordinate but declares no domain model
687
+ * mapped to it is malformed; that case throws rather than degrading to a
688
+ * silent drop, which would contradict the dangling definition above.
689
+ */
690
+ function resolveForeignKeys(tables, owners) {
691
+ const resultTables = {};
692
+ const extraRelationsByTable = /* @__PURE__ */ new Map();
693
+ const crossSpaceFieldNamesByTable = /* @__PURE__ */ new Map();
694
+ for (const [tableName, table] of Object.entries(tables)) {
695
+ const keptForeignKeys = [];
696
+ for (const fk of table.foreignKeys) {
697
+ if (fk.referencedSchema !== void 0) {
698
+ const owner = owners.get(coordinateKey({
699
+ namespaceId: fk.referencedSchema,
700
+ entityKind: "table",
701
+ entityName: fk.referencedTable
702
+ }));
703
+ if (owner !== void 0) {
704
+ const target = resolveCrossSpaceTarget(owner, fk.referencedSchema, fk.referencedTable);
705
+ if (target === void 0) throw new Error(`contract infer: described contract space "${owner.spaceId}" owns storage coordinate "${fk.referencedSchema}.${fk.referencedTable}" but declares no domain model mapped to it. A pack that describes a table must also declare the domain model it maps to; this pack is malformed.`);
706
+ if (!crossSpaceFieldNamesByTable.has(fk.referencedTable)) crossSpaceFieldNamesByTable.set(fk.referencedTable, target.fieldNamesByColumn);
707
+ const fieldName = deriveRelationFieldName(fk.columns, fk.referencedTable);
708
+ const optional = fk.columns.some((columnName) => table.columns[columnName]?.nullable ?? false);
709
+ const relationField = {
710
+ ...buildChildRelationField(fieldName, target.modelName, fk, optional, void 0, table),
711
+ typeNamespaceId: target.namespaceId,
712
+ typeContractSpaceId: target.spaceId
713
+ };
714
+ const existingRelations = extraRelationsByTable.get(tableName);
715
+ if (existingRelations) existingRelations.push(relationField);
716
+ else extraRelationsByTable.set(tableName, [relationField]);
717
+ continue;
718
+ }
719
+ }
720
+ if (tables[fk.referencedTable] !== void 0) keptForeignKeys.push(fk);
721
+ }
722
+ resultTables[tableName] = keptForeignKeys.length === table.foreignKeys.length ? table : new SqlTableIR({
723
+ ...table,
724
+ foreignKeys: keptForeignKeys
725
+ });
726
+ }
727
+ return {
728
+ tables: resultTables,
729
+ extraRelationsByTable,
730
+ crossSpaceFieldNamesByTable
731
+ };
732
+ }
733
+ /**
734
+ * Infers a PSL AST (for `printPsl`) from an introspected Postgres schema tree.
735
+ *
736
+ * Target-owned inference: it walks the `PostgresDatabaseSchemaNode` tree and
737
+ * owns the Postgres dialect knowledge — the native type map and default map.
738
+ * Relation inference, name transforms, generic default mapping, and raw-default
739
+ * parsing are shape-neutral utilities imported from the SQL family.
740
+ *
741
+ * This slice emits relational-only PSL, byte-identical to the prior flat
742
+ * inference: the tree's tables (across its namespaces — `contract infer`
743
+ * introspects a single live namespace) are gathered into the model set and
744
+ * emitted as one `UNSPECIFIED_PSL_NAMESPACE_ID` bucket. Top-level entities
745
+ * (policies/roles → PSL extension blocks) are a later slice.
746
+ *
747
+ * `describedContracts` — the stack's extension packs' already-assembled
748
+ * contracts, each paired with its space id — is consulted while gathering
749
+ * tables: a table whose coordinate `(schemaName, 'table', tableName)` one of
750
+ * those contracts already declares is omitted, before the duplicate-name
751
+ * check below and before relation inference, so it cannot spuriously
752
+ * collide with an app table and never contributes a bare relation field. A
753
+ * surviving table's foreign key into an omitted, pack-owned table is not
754
+ * dropped: {@link resolveForeignKeys} rewrites it into a relation qualified
755
+ * with the pack's space id (`<spaceId>:<namespaceId>.<Model>`) instead.
756
+ */
757
+ function inferPostgresPslContract(tree, describedContracts) {
758
+ const namespaces = Object.values(tree.namespaces);
759
+ const owners = describedContractOwners(describedContracts ?? []);
760
+ const enumDefinitions = /* @__PURE__ */ new Map();
761
+ const packOwnedEnumTypesByNamespace = /* @__PURE__ */ new Map();
762
+ const enumNamespaceNames = /* @__PURE__ */ new Set();
763
+ for (const namespace of namespaces) for (const { typeName, members } of namespace.nativeEnums) {
764
+ const owner = owners.get(coordinateKey({
765
+ namespaceId: namespace.schemaName,
766
+ entityKind: "native_enum",
767
+ entityName: typeName
768
+ }));
769
+ if (owner !== void 0) {
770
+ const owned = packOwnedEnumTypesByNamespace.get(namespace.schemaName) ?? /* @__PURE__ */ new Map();
771
+ owned.set(typeName, owner.spaceId);
772
+ owned.set(`${namespace.schemaName}.${typeName}`, owner.spaceId);
773
+ packOwnedEnumTypesByNamespace.set(namespace.schemaName, owned);
774
+ continue;
775
+ }
776
+ enumDefinitions.set(typeName, members);
777
+ enumNamespaceNames.add(namespace.schemaName);
778
+ }
779
+ const tables = {};
780
+ const tableNamespaceNames = /* @__PURE__ */ new Set();
781
+ for (const namespace of namespaces) {
782
+ const ownedEnumTypes = packOwnedEnumTypesByNamespace.get(namespace.schemaName);
783
+ for (const [tableName, table] of Object.entries(namespace.tables)) {
784
+ if (owners.has(coordinateKey({
785
+ namespaceId: namespace.schemaName,
786
+ entityKind: "table",
787
+ entityName: tableName
788
+ }))) continue;
789
+ if (tables[tableName] !== void 0) throw new Error(`contract infer: duplicate table name "${tableName}" across schemas is not yet supported (single-namespace PSL inference emits one flat bucket; multi-namespace \`namespace { … }\` output is a later slice).`);
790
+ if (ownedEnumTypes !== void 0) for (const column of Object.values(table.columns)) {
791
+ const owningSpaceId = ownedEnumTypes.get(column.nativeType);
792
+ if (owningSpaceId !== void 0) throw new Error(`contract infer: column "${tableName}"."${column.name}" is typed by native enum type "${column.nativeType}", which extension pack space "${owningSpaceId}" already describes. A cross-space enum-typed column has no authorable PSL form yet; describe the table in that pack's contract or retype the column before re-running contract infer.`);
793
+ }
794
+ tables[tableName] = new SqlTableIR(table);
795
+ tableNamespaceNames.add(namespace.schemaName);
796
+ }
797
+ }
798
+ let wrapNamespaceName;
799
+ if (enumDefinitions.size > 0) {
800
+ const contentNamespaces = /* @__PURE__ */ new Set([...enumNamespaceNames, ...tableNamespaceNames]);
801
+ if (contentNamespaces.size > 1) throw new Error(`contract infer: native enum adoption with content across multiple schemas is not yet supported (single-namespace PSL inference emits one \`namespace { … }\` block; multi-namespace output is a later slice). Schemas: ${[...contentNamespaces].sort().join(", ")}.`);
802
+ wrapNamespaceName = [...contentNamespaces][0];
803
+ }
804
+ const { tables: resolvedTables, extraRelationsByTable, crossSpaceFieldNamesByTable } = resolveForeignKeys(tables, owners);
805
+ const schemaIR = new SqlSchemaIR({ tables: resolvedTables });
806
+ const enumTypeNames = new Set(enumDefinitions.keys());
807
+ if (wrapNamespaceName !== void 0) for (const typeName of enumDefinitions.keys()) enumTypeNames.add(`${wrapNamespaceName}.${typeName}`);
808
+ const enumInfo = {
809
+ typeNames: enumTypeNames,
810
+ definitions: enumDefinitions
811
+ };
812
+ return buildPslDocumentAst(schemaIR, {
813
+ typeMap: createPostgresTypeMap(enumInfo.typeNames),
814
+ defaultMapping: createPostgresDefaultMapping(),
815
+ parseRawDefault,
816
+ ...enumDefinitions.size > 0 ? { enumInfo } : {}
817
+ }, {
818
+ extraRelationsByTable,
819
+ crossSpaceFieldNamesByTable
820
+ }, wrapNamespaceName);
821
+ }
822
+ function buildPslDocumentAst(schemaIR, options, foreignKeyExtras, namespaceName) {
823
+ const { typeMap, defaultMapping, parseRawDefault: rawDefaultParser } = options;
824
+ const { extraRelationsByTable, crossSpaceFieldNamesByTable } = foreignKeyExtras;
825
+ const modelNames = buildTopLevelNameMap(Object.keys(schemaIR.tables), toModelName, "model", "table");
826
+ const modelNameMap = new Map([...modelNames].map(([tableName, result]) => [tableName, result.name]));
827
+ const { enumNameMap: bareEnumNameMap, enumBlocks } = buildNativeEnumBlocks(options.enumInfo?.definitions ?? /* @__PURE__ */ new Map(), modelNames);
828
+ const enumNameMap = new Map(bareEnumNameMap);
829
+ if (namespaceName !== void 0) for (const [typeName, pslName] of bareEnumNameMap) enumNameMap.set(`${namespaceName}.${typeName}`, pslName);
830
+ const reservedNamedTypeNames = createReservedNamedTypeNames(modelNames, enumNameMap);
831
+ const fieldNamesByTable = new Map([...crossSpaceFieldNamesByTable, ...buildFieldNamesByTable(schemaIR.tables)]);
832
+ const { relationsByTable } = inferRelations(schemaIR.tables, modelNameMap);
833
+ const namedTypes = seedNamedTypeRegistry(schemaIR, typeMap, enumNameMap, reservedNamedTypeNames);
834
+ const models = [];
835
+ for (const table of Object.values(schemaIR.tables)) models.push(buildModel(table, typeMap, enumNameMap, fieldNamesByTable, namedTypes, defaultMapping, rawDefaultParser, [...relationsByTable.get(table.name) ?? [], ...extraRelationsByTable.get(table.name) ?? []]));
836
+ const sortedModels = topologicalSort(models, schemaIR.tables, modelNameMap);
837
+ const namedTypeEntries = [...namedTypes.entriesByKey.values()].sort((a, b) => a.name.localeCompare(b.name));
838
+ const types = namedTypeEntries.length > 0 ? {
839
+ kind: "types",
840
+ declarations: namedTypeEntries.map(buildNamedTypeDeclaration),
841
+ span: SYNTHETIC_SPAN
842
+ } : void 0;
843
+ return {
844
+ kind: "document",
845
+ sourceId: "<sql-schema-ir>",
846
+ namespaces: [makePslNamespace({
847
+ kind: "namespace",
848
+ name: namespaceName ?? UNSPECIFIED_PSL_NAMESPACE_ID,
849
+ entries: makePslNamespaceEntries(sortedModels, [], enumBlocks),
850
+ span: SYNTHETIC_SPAN
851
+ })],
852
+ ...types ? { types } : {},
853
+ span: SYNTHETIC_SPAN
854
+ };
855
+ }
856
+ /**
857
+ * Builds one `native_enum` extension-block AST node per introspected enum
858
+ * definition. Block names go through the shared top-level transform
859
+ * (`toEnumName`, intra-enum collisions throw like model collisions) and are
860
+ * then reserved against the model names — an enum whose PSL name a model
861
+ * already claims gets a numeric suffix, with `@@map` carrying the real type
862
+ * name. Members print as explicit `member = "value"` pairs: the member name
863
+ * is the sanitized value (deduplicated within the block), the JSON-encoded
864
+ * value carries the truth verbatim.
865
+ */
866
+ function buildNativeEnumBlocks(definitions, modelNames) {
867
+ const enumNames = buildTopLevelNameMap([...definitions.keys()].sort(), toEnumName, "enum", "enum type");
868
+ const usedTopLevelNames = new Set(PSL_SCALAR_TYPE_NAMES);
869
+ for (const result of modelNames.values()) usedTopLevelNames.add(result.name);
870
+ const enumNameMap = /* @__PURE__ */ new Map();
871
+ const enumBlocks = [];
872
+ for (const [typeName, result] of enumNames) {
873
+ const name = createUniqueFieldName(result.name, usedTopLevelNames);
874
+ usedTopLevelNames.add(name);
875
+ enumNameMap.set(typeName, name);
876
+ enumBlocks.push(buildNativeEnumBlock(name, typeName, definitions.get(typeName) ?? []));
877
+ }
878
+ return {
879
+ enumNameMap,
880
+ enumBlocks
881
+ };
882
+ }
883
+ function buildNativeEnumBlock(name, typeName, values) {
884
+ const usedMemberNames = /* @__PURE__ */ new Set();
885
+ const parameters = {};
886
+ for (const value of values) {
887
+ const memberName = createUniqueFieldName(toEnumMemberName(value), usedMemberNames);
888
+ usedMemberNames.add(memberName);
889
+ parameters[memberName] = {
890
+ kind: "value",
891
+ raw: JSON.stringify(value),
892
+ span: SYNTHETIC_SPAN
893
+ };
894
+ }
895
+ return {
896
+ kind: "native_enum",
897
+ keyword: "native_enum",
898
+ name,
899
+ parameters,
900
+ blockAttributes: name === typeName ? [] : [{
901
+ name: "map",
902
+ args: [{
903
+ kind: "positional",
904
+ value: `"${escapePslString(typeName)}"`,
905
+ span: SYNTHETIC_SPAN
906
+ }],
907
+ span: SYNTHETIC_SPAN
908
+ }],
909
+ span: SYNTHETIC_SPAN
910
+ };
911
+ }
912
+ function buildModel(table, typeMap, enumNameMap, fieldNamesByTable, namedTypes, defaultMapping, rawDefaultParser, relationFields) {
913
+ const { name: modelName, map: mapName } = toModelName(table.name);
914
+ const fieldNameMap = fieldNamesByTable.get(table.name);
915
+ const pkColumns = new Set(table.primaryKey?.columns ?? []);
916
+ const isSinglePk = pkColumns.size === 1;
917
+ const singlePkConstraintName = isSinglePk ? table.primaryKey?.name : void 0;
918
+ const uniqueColumns = /* @__PURE__ */ new Map();
919
+ for (const unique of table.uniques) if (unique.columns.length === 1) {
920
+ const [columnName = ""] = unique.columns;
921
+ const existingConstraintName = uniqueColumns.get(columnName);
922
+ if (!uniqueColumns.has(columnName) || existingConstraintName === void 0 && unique.name) uniqueColumns.set(columnName, unique.name);
923
+ }
924
+ const fields = [];
925
+ for (const column of Object.values(table.columns)) fields.push(buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, namedTypes, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns));
926
+ const usedFieldNames = new Set(fields.map((field) => field.name));
927
+ for (const rel of relationFields) fields.push(buildRelationField(rel, table.name, fieldNamesByTable, usedFieldNames));
928
+ const modelAttributes = [];
929
+ if (table.primaryKey && table.primaryKey.columns.length > 1) {
930
+ const pkFieldNames = table.primaryKey.columns.map((columnName) => resolveColumnFieldName(fieldNamesByTable, table.name, columnName));
931
+ modelAttributes.push(buildModelConstraintAttribute("id", pkFieldNames, table.primaryKey.name));
932
+ }
933
+ for (const unique of table.uniques) if (unique.columns.length > 1) {
934
+ const uniqueFieldNames = unique.columns.map((columnName) => resolveColumnFieldName(fieldNamesByTable, table.name, columnName));
935
+ modelAttributes.push(buildModelConstraintAttribute("unique", uniqueFieldNames, unique.name));
936
+ }
937
+ for (const index of table.indexes) if (!index.unique) {
938
+ const indexFieldNames = index.columns.map((columnName) => resolveColumnFieldName(fieldNamesByTable, table.name, columnName));
939
+ modelAttributes.push(buildModelConstraintAttribute("index", indexFieldNames, index.name, index.type));
940
+ }
941
+ if (mapName) modelAttributes.push(buildMapAttribute("model", mapName));
942
+ const comment = table.primaryKey ? void 0 : "// WARNING: This table has no primary key in the database";
943
+ return {
944
+ kind: "model",
945
+ name: modelName,
946
+ fields,
947
+ attributes: modelAttributes,
948
+ span: SYNTHETIC_SPAN,
949
+ ...comment !== void 0 ? { comment } : {}
950
+ };
951
+ }
952
+ function buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, namedTypes, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns) {
953
+ const resolvedField = fieldNameMap?.get(column.name);
954
+ const fieldName = resolvedField?.fieldName ?? toFieldName(column.name).name;
955
+ const fieldMap = resolvedField?.fieldMap;
956
+ const resolution = typeMap.resolve(column.nativeType, table.annotations);
957
+ if ("unsupported" in resolution) {
958
+ const attrs = [];
959
+ if (fieldMap !== void 0) attrs.push(buildMapAttribute("field", fieldMap));
960
+ return {
961
+ kind: "field",
962
+ name: fieldName,
963
+ typeName: `Unsupported("${escapePslString(resolution.nativeType)}")`,
964
+ optional: column.nullable,
965
+ list: column.many === true,
966
+ attributes: attrs,
967
+ span: SYNTHETIC_SPAN
968
+ };
969
+ }
970
+ let typeName = resolution.pslType;
971
+ let typeConstructor;
972
+ const enumPslName = enumNameMap.get(column.nativeType);
973
+ if (enumPslName) {
974
+ typeName = enumPslName;
975
+ typeConstructor = {
976
+ kind: "typeConstructor",
977
+ path: ["pg", "enum"],
978
+ args: [positionalArg(enumPslName)],
979
+ span: SYNTHETIC_SPAN
980
+ };
981
+ }
982
+ if (resolution.nativeTypeAttribute && !enumPslName) typeName = resolveNamedTypeName(namedTypes, resolution);
983
+ const attributes = [];
984
+ const isId = isSinglePk && pkColumns.has(column.name);
985
+ if (isId) attributes.push(buildSimpleConstraintFieldAttribute("id", singlePkConstraintName));
986
+ if (column.default !== void 0) {
987
+ const parsed = parseColumnDefault(column.default, column.nativeType, rawDefaultParser);
988
+ if (parsed) {
989
+ const result = mapDefault(parsed, defaultMapping);
990
+ if ("attribute" in result) attributes.push(parseDefaultAttributeString(result.attribute));
991
+ }
992
+ }
993
+ if (uniqueColumns.has(column.name) && !isId) {
994
+ const uniqueConstraintName = uniqueColumns.get(column.name);
995
+ attributes.push(buildSimpleConstraintFieldAttribute("unique", uniqueConstraintName));
996
+ }
997
+ if (fieldMap !== void 0) attributes.push(buildMapAttribute("field", fieldMap));
998
+ return {
999
+ kind: "field",
1000
+ name: fieldName,
1001
+ typeName,
1002
+ ...ifDefined("typeConstructor", typeConstructor),
1003
+ optional: column.nullable,
1004
+ list: column.many === true,
1005
+ attributes,
1006
+ span: SYNTHETIC_SPAN
1007
+ };
1008
+ }
1009
+ function buildRelationField(rel, hostTableName, fieldNamesByTable, usedFieldNames) {
1010
+ const fieldName = createUniqueFieldName(rel.fieldName, usedFieldNames);
1011
+ usedFieldNames.add(fieldName);
1012
+ const args = [];
1013
+ if (rel.fields && rel.references) {
1014
+ if (rel.relationName) args.push(namedArg("name", `"${escapePslString(rel.relationName)}"`));
1015
+ args.push(namedArg("fields", `[${rel.fields.map((columnName) => resolveColumnFieldName(fieldNamesByTable, hostTableName, columnName)).join(", ")}]`));
1016
+ args.push(namedArg("references", `[${rel.references.map((columnName) => resolveColumnFieldName(fieldNamesByTable, rel.referencedTableName ?? "", columnName)).join(", ")}]`));
1017
+ if (rel.onDelete) args.push(namedArg("onDelete", rel.onDelete));
1018
+ if (rel.onUpdate) args.push(namedArg("onUpdate", rel.onUpdate));
1019
+ if (rel.fkName) args.push(namedArg("map", `"${escapePslString(rel.fkName)}"`));
1020
+ if (rel.index === false) args.push(namedArg("index", "false"));
1021
+ } else if (rel.relationName) args.push(namedArg("name", `"${escapePslString(rel.relationName)}"`));
1022
+ const attrs = args.length > 0 ? [buildAttribute("field", "relation", args)] : [];
1023
+ return {
1024
+ kind: "field",
1025
+ name: fieldName,
1026
+ typeName: rel.typeName,
1027
+ ...ifDefined("typeNamespaceId", rel.typeNamespaceId),
1028
+ ...ifDefined("typeContractSpaceId", rel.typeContractSpaceId),
1029
+ optional: rel.optional,
1030
+ list: rel.list,
1031
+ attributes: attrs,
1032
+ span: SYNTHETIC_SPAN
1033
+ };
1034
+ }
1035
+ /**
1036
+ * `indexType` carries a non-default index access method (e.g. `hash`) —
1037
+ * introspection already drops `btree` (the Postgres default) to `undefined`
1038
+ * (see the postgres control adapter), so this only ever fires for a real
1039
+ * non-default index, matching the same `@@index(type: "...")` argument
1040
+ * `contract-to-schema-ir.ts` reads back into the FK-backing-index
1041
+ * expectation `db verify` checks against the live database.
1042
+ */
1043
+ function buildModelConstraintAttribute(name, fields, constraintName, indexType) {
1044
+ const args = [positionalArg(`[${fields.join(", ")}]`)];
1045
+ if (constraintName !== void 0) args.push(namedArg("map", `"${escapePslString(constraintName)}"`));
1046
+ if (indexType !== void 0) args.push(namedArg("type", `"${escapePslString(indexType)}"`));
1047
+ return buildAttribute("model", name, args);
1048
+ }
1049
+ function buildSimpleConstraintFieldAttribute(name, constraintName) {
1050
+ if (constraintName === void 0) return buildAttribute("field", name, []);
1051
+ return buildAttribute("field", name, [namedArg("map", `"${escapePslString(constraintName)}"`)]);
1052
+ }
1053
+ function parseDefaultAttributeString(attributeText) {
1054
+ return buildAttribute("field", "default", [positionalArg(attributeText.replace(/^@default\(/, "").replace(/\)$/, ""))]);
1055
+ }
1056
+ function buildMapAttribute(target, mapName) {
1057
+ return buildAttribute(target, "map", [positionalArg(`"${escapePslString(mapName)}"`)]);
1058
+ }
1059
+ function buildAttribute(target, name, args) {
1060
+ return {
1061
+ kind: "attribute",
1062
+ target,
1063
+ name,
1064
+ args,
1065
+ span: SYNTHETIC_SPAN
421
1066
  };
422
1067
  }
1068
+ function positionalArg(value) {
1069
+ return {
1070
+ kind: "positional",
1071
+ value,
1072
+ span: SYNTHETIC_SPAN
1073
+ };
1074
+ }
1075
+ function namedArg(name, value) {
1076
+ return {
1077
+ kind: "named",
1078
+ name,
1079
+ value,
1080
+ span: SYNTHETIC_SPAN
1081
+ };
1082
+ }
1083
+ function buildNamedTypeDeclaration(entry) {
1084
+ const attribute = buildAttribute("namedType", entry.nativeTypeAttribute.name, (entry.nativeTypeAttribute.args ?? []).map(positionalArg));
1085
+ return {
1086
+ kind: "namedType",
1087
+ name: entry.name,
1088
+ baseType: entry.baseType,
1089
+ attributes: [attribute],
1090
+ span: SYNTHETIC_SPAN
1091
+ };
1092
+ }
1093
+ function escapePslString(value) {
1094
+ return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
1095
+ }
1096
+ /**
1097
+ * Resolves a `SqlColumnIR.default` value into a normalized {@link ColumnDefault}.
1098
+ *
1099
+ * `SqlSchemaIR` types the column default as `string` (a raw database default
1100
+ * expression). Some legacy fixtures and tests still pass already-normalized
1101
+ * `ColumnDefault` objects in the same slot, so we accept either shape
1102
+ * defensively at runtime.
1103
+ */
1104
+ function parseColumnDefault(value, nativeType, rawDefaultParser) {
1105
+ if (typeof value === "string") return rawDefaultParser ? rawDefaultParser(value, nativeType) : void 0;
1106
+ if (value !== null && typeof value === "object" && "kind" in value) return value;
1107
+ }
1108
+ function buildFieldNamesByTable(tables) {
1109
+ const fieldNamesByTable = /* @__PURE__ */ new Map();
1110
+ for (const table of Object.values(tables)) {
1111
+ const assignmentOrder = [...Object.values(table.columns).map((column, index) => {
1112
+ const { name, map } = toFieldName(column.name);
1113
+ return {
1114
+ columnName: column.name,
1115
+ desiredFieldName: name,
1116
+ fieldMap: map,
1117
+ index
1118
+ };
1119
+ })].sort((left, right) => {
1120
+ const mapComparison = Number(left.fieldMap !== void 0) - Number(right.fieldMap !== void 0);
1121
+ if (mapComparison !== 0) return mapComparison;
1122
+ return left.index - right.index;
1123
+ });
1124
+ const usedFieldNames = /* @__PURE__ */ new Set();
1125
+ const tableFieldNames = /* @__PURE__ */ new Map();
1126
+ for (const column of assignmentOrder) {
1127
+ const fieldName = createUniqueFieldName(column.desiredFieldName, usedFieldNames);
1128
+ usedFieldNames.add(fieldName);
1129
+ tableFieldNames.set(column.columnName, {
1130
+ fieldName,
1131
+ fieldMap: column.fieldMap
1132
+ });
1133
+ }
1134
+ fieldNamesByTable.set(table.name, tableFieldNames);
1135
+ }
1136
+ return fieldNamesByTable;
1137
+ }
1138
+ function resolveColumnFieldName(fieldNamesByTable, tableName, columnName) {
1139
+ return fieldNamesByTable.get(tableName)?.get(columnName)?.fieldName ?? toFieldName(columnName).name;
1140
+ }
1141
+ function createUniqueFieldName(desiredName, usedFieldNames) {
1142
+ if (!usedFieldNames.has(desiredName)) return desiredName;
1143
+ let counter = 2;
1144
+ while (usedFieldNames.has(`${desiredName}${counter}`)) counter++;
1145
+ return `${desiredName}${counter}`;
1146
+ }
1147
+ function buildTopLevelNameMap(sources, normalize, kind, sourceKind) {
1148
+ const results = /* @__PURE__ */ new Map();
1149
+ const normalizedToSources = /* @__PURE__ */ new Map();
1150
+ for (const source of sources) {
1151
+ const normalized = normalize(source);
1152
+ results.set(source, normalized);
1153
+ normalizedToSources.set(normalized.name, [...normalizedToSources.get(normalized.name) ?? [], source]);
1154
+ }
1155
+ const duplicates = [...normalizedToSources.entries()].filter(([, conflictingSources]) => conflictingSources.length > 1);
1156
+ if (duplicates.length > 0) {
1157
+ const details = duplicates.map(([normalizedName, conflictingSources]) => `- ${kind} "${normalizedName}" from ${sourceKind}s ${conflictingSources.map((source) => `"${source}"`).join(", ")}`);
1158
+ throw new Error(`PSL ${kind} name collisions detected:\n${details.join("\n")}`);
1159
+ }
1160
+ return results;
1161
+ }
1162
+ function createReservedNamedTypeNames(modelNames, enumNameMap) {
1163
+ const reservedNames = new Set(PSL_SCALAR_TYPE_NAMES);
1164
+ for (const result of modelNames.values()) reservedNames.add(result.name);
1165
+ for (const enumPslName of enumNameMap.values()) reservedNames.add(enumPslName);
1166
+ return reservedNames;
1167
+ }
1168
+ function seedNamedTypeRegistry(schemaIR, typeMap, enumNameMap, reservedNames) {
1169
+ const seeds = /* @__PURE__ */ new Map();
1170
+ for (const tableName of Object.keys(schemaIR.tables).sort()) {
1171
+ const table = schemaIR.tables[tableName];
1172
+ if (!table) continue;
1173
+ for (const columnName of Object.keys(table.columns).sort()) {
1174
+ const column = table.columns[columnName];
1175
+ if (!column) continue;
1176
+ const resolution = typeMap.resolve(column.nativeType, table.annotations);
1177
+ if ("unsupported" in resolution || enumNameMap.has(column.nativeType) || !resolution.nativeTypeAttribute) continue;
1178
+ const signatureKey = createNamedTypeSignatureKey(resolution);
1179
+ if (!seeds.has(signatureKey)) seeds.set(signatureKey, {
1180
+ baseType: resolution.pslType,
1181
+ desiredName: toNamedTypeName(column.name),
1182
+ nativeTypeAttribute: resolution.nativeTypeAttribute
1183
+ });
1184
+ }
1185
+ }
1186
+ const registry = {
1187
+ entriesByKey: /* @__PURE__ */ new Map(),
1188
+ usedNames: new Set(reservedNames)
1189
+ };
1190
+ const sortedSeeds = [...seeds.entries()].sort((left, right) => {
1191
+ const desiredNameComparison = left[1].desiredName.localeCompare(right[1].desiredName);
1192
+ if (desiredNameComparison !== 0) return desiredNameComparison;
1193
+ return left[0].localeCompare(right[0]);
1194
+ });
1195
+ for (const [signatureKey, seed] of sortedSeeds) {
1196
+ const name = createUniqueFieldName(seed.desiredName, registry.usedNames);
1197
+ registry.entriesByKey.set(signatureKey, {
1198
+ name,
1199
+ baseType: seed.baseType,
1200
+ nativeTypeAttribute: seed.nativeTypeAttribute
1201
+ });
1202
+ registry.usedNames.add(name);
1203
+ }
1204
+ return registry;
1205
+ }
1206
+ function resolveNamedTypeName(registry, resolution) {
1207
+ const key = createNamedTypeSignatureKey(resolution);
1208
+ const existing = registry.entriesByKey.get(key);
1209
+ if (existing) return existing.name;
1210
+ throw new Error(`Named type registry was not seeded for native type "${resolution.nativeType}"`);
1211
+ }
1212
+ function createNamedTypeSignatureKey(resolution) {
1213
+ return JSON.stringify({
1214
+ baseType: resolution.pslType,
1215
+ nativeTypeAttribute: resolution.nativeTypeAttribute ? {
1216
+ name: resolution.nativeTypeAttribute.name,
1217
+ args: resolution.nativeTypeAttribute.args ?? null
1218
+ } : null
1219
+ });
1220
+ }
1221
+ function topologicalSort(models, tables, modelNameMap) {
1222
+ const modelByName = /* @__PURE__ */ new Map();
1223
+ for (const model of models) modelByName.set(model.name, model);
1224
+ const deps = /* @__PURE__ */ new Map();
1225
+ const tableToModel = /* @__PURE__ */ new Map();
1226
+ for (const tableName of Object.keys(tables)) {
1227
+ const modelName = modelNameMap.get(tableName);
1228
+ tableToModel.set(tableName, modelName);
1229
+ deps.set(modelName, /* @__PURE__ */ new Set());
1230
+ }
1231
+ for (const [tableName, table] of Object.entries(tables)) {
1232
+ const modelName = tableToModel.get(tableName);
1233
+ for (const fk of table.foreignKeys) {
1234
+ const refModelName = tableToModel.get(fk.referencedTable);
1235
+ if (refModelName && refModelName !== modelName) deps.get(modelName).add(refModelName);
1236
+ }
1237
+ }
1238
+ const result = [];
1239
+ const visited = /* @__PURE__ */ new Set();
1240
+ const visiting = /* @__PURE__ */ new Set();
1241
+ const sortedNames = [...deps.keys()].sort();
1242
+ function visit(name) {
1243
+ if (visited.has(name)) return;
1244
+ if (visiting.has(name)) return;
1245
+ visiting.add(name);
1246
+ const sortedDeps = [...deps.get(name)].sort();
1247
+ for (const dep of sortedDeps) visit(dep);
1248
+ visiting.delete(name);
1249
+ visited.add(name);
1250
+ result.push(modelByName.get(name));
1251
+ }
1252
+ for (const name of sortedNames) visit(name);
1253
+ return result;
1254
+ }
1255
+ //#endregion
1256
+ //#region src/exports/control.ts
423
1257
  function postgresRenderDefault(def, column) {
424
1258
  if (def.kind === "function") return def.expression;
425
1259
  return renderDefaultLiteral(def.value, column);
@@ -428,6 +1262,15 @@ const postgresTargetDescriptor = {
428
1262
  ...postgresTargetDescriptorMeta,
429
1263
  contractSerializer: new PostgresContractSerializer(),
430
1264
  schemaVerifier: new PostgresSchemaVerifier(),
1265
+ inferPslContract(schema, describedContracts) {
1266
+ PostgresDatabaseSchemaNode.assert(schema);
1267
+ return inferPostgresPslContract(schema, describedContracts);
1268
+ },
1269
+ diffSchema(input) {
1270
+ return diffPostgresSchema(input);
1271
+ },
1272
+ classifySubjectGranularity: postgresDiffSubjectGranularity,
1273
+ classifyEntityKind: postgresDiffSubjectEntityKind,
431
1274
  migrations: {
432
1275
  createPlanner(adapter) {
433
1276
  return createPostgresMigrationPlanner(adapter);
@@ -436,9 +1279,10 @@ const postgresTargetDescriptor = {
436
1279
  return createPostgresMigrationRunner(family);
437
1280
  },
438
1281
  contractToSchema(contract, frameworkComponents) {
439
- return contractToSchemaIR(contract, {
1282
+ const expander = buildNativeTypeExpander(frameworkComponents);
1283
+ return contractToPostgresDatabaseSchemaNode(blindCast(contract), {
440
1284
  annotationNamespace: "pg",
441
- ...ifDefined("expandNativeType", buildNativeTypeExpander(frameworkComponents)),
1285
+ ...ifDefined("expandNativeType", expander),
442
1286
  renderDefault: postgresRenderDefault
443
1287
  });
444
1288
  }