@prisma-next/target-postgres 0.12.0 → 0.13.0-dev.10

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 (211) hide show
  1. package/dist/{codec-ids-D9fJ4HP5.d.mts → codec-ids-B1vOchLE.d.mts} +3 -2
  2. package/dist/codec-ids-B1vOchLE.d.mts.map +1 -0
  3. package/dist/{codec-ids-C5qzBqus.mjs → codec-ids-CTikp1if.mjs} +3 -2
  4. package/dist/codec-ids-CTikp1if.mjs.map +1 -0
  5. package/dist/codec-ids.d.mts +2 -2
  6. package/dist/codec-ids.mjs +2 -2
  7. package/dist/{codec-types-CRlHq7Cz.d.mts → codec-types-CnFiNML4.d.mts} +8 -9
  8. package/dist/codec-types-CnFiNML4.d.mts.map +1 -0
  9. package/dist/codec-types.d.mts +2 -2
  10. package/dist/{codecs-Dud5KDNk.d.mts → codecs-CBpEv4s5.d.mts} +33 -35
  11. package/dist/codecs-CBpEv4s5.d.mts.map +1 -0
  12. package/dist/codecs.d.mts +1 -1
  13. package/dist/codecs.mjs +37 -2
  14. package/dist/codecs.mjs.map +1 -1
  15. package/dist/contract-free.d.mts +80 -0
  16. package/dist/contract-free.d.mts.map +1 -0
  17. package/dist/contract-free.mjs +117 -0
  18. package/dist/contract-free.mjs.map +1 -0
  19. package/dist/control.d.mts +1 -1
  20. package/dist/control.d.mts.map +1 -1
  21. package/dist/control.mjs +67 -41
  22. package/dist/control.mjs.map +1 -1
  23. package/dist/{data-transform-CdtGUWp2.mjs → data-transform-D25tLeYU.mjs} +1 -1
  24. package/dist/{data-transform-CdtGUWp2.mjs.map → data-transform-D25tLeYU.mjs.map} +1 -1
  25. package/dist/{data-transform-bmOKkygi.d.mts → data-transform-DGOqcLrf.d.mts} +2 -2
  26. package/dist/{data-transform-bmOKkygi.d.mts.map → data-transform-DGOqcLrf.d.mts.map} +1 -1
  27. package/dist/data-transform.d.mts +1 -1
  28. package/dist/data-transform.mjs +1 -1
  29. package/dist/ddl-77SyXgFt.mjs +30 -0
  30. package/dist/ddl-77SyXgFt.mjs.map +1 -0
  31. package/dist/ddl.d.mts +2 -0
  32. package/dist/ddl.mjs +2 -0
  33. package/dist/{default-normalizer-CRscvhS5.mjs → default-normalizer-DyyCHQWs.mjs} +1 -1
  34. package/dist/{default-normalizer-CRscvhS5.mjs.map → default-normalizer-DyyCHQWs.mjs.map} +1 -1
  35. package/dist/default-normalizer.mjs +1 -1
  36. package/dist/descriptor-meta-DKmj-IMN.mjs +14 -0
  37. package/dist/descriptor-meta-DKmj-IMN.mjs.map +1 -0
  38. package/dist/{descriptor-meta-DLA2xV6B.mjs → descriptor-meta-runtime-My8_s4cs.mjs} +82 -78
  39. package/dist/descriptor-meta-runtime-My8_s4cs.mjs.map +1 -0
  40. package/dist/{enum-planning-Dz0Ye3Lb.mjs → enum-planning-DTMrPLkN.mjs} +0 -0
  41. package/dist/enum-planning-DTMrPLkN.mjs.map +1 -0
  42. package/dist/enum-planning.d.mts +14 -8
  43. package/dist/enum-planning.d.mts.map +1 -1
  44. package/dist/enum-planning.mjs +2 -2
  45. package/dist/{errors--zafB5_n.mjs → errors-CUk87ByX.mjs} +1 -1
  46. package/dist/{errors--zafB5_n.mjs.map → errors-CUk87ByX.mjs.map} +1 -1
  47. package/dist/errors.d.mts.map +1 -1
  48. package/dist/errors.mjs +1 -1
  49. package/dist/{issue-planner-ByQhUzS4.mjs → issue-planner-B0A7RFN2.mjs} +130 -28
  50. package/dist/issue-planner-B0A7RFN2.mjs.map +1 -0
  51. package/dist/issue-planner.d.mts +1 -1
  52. package/dist/issue-planner.d.mts.map +1 -1
  53. package/dist/issue-planner.mjs +1 -1
  54. package/dist/migration.d.mts +7 -8
  55. package/dist/migration.d.mts.map +1 -1
  56. package/dist/migration.mjs +5 -4
  57. package/dist/migration.mjs.map +1 -1
  58. package/dist/{native-type-normalizer-ClNPq__-.mjs → native-type-normalizer-Bc9XJzWC.mjs} +1 -1
  59. package/dist/{native-type-normalizer-ClNPq__-.mjs.map → native-type-normalizer-Bc9XJzWC.mjs.map} +1 -1
  60. package/dist/native-type-normalizer.mjs +1 -1
  61. package/dist/nodes-779hmCfL.d.mts +40 -0
  62. package/dist/nodes-779hmCfL.d.mts.map +1 -0
  63. package/dist/nodes-DZk2JZG3.mjs +47 -0
  64. package/dist/nodes-DZk2JZG3.mjs.map +1 -0
  65. package/dist/op-factory-call-Clp7Zr1z.mjs +1307 -0
  66. package/dist/op-factory-call-Clp7Zr1z.mjs.map +1 -0
  67. package/dist/{op-factory-call-Drccm_JD.d.mts → op-factory-call-DMA86_2D.d.mts} +39 -14
  68. package/dist/op-factory-call-DMA86_2D.d.mts.map +1 -0
  69. package/dist/op-factory-call.d.mts +2 -2
  70. package/dist/op-factory-call.mjs +2 -2
  71. package/dist/pack.d.mts +13 -12
  72. package/dist/pack.d.mts.map +1 -1
  73. package/dist/pack.mjs +1 -1
  74. package/dist/planner-DID7RZCQ.mjs +344 -0
  75. package/dist/planner-DID7RZCQ.mjs.map +1 -0
  76. package/dist/{planner-ddl-builders-BxRCSn_b.mjs → planner-ddl-builders-Cw2n2llW.mjs} +7 -30
  77. package/dist/planner-ddl-builders-Cw2n2llW.mjs.map +1 -0
  78. package/dist/planner-ddl-builders.d.mts +6 -7
  79. package/dist/planner-ddl-builders.d.mts.map +1 -1
  80. package/dist/planner-ddl-builders.mjs +2 -2
  81. package/dist/{planner-identity-values-ojX-6cPV.mjs → planner-identity-values-BIpa5p2I.mjs} +1 -1
  82. package/dist/{planner-identity-values-ojX-6cPV.mjs.map → planner-identity-values-BIpa5p2I.mjs.map} +1 -1
  83. package/dist/planner-identity-values.mjs +1 -1
  84. package/dist/{planner-produced-postgres-migration-p-VKkCia.d.mts → planner-produced-postgres-migration-B4EDvLdz.d.mts} +5 -4
  85. package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +1 -0
  86. package/dist/{planner-produced-postgres-migration-N1yqYg20.mjs → planner-produced-postgres-migration-B8gZBPOR.mjs} +8 -6
  87. package/dist/planner-produced-postgres-migration-B8gZBPOR.mjs.map +1 -0
  88. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  89. package/dist/planner-produced-postgres-migration.mjs +1 -1
  90. package/dist/{planner-schema-lookup-BGyukuzG.mjs → planner-schema-lookup-CiVaAQP-.mjs} +1 -1
  91. package/dist/{planner-schema-lookup-BGyukuzG.mjs.map → planner-schema-lookup-CiVaAQP-.mjs.map} +1 -1
  92. package/dist/planner-schema-lookup.mjs +1 -1
  93. package/dist/{planner-sql-checks-D3H-xOO1.mjs → planner-sql-checks-DRD5E8A1.mjs} +41 -30
  94. package/dist/planner-sql-checks-DRD5E8A1.mjs.map +1 -0
  95. package/dist/planner-sql-checks.d.mts.map +1 -1
  96. package/dist/planner-sql-checks.mjs +1 -1
  97. package/dist/{planner-target-details-CIj61DUj.d.mts → planner-target-details-CIY6tLeo.d.mts} +2 -2
  98. package/dist/planner-target-details-CIY6tLeo.d.mts.map +1 -0
  99. package/dist/planner-target-details.d.mts +2 -2
  100. package/dist/planner-type-resolution-836DExFN.mjs +20 -0
  101. package/dist/planner-type-resolution-836DExFN.mjs.map +1 -0
  102. package/dist/planner.d.mts +7 -3
  103. package/dist/planner.d.mts.map +1 -1
  104. package/dist/planner.mjs +1 -1
  105. package/dist/{postgres-contract-serializer-YJvjKrmo.mjs → postgres-contract-serializer-DCg7YaP3.mjs} +40 -24
  106. package/dist/postgres-contract-serializer-DCg7YaP3.mjs.map +1 -0
  107. package/dist/{postgres-enum-type-CNhPTDhy.d.mts → postgres-enum-type-BVn63a89.d.mts} +4 -1
  108. package/dist/postgres-enum-type-BVn63a89.d.mts.map +1 -0
  109. package/dist/{postgres-enum-type-DS-KLVRH.mjs → postgres-enum-type-DPKqCBem.mjs} +2 -1
  110. package/dist/postgres-enum-type-DPKqCBem.mjs.map +1 -0
  111. package/dist/{postgres-migration-uADmx0dW.mjs → postgres-migration-BCQEjFHK.mjs} +23 -3
  112. package/dist/postgres-migration-BCQEjFHK.mjs.map +1 -0
  113. package/dist/{postgres-migration-Fd4fQkBw.d.mts → postgres-migration-DZ_gLUOW.d.mts} +25 -3
  114. package/dist/postgres-migration-DZ_gLUOW.d.mts.map +1 -0
  115. package/dist/{postgres-schema-Bm7vjlOv.mjs → postgres-schema-BVTA2QH7.mjs} +41 -15
  116. package/dist/postgres-schema-BVTA2QH7.mjs.map +1 -0
  117. package/dist/{render-ops-BC2PtCkj.mjs → render-ops-BpjstrKQ.mjs} +4 -3
  118. package/dist/{render-ops-BC2PtCkj.mjs.map → render-ops-BpjstrKQ.mjs.map} +1 -1
  119. package/dist/render-ops.d.mts +3 -2
  120. package/dist/render-ops.d.mts.map +1 -1
  121. package/dist/render-ops.mjs +1 -1
  122. package/dist/{render-typescript-CPk7hhWH.mjs → render-typescript-KMgosran.mjs} +5 -2
  123. package/dist/render-typescript-KMgosran.mjs.map +1 -0
  124. package/dist/render-typescript.mjs +1 -1
  125. package/dist/runtime.d.mts.map +1 -1
  126. package/dist/runtime.mjs +3 -3
  127. package/dist/runtime.mjs.map +1 -1
  128. package/dist/{shared-ByhSooBS.d.mts → shared-DarONYBZ.d.mts} +5 -5
  129. package/dist/{shared-ByhSooBS.d.mts.map → shared-DarONYBZ.d.mts.map} +1 -1
  130. package/dist/{sql-utils-B_ruBD-M.mjs → sql-utils-DcfMz4MQ.mjs} +1 -1
  131. package/dist/{sql-utils-B_ruBD-M.mjs.map → sql-utils-DcfMz4MQ.mjs.map} +1 -1
  132. package/dist/sql-utils.mjs +1 -1
  133. package/dist/{types-D-XIpzHA.d.mts → types-BDKkx8MA.d.mts} +1 -1
  134. package/dist/types-BDKkx8MA.d.mts.map +1 -0
  135. package/dist/types.d.mts +18 -11
  136. package/dist/types.d.mts.map +1 -1
  137. package/dist/types.mjs +2 -2
  138. package/package.json +21 -20
  139. package/src/contract-free/columns.ts +49 -0
  140. package/src/contract-free/control-bootstrap.ts +55 -0
  141. package/src/contract-free/ddl.ts +37 -0
  142. package/src/core/ast/table-source.ts +23 -0
  143. package/src/core/authoring.ts +1 -1
  144. package/src/core/codec-ids.ts +1 -0
  145. package/src/core/codecs.ts +44 -0
  146. package/src/core/ddl/nodes.ts +72 -0
  147. package/src/core/descriptor-meta-runtime.ts +28 -0
  148. package/src/core/descriptor-meta.ts +3 -6
  149. package/src/core/migrations/control-policy.ts +234 -0
  150. package/src/core/migrations/enum-planning.ts +33 -29
  151. package/src/core/migrations/issue-planner.ts +81 -13
  152. package/src/core/migrations/op-factory-call.ts +289 -46
  153. package/src/core/migrations/operations/constraints.ts +79 -10
  154. package/src/core/migrations/operations/dependencies.ts +0 -17
  155. package/src/core/migrations/operations/shared.ts +3 -3
  156. package/src/core/migrations/operations/tables.ts +1 -39
  157. package/src/core/migrations/planner-ddl-builders.ts +7 -48
  158. package/src/core/migrations/planner-produced-postgres-migration.ts +11 -6
  159. package/src/core/migrations/planner-sql-checks.ts +9 -9
  160. package/src/core/migrations/planner-strategies.ts +149 -11
  161. package/src/core/migrations/planner-target-details.ts +2 -1
  162. package/src/core/migrations/planner.ts +66 -8
  163. package/src/core/migrations/postgres-migration.ts +41 -0
  164. package/src/core/migrations/render-ops.ts +7 -2
  165. package/src/core/migrations/render-typescript.ts +5 -1
  166. package/src/core/migrations/runner.ts +78 -50
  167. package/src/core/postgres-contract-serializer.ts +66 -46
  168. package/src/core/postgres-enum-type.ts +4 -0
  169. package/src/core/postgres-schema.ts +56 -19
  170. package/src/exports/contract-free.ts +7 -0
  171. package/src/exports/control.ts +15 -24
  172. package/src/exports/ddl.ts +7 -0
  173. package/src/exports/enum-planning.ts +0 -1
  174. package/src/exports/migration.ts +11 -2
  175. package/src/exports/op-factory-call.ts +2 -0
  176. package/src/exports/planner-ddl-builders.ts +0 -1
  177. package/src/exports/runtime.ts +2 -2
  178. package/dist/codec-ids-C5qzBqus.mjs.map +0 -1
  179. package/dist/codec-ids-D9fJ4HP5.d.mts.map +0 -1
  180. package/dist/codec-types-CRlHq7Cz.d.mts.map +0 -1
  181. package/dist/codecs-Dud5KDNk.d.mts.map +0 -1
  182. package/dist/descriptor-meta-DLA2xV6B.mjs.map +0 -1
  183. package/dist/enum-planning-Dz0Ye3Lb.mjs.map +0 -1
  184. package/dist/issue-planner-ByQhUzS4.mjs.map +0 -1
  185. package/dist/op-factory-call-B0WNg30h.mjs +0 -625
  186. package/dist/op-factory-call-B0WNg30h.mjs.map +0 -1
  187. package/dist/op-factory-call-Drccm_JD.d.mts.map +0 -1
  188. package/dist/planner-ClF0y0YR.mjs +0 -177
  189. package/dist/planner-ClF0y0YR.mjs.map +0 -1
  190. package/dist/planner-ddl-builders-BxRCSn_b.mjs.map +0 -1
  191. package/dist/planner-produced-postgres-migration-N1yqYg20.mjs.map +0 -1
  192. package/dist/planner-produced-postgres-migration-p-VKkCia.d.mts.map +0 -1
  193. package/dist/planner-sql-checks-D3H-xOO1.mjs.map +0 -1
  194. package/dist/planner-target-details-CIj61DUj.d.mts.map +0 -1
  195. package/dist/postgres-contract-serializer-YJvjKrmo.mjs.map +0 -1
  196. package/dist/postgres-enum-type-CNhPTDhy.d.mts.map +0 -1
  197. package/dist/postgres-enum-type-DS-KLVRH.mjs.map +0 -1
  198. package/dist/postgres-migration-Fd4fQkBw.d.mts.map +0 -1
  199. package/dist/postgres-migration-uADmx0dW.mjs.map +0 -1
  200. package/dist/postgres-schema-Bm7vjlOv.mjs.map +0 -1
  201. package/dist/render-typescript-CPk7hhWH.mjs.map +0 -1
  202. package/dist/statement-builders-vImtdfmM.mjs +0 -131
  203. package/dist/statement-builders-vImtdfmM.mjs.map +0 -1
  204. package/dist/statement-builders.d.mts +0 -51
  205. package/dist/statement-builders.d.mts.map +0 -1
  206. package/dist/statement-builders.mjs +0 -2
  207. package/dist/tables-Dcb2q9zV.mjs +0 -516
  208. package/dist/tables-Dcb2q9zV.mjs.map +0 -1
  209. package/dist/types-D-XIpzHA.d.mts.map +0 -1
  210. package/src/core/migrations/statement-builders.ts +0 -183
  211. package/src/exports/statement-builders.ts +0 -8
@@ -0,0 +1,55 @@
1
+ import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
2
+ import type { DdlNode } from '@prisma-next/sql-relational-core/ast';
3
+ import { col, fn, lit } from '@prisma-next/sql-relational-core/contract-free';
4
+ import { createSchema, createTable } from './ddl';
5
+
6
+ const markerColumns = [
7
+ col('space', 'text', { notNull: true, primaryKey: true, default: lit(APP_SPACE_ID) }),
8
+ col('core_hash', 'text', { notNull: true }),
9
+ col('profile_hash', 'text', { notNull: true }),
10
+ col('contract_json', 'jsonb'),
11
+ col('canonical_version', 'int'),
12
+ col('updated_at', 'timestamptz', { notNull: true, default: fn('now()') }),
13
+ col('app_tag', 'text'),
14
+ col('meta', 'jsonb', { notNull: true, default: lit('{}') }),
15
+ col('invariants', 'text[]', { notNull: true, default: lit('{}') }),
16
+ ] as const;
17
+
18
+ const ledgerColumns = [
19
+ col('id', 'bigserial', { primaryKey: true }),
20
+ col('created_at', 'timestamptz', { notNull: true, default: fn('now()') }),
21
+ col('space', 'text', { notNull: true }),
22
+ col('migration_name', 'text', { notNull: true }),
23
+ col('migration_hash', 'text', { notNull: true }),
24
+ col('origin_core_hash', 'text'),
25
+ col('origin_profile_hash', 'text'),
26
+ col('destination_core_hash', 'text', { notNull: true }),
27
+ col('destination_profile_hash', 'text'),
28
+ col('contract_json_before', 'jsonb'),
29
+ col('contract_json_after', 'jsonb'),
30
+ col('operations', 'jsonb', { notNull: true }),
31
+ ] as const;
32
+
33
+ const markerTable = createTable({
34
+ schema: 'prisma_contract',
35
+ table: 'marker',
36
+ ifNotExists: true,
37
+ columns: markerColumns,
38
+ });
39
+
40
+ const ledgerTable = createTable({
41
+ schema: 'prisma_contract',
42
+ table: 'ledger',
43
+ ifNotExists: true,
44
+ columns: ledgerColumns,
45
+ });
46
+
47
+ const controlSchema = createSchema({ schema: 'prisma_contract', ifNotExists: true });
48
+
49
+ export function buildSignMarkerBootstrapQueries(): readonly DdlNode[] {
50
+ return [controlSchema, markerTable];
51
+ }
52
+
53
+ export function buildControlTableBootstrapQueries(): readonly DdlNode[] {
54
+ return [controlSchema, markerTable, ledgerTable];
55
+ }
@@ -0,0 +1,37 @@
1
+ import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
2
+ import { PostgresCreateSchema, PostgresCreateTable } from '../core/ddl/nodes';
3
+
4
+ /**
5
+ * Build a Postgres `CREATE TABLE` query node.
6
+ *
7
+ * Pass `constraints` for table-level composite primary keys, foreign keys, and
8
+ * unique constraints — use the {@link PrimaryKeyConstraint}, {@link ForeignKeyConstraint},
9
+ * and {@link UniqueConstraint} classes from `@prisma-next/sql-relational-core/ast`.
10
+ *
11
+ * Precondition: identifiers (`table`, `schema`, column names/types) are
12
+ * emitted to SQL verbatim — they are not quoted or escaped, so callers must
13
+ * pass pre-trusted values (e.g. fixed control-plane identifiers). String-literal
14
+ * default values, by contrast, are single-quote-escaped (embedded `'` doubled)
15
+ * by the renderer. Identifier quoting for untrusted identifiers is added when
16
+ * the migration planner adopts this lowering path.
17
+ */
18
+ export function createTable(options: {
19
+ readonly table: string;
20
+ readonly schema?: string;
21
+ readonly ifNotExists?: boolean;
22
+ readonly columns: readonly DdlColumn[];
23
+ readonly constraints?: readonly DdlTableConstraint[];
24
+ }): PostgresCreateTable {
25
+ return new PostgresCreateTable(options);
26
+ }
27
+
28
+ /**
29
+ * Build a Postgres `CREATE SCHEMA` query node. See {@link createTable} for the
30
+ * pre-trusted-identifier precondition.
31
+ */
32
+ export function createSchema(options: {
33
+ readonly schema: string;
34
+ readonly ifNotExists?: boolean;
35
+ }): PostgresCreateSchema {
36
+ return new PostgresCreateSchema(options);
37
+ }
@@ -0,0 +1,23 @@
1
+ import {
2
+ type AnyFromSource,
3
+ type AstRewriter,
4
+ TableSource,
5
+ } from '@prisma-next/sql-relational-core/ast';
6
+
7
+ export class PostgresTableSource extends TableSource {
8
+ readonly schema: string | undefined;
9
+
10
+ constructor(options: {
11
+ readonly name: string;
12
+ readonly schema?: string;
13
+ readonly alias?: string;
14
+ }) {
15
+ super(options.name, options.alias);
16
+ this.schema = options.schema;
17
+ this.freeze();
18
+ }
19
+
20
+ override rewrite(rewriter: AstRewriter): AnyFromSource {
21
+ return rewriter.tableSource ? rewriter.tableSource(this) : this;
22
+ }
23
+ }
@@ -124,7 +124,7 @@ export const postgresAuthoringFieldPresets = {
124
124
  nativeType: 'timestamptz',
125
125
  },
126
126
  },
127
- temporal: temporalAuthoringPresets({
127
+ temporal: /* @__PURE__ */ temporalAuthoringPresets({
128
128
  codecId: 'pg/timestamptz@1',
129
129
  nativeType: 'timestamptz',
130
130
  }),
@@ -7,6 +7,7 @@ export {
7
7
  SQL_VARCHAR_CODEC_ID,
8
8
  } from '@prisma-next/sql-relational-core/ast';
9
9
  export const PG_TEXT_CODEC_ID = 'pg/text@1' as const;
10
+ export const PG_TEXT_ARRAY_CODEC_ID = 'pg/text-array@1' as const;
10
11
  export const PG_ENUM_CODEC_ID = 'pg/enum@1' as const;
11
12
  export const PG_CHAR_CODEC_ID = 'pg/char@1' as const;
12
13
  export const PG_VARCHAR_CODEC_ID = 'pg/varchar@1' as const;
@@ -71,6 +71,7 @@ import {
71
71
  PG_JSON_CODEC_ID,
72
72
  PG_JSONB_CODEC_ID,
73
73
  PG_NUMERIC_CODEC_ID,
74
+ PG_TEXT_ARRAY_CODEC_ID,
74
75
  PG_TEXT_CODEC_ID,
75
76
  PG_TIME_CODEC_ID,
76
77
  PG_TIMESTAMP_CODEC_ID,
@@ -99,6 +100,7 @@ const precisionParamsSchema = arktype({
99
100
  }) satisfies StandardSchemaV1<PrecisionParams>;
100
101
 
101
102
  const PG_TEXT_META = { db: { sql: { postgres: { nativeType: 'text' } } } } as const;
103
+ const PG_TEXT_ARRAY_META = { db: { sql: { postgres: { nativeType: 'text[]' } } } } as const;
102
104
  const PG_INT4_META = { db: { sql: { postgres: { nativeType: 'integer' } } } } as const;
103
105
  const PG_INT2_META = { db: { sql: { postgres: { nativeType: 'smallint' } } } } as const;
104
106
  const PG_INT8_META = { db: { sql: { postgres: { nativeType: 'bigint' } } } } as const;
@@ -160,6 +162,47 @@ export const pgTextColumn = () =>
160
162
  pgTextColumn satisfies ColumnHelperFor<PgTextDescriptor>;
161
163
  pgTextColumn satisfies ColumnHelperForStrict<PgTextDescriptor>;
162
164
 
165
+ /**
166
+ * Postgres `text[]` codec. Encode is an identity pass-through: the pg wire
167
+ * driver serialises a JS `string[]` to a Postgres array literal under the
168
+ * `$N::text[]` cast the renderer emits from this codec's `text[]` native type,
169
+ * and decode reads it back as a JS array. Used by the control plane to write
170
+ * the marker's `invariants` column. Not a user-facing scalar — it is not part
171
+ * of the authorable `CodecTypes` surface, only the runtime codec registry.
172
+ */
173
+ export class PgTextArrayCodec extends CodecImpl<
174
+ typeof PG_TEXT_ARRAY_CODEC_ID,
175
+ readonly ['equality'],
176
+ readonly string[],
177
+ readonly string[]
178
+ > {
179
+ async encode(value: readonly string[], _ctx: CodecCallContext): Promise<readonly string[]> {
180
+ return value;
181
+ }
182
+ async decode(wire: readonly string[], _ctx: CodecCallContext): Promise<readonly string[]> {
183
+ return wire;
184
+ }
185
+ encodeJson(value: readonly string[]): JsonValue {
186
+ return [...value];
187
+ }
188
+ decodeJson(json: JsonValue): readonly string[] {
189
+ return Array.isArray(json) ? json.map((entry) => String(entry)) : [];
190
+ }
191
+ }
192
+
193
+ export class PgTextArrayDescriptor extends CodecDescriptorImpl<void> {
194
+ override readonly codecId = PG_TEXT_ARRAY_CODEC_ID;
195
+ override readonly traits = ['equality'] as const;
196
+ override readonly targetTypes = ['text[]'] as const;
197
+ override readonly meta = PG_TEXT_ARRAY_META;
198
+ override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
199
+ override factory(): (ctx: CodecInstanceContext) => PgTextArrayCodec {
200
+ return () => new PgTextArrayCodec(this);
201
+ }
202
+ }
203
+
204
+ export const pgTextArrayDescriptor = new PgTextArrayDescriptor();
205
+
163
206
  export class PgInt4Codec extends CodecImpl<
164
207
  typeof PG_INT4_CODEC_ID,
165
208
  readonly ['equality', 'order', 'numeric'],
@@ -1036,4 +1079,5 @@ export const codecDescriptors: readonly AnyCodecDescriptor[] = [
1036
1079
  pgEnumDescriptor,
1037
1080
  pgJsonDescriptor,
1038
1081
  pgJsonbDescriptor,
1082
+ pgTextArrayDescriptor,
1039
1083
  ];
@@ -0,0 +1,72 @@
1
+ import {
2
+ type DdlColumn,
3
+ DdlNode,
4
+ type DdlTableConstraint,
5
+ } from '@prisma-next/sql-relational-core/ast';
6
+
7
+ export interface PostgresDdlVisitor<R> {
8
+ createTable(node: PostgresCreateTable): R;
9
+ createSchema(node: PostgresCreateSchema): R;
10
+ }
11
+
12
+ export abstract class PostgresDdlNode extends DdlNode {
13
+ abstract accept<R>(visitor: PostgresDdlVisitor<R>): R;
14
+ }
15
+
16
+ function freezeDdlColumns(columns: readonly DdlColumn[]): ReadonlyArray<DdlColumn> {
17
+ return Object.freeze([...columns]);
18
+ }
19
+
20
+ function freezeConstraints(
21
+ constraints: readonly DdlTableConstraint[] | undefined,
22
+ ): ReadonlyArray<DdlTableConstraint> | undefined {
23
+ return constraints ? Object.freeze([...constraints]) : undefined;
24
+ }
25
+
26
+ export class PostgresCreateTable extends PostgresDdlNode {
27
+ readonly kind = 'create-table' as const;
28
+ readonly table: string;
29
+ readonly schema: string | undefined;
30
+ readonly ifNotExists: boolean | undefined;
31
+ readonly columns: ReadonlyArray<DdlColumn>;
32
+ readonly constraints: ReadonlyArray<DdlTableConstraint> | undefined;
33
+
34
+ constructor(options: {
35
+ readonly table: string;
36
+ readonly schema?: string;
37
+ readonly ifNotExists?: boolean;
38
+ readonly columns: readonly DdlColumn[];
39
+ readonly constraints?: readonly DdlTableConstraint[];
40
+ }) {
41
+ super();
42
+ this.table = options.table;
43
+ this.schema = options.schema;
44
+ this.ifNotExists = options.ifNotExists;
45
+ this.columns = freezeDdlColumns(options.columns);
46
+ this.constraints = freezeConstraints(options.constraints);
47
+ this.freeze();
48
+ }
49
+
50
+ override accept<R>(visitor: PostgresDdlVisitor<R>): R {
51
+ return visitor.createTable(this);
52
+ }
53
+ }
54
+
55
+ export class PostgresCreateSchema extends PostgresDdlNode {
56
+ readonly kind = 'create-schema' as const;
57
+ readonly schema: string;
58
+ readonly ifNotExists: boolean | undefined;
59
+
60
+ constructor(options: { readonly schema: string; readonly ifNotExists?: boolean }) {
61
+ super();
62
+ this.schema = options.schema;
63
+ this.ifNotExists = options.ifNotExists;
64
+ this.freeze();
65
+ }
66
+
67
+ override accept<R>(visitor: PostgresDdlVisitor<R>): R {
68
+ return visitor.createSchema(this);
69
+ }
70
+ }
71
+
72
+ export type AnyPostgresDdlNode = PostgresCreateTable | PostgresCreateSchema;
@@ -0,0 +1,28 @@
1
+ // Runtime-safe slice of the postgres target descriptor metadata.
2
+ //
3
+ // This file exists separately from ./descriptor-meta on purpose: the runtime
4
+ // plane reads only `kind/familyId/targetId/id/version/capabilities` (plus the
5
+ // `__codecTypes` phantom). The `authoring` slot lives on the pack/control
6
+ // descriptor only, because authoring contributions are consumed at
7
+ // contract-construction time by `assembleAuthoringContributions` (control
8
+ // plane) and the PSL interpreter — never at runtime.
9
+ //
10
+ // Keeping the runtime closure free of the `./authoring` import is what lets
11
+ // the bundler tree-shake `@prisma-next/family-sql/control` (and its
12
+ // transitive `verify-sql-schema` chunk) out of the runtime entry. Do not
13
+ // add an `authoring` field here — if you need to, the pack/control meta in
14
+ // `./descriptor-meta` is the right place. See TML-2766 for context.
15
+ import type { CodecTypes } from '../exports/codec-types';
16
+
17
+ const postgresTargetDescriptorMetaRuntimeBase = {
18
+ kind: 'target',
19
+ familyId: 'sql',
20
+ targetId: 'postgres',
21
+ id: 'postgres',
22
+ version: '0.0.1',
23
+ capabilities: {},
24
+ } as const;
25
+
26
+ export const postgresTargetDescriptorMetaRuntime: typeof postgresTargetDescriptorMetaRuntimeBase & {
27
+ readonly __codecTypes?: CodecTypes;
28
+ } = postgresTargetDescriptorMetaRuntimeBase;
@@ -4,14 +4,11 @@ import {
4
4
  postgresAuthoringFieldPresets,
5
5
  postgresAuthoringTypes,
6
6
  } from './authoring';
7
+ import { postgresTargetDescriptorMetaRuntime } from './descriptor-meta-runtime';
7
8
 
8
9
  const postgresTargetDescriptorMetaBase = {
9
- kind: 'target',
10
- familyId: 'sql',
11
- targetId: 'postgres',
12
- id: 'postgres',
13
- version: '0.0.1',
14
- capabilities: {},
10
+ ...postgresTargetDescriptorMetaRuntime,
11
+ defaultNamespaceId: 'public',
15
12
  authoring: {
16
13
  type: postgresAuthoringTypes,
17
14
  field: postgresAuthoringFieldPresets,
@@ -0,0 +1,234 @@
1
+ import type { Contract } from '@prisma-next/contract/types';
2
+ import type { ControlPolicySubject } from '@prisma-next/family-sql/control';
3
+ import type { SchemaIssue } from '@prisma-next/framework-components/control';
4
+ import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
5
+ import {
6
+ isPostgresEnumStorageEntry,
7
+ type SqlStorage,
8
+ storageTableAt,
9
+ } from '@prisma-next/sql-contract/types';
10
+ import { ifDefined } from '@prisma-next/utils/defined';
11
+ import { isPostgresSchema } from '../postgres-schema';
12
+ import type { PostgresOpFactoryCall } from './op-factory-call';
13
+
14
+ /**
15
+ * Factory calls that create a whole, previously-absent top-level storage
16
+ * object. Used to decide whether `tolerated` permits a call (it only allows
17
+ * creating absent objects, never modifying existing ones).
18
+ *
19
+ * Deliberately an explicit, closed set rather than a `factoryName`
20
+ * create/alter/drop classification: it answers exactly one yes/no question
21
+ * and is fail-closed. Any call not listed here — including future or
22
+ * extension-contributed factories — is treated as NOT object-creation, so it
23
+ * is suppressed under `tolerated` rather than permissively emitted.
24
+ */
25
+ const OBJECT_CREATION_FACTORIES: ReadonlySet<string> = new Set<string>([
26
+ 'createTable',
27
+ 'createEnumType',
28
+ 'createSchema',
29
+ ]);
30
+
31
+ function createsNewTopLevelObject(call: PostgresOpFactoryCall): boolean {
32
+ return OBJECT_CREATION_FACTORIES.has(call.factoryName);
33
+ }
34
+
35
+ function ddlSchemaNameForNamespace(contract: Contract<SqlStorage>, namespaceId: string): string {
36
+ const namespace = contract.storage.namespaces[namespaceId];
37
+ return isPostgresSchema(namespace) ? namespace.ddlSchemaName(contract.storage) : namespaceId;
38
+ }
39
+
40
+ function resolveNamespaceIdForTable(
41
+ contract: Contract<SqlStorage>,
42
+ tableName: string,
43
+ ddlSchemaName: string | undefined,
44
+ ): string {
45
+ for (const namespaceId of Object.keys(contract.storage.namespaces)) {
46
+ const table = storageTableAt(contract.storage, namespaceId, tableName);
47
+ if (!table) continue;
48
+ if (
49
+ ddlSchemaName === undefined ||
50
+ ddlSchemaNameForNamespace(contract, namespaceId) === ddlSchemaName
51
+ ) {
52
+ return namespaceId;
53
+ }
54
+ }
55
+ return UNBOUND_NAMESPACE_ID;
56
+ }
57
+
58
+ function resolveNamespaceIdForDdlSchema(
59
+ contract: Contract<SqlStorage>,
60
+ ddlSchemaName: string,
61
+ ): string {
62
+ for (const namespaceId of Object.keys(contract.storage.namespaces)) {
63
+ const ns = contract.storage.namespaces[namespaceId];
64
+ if (isPostgresSchema(ns) && ns.ddlSchemaName(contract.storage) === ddlSchemaName) {
65
+ return namespaceId;
66
+ }
67
+ if (namespaceId === ddlSchemaName) {
68
+ return namespaceId;
69
+ }
70
+ }
71
+ return UNBOUND_NAMESPACE_ID;
72
+ }
73
+
74
+ interface PostgresCallFields {
75
+ readonly schemaName?: string;
76
+ readonly tableName?: string;
77
+ readonly columnName?: string;
78
+ readonly typeName?: string;
79
+ }
80
+
81
+ function postgresCallFields(call: PostgresOpFactoryCall): PostgresCallFields {
82
+ return {
83
+ ...ifDefined('schemaName', 'schemaName' in call ? call.schemaName : undefined),
84
+ ...ifDefined('tableName', 'tableName' in call ? call.tableName : undefined),
85
+ ...ifDefined('columnName', 'columnName' in call ? call.columnName : undefined),
86
+ ...ifDefined('typeName', 'typeName' in call ? call.typeName : undefined),
87
+ };
88
+ }
89
+
90
+ export function formatPostgresControlPolicySubjectLabel(
91
+ factoryName: string,
92
+ subject: ControlPolicySubject | undefined,
93
+ contract: Contract<SqlStorage>,
94
+ ): string {
95
+ if (subject?.table) {
96
+ const ddlSchema = ddlSchemaNameForNamespace(contract, subject.namespaceId);
97
+ return `${factoryName}(${ddlSchema}.${subject.table})`;
98
+ }
99
+ if (subject?.typeName) {
100
+ const ddlSchema = ddlSchemaNameForNamespace(contract, subject.namespaceId);
101
+ return `${factoryName}(${ddlSchema}.${subject.typeName})`;
102
+ }
103
+ return factoryName;
104
+ }
105
+
106
+ export function resolvePostgresCallControlPolicySubject(
107
+ call: PostgresOpFactoryCall,
108
+ contract: Contract<SqlStorage>,
109
+ ): ControlPolicySubject | undefined {
110
+ const callFields = postgresCallFields(call);
111
+ const createsNewObject = createsNewTopLevelObject(call);
112
+
113
+ if (call.factoryName === 'createSchema' && callFields.schemaName) {
114
+ return {
115
+ namespaceId: resolveNamespaceIdForDdlSchema(contract, callFields.schemaName),
116
+ createsNewObject,
117
+ };
118
+ }
119
+
120
+ if (callFields.typeName && call.factoryName !== 'addColumn') {
121
+ const namespaceId = callFields.schemaName
122
+ ? resolveNamespaceIdForDdlSchema(contract, callFields.schemaName)
123
+ : UNBOUND_NAMESPACE_ID;
124
+ const ns = contract.storage.namespaces[namespaceId];
125
+ const rawEnum = isPostgresSchema(ns) ? ns.entries.type[callFields.typeName] : undefined;
126
+ const controlPolicy = isPostgresEnumStorageEntry(rawEnum) ? rawEnum.control : undefined;
127
+ return {
128
+ namespaceId,
129
+ ...ifDefined('explicitNodeControlPolicy', controlPolicy),
130
+ typeName: callFields.typeName,
131
+ createsNewObject,
132
+ };
133
+ }
134
+
135
+ if (callFields.tableName) {
136
+ const namespaceId = resolveNamespaceIdForTable(
137
+ contract,
138
+ callFields.tableName,
139
+ callFields.schemaName,
140
+ );
141
+ const table = storageTableAt(contract.storage, namespaceId, callFields.tableName);
142
+ const tableControlPolicy = table?.control;
143
+ return {
144
+ namespaceId,
145
+ ...ifDefined('explicitNodeControlPolicy', tableControlPolicy),
146
+ table: callFields.tableName,
147
+ ...ifDefined('column', callFields.columnName),
148
+ createsNewObject,
149
+ };
150
+ }
151
+
152
+ if (callFields.schemaName) {
153
+ return {
154
+ namespaceId: resolveNamespaceIdForDdlSchema(contract, callFields.schemaName),
155
+ createsNewObject,
156
+ };
157
+ }
158
+
159
+ return undefined;
160
+ }
161
+
162
+ /**
163
+ * Issue kinds that describe the absence of a whole, top-level Postgres
164
+ * object — the same kinds `createsNewTopLevelObject` recognises for calls.
165
+ * Used by {@link resolvePostgresIssueCreationFactoryName} to decide whether
166
+ * a `tolerated` subject permits the issue to flow into the planner
167
+ * (create-if-absent) and to seed the suppressed-subject warning's
168
+ * `factoryName` when the planner is skipped.
169
+ */
170
+ const POSTGRES_ISSUE_CREATION_FACTORY: Readonly<Record<string, string>> = Object.freeze({
171
+ missing_schema: 'createSchema',
172
+ missing_table: 'createTable',
173
+ type_missing: 'createEnumType',
174
+ });
175
+
176
+ export function resolvePostgresIssueCreationFactoryName(issue: SchemaIssue): string | undefined {
177
+ return POSTGRES_ISSUE_CREATION_FACTORY[issue.kind];
178
+ }
179
+
180
+ /**
181
+ * Resolve the control-policy subject coordinate for a single
182
+ * {@link SchemaIssue}. Mirrors the resolution `resolvePostgresCallControlPolicySubject`
183
+ * performs for a generated DDL call, but works *off the issue* — so the
184
+ * planner can partition issues by effective policy before the diff engine
185
+ * runs. `createsNewObject` is derived from the issue's kind: schema/table/
186
+ * type-missing issues describe a brand-new top-level object; everything else
187
+ * touches an existing object.
188
+ *
189
+ * An `extra_table` issue carries no contract namespace coordinate (the table
190
+ * isn't in any contract namespace), so the subject's `namespaceId` falls
191
+ * back to {@link UNBOUND_NAMESPACE_ID}; the call-side resolver does the same
192
+ * for the `DropTableCall` it produces.
193
+ */
194
+ export function resolvePostgresIssueControlPolicySubject(
195
+ issue: SchemaIssue,
196
+ contract: Contract<SqlStorage>,
197
+ ): ControlPolicySubject | undefined {
198
+ const createsNewObject = POSTGRES_ISSUE_CREATION_FACTORY[issue.kind] !== undefined;
199
+
200
+ if (issue.kind === 'missing_schema' && issue.namespaceId) {
201
+ return { namespaceId: issue.namespaceId, createsNewObject };
202
+ }
203
+
204
+ if ('typeName' in issue && issue.typeName) {
205
+ const namespaceId =
206
+ 'namespaceId' in issue && issue.namespaceId ? issue.namespaceId : UNBOUND_NAMESPACE_ID;
207
+ const ns = contract.storage.namespaces[namespaceId];
208
+ const rawEnum = isPostgresSchema(ns) ? ns.entries.type[issue.typeName] : undefined;
209
+ const controlPolicy = isPostgresEnumStorageEntry(rawEnum) ? rawEnum.control : undefined;
210
+ return {
211
+ namespaceId,
212
+ ...ifDefined('explicitNodeControlPolicy', controlPolicy),
213
+ typeName: issue.typeName,
214
+ createsNewObject,
215
+ };
216
+ }
217
+
218
+ if ('table' in issue && issue.table) {
219
+ const namespaceId =
220
+ 'namespaceId' in issue && issue.namespaceId
221
+ ? issue.namespaceId
222
+ : resolveNamespaceIdForTable(contract, issue.table, undefined);
223
+ const table = storageTableAt(contract.storage, namespaceId, issue.table);
224
+ return {
225
+ namespaceId,
226
+ ...ifDefined('explicitNodeControlPolicy', table?.control),
227
+ table: issue.table,
228
+ ...ifDefined('column', 'column' in issue ? issue.column : undefined),
229
+ createsNewObject,
230
+ };
231
+ }
232
+
233
+ return undefined;
234
+ }
@@ -14,17 +14,25 @@ import { isPostgresSchema } from '../postgres-schema';
14
14
 
15
15
  /**
16
16
  * Codec-typed enum entry shape stored under
17
- * `schema.annotations.pg.storageTypes[(schemaName, nativeType)]`.
17
+ * `schema.annotations.pg.enumTypes[schemaName][nativeType]`.
18
18
  */
19
19
  interface PgStorageTypeEntry {
20
20
  readonly codecId?: string;
21
21
  readonly typeParams?: { readonly values?: unknown };
22
22
  }
23
23
 
24
+ /**
25
+ * Live enum types keyed by `(schemaName, nativeType)` as a nested map, so two
26
+ * schemas sharing a native enum name stay distinct without packing the pair
27
+ * into a string. This is the same `(namespace, entityName)` coordinate the
28
+ * contract side addresses entities by.
29
+ */
30
+ type PgEnumTypesMap = Readonly<Record<string, Readonly<Record<string, PgStorageTypeEntry>>>>;
31
+
24
32
  /** Postgres-specific subtree on family `SqlSchemaIR.annotations`. */
25
33
  export interface PostgresSchemaIrAnnotations {
26
34
  readonly schema?: string;
27
- readonly storageTypes?: Readonly<Record<string, PgStorageTypeEntry>>;
35
+ readonly enumTypes?: PgEnumTypesMap;
28
36
  }
29
37
 
30
38
  function readOptionalString(value: unknown): string | undefined {
@@ -50,20 +58,27 @@ function readPgStorageTypeEntry(value: unknown): PgStorageTypeEntry | undefined
50
58
  };
51
59
  }
52
60
 
53
- function readPgStorageTypesMap(
54
- value: unknown,
55
- ): Readonly<Record<string, PgStorageTypeEntry>> | undefined {
61
+ function readPgEnumTypesMap(value: unknown): PgEnumTypesMap | undefined {
56
62
  if (value === null || typeof value !== 'object' || Array.isArray(value)) {
57
63
  return undefined;
58
64
  }
59
- const entries: Record<string, PgStorageTypeEntry> = {};
60
- for (const [key, entryValue] of Object.entries(value)) {
61
- const entry = readPgStorageTypeEntry(entryValue);
62
- if (entry !== undefined) {
63
- entries[key] = entry;
65
+ const bySchema: Record<string, Record<string, PgStorageTypeEntry>> = {};
66
+ for (const [schemaName, byTypeRaw] of Object.entries(value)) {
67
+ if (byTypeRaw === null || typeof byTypeRaw !== 'object' || Array.isArray(byTypeRaw)) {
68
+ continue;
69
+ }
70
+ const byType: Record<string, PgStorageTypeEntry> = {};
71
+ for (const [nativeType, entryValue] of Object.entries(byTypeRaw)) {
72
+ const entry = readPgStorageTypeEntry(entryValue);
73
+ if (entry !== undefined) {
74
+ byType[nativeType] = entry;
75
+ }
76
+ }
77
+ if (Object.keys(byType).length > 0) {
78
+ bySchema[schemaName] = byType;
64
79
  }
65
80
  }
66
- return Object.keys(entries).length > 0 ? entries : undefined;
81
+ return Object.keys(bySchema).length > 0 ? bySchema : undefined;
67
82
  }
68
83
 
69
84
  /**
@@ -78,25 +93,13 @@ export function readPostgresSchemaIrAnnotations(schema: SqlSchemaIR): PostgresSc
78
93
  return {};
79
94
  }
80
95
  const schemaField = readOptionalString(Reflect.get(raw, 'schema'));
81
- const storageTypes = readPgStorageTypesMap(Reflect.get(raw, 'storageTypes'));
96
+ const enumTypes = readPgEnumTypesMap(Reflect.get(raw, 'enumTypes'));
82
97
  return {
83
98
  ...(schemaField !== undefined ? { schema: schemaField } : {}),
84
- ...(storageTypes !== undefined ? { storageTypes } : {}),
99
+ ...(enumTypes !== undefined ? { enumTypes } : {}),
85
100
  };
86
101
  }
87
102
 
88
- /**
89
- * Separator for `(schemaName, nativeType)` keys in introspected
90
- * `schema.annotations.pg.storageTypes`. NUL cannot appear in Postgres
91
- * identifiers, so the pair is unambiguous.
92
- */
93
- export const ENUM_STORAGE_KEY_SEP = '\u0000';
94
-
95
- /** Builds the schema-qualified storageTypes map key for a live Postgres enum. */
96
- export function enumStorageCompoundKey(schemaName: string, nativeType: string): string {
97
- return `${schemaName}${ENUM_STORAGE_KEY_SEP}${nativeType}`;
98
- }
99
-
100
103
  /**
101
104
  * Resolves the live-schema name a namespace's enums are introspected under,
102
105
  * for keying `readExistingEnumValues` lookups. The unbound namespace's
@@ -149,9 +152,10 @@ export type EnumDiff =
149
152
 
150
153
  /**
151
154
  * Reads existing enum values for `(schemaName, nativeType)` from the
152
- * Postgres-introspected `schema.annotations.pg.storageTypes` map.
155
+ * Postgres-introspected `schema.annotations.pg.enumTypes` map, addressed by
156
+ * the `(schema, nativeType)` coordinate.
153
157
  *
154
- * Schema IR's `storageTypes` slots are always codec-typed
158
+ * Schema IR's enum entries are always codec-typed
155
159
  * (`{codecId: PG_ENUM_CODEC_ID, typeParams.values}`): the introspector
156
160
  * writes that shape, and the Contract→Schema IR projector resolves
157
161
  * `PostgresEnumType` instances down to the same codec-typed triple before
@@ -165,8 +169,8 @@ export function readExistingEnumValues(
165
169
  schemaName: string,
166
170
  nativeType: string,
167
171
  ): readonly string[] | null {
168
- const storageTypes = readPostgresSchemaIrAnnotations(schema).storageTypes;
169
- const existing = storageTypes?.[enumStorageCompoundKey(schemaName, nativeType)];
172
+ const enumTypes = readPostgresSchemaIrAnnotations(schema).enumTypes;
173
+ const existing = enumTypes?.[schemaName]?.[nativeType];
170
174
  if (!existing || existing.codecId !== PG_ENUM_CODEC_ID) {
171
175
  return null;
172
176
  }