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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/dist/authoring-BLkL4fFG.mjs +528 -0
  2. package/dist/authoring-BLkL4fFG.mjs.map +1 -0
  3. package/dist/canonicalize-CAbXtVtB.d.mts +37 -0
  4. package/dist/canonicalize-CAbXtVtB.d.mts.map +1 -0
  5. package/dist/{codec-ids-CnXu9Qy3.d.mts → codec-ids-BzrFF-I4.d.mts} +3 -2
  6. package/dist/codec-ids-BzrFF-I4.d.mts.map +1 -0
  7. package/dist/{codec-ids-BvytN2P8.mjs → codec-ids-C_-Hj6bL.mjs} +3 -2
  8. package/dist/codec-ids-C_-Hj6bL.mjs.map +1 -0
  9. package/dist/codec-ids.d.mts +2 -2
  10. package/dist/codec-ids.mjs +2 -2
  11. package/dist/{codec-types-DHCkwPKE.d.mts → codec-types-BiIWziRO.d.mts} +3 -2
  12. package/dist/codec-types-BiIWziRO.d.mts.map +1 -0
  13. package/dist/codec-types.d.mts +1 -1
  14. package/dist/codecs-CkVQrZ4G.mjs +913 -0
  15. package/dist/codecs-CkVQrZ4G.mjs.map +1 -0
  16. package/dist/{codecs--0A5_4Bq.d.mts → codecs-Cm-nS4mQ.d.mts} +111 -4
  17. package/dist/codecs-Cm-nS4mQ.d.mts.map +1 -0
  18. package/dist/codecs.d.mts +2 -2
  19. package/dist/codecs.mjs +3 -757
  20. package/dist/codecs.mjs.map +1 -1
  21. package/dist/contract-free.d.mts +33 -3
  22. package/dist/contract-free.d.mts.map +1 -1
  23. package/dist/contract-free.mjs +4 -4
  24. package/dist/control-policy-BpmChlAK.mjs +1151 -0
  25. package/dist/control-policy-BpmChlAK.mjs.map +1 -0
  26. package/dist/control.d.mts +2 -2
  27. package/dist/control.d.mts.map +1 -1
  28. package/dist/control.mjs +901 -35
  29. package/dist/control.mjs.map +1 -1
  30. package/dist/data-transform-BOWpliq8.mjs.map +1 -1
  31. package/dist/{data-transform-DDgWdB5o.d.mts → data-transform-DPzwBMhW.d.mts} +3 -3
  32. package/dist/{data-transform-DDgWdB5o.d.mts.map → data-transform-DPzwBMhW.d.mts.map} +1 -1
  33. package/dist/data-transform.d.mts +1 -1
  34. package/dist/{ddl-QDyOSeLc.mjs → ddl-BovUVFVi.mjs} +77 -6
  35. package/dist/ddl-BovUVFVi.mjs.map +1 -0
  36. package/dist/ddl.d.mts +3 -2
  37. package/dist/ddl.mjs +2 -2
  38. package/dist/default-normalizer.d.mts +1 -1
  39. package/dist/default-normalizer.d.mts.map +1 -1
  40. package/dist/default-normalizer.mjs +247 -1
  41. package/dist/default-normalizer.mjs.map +1 -0
  42. package/dist/descriptor-meta-C1T4BXJ8.mjs +22 -0
  43. package/dist/descriptor-meta-C1T4BXJ8.mjs.map +1 -0
  44. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs +12 -0
  45. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs.map +1 -0
  46. package/dist/diff-database-schema-RMwnSOnz.mjs +298 -0
  47. package/dist/diff-database-schema-RMwnSOnz.mjs.map +1 -0
  48. package/dist/diff-database-schema.d.mts +46 -0
  49. package/dist/diff-database-schema.d.mts.map +1 -0
  50. package/dist/diff-database-schema.mjs +2 -0
  51. package/dist/errors-DO-w0EUS.mjs +35 -0
  52. package/dist/errors-DO-w0EUS.mjs.map +1 -0
  53. package/dist/errors.d.mts +11 -9
  54. package/dist/errors.d.mts.map +1 -1
  55. package/dist/errors.mjs +1 -1
  56. package/dist/issue-planner.d.mts +35 -11
  57. package/dist/issue-planner.d.mts.map +1 -1
  58. package/dist/issue-planner.mjs +2 -2
  59. package/dist/migration.d.mts +5 -5
  60. package/dist/migration.d.mts.map +1 -1
  61. package/dist/migration.mjs +4 -4
  62. package/dist/namespace-ids-xtp_ZY86.mjs +7 -0
  63. package/dist/namespace-ids-xtp_ZY86.mjs.map +1 -0
  64. package/dist/native-type-normalizer.mjs +37 -1
  65. package/dist/native-type-normalizer.mjs.map +1 -0
  66. package/dist/nodes-B815pj_X.mjs +162 -0
  67. package/dist/nodes-B815pj_X.mjs.map +1 -0
  68. package/dist/nodes-BtQyZha6.d.mts +146 -0
  69. package/dist/nodes-BtQyZha6.d.mts.map +1 -0
  70. package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-CI00nS4z.mjs} +300 -31
  71. package/dist/op-factory-call-CI00nS4z.mjs.map +1 -0
  72. package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-D6_7-7Vc.d.mts} +68 -15
  73. package/dist/op-factory-call-D6_7-7Vc.d.mts.map +1 -0
  74. package/dist/op-factory-call.d.mts +2 -2
  75. package/dist/op-factory-call.mjs +2 -2
  76. package/dist/pack.d.mts +287 -3
  77. package/dist/pack.d.mts.map +1 -1
  78. package/dist/pack.mjs +1 -1
  79. package/dist/planner-CAHZN1Ez.mjs +422 -0
  80. package/dist/planner-CAHZN1Ez.mjs.map +1 -0
  81. package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-B8Nn6nHN.mjs} +12 -27
  82. package/dist/planner-ddl-builders-B8Nn6nHN.mjs.map +1 -0
  83. package/dist/planner-ddl-builders.d.mts +4 -6
  84. package/dist/planner-ddl-builders.d.mts.map +1 -1
  85. package/dist/planner-ddl-builders.mjs +2 -2
  86. package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -1
  87. package/dist/planner-identity-values.d.mts +8 -2
  88. package/dist/planner-identity-values.d.mts.map +1 -1
  89. package/dist/planner-identity-values.mjs +2 -2
  90. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-a-tjfKsA.d.mts} +4 -4
  91. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-a-tjfKsA.d.mts.map} +1 -1
  92. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-flkG4Y7n.mjs} +3 -3
  93. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-flkG4Y7n.mjs.map} +1 -1
  94. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  95. package/dist/planner-produced-postgres-migration.mjs +1 -1
  96. package/dist/{planner-sql-checks-jqUUGyQR.mjs → planner-sql-checks-C1-Kk3Eu.mjs} +2 -2
  97. package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-C1-Kk3Eu.mjs.map} +1 -1
  98. package/dist/planner-sql-checks.d.mts +2 -2
  99. package/dist/planner-sql-checks.d.mts.map +1 -1
  100. package/dist/planner-sql-checks.mjs +1 -1
  101. package/dist/{planner-target-details-CIY6tLeo.d.mts → planner-target-details-HkP4RrRO.d.mts} +2 -2
  102. package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -0
  103. package/dist/planner-target-details.d.mts +1 -1
  104. package/dist/planner.d.mts +72 -17
  105. package/dist/planner.d.mts.map +1 -1
  106. package/dist/planner.mjs +3 -2
  107. package/dist/postgres-contract-view-C9j5cqP0.d.mts +34 -0
  108. package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +1 -0
  109. package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-DWLNQbdR.mjs} +45 -41
  110. package/dist/postgres-contract-view-DWLNQbdR.mjs.map +1 -0
  111. package/dist/postgres-database-schema-node-BVdOffjC.d.mts +221 -0
  112. package/dist/postgres-database-schema-node-BVdOffjC.d.mts.map +1 -0
  113. package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-Bzzi0Asr.d.mts} +28 -9
  114. package/dist/postgres-migration-Bzzi0Asr.d.mts.map +1 -0
  115. package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-C92swCzd.mjs} +53 -45
  116. package/dist/postgres-migration-C92swCzd.mjs.map +1 -0
  117. package/dist/postgres-native-enum-xdiqmBf_.mjs +41 -0
  118. package/dist/postgres-native-enum-xdiqmBf_.mjs.map +1 -0
  119. package/dist/postgres-rls-policy--CSddvMR.d.mts +52 -0
  120. package/dist/postgres-rls-policy--CSddvMR.d.mts.map +1 -0
  121. package/dist/postgres-role-schema-node-BmCboEa_.mjs +198 -0
  122. package/dist/postgres-role-schema-node-BmCboEa_.mjs.map +1 -0
  123. package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-COEca21H.mjs} +188 -10
  124. package/dist/postgres-schema-COEca21H.mjs.map +1 -0
  125. package/dist/postgres-schema-DsrtYp2v.d.mts +269 -0
  126. package/dist/postgres-schema-DsrtYp2v.d.mts.map +1 -0
  127. package/dist/postgres-table-schema-node-9FCtCUz2.mjs +153 -0
  128. package/dist/postgres-table-schema-node-9FCtCUz2.mjs.map +1 -0
  129. package/dist/render-ops.d.mts +1 -1
  130. package/dist/{render-typescript-KMgosran.mjs → render-typescript-7yqILcwr.mjs} +45 -16
  131. package/dist/render-typescript-7yqILcwr.mjs.map +1 -0
  132. package/dist/render-typescript.mjs +1 -1
  133. package/dist/resolve-ddl-schema-ZkKxt2Fm.mjs +22 -0
  134. package/dist/resolve-ddl-schema-ZkKxt2Fm.mjs.map +1 -0
  135. package/dist/rls-canonicalize.d.mts +20 -0
  136. package/dist/rls-canonicalize.d.mts.map +1 -0
  137. package/dist/rls-canonicalize.mjs +2 -0
  138. package/dist/runtime.d.mts +6 -8
  139. package/dist/runtime.d.mts.map +1 -1
  140. package/dist/runtime.mjs +3 -3
  141. package/dist/runtime.mjs.map +1 -1
  142. package/dist/schema-ir-annotations.d.mts +15 -0
  143. package/dist/schema-ir-annotations.d.mts.map +1 -0
  144. package/dist/schema-ir-annotations.mjs +2 -0
  145. package/dist/types.d.mts +4 -140
  146. package/dist/types.mjs +5 -2
  147. package/dist/wire-name-rHHtr1h0.mjs +75 -0
  148. package/dist/wire-name-rHHtr1h0.mjs.map +1 -0
  149. package/package.json +23 -17
  150. package/src/contract-free/checks.ts +73 -0
  151. package/src/contract-free/ddl.ts +71 -1
  152. package/src/core/authoring.ts +467 -2
  153. package/src/core/codec-ids.ts +1 -0
  154. package/src/core/codec-type-map.ts +2 -0
  155. package/src/core/codecs.ts +180 -1
  156. package/src/core/ddl/nodes.ts +141 -2
  157. package/src/core/default-normalizer.ts +122 -2
  158. package/src/core/descriptor-meta.ts +10 -1
  159. package/src/core/entity-kinds.ts +41 -0
  160. package/src/core/errors.ts +14 -12
  161. package/src/core/migrations/bound-schema.ts +10 -0
  162. package/src/core/migrations/column-ddl-rendering.ts +117 -0
  163. package/src/core/migrations/contract-to-postgres-database-schema-node.ts +160 -0
  164. package/src/core/migrations/control-policy.ts +126 -44
  165. package/src/core/migrations/diff-database-schema.ts +253 -0
  166. package/src/core/migrations/issue-planner.ts +692 -652
  167. package/src/core/migrations/op-factory-call.ts +189 -21
  168. package/src/core/migrations/operations/columns.ts +24 -12
  169. package/src/core/migrations/operations/constraints.ts +1 -1
  170. package/src/core/migrations/operations/data-transform.ts +6 -0
  171. package/src/core/migrations/operations/dependencies.ts +2 -1
  172. package/src/core/migrations/operations/rls.ts +187 -0
  173. package/src/core/migrations/operations/shared.ts +0 -30
  174. package/src/core/migrations/planner-ddl-builders.ts +20 -58
  175. package/src/core/migrations/planner-identity-values.ts +1 -1
  176. package/src/core/migrations/planner-recipes.ts +31 -13
  177. package/src/core/migrations/planner-sql-checks.ts +1 -1
  178. package/src/core/migrations/planner-strategies.ts +248 -216
  179. package/src/core/migrations/planner-target-details.ts +3 -1
  180. package/src/core/migrations/planner.ts +386 -59
  181. package/src/core/migrations/postgres-migration.ts +70 -86
  182. package/src/core/migrations/render-typescript.ts +42 -15
  183. package/src/core/migrations/resolve-ddl-schema.ts +26 -0
  184. package/src/core/migrations/runner.ts +10 -16
  185. package/src/core/migrations/verify-postgres-namespaces.ts +47 -31
  186. package/src/core/namespace-ids.ts +3 -0
  187. package/src/core/postgres-contract-serializer.ts +46 -71
  188. package/src/core/postgres-contract-view.ts +48 -0
  189. package/src/core/postgres-native-enum.ts +51 -0
  190. package/src/core/postgres-rls-enablement.ts +34 -0
  191. package/src/core/postgres-rls-policy.ts +64 -0
  192. package/src/core/postgres-role.ts +59 -0
  193. package/src/core/postgres-schema-verifier.ts +10 -7
  194. package/src/core/postgres-schema.ts +64 -15
  195. package/src/core/postgres-validators.ts +34 -0
  196. package/src/core/psl-infer/infer-psl-contract.ts +1326 -0
  197. package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
  198. package/src/core/psl-infer/postgres-type-map.ts +128 -0
  199. package/src/core/rls/canonicalize.ts +48 -0
  200. package/src/core/rls/wire-name.ts +33 -0
  201. package/src/core/schema-ir/postgres-database-schema-node.ts +61 -0
  202. package/src/core/schema-ir/postgres-namespace-schema-node.ts +79 -0
  203. package/src/core/schema-ir/postgres-policy-schema-node.ts +90 -0
  204. package/src/core/schema-ir/postgres-role-schema-node.ts +65 -0
  205. package/src/core/schema-ir/postgres-table-schema-node.ts +140 -0
  206. package/src/core/schema-ir/schema-node-kinds.ts +113 -0
  207. package/src/exports/codecs.ts +3 -0
  208. package/src/exports/contract-free.ts +11 -1
  209. package/src/exports/control.ts +27 -33
  210. package/src/exports/ddl.ts +6 -0
  211. package/src/exports/diff-database-schema.ts +7 -0
  212. package/src/exports/issue-planner.ts +1 -1
  213. package/src/exports/migration.ts +1 -0
  214. package/src/exports/op-factory-call.ts +1 -0
  215. package/src/exports/planner-ddl-builders.ts +0 -2
  216. package/src/exports/planner-identity-values.ts +4 -1
  217. package/src/exports/planner.ts +1 -0
  218. package/src/exports/rls-canonicalize.ts +7 -0
  219. package/src/exports/runtime.ts +1 -0
  220. package/src/exports/schema-ir-annotations.ts +1 -0
  221. package/src/exports/types.ts +34 -0
  222. package/dist/codec-ids-BvytN2P8.mjs.map +0 -1
  223. package/dist/codec-ids-CnXu9Qy3.d.mts.map +0 -1
  224. package/dist/codec-types-DHCkwPKE.d.mts.map +0 -1
  225. package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
  226. package/dist/ddl-QDyOSeLc.mjs.map +0 -1
  227. package/dist/default-normalizer-DyyCHQWs.mjs +0 -131
  228. package/dist/default-normalizer-DyyCHQWs.mjs.map +0 -1
  229. package/dist/descriptor-meta-CpGygXpI.mjs +0 -140
  230. package/dist/descriptor-meta-CpGygXpI.mjs.map +0 -1
  231. package/dist/errors-CUk87ByX.mjs +0 -33
  232. package/dist/errors-CUk87ByX.mjs.map +0 -1
  233. package/dist/issue-planner-DL6g3CmE.mjs +0 -824
  234. package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
  235. package/dist/native-type-normalizer-Bc9XJzWC.mjs +0 -38
  236. package/dist/native-type-normalizer-Bc9XJzWC.mjs.map +0 -1
  237. package/dist/nodes-Bbhs2rwj.mjs +0 -76
  238. package/dist/nodes-Bbhs2rwj.mjs.map +0 -1
  239. package/dist/nodes-pLeLgdis.d.mts +0 -67
  240. package/dist/nodes-pLeLgdis.d.mts.map +0 -1
  241. package/dist/op-factory-call-D_p5vxwt.mjs.map +0 -1
  242. package/dist/op-factory-call-DmQEc3XV.d.mts.map +0 -1
  243. package/dist/planner-Bs_baQax.mjs +0 -324
  244. package/dist/planner-Bs_baQax.mjs.map +0 -1
  245. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +0 -1
  246. package/dist/planner-target-details-CIY6tLeo.d.mts.map +0 -1
  247. package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +0 -1
  248. package/dist/postgres-migration-B5jKrXv3.mjs.map +0 -1
  249. package/dist/postgres-migration-Y4YBJqkS.d.mts.map +0 -1
  250. package/dist/postgres-schema-COGZ1ark.mjs.map +0 -1
  251. package/dist/render-typescript-KMgosran.mjs.map +0 -1
  252. package/dist/types.d.mts.map +0 -1
  253. package/src/core/postgres-enum-type-schema.ts +0 -17
@@ -1,13 +1,344 @@
1
1
  import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';
2
2
  import type {
3
+ AuthoringEntityContext,
4
+ AuthoringEntityTypeFactoryOutput,
3
5
  AuthoringEntityTypeNamespace,
4
6
  AuthoringFieldNamespace,
7
+ AuthoringModelAttributeContext,
8
+ AuthoringModelAttributeDescriptorNamespace,
9
+ AuthoringPslBlockDescriptorNamespace,
5
10
  AuthoringTypeNamespace,
11
+ PslExtensionBlock,
6
12
  } from '@prisma-next/framework-components/authoring';
13
+ import { modelAttribute } from '@prisma-next/psl-parser';
14
+ import type { SqlValueSetDerivingEntityTypeOutput } from '@prisma-next/sql-contract/value-set-derivation-hook';
15
+ import { ifDefined } from '@prisma-next/utils/defined';
16
+ import { PG_ENUM_CODEC_ID } from './codec-ids';
17
+ import { PostgresNativeEnum } from './postgres-native-enum';
18
+ import { PostgresRlsEnablement, type PostgresRlsEnablementInput } from './postgres-rls-enablement';
19
+ import { PostgresRlsPolicy, type RlsPolicyOperation } from './postgres-rls-policy';
20
+ import { PostgresRole, type PostgresRoleInput } from './postgres-role';
21
+ import {
22
+ PostgresNativeEnumSchema,
23
+ PostgresRlsEnablementSchema,
24
+ PostgresRlsPolicySchema,
25
+ PostgresRoleSchema,
26
+ } from './postgres-validators';
27
+ import { computeContentHash, normalizePredicate } from './rls/canonicalize';
28
+ import { formatRlsPolicyWireName } from './rls/wire-name';
7
29
 
8
- export const postgresAuthoringTypes = {} as const satisfies AuthoringTypeNamespace;
30
+ /**
31
+ * `pg.enum(<ref>)` registers as an ordinary type constructor whose sole
32
+ * positional argument names a `native_enum` entity instead of carrying a
33
+ * literal value. The interpreter resolves the ref to the `native_enum`
34
+ * entity generically (driven by `entityRefArg`); the `pg/enum@1` codec
35
+ * descriptor's `columnFromEntity` hook (see `codecs.ts`) converts that
36
+ * entity into the column's `typeParams` and native type.
37
+ */
38
+ export const postgresAuthoringTypes = {
39
+ pg: {
40
+ enum: {
41
+ kind: 'typeConstructor',
42
+ entityRefArg: { index: 0, entityKind: 'native_enum' },
43
+ output: {
44
+ codecId: PG_ENUM_CODEC_ID,
45
+ },
46
+ },
47
+ },
48
+ } as const satisfies AuthoringTypeNamespace;
49
+
50
+ export interface RlsPolicyExtensionBlock extends PslExtensionBlock {
51
+ readonly namespaceId: string;
52
+ }
53
+
54
+ /**
55
+ * Maps a `policy_<op>` keyword to the RLS operation it authors. The keyword
56
+ * IS the operation (per the project's rejection of a `policy { operation = … }`
57
+ * conditional block).
58
+ */
59
+ const POLICY_KEYWORD_OPERATION: Readonly<Record<string, RlsPolicyOperation>> = {
60
+ policy_select: 'select',
61
+ policy_insert: 'insert',
62
+ policy_update: 'update',
63
+ policy_delete: 'delete',
64
+ policy_all: 'all',
65
+ };
66
+
67
+ /**
68
+ * Which predicate each RLS operation admits, mirroring Postgres: SELECT and
69
+ * DELETE decide row visibility/eligibility with `USING` only; INSERT validates
70
+ * the new row with `WITH CHECK` only; UPDATE and ALL take both. A predicate
71
+ * outside this set is a load-time error (see {@link lowerRlsPolicyFromBlock}).
72
+ */
73
+ const POLICY_OPERATION_PREDICATES: Readonly<
74
+ Record<RlsPolicyOperation, { readonly using: boolean; readonly withCheck: boolean }>
75
+ > = {
76
+ select: { using: true, withCheck: false },
77
+ insert: { using: false, withCheck: true },
78
+ update: { using: true, withCheck: true },
79
+ delete: { using: true, withCheck: false },
80
+ all: { using: true, withCheck: true },
81
+ };
82
+
83
+ function readRefParam(block: PslExtensionBlock, key: string): string | undefined {
84
+ const param = block.parameters[key];
85
+ return param?.kind === 'ref' ? param.identifier : undefined;
86
+ }
87
+
88
+ function readValueParam(block: PslExtensionBlock, key: string): string | undefined {
89
+ const param = block.parameters[key];
90
+ return param?.kind === 'value' ? param.raw : undefined;
91
+ }
92
+
93
+ function readListRefParams(block: PslExtensionBlock, key: string): string[] {
94
+ const param = block.parameters[key];
95
+ if (param?.kind !== 'list') return [];
96
+ return param.items.flatMap((item) => (item.kind === 'ref' ? [item.identifier] : []));
97
+ }
98
+
99
+ /**
100
+ * Unwraps a quoted PSL string argument, inverting the printer's
101
+ * `escapePslString` escapes (`\\`, `\"`, `\n`, `\r`). An unknown escape
102
+ * sequence is kept verbatim, matching the printer-side `unescapePslString`
103
+ * convention.
104
+ */
105
+ function unwrapQuotedString(raw: string): string {
106
+ if (!(raw.startsWith('"') && raw.endsWith('"') && raw.length >= 2)) {
107
+ return raw;
108
+ }
109
+ const inner = raw.slice(1, -1);
110
+ let result = '';
111
+ for (let i = 0; i < inner.length; i++) {
112
+ if (inner[i] !== '\\' || i + 1 >= inner.length) {
113
+ result += inner[i];
114
+ continue;
115
+ }
116
+ const next = inner[i + 1];
117
+ if (next === '\\' || next === '"') {
118
+ result += next;
119
+ } else if (next === 'n') {
120
+ result += '\n';
121
+ } else if (next === 'r') {
122
+ result += '\r';
123
+ } else {
124
+ result += '\\';
125
+ result += next;
126
+ }
127
+ i++;
128
+ }
129
+ return result;
130
+ }
131
+
132
+ function lowerRlsPolicyFromBlock(
133
+ block: RlsPolicyExtensionBlock,
134
+ ctx: AuthoringEntityContext,
135
+ ): PostgresRlsPolicy | undefined {
136
+ const prefix = block.name;
137
+ const operation = POLICY_KEYWORD_OPERATION[block.keyword] ?? 'select';
138
+ const targetModelName = readRefParam(block, 'target') ?? '';
139
+ const tableName = targetModelName.charAt(0).toLowerCase() + targetModelName.slice(1);
140
+ const roles = [...readListRefParams(block, 'roles')].sort();
141
+
142
+ const usingRaw = readValueParam(block, 'using');
143
+ const withCheckRaw = readValueParam(block, 'withCheck');
144
+
145
+ // Reject a predicate the operation does not take (e.g. `using` on INSERT, or
146
+ // `withCheck` on SELECT/DELETE). The descriptor's param set already omits it,
147
+ // but the generic descriptor validator is not wired into the SQL-family
148
+ // interpreter, so the lowering enforces the per-operation predicate matrix
149
+ // directly — a wrong predicate is a load-time diagnostic, not a silent drop.
150
+ const support = POLICY_OPERATION_PREDICATES[operation];
151
+ const rejectPredicate = (predicate: 'using' | 'withCheck'): undefined => {
152
+ ctx.diagnostics?.push({
153
+ code: 'PSL_RLS_PREDICATE_NOT_FOR_OPERATION',
154
+ message: `\`${block.keyword}\` policy "${block.name}" does not take a \`${predicate}\` predicate; the ${operation.toUpperCase()} operation uses ${support.using ? '`using`' : '`withCheck`'}${support.using && support.withCheck ? ' and `withCheck`' : ' only'}.`,
155
+ sourceId: ctx.sourceId ?? 'unknown',
156
+ span: block.parameters[predicate]?.span ?? block.span,
157
+ });
158
+ return undefined;
159
+ };
160
+ if (usingRaw !== undefined && !support.using) return rejectPredicate('using');
161
+ if (withCheckRaw !== undefined && !support.withCheck) return rejectPredicate('withCheck');
9
162
 
10
- export const postgresAuthoringEntityTypes = {} as const satisfies AuthoringEntityTypeNamespace;
163
+ const using = usingRaw !== undefined ? unwrapQuotedString(usingRaw) : undefined;
164
+ const withCheck = withCheckRaw !== undefined ? unwrapQuotedString(withCheckRaw) : undefined;
165
+
166
+ const wireHash = computeContentHash({
167
+ ...ifDefined('using', using !== undefined ? normalizePredicate(using) : undefined),
168
+ ...ifDefined('withCheck', withCheck !== undefined ? normalizePredicate(withCheck) : undefined),
169
+ roles,
170
+ operation,
171
+ permissive: true,
172
+ });
173
+ const wireName = formatRlsPolicyWireName(prefix, wireHash);
174
+
175
+ return new PostgresRlsPolicy({
176
+ name: wireName,
177
+ prefix,
178
+ tableName,
179
+ namespaceId: block.namespaceId,
180
+ operation,
181
+ roles,
182
+ ...ifDefined('using', using),
183
+ ...ifDefined('withCheck', withCheck),
184
+ permissive: true,
185
+ });
186
+ }
187
+
188
+ /**
189
+ * Lowers a `native_enum { memberName = "value" … @@map("type_name") }` block
190
+ * into a {@link PostgresNativeEnum}. Members must be authored as explicit
191
+ * `key = "value"` pairs — a bare (value-less) member is a diagnostic, not
192
+ * accepted (authoring-design.md §2.1). The parsed `memberName` is only used
193
+ * to duplicate-check and report diagnostics; the lowered entity carries just
194
+ * the member values (a native enum is value-only — the member "name" isn't
195
+ * a separate authoring concept from the value). `typeName` comes from
196
+ * `@@map` or defaults to the block name verbatim.
197
+ */
198
+ function lowerNativeEnumFromBlock(
199
+ block: PslExtensionBlock,
200
+ ctx: AuthoringEntityContext,
201
+ ): PostgresNativeEnum | undefined {
202
+ const sourceId = ctx.sourceId ?? 'unknown';
203
+ const diagnostics = ctx.diagnostics;
204
+
205
+ const mapAttr = block.blockAttributes.find((a) => a.name === 'map');
206
+ let typeName = block.name;
207
+ if (mapAttr) {
208
+ const rawArg = mapAttr.args[0]?.value;
209
+ const mapped = rawArg !== undefined ? unwrapQuotedString(rawArg) : undefined;
210
+ if (mapped === undefined) {
211
+ diagnostics?.push({
212
+ code: 'PSL_NATIVE_ENUM_INVALID_MAP',
213
+ message: `native_enum "${block.name}" @@map attribute must have a quoted type-name argument`,
214
+ sourceId,
215
+ span: mapAttr.span,
216
+ });
217
+ return undefined;
218
+ }
219
+ typeName = mapped;
220
+ }
221
+
222
+ let memberError = false;
223
+ const seenValues = new Set<string>();
224
+ const members: string[] = [];
225
+ for (const [memberName, paramValue] of Object.entries(block.parameters)) {
226
+ if (paramValue.kind === 'bare') {
227
+ diagnostics?.push({
228
+ code: 'PSL_NATIVE_ENUM_BARE_MEMBER',
229
+ message: `native_enum "${block.name}" member "${memberName}" has no value; members must be authored as "${memberName} = \\"value\\""`,
230
+ sourceId,
231
+ span: paramValue.span,
232
+ });
233
+ memberError = true;
234
+ continue;
235
+ }
236
+ if (paramValue.kind !== 'value') continue;
237
+
238
+ let jsonValue: unknown;
239
+ try {
240
+ jsonValue = JSON.parse(paramValue.raw);
241
+ } catch {
242
+ diagnostics?.push({
243
+ code: 'PSL_EXTENSION_INVALID_VALUE',
244
+ message: `native_enum "${block.name}" member "${memberName}" value "${paramValue.raw}" is not valid JSON`,
245
+ sourceId,
246
+ span: paramValue.span,
247
+ });
248
+ memberError = true;
249
+ continue;
250
+ }
251
+ if (typeof jsonValue !== 'string') {
252
+ diagnostics?.push({
253
+ code: 'PSL_EXTENSION_INVALID_VALUE',
254
+ message: `native_enum "${block.name}" member "${memberName}" value must be a string`,
255
+ sourceId,
256
+ span: paramValue.span,
257
+ });
258
+ memberError = true;
259
+ continue;
260
+ }
261
+ if (seenValues.has(jsonValue)) {
262
+ diagnostics?.push({
263
+ code: 'PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE',
264
+ message: `native_enum "${block.name}": duplicate member value "${jsonValue}"`,
265
+ sourceId,
266
+ span: paramValue.span,
267
+ });
268
+ memberError = true;
269
+ continue;
270
+ }
271
+ seenValues.add(jsonValue);
272
+ members.push(jsonValue);
273
+ }
274
+
275
+ if (memberError) return undefined;
276
+
277
+ if (members.length === 0) {
278
+ diagnostics?.push({
279
+ code: 'PSL_NATIVE_ENUM_MISSING_MEMBERS',
280
+ message: `native_enum "${block.name}" must have at least one member`,
281
+ sourceId,
282
+ span: block.span,
283
+ });
284
+ return undefined;
285
+ }
286
+
287
+ // `control` stays unset — the effective grade is resolved at read time via `effectiveControlPolicy`, like `StorageTable`/`StorageColumn`.
288
+ return new PostgresNativeEnum({ typeName, members });
289
+ }
290
+
291
+ /**
292
+ * `native_enum`'s entity-type factory output, checked separately from the assembled
293
+ * `postgresAuthoringEntityTypes` map below: `deriveValueSet` is SQL-family surface
294
+ * ({@link SqlValueSetDerivingEntityTypeOutput}), not part of the framework
295
+ * `AuthoringEntityTypeFactoryOutput` shape, so folding it directly into the map's single
296
+ * `satisfies AuthoringEntityTypeNamespace` check would trip an excess-property error. Checking it
297
+ * here against the intersection of both shapes keeps it structurally valid against each without
298
+ * widening the map's own check.
299
+ */
300
+ const nativeEnumEntityTypeOutput = {
301
+ factory: lowerNativeEnumFromBlock,
302
+ deriveValueSet: (entity: PostgresNativeEnum) => ({
303
+ kind: 'valueSet' as const,
304
+ values: [...entity.members],
305
+ }),
306
+ } satisfies AuthoringEntityTypeFactoryOutput<PslExtensionBlock, PostgresNativeEnum | undefined> &
307
+ SqlValueSetDerivingEntityTypeOutput;
308
+
309
+ export const postgresAuthoringEntityTypes = {
310
+ role: {
311
+ kind: 'entity',
312
+ discriminator: 'role',
313
+ validatorSchema: PostgresRoleSchema,
314
+ output: {
315
+ factory: (input: PostgresRoleInput): PostgresRole => new PostgresRole(input),
316
+ },
317
+ },
318
+ rls: {
319
+ kind: 'entity',
320
+ discriminator: 'rls',
321
+ validatorSchema: PostgresRlsEnablementSchema,
322
+ output: {
323
+ factory: (input: PostgresRlsEnablementInput): PostgresRlsEnablement =>
324
+ new PostgresRlsEnablement(input),
325
+ },
326
+ },
327
+ policy: {
328
+ kind: 'entity',
329
+ discriminator: 'policy',
330
+ validatorSchema: PostgresRlsPolicySchema,
331
+ output: {
332
+ factory: lowerRlsPolicyFromBlock,
333
+ },
334
+ },
335
+ native_enum: {
336
+ kind: 'entity',
337
+ discriminator: 'native_enum',
338
+ validatorSchema: PostgresNativeEnumSchema,
339
+ output: nativeEnumEntityTypeOutput,
340
+ },
341
+ } as const satisfies AuthoringEntityTypeNamespace;
11
342
 
12
343
  /**
13
344
  * Field presets contributed by the Postgres target pack.
@@ -22,6 +353,140 @@ export const postgresAuthoringEntityTypes = {} as const satisfies AuthoringEntit
22
353
  * portability use `uuidString` / `id.uuidv4String` / `id.uuidv7String` from
23
354
  * the family pack instead.
24
355
  */
356
+ /**
357
+ * Shared parameter descriptors for the five `policy_<op>` PSL block
358
+ * keywords. All five share the `policy` discriminator — the parser
359
+ * dispatches by keyword (see the framework's PSL-block SPI), and every
360
+ * keyword's factory lowers to `PostgresRlsPolicy` via `lowerRlsPolicyFromBlock`.
361
+ *
362
+ * The `roles` list uses `scope:'cross-space'` because same-namespace
363
+ * role ref resolution requires PSL namespace entries keyed by `refKind`
364
+ * (i.e. `'role'`), which in turn requires the role block discriminator to
365
+ * equal `'role'`. Aligning discriminator with refKind is tracked for
366
+ * slice 4 (cross-space roles). Until then cross-space passes validation
367
+ * unconditionally and the authored role names flow through unchanged.
368
+ */
369
+ const policyTargetParam = {
370
+ kind: 'ref',
371
+ refKind: 'model',
372
+ scope: 'same-namespace',
373
+ required: true,
374
+ } as const;
375
+ const policyRolesParam = {
376
+ kind: 'list',
377
+ of: { kind: 'ref', refKind: 'role', scope: 'cross-space' },
378
+ } as const;
379
+ const policyPredicateParam = { kind: 'value', codecId: 'pg/text@1', required: true } as const;
380
+ // A policy may only target an RLS-controlled model: the model named by
381
+ // `target` must declare `@@rls`, or the load fails with a diagnostic naming
382
+ // the model and the policy prefix.
383
+ const policyRequiresRls = { parameter: 'target', attribute: 'rls' } as const;
384
+
385
+ export const postgresAuthoringPslBlockDescriptors = {
386
+ // The predicate param set per keyword mirrors Postgres: SELECT/DELETE take
387
+ // USING only; INSERT takes WITH CHECK only; UPDATE/ALL take both. The
388
+ // per-operation predicate matrix is enforced in `lowerRlsPolicyFromBlock`
389
+ // (a wrong predicate for the operation is a load-time diagnostic there),
390
+ // since the generic descriptor validator is not wired into the SQL-family
391
+ // interpreter.
392
+ policy_select: {
393
+ kind: 'pslBlock',
394
+ keyword: 'policy_select',
395
+ discriminator: 'policy',
396
+ name: { required: true },
397
+ parameters: { target: policyTargetParam, roles: policyRolesParam, using: policyPredicateParam },
398
+ requiresModelAttribute: policyRequiresRls,
399
+ },
400
+ policy_delete: {
401
+ kind: 'pslBlock',
402
+ keyword: 'policy_delete',
403
+ discriminator: 'policy',
404
+ name: { required: true },
405
+ parameters: { target: policyTargetParam, roles: policyRolesParam, using: policyPredicateParam },
406
+ requiresModelAttribute: policyRequiresRls,
407
+ },
408
+ policy_insert: {
409
+ kind: 'pslBlock',
410
+ keyword: 'policy_insert',
411
+ discriminator: 'policy',
412
+ name: { required: true },
413
+ parameters: {
414
+ target: policyTargetParam,
415
+ roles: policyRolesParam,
416
+ withCheck: policyPredicateParam,
417
+ },
418
+ requiresModelAttribute: policyRequiresRls,
419
+ },
420
+ policy_update: {
421
+ kind: 'pslBlock',
422
+ keyword: 'policy_update',
423
+ discriminator: 'policy',
424
+ name: { required: true },
425
+ parameters: {
426
+ target: policyTargetParam,
427
+ roles: policyRolesParam,
428
+ using: policyPredicateParam,
429
+ withCheck: policyPredicateParam,
430
+ },
431
+ requiresModelAttribute: policyRequiresRls,
432
+ },
433
+ policy_all: {
434
+ kind: 'pslBlock',
435
+ keyword: 'policy_all',
436
+ discriminator: 'policy',
437
+ name: { required: true },
438
+ parameters: {
439
+ target: policyTargetParam,
440
+ roles: policyRolesParam,
441
+ using: policyPredicateParam,
442
+ withCheck: policyPredicateParam,
443
+ },
444
+ requiresModelAttribute: policyRequiresRls,
445
+ },
446
+ /**
447
+ * PSL block descriptor for `native_enum`.
448
+ *
449
+ * Reuses the existing variadic-block mechanism (the same shape the SQL
450
+ * family's `enum` block ships): the body is an open `memberName = "value"`
451
+ * list. `variadicParameters: true` opens the block to arbitrary keys
452
+ * beyond the declared (empty) `parameters` set — the lowering factory
453
+ * (`lowerNativeEnumFromBlock`) turns the variadic entries into ordered
454
+ * members and rejects a bare (value-less) member.
455
+ */
456
+ native_enum: {
457
+ kind: 'pslBlock',
458
+ keyword: 'native_enum',
459
+ discriminator: 'native_enum',
460
+ name: { required: true },
461
+ parameters: {},
462
+ variadicParameters: true,
463
+ },
464
+ } as const satisfies AuthoringPslBlockDescriptorNamespace;
465
+
466
+ /**
467
+ * `@@` model attributes contributed by the Postgres target pack.
468
+ *
469
+ * `@@rls` is argument-less: presence marks the model's table
470
+ * RLS-controlled. It lowers to a {@link PostgresRlsEnablement} marker in
471
+ * the namespace's `entries.rls`, keyed by the model's table name — the
472
+ * marker (never the policy set) is what drives
473
+ * `ENABLE`/`DISABLE ROW LEVEL SECURITY` planning.
474
+ */
475
+ export const postgresAuthoringModelAttributes = {
476
+ rls: {
477
+ kind: 'modelAttribute',
478
+ attribute: 'rls',
479
+ spec: modelAttribute('rls', {}),
480
+ lower: (_parsed: Record<never, never>, ctx: AuthoringModelAttributeContext) => ({
481
+ key: ctx.storageName,
482
+ entity: new PostgresRlsEnablement({
483
+ tableName: ctx.storageName,
484
+ namespaceId: ctx.namespaceId,
485
+ }),
486
+ }),
487
+ },
488
+ } as const satisfies AuthoringModelAttributeDescriptorNamespace;
489
+
25
490
  export const postgresAuthoringFieldPresets = {
26
491
  text: {
27
492
  kind: 'fieldPreset',
@@ -8,6 +8,7 @@ export {
8
8
  } from '@prisma-next/sql-relational-core/ast';
9
9
  export const PG_TEXT_CODEC_ID = 'pg/text@1' as const;
10
10
  export const PG_TEXT_ARRAY_CODEC_ID = 'pg/text-array@1' as const;
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;
13
14
  export const PG_INT_CODEC_ID = 'pg/int@1' as const;
@@ -21,6 +21,7 @@ import {
21
21
  pgBoolDescriptor,
22
22
  pgByteaDescriptor,
23
23
  pgCharDescriptor,
24
+ pgEnumDescriptor,
24
25
  pgFloat4Descriptor,
25
26
  pgFloat8Descriptor,
26
27
  pgFloatDescriptor,
@@ -50,6 +51,7 @@ export const codecDescriptorMap = {
50
51
  'sql-text': sqlTextDescriptor,
51
52
  'sql-timestamp': sqlTimestampDescriptor,
52
53
  text: pgTextDescriptor,
54
+ enum: pgEnumDescriptor,
53
55
  character: pgCharDescriptor,
54
56
  'character varying': pgVarcharDescriptor,
55
57
  integer: pgIntDescriptor,