@prisma-next/target-postgres 0.14.0-dev.4 → 0.14.0-dev.41

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 (191) hide show
  1. package/dist/authoring-BX1WHIdN.mjs +220 -0
  2. package/dist/authoring-BX1WHIdN.mjs.map +1 -0
  3. package/dist/canonicalize-Bn3BM1Cn.mjs +46 -0
  4. package/dist/canonicalize-Bn3BM1Cn.mjs.map +1 -0
  5. package/dist/canonicalize-CAbXtVtB.d.mts +37 -0
  6. package/dist/canonicalize-CAbXtVtB.d.mts.map +1 -0
  7. package/dist/{codec-types-DHCkwPKE.d.mts → codec-types-CueCoGD0.d.mts} +2 -2
  8. package/dist/{codec-types-DHCkwPKE.d.mts.map → codec-types-CueCoGD0.d.mts.map} +1 -1
  9. package/dist/codec-types.d.mts +1 -1
  10. package/dist/{codecs--0A5_4Bq.d.mts → codecs-Ca8upop6.d.mts} +12 -1
  11. package/dist/codecs-Ca8upop6.d.mts.map +1 -0
  12. package/dist/codecs.d.mts +1 -1
  13. package/dist/codecs.mjs +34 -1
  14. package/dist/codecs.mjs.map +1 -1
  15. package/dist/contract-free.d.mts +8 -3
  16. package/dist/contract-free.d.mts.map +1 -1
  17. package/dist/contract-free.mjs +3 -3
  18. package/dist/control.d.mts +1 -1
  19. package/dist/control.d.mts.map +1 -1
  20. package/dist/control.mjs +639 -21
  21. package/dist/control.mjs.map +1 -1
  22. package/dist/data-transform-BOWpliq8.mjs.map +1 -1
  23. package/dist/{data-transform-DDgWdB5o.d.mts → data-transform-qKy1U5V9.d.mts} +2 -2
  24. package/dist/{data-transform-DDgWdB5o.d.mts.map → data-transform-qKy1U5V9.d.mts.map} +1 -1
  25. package/dist/data-transform.d.mts +1 -1
  26. package/dist/{ddl-QDyOSeLc.mjs → ddl-BmLIe1z_.mjs} +62 -5
  27. package/dist/ddl-BmLIe1z_.mjs.map +1 -0
  28. package/dist/ddl.d.mts +3 -2
  29. package/dist/ddl.mjs +2 -2
  30. package/dist/{default-normalizer-DyyCHQWs.mjs → default-normalizer-Dug8Fez9.mjs} +119 -2
  31. package/dist/default-normalizer-Dug8Fez9.mjs.map +1 -0
  32. package/dist/default-normalizer.d.mts +1 -1
  33. package/dist/default-normalizer.d.mts.map +1 -1
  34. package/dist/default-normalizer.mjs +1 -1
  35. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs +12 -0
  36. package/dist/descriptor-meta-runtime-UwYdV8fD.mjs.map +1 -0
  37. package/dist/descriptor-meta-tjatyhtZ.mjs +18 -0
  38. package/dist/descriptor-meta-tjatyhtZ.mjs.map +1 -0
  39. package/dist/{issue-planner-DL6g3CmE.mjs → issue-planner-DbFvaAgu.mjs} +35 -10
  40. package/dist/issue-planner-DbFvaAgu.mjs.map +1 -0
  41. package/dist/issue-planner.d.mts +3 -3
  42. package/dist/issue-planner.d.mts.map +1 -1
  43. package/dist/issue-planner.mjs +1 -1
  44. package/dist/migration.d.mts +5 -5
  45. package/dist/migration.mjs +4 -4
  46. package/dist/nodes-CSkPX3rI.d.mts +120 -0
  47. package/dist/nodes-CSkPX3rI.d.mts.map +1 -0
  48. package/dist/{nodes-Bbhs2rwj.mjs → nodes-Dh__NS58.mjs} +56 -2
  49. package/dist/nodes-Dh__NS58.mjs.map +1 -0
  50. package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-CJWUxyUW.d.mts} +44 -13
  51. package/dist/op-factory-call-CJWUxyUW.d.mts.map +1 -0
  52. package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-t65c4jyY.mjs} +201 -28
  53. package/dist/op-factory-call-t65c4jyY.mjs.map +1 -0
  54. package/dist/op-factory-call.d.mts +1 -1
  55. package/dist/op-factory-call.mjs +1 -1
  56. package/dist/pack.d.mts +74 -2
  57. package/dist/pack.d.mts.map +1 -1
  58. package/dist/pack.mjs +1 -1
  59. package/dist/planner-CG2pLHk-.mjs +640 -0
  60. package/dist/planner-CG2pLHk-.mjs.map +1 -0
  61. package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-B8Nn6nHN.mjs} +12 -27
  62. package/dist/planner-ddl-builders-B8Nn6nHN.mjs.map +1 -0
  63. package/dist/planner-ddl-builders.d.mts +2 -4
  64. package/dist/planner-ddl-builders.d.mts.map +1 -1
  65. package/dist/planner-ddl-builders.mjs +2 -2
  66. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-BolD0Mvc.mjs} +3 -3
  67. package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-BolD0Mvc.mjs.map} +1 -1
  68. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-Cz9--XOT.d.mts} +4 -4
  69. package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-Cz9--XOT.d.mts.map} +1 -1
  70. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  71. package/dist/planner-produced-postgres-migration.mjs +1 -1
  72. package/dist/{planner-sql-checks-jqUUGyQR.mjs → planner-sql-checks-DE9c4519.mjs} +2 -2
  73. package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-DE9c4519.mjs.map} +1 -1
  74. package/dist/planner-sql-checks.mjs +1 -1
  75. package/dist/{planner-target-details-CIY6tLeo.d.mts → planner-target-details-HkP4RrRO.d.mts} +2 -2
  76. package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -0
  77. package/dist/planner-target-details.d.mts +1 -1
  78. package/dist/planner.d.mts +82 -4
  79. package/dist/planner.d.mts.map +1 -1
  80. package/dist/planner.mjs +2 -2
  81. package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-BegduLr6.mjs} +50 -23
  82. package/dist/postgres-contract-view-BegduLr6.mjs.map +1 -0
  83. package/dist/postgres-contract-view-C9j5cqP0.d.mts +34 -0
  84. package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +1 -0
  85. package/dist/postgres-database-schema-node-os8ogEap.d.mts +183 -0
  86. package/dist/postgres-database-schema-node-os8ogEap.d.mts.map +1 -0
  87. package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-BfMmK6tv.mjs} +21 -2
  88. package/dist/postgres-migration-BfMmK6tv.mjs.map +1 -0
  89. package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-D7kNVWVG.d.mts} +19 -6
  90. package/dist/postgres-migration-D7kNVWVG.d.mts.map +1 -0
  91. package/dist/postgres-rls-policy--CSddvMR.d.mts +52 -0
  92. package/dist/postgres-rls-policy--CSddvMR.d.mts.map +1 -0
  93. package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-BLIHBEfX.mjs} +108 -5
  94. package/dist/postgres-schema-BLIHBEfX.mjs.map +1 -0
  95. package/dist/postgres-schema-BywoeKlt.d.mts +189 -0
  96. package/dist/postgres-schema-BywoeKlt.d.mts.map +1 -0
  97. package/dist/postgres-table-schema-node-1nNc8XDT.mjs +248 -0
  98. package/dist/postgres-table-schema-node-1nNc8XDT.mjs.map +1 -0
  99. package/dist/render-ops.d.mts +1 -1
  100. package/dist/{render-typescript-KMgosran.mjs → render-typescript-7yqILcwr.mjs} +45 -16
  101. package/dist/render-typescript-7yqILcwr.mjs.map +1 -0
  102. package/dist/render-typescript.mjs +1 -1
  103. package/dist/resolve-ddl-schema-CL1RR1mx.mjs +20 -0
  104. package/dist/resolve-ddl-schema-CL1RR1mx.mjs.map +1 -0
  105. package/dist/rls-canonicalize.d.mts +2 -0
  106. package/dist/rls-canonicalize.mjs +2 -0
  107. package/dist/runtime.d.mts +7 -6
  108. package/dist/runtime.d.mts.map +1 -1
  109. package/dist/runtime.mjs +3 -3
  110. package/dist/runtime.mjs.map +1 -1
  111. package/dist/schema-ir-annotations.d.mts +14 -0
  112. package/dist/schema-ir-annotations.d.mts.map +1 -0
  113. package/dist/schema-ir-annotations.mjs +2 -0
  114. package/dist/types.d.mts +4 -140
  115. package/dist/types.mjs +3 -2
  116. package/package.json +22 -17
  117. package/src/contract-free/checks.ts +73 -0
  118. package/src/contract-free/ddl.ts +45 -1
  119. package/src/core/authoring.ts +115 -1
  120. package/src/core/codecs.ts +35 -1
  121. package/src/core/ddl/nodes.ts +94 -2
  122. package/src/core/default-normalizer.ts +122 -2
  123. package/src/core/descriptor-meta.ts +4 -0
  124. package/src/core/entity-kinds.ts +16 -0
  125. package/src/core/migrations/bound-schema.ts +10 -0
  126. package/src/core/migrations/contract-to-postgres-database-schema-node.ts +125 -0
  127. package/src/core/migrations/control-policy.ts +3 -0
  128. package/src/core/migrations/diff-database-schema.ts +191 -0
  129. package/src/core/migrations/issue-planner.ts +44 -3
  130. package/src/core/migrations/op-factory-call.ts +109 -21
  131. package/src/core/migrations/operations/columns.ts +24 -12
  132. package/src/core/migrations/operations/data-transform.ts +6 -0
  133. package/src/core/migrations/operations/rls.ts +106 -0
  134. package/src/core/migrations/operations/shared.ts +0 -30
  135. package/src/core/migrations/planner-ddl-builders.ts +15 -56
  136. package/src/core/migrations/planner-recipes.ts +31 -13
  137. package/src/core/migrations/planner-strategies.ts +3 -11
  138. package/src/core/migrations/planner-target-details.ts +3 -1
  139. package/src/core/migrations/planner.ts +165 -33
  140. package/src/core/migrations/postgres-migration.ts +34 -4
  141. package/src/core/migrations/render-typescript.ts +42 -15
  142. package/src/core/migrations/resolve-ddl-schema.ts +24 -0
  143. package/src/core/migrations/runner.ts +13 -16
  144. package/src/core/migrations/verify-postgres-namespaces.ts +24 -19
  145. package/src/core/postgres-contract-serializer.ts +50 -33
  146. package/src/core/postgres-contract-view.ts +48 -0
  147. package/src/core/postgres-rls-policy.ts +64 -0
  148. package/src/core/postgres-role.ts +37 -0
  149. package/src/core/postgres-schema.ts +37 -13
  150. package/src/core/postgres-validators.ts +20 -0
  151. package/src/core/psl-infer/infer-psl-contract.ts +834 -0
  152. package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
  153. package/src/core/psl-infer/postgres-type-map.ts +157 -0
  154. package/src/core/rls/canonicalize.ts +48 -0
  155. package/src/core/schema-ir/postgres-database-schema-node.ts +63 -0
  156. package/src/core/schema-ir/postgres-namespace-schema-node.ts +61 -0
  157. package/src/core/schema-ir/postgres-policy-schema-node.ts +93 -0
  158. package/src/core/schema-ir/postgres-role-schema-node.ts +66 -0
  159. package/src/core/schema-ir/postgres-table-schema-node.ts +107 -0
  160. package/src/core/schema-ir/schema-node-kinds.ts +28 -0
  161. package/src/exports/contract-free.ts +7 -1
  162. package/src/exports/control.ts +39 -12
  163. package/src/exports/ddl.ts +4 -0
  164. package/src/exports/migration.ts +1 -0
  165. package/src/exports/planner-ddl-builders.ts +0 -2
  166. package/src/exports/planner.ts +2 -0
  167. package/src/exports/rls-canonicalize.ts +6 -0
  168. package/src/exports/runtime.ts +1 -0
  169. package/src/exports/schema-ir-annotations.ts +1 -0
  170. package/src/exports/types.ts +28 -0
  171. package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
  172. package/dist/ddl-QDyOSeLc.mjs.map +0 -1
  173. package/dist/default-normalizer-DyyCHQWs.mjs.map +0 -1
  174. package/dist/descriptor-meta-CpGygXpI.mjs +0 -140
  175. package/dist/descriptor-meta-CpGygXpI.mjs.map +0 -1
  176. package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
  177. package/dist/nodes-Bbhs2rwj.mjs.map +0 -1
  178. package/dist/nodes-pLeLgdis.d.mts +0 -67
  179. package/dist/nodes-pLeLgdis.d.mts.map +0 -1
  180. package/dist/op-factory-call-D_p5vxwt.mjs.map +0 -1
  181. package/dist/op-factory-call-DmQEc3XV.d.mts.map +0 -1
  182. package/dist/planner-Bs_baQax.mjs +0 -324
  183. package/dist/planner-Bs_baQax.mjs.map +0 -1
  184. package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +0 -1
  185. package/dist/planner-target-details-CIY6tLeo.d.mts.map +0 -1
  186. package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +0 -1
  187. package/dist/postgres-migration-B5jKrXv3.mjs.map +0 -1
  188. package/dist/postgres-migration-Y4YBJqkS.d.mts.map +0 -1
  189. package/dist/postgres-schema-COGZ1ark.mjs.map +0 -1
  190. package/dist/render-typescript-KMgosran.mjs.map +0 -1
  191. package/dist/types.d.mts.map +0 -1
@@ -2,9 +2,13 @@ import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-
2
2
  import {
3
3
  AddColumnAction,
4
4
  type AnyAlterTableAction,
5
+ DropDefaultAction,
5
6
  PostgresAlterTable,
7
+ PostgresCreatePolicy,
6
8
  PostgresCreateSchema,
7
9
  PostgresCreateTable,
10
+ PostgresDropPolicy,
11
+ type RlsPolicyOperation,
8
12
  } from '../core/ddl/nodes';
9
13
 
10
14
  /**
@@ -51,9 +55,17 @@ export function addColumnAction(column: DdlColumn): AddColumnAction {
51
55
  return new AddColumnAction(column);
52
56
  }
53
57
 
58
+ /**
59
+ * Build a `DROP DEFAULT` action (`ALTER COLUMN "<name>" DROP DEFAULT`) for
60
+ * use inside {@link alterTable}. The renderer quotes the column name.
61
+ */
62
+ export function dropDefaultAction(columnName: string): DropDefaultAction {
63
+ return new DropDefaultAction(columnName);
64
+ }
65
+
54
66
  /**
55
67
  * Build a Postgres `ALTER TABLE` query node carrying one or more actions.
56
- * See {@link addColumnAction} for building actions.
68
+ * See {@link addColumnAction} / {@link dropDefaultAction} for building actions.
57
69
  */
58
70
  export function alterTable(options: {
59
71
  readonly table: string;
@@ -62,3 +74,35 @@ export function alterTable(options: {
62
74
  }): PostgresAlterTable {
63
75
  return new PostgresAlterTable(options);
64
76
  }
77
+
78
+ /**
79
+ * Build a Postgres `CREATE POLICY` DDL node.
80
+ *
81
+ * Identifiers (`schema`, `table`, `name`) are quoted by the renderer.
82
+ * `using` and `withCheck` are emitted verbatim as predicate SQL — callers
83
+ * must supply safe, pre-validated SQL expressions.
84
+ */
85
+ export function createPolicy(options: {
86
+ readonly schema: string;
87
+ readonly table: string;
88
+ readonly name: string;
89
+ readonly permissive: boolean;
90
+ readonly operation: RlsPolicyOperation;
91
+ readonly roles: readonly string[];
92
+ readonly using?: string;
93
+ readonly withCheck?: string;
94
+ }): PostgresCreatePolicy {
95
+ return new PostgresCreatePolicy(options);
96
+ }
97
+
98
+ /**
99
+ * Build a Postgres `DROP POLICY` DDL node.
100
+ * Identifiers (`schema`, `table`, `name`) are quoted by the renderer.
101
+ */
102
+ export function dropPolicy(options: {
103
+ readonly schema: string;
104
+ readonly table: string;
105
+ readonly name: string;
106
+ }): PostgresDropPolicy {
107
+ return new PostgresDropPolicy(options);
108
+ }
@@ -1,13 +1,94 @@
1
1
  import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';
2
2
  import type {
3
+ AuthoringEntityContext,
3
4
  AuthoringEntityTypeNamespace,
4
5
  AuthoringFieldNamespace,
6
+ AuthoringPslBlockDescriptorNamespace,
5
7
  AuthoringTypeNamespace,
8
+ PslExtensionBlock,
6
9
  } from '@prisma-next/framework-components/authoring';
10
+ import { PostgresRlsPolicy } from './postgres-rls-policy';
11
+ import { PostgresRole, type PostgresRoleInput } from './postgres-role';
12
+ import { PostgresRlsPolicySchema, PostgresRoleSchema } from './postgres-validators';
13
+ import { computeContentHash, normalizePredicate } from './rls/canonicalize';
7
14
 
8
15
  export const postgresAuthoringTypes = {} as const satisfies AuthoringTypeNamespace;
9
16
 
10
- export const postgresAuthoringEntityTypes = {} as const satisfies AuthoringEntityTypeNamespace;
17
+ export interface RlsPolicyExtensionBlock extends PslExtensionBlock {
18
+ readonly namespaceId: string;
19
+ }
20
+
21
+ function readRefParam(block: PslExtensionBlock, key: string): string | undefined {
22
+ const param = block.parameters[key];
23
+ return param?.kind === 'ref' ? param.identifier : undefined;
24
+ }
25
+
26
+ function readValueParam(block: PslExtensionBlock, key: string): string | undefined {
27
+ const param = block.parameters[key];
28
+ return param?.kind === 'value' ? param.raw : undefined;
29
+ }
30
+
31
+ function readListRefParams(block: PslExtensionBlock, key: string): string[] {
32
+ const param = block.parameters[key];
33
+ if (param?.kind !== 'list') return [];
34
+ return param.items.flatMap((item) => (item.kind === 'ref' ? [item.identifier] : []));
35
+ }
36
+
37
+ function unwrapQuotedString(raw: string): string {
38
+ if (raw.startsWith('"') && raw.endsWith('"') && raw.length >= 2) {
39
+ return raw.slice(1, -1).replace(/\\"/g, '"');
40
+ }
41
+ return raw;
42
+ }
43
+
44
+ function lowerRlsPolicyFromBlock(
45
+ block: RlsPolicyExtensionBlock,
46
+ _ctx: AuthoringEntityContext,
47
+ ): PostgresRlsPolicy {
48
+ const prefix = block.name;
49
+ const targetModelName = readRefParam(block, 'target') ?? '';
50
+ const tableName = targetModelName.charAt(0).toLowerCase() + targetModelName.slice(1);
51
+ const roles = [...readListRefParams(block, 'roles')].sort();
52
+ const using = unwrapQuotedString(readValueParam(block, 'using') ?? '');
53
+
54
+ const wireHash = computeContentHash({
55
+ using: normalizePredicate(using),
56
+ roles,
57
+ operation: 'select',
58
+ permissive: true,
59
+ });
60
+ const wireName = `${prefix}_${wireHash}`;
61
+
62
+ return new PostgresRlsPolicy({
63
+ name: wireName,
64
+ prefix,
65
+ tableName,
66
+ namespaceId: block.namespaceId,
67
+ operation: 'select',
68
+ roles,
69
+ using,
70
+ permissive: true,
71
+ });
72
+ }
73
+
74
+ export const postgresAuthoringEntityTypes = {
75
+ role: {
76
+ kind: 'entity',
77
+ discriminator: 'role',
78
+ validatorSchema: PostgresRoleSchema,
79
+ output: {
80
+ factory: (input: PostgresRoleInput): PostgresRole => new PostgresRole(input),
81
+ },
82
+ },
83
+ policy: {
84
+ kind: 'entity',
85
+ discriminator: 'policy',
86
+ validatorSchema: PostgresRlsPolicySchema,
87
+ output: {
88
+ factory: lowerRlsPolicyFromBlock,
89
+ },
90
+ },
91
+ } as const satisfies AuthoringEntityTypeNamespace;
11
92
 
12
93
  /**
13
94
  * Field presets contributed by the Postgres target pack.
@@ -22,6 +103,39 @@ export const postgresAuthoringEntityTypes = {} as const satisfies AuthoringEntit
22
103
  * portability use `uuidString` / `id.uuidv4String` / `id.uuidv7String` from
23
104
  * the family pack instead.
24
105
  */
106
+ /**
107
+ * PSL block descriptor for `policy_select`.
108
+ *
109
+ * The parser learns the block shape from this descriptor; lowering from
110
+ * `PslExtensionBlock` to `PostgresRlsPolicy` is wired in the PSL
111
+ * interpreter (a later dispatch). The `discriminator` matches
112
+ * `PostgresRlsPolicy.kind` so the parsed block node carries the same
113
+ * discriminant as the IR class it will lower to.
114
+ *
115
+ * The `roles` list uses `scope:'cross-space'` because same-namespace
116
+ * role ref resolution requires PSL namespace entries keyed by `refKind`
117
+ * (i.e. `'role'`), which in turn requires the role block discriminator to
118
+ * equal `'role'`. Aligning discriminator with refKind is tracked for
119
+ * slice 4 (cross-space roles). Until then cross-space passes validation
120
+ * unconditionally and the authored role names flow through unchanged.
121
+ */
122
+ export const postgresAuthoringPslBlockDescriptors = {
123
+ policy_select: {
124
+ kind: 'pslBlock',
125
+ keyword: 'policy_select',
126
+ discriminator: 'policy',
127
+ name: { required: true },
128
+ parameters: {
129
+ target: { kind: 'ref', refKind: 'model', scope: 'same-namespace', required: true },
130
+ roles: {
131
+ kind: 'list',
132
+ of: { kind: 'ref', refKind: 'role', scope: 'cross-space' },
133
+ },
134
+ using: { kind: 'value', codecId: 'pg/text@1', required: true },
135
+ },
136
+ },
137
+ } as const satisfies AuthoringPslBlockDescriptorNamespace;
138
+
25
139
  export const postgresAuthoringFieldPresets = {
26
140
  text: {
27
141
  kind: 'fieldPreset',
@@ -4,7 +4,7 @@
4
4
  * Each codec ships as three artifacts:
5
5
  *
6
6
  * 1. A `PgXCodec` class extending {@link CodecImpl} that wraps the module-level encode/decode/encodeJson/decodeJson constants exported from `codec-helpers.ts` (the single source of truth for non-trivial runtime conversions; trivial identity passthroughs are inlined). 2. A `PgXDescriptor` class extending {@link CodecDescriptorImpl} declaring the codec id, traits, target types, params schema, meta, and (where applicable)
7
- * the emit-path `renderOutputType`. 3. A per-codec column helper (`pgXColumn`) that calls `descriptor.factory(...)` directly and packages the result into a {@link ColumnSpec} via the framework {@link column} packager. The helper is tied to its descriptor with `satisfies ColumnHelperFor` (and `ColumnHelperForStrict` where the resolved codec type is well-defined).
7
+ * the emit-path `renderOutputType`. 3. A per-codec column helper (`pgXColumn`) that calls `descriptor.factory(...)` directly and packages the result into a framework `ColumnSpec` via the framework {@link column} packager. The helper is tied to its descriptor with `satisfies ColumnHelperFor` (and `ColumnHelperForStrict` where the resolved codec type is well-defined).
8
8
  *
9
9
  * After TML-2357 this is the canonical source of Postgres codec metadata and runtime behaviour — the legacy `mkCodec` / `defineCodec` carriers (and the parallel `byScalar`/`codecDescriptorDefinitions`/ `codecDescriptorList` collection exports) retired with the deletion sweep.
10
10
  *
@@ -22,6 +22,7 @@ import {
22
22
  type ColumnHelperFor,
23
23
  type ColumnHelperForStrict,
24
24
  column,
25
+ renderTsLiteral,
25
26
  voidParamsSchema,
26
27
  } from '@prisma-next/framework-components/codec';
27
28
  import {
@@ -148,6 +149,9 @@ export class PgTextDescriptor extends CodecDescriptorImpl<void> {
148
149
  override readonly targetTypes = ['text'] as const;
149
150
  override readonly meta = PG_TEXT_META;
150
151
  override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
152
+ override renderValueLiteral(value: JsonValue): string | undefined {
153
+ return renderTsLiteral(value);
154
+ }
151
155
  override factory(): (ctx: CodecInstanceContext) => PgTextCodec {
152
156
  return () => new PgTextCodec(this);
153
157
  }
@@ -228,6 +232,9 @@ export class PgInt4Descriptor extends CodecDescriptorImpl<void> {
228
232
  override readonly targetTypes = ['int4'] as const;
229
233
  override readonly meta = PG_INT4_META;
230
234
  override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
235
+ override renderValueLiteral(value: JsonValue): string | undefined {
236
+ return renderTsLiteral(value);
237
+ }
231
238
  override factory(): (ctx: CodecInstanceContext) => PgInt4Codec {
232
239
  return () => new PgInt4Codec(this);
233
240
  }
@@ -267,6 +274,9 @@ export class PgInt2Descriptor extends CodecDescriptorImpl<void> {
267
274
  override readonly targetTypes = ['int2'] as const;
268
275
  override readonly meta = PG_INT2_META;
269
276
  override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
277
+ override renderValueLiteral(value: JsonValue): string | undefined {
278
+ return renderTsLiteral(value);
279
+ }
270
280
  override factory(): (ctx: CodecInstanceContext) => PgInt2Codec {
271
281
  return () => new PgInt2Codec(this);
272
282
  }
@@ -306,6 +316,9 @@ export class PgInt8Descriptor extends CodecDescriptorImpl<void> {
306
316
  override readonly targetTypes = ['int8'] as const;
307
317
  override readonly meta = PG_INT8_META;
308
318
  override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
319
+ override renderValueLiteral(value: JsonValue): string | undefined {
320
+ return renderTsLiteral(value);
321
+ }
309
322
  override factory(): (ctx: CodecInstanceContext) => PgInt8Codec {
310
323
  return () => new PgInt8Codec(this);
311
324
  }
@@ -345,6 +358,9 @@ export class PgFloat4Descriptor extends CodecDescriptorImpl<void> {
345
358
  override readonly targetTypes = ['float4'] as const;
346
359
  override readonly meta = PG_FLOAT4_META;
347
360
  override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
361
+ override renderValueLiteral(value: JsonValue): string | undefined {
362
+ return renderTsLiteral(value);
363
+ }
348
364
  override factory(): (ctx: CodecInstanceContext) => PgFloat4Codec {
349
365
  return () => new PgFloat4Codec(this);
350
366
  }
@@ -384,6 +400,9 @@ export class PgFloat8Descriptor extends CodecDescriptorImpl<void> {
384
400
  override readonly targetTypes = ['float8'] as const;
385
401
  override readonly meta = PG_FLOAT8_META;
386
402
  override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
403
+ override renderValueLiteral(value: JsonValue): string | undefined {
404
+ return renderTsLiteral(value);
405
+ }
387
406
  override factory(): (ctx: CodecInstanceContext) => PgFloat8Codec {
388
407
  return () => new PgFloat8Codec(this);
389
408
  }
@@ -423,6 +442,9 @@ export class PgBoolDescriptor extends CodecDescriptorImpl<void> {
423
442
  override readonly targetTypes = ['bool'] as const;
424
443
  override readonly meta = PG_BOOL_META;
425
444
  override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
445
+ override renderValueLiteral(value: JsonValue): string | undefined {
446
+ return renderTsLiteral(value);
447
+ }
426
448
  override factory(): (ctx: CodecInstanceContext) => PgBoolCodec {
427
449
  return () => new PgBoolCodec(this);
428
450
  }
@@ -968,6 +990,9 @@ export class PgCharDescriptor extends CodecDescriptorImpl<LengthParams> {
968
990
  override renderOutputType(params: LengthParams): string | undefined {
969
991
  return sqlCharDescriptor.renderOutputType(params);
970
992
  }
993
+ override renderValueLiteral(value: JsonValue): string | undefined {
994
+ return renderTsLiteral(value);
995
+ }
971
996
  override factory(_params: LengthParams): (ctx: CodecInstanceContext) => SqlCharCodec {
972
997
  return () => new SqlCharCodec(this);
973
998
  }
@@ -989,6 +1014,9 @@ export class PgVarcharDescriptor extends CodecDescriptorImpl<LengthParams> {
989
1014
  override renderOutputType(params: LengthParams): string | undefined {
990
1015
  return sqlVarcharDescriptor.renderOutputType(params);
991
1016
  }
1017
+ override renderValueLiteral(value: JsonValue): string | undefined {
1018
+ return renderTsLiteral(value);
1019
+ }
992
1020
  override factory(_params: LengthParams): (ctx: CodecInstanceContext) => SqlVarcharCodec {
993
1021
  return () => new SqlVarcharCodec(this);
994
1022
  }
@@ -1012,6 +1040,9 @@ export class PgIntDescriptor extends CodecDescriptorImpl<void> {
1012
1040
  override readonly meta = PG_INT_META;
1013
1041
  override readonly traits = sqlIntDescriptor.traits;
1014
1042
  override readonly paramsSchema = sqlIntDescriptor.paramsSchema;
1043
+ override renderValueLiteral(value: JsonValue): string | undefined {
1044
+ return renderTsLiteral(value);
1045
+ }
1015
1046
  override factory(): (ctx: CodecInstanceContext) => SqlIntCodec {
1016
1047
  return () => new SqlIntCodec(this);
1017
1048
  }
@@ -1030,6 +1061,9 @@ export class PgFloatDescriptor extends CodecDescriptorImpl<void> {
1030
1061
  override readonly meta = PG_FLOAT_META;
1031
1062
  override readonly traits = sqlFloatDescriptor.traits;
1032
1063
  override readonly paramsSchema = sqlFloatDescriptor.paramsSchema;
1064
+ override renderValueLiteral(value: JsonValue): string | undefined {
1065
+ return renderTsLiteral(value);
1066
+ }
1033
1067
  override factory(): (ctx: CodecInstanceContext) => SqlFloatCodec {
1034
1068
  return () => new SqlFloatCodec(this);
1035
1069
  }
@@ -3,6 +3,7 @@ import {
3
3
  DdlNode,
4
4
  type DdlTableConstraint,
5
5
  } from '@prisma-next/sql-relational-core/ast';
6
+ import type { RlsPolicyOperation } from '../rls/canonicalize';
6
7
 
7
8
  // ---------------------------------------------------------------------------
8
9
  // AlterTableAction — nested polymorphic hierarchy
@@ -10,6 +11,7 @@ import {
10
11
 
11
12
  export interface AlterTableActionVisitor<R> {
12
13
  addColumn(action: AddColumnAction): R;
14
+ dropDefault(action: DropDefaultAction): R;
13
15
  }
14
16
 
15
17
  export abstract class AlterTableAction {
@@ -32,7 +34,31 @@ export class AddColumnAction extends AlterTableAction {
32
34
  }
33
35
  }
34
36
 
35
- export type AnyAlterTableAction = AddColumnAction;
37
+ export class DropDefaultAction extends AlterTableAction {
38
+ readonly kind = 'drop-default' as const;
39
+ readonly columnName: string;
40
+
41
+ constructor(columnName: string) {
42
+ super();
43
+ this.columnName = columnName;
44
+ Object.freeze(this);
45
+ }
46
+
47
+ override accept<R>(visitor: AlterTableActionVisitor<R>): R {
48
+ return visitor.dropDefault(this);
49
+ }
50
+ }
51
+
52
+ /**
53
+ * The set of ALTER TABLE subactions currently expressible as typed DDL.
54
+ *
55
+ * The remaining actions — SetDefault, SetNotNull, DropNotNull,
56
+ * AlterColumnType — are still emitted as raw SQL by `operations/columns.ts`
57
+ * and join this union as they are converted to typed DDL. Until then it is
58
+ * intentionally partial: only the ALTER subactions used by the
59
+ * already-converted ops (AddColumn, DropDefault) appear here.
60
+ */
61
+ export type AnyAlterTableAction = AddColumnAction | DropDefaultAction;
36
62
 
37
63
  // ---------------------------------------------------------------------------
38
64
  // Top-level DDL visitor
@@ -42,6 +68,8 @@ export interface PostgresDdlVisitor<R> {
42
68
  createTable(node: PostgresCreateTable): R;
43
69
  createSchema(node: PostgresCreateSchema): R;
44
70
  alterTable(node: PostgresAlterTable): R;
71
+ createPolicy(node: PostgresCreatePolicy): R;
72
+ dropPolicy(node: PostgresDropPolicy): R;
45
73
  }
46
74
 
47
75
  export abstract class PostgresDdlNode extends DdlNode {
@@ -127,4 +155,68 @@ export class PostgresAlterTable extends PostgresDdlNode {
127
155
  }
128
156
  }
129
157
 
130
- export type AnyPostgresDdlNode = PostgresCreateTable | PostgresCreateSchema | PostgresAlterTable;
158
+ export type { RlsPolicyOperation };
159
+
160
+ export class PostgresCreatePolicy extends PostgresDdlNode {
161
+ readonly kind = 'create-policy' as const;
162
+ readonly schema: string;
163
+ readonly table: string;
164
+ readonly name: string;
165
+ readonly permissive: boolean;
166
+ readonly operation: RlsPolicyOperation;
167
+ readonly roles: ReadonlyArray<string>;
168
+ readonly using: string | undefined;
169
+ readonly withCheck: string | undefined;
170
+
171
+ constructor(options: {
172
+ readonly schema: string;
173
+ readonly table: string;
174
+ readonly name: string;
175
+ readonly permissive: boolean;
176
+ readonly operation: RlsPolicyOperation;
177
+ readonly roles: readonly string[];
178
+ readonly using?: string;
179
+ readonly withCheck?: string;
180
+ }) {
181
+ super();
182
+ this.schema = options.schema;
183
+ this.table = options.table;
184
+ this.name = options.name;
185
+ this.permissive = options.permissive;
186
+ this.operation = options.operation;
187
+ this.roles = Object.freeze([...options.roles]);
188
+ this.using = options.using;
189
+ this.withCheck = options.withCheck;
190
+ this.freeze();
191
+ }
192
+
193
+ override accept<R>(visitor: PostgresDdlVisitor<R>): R {
194
+ return visitor.createPolicy(this);
195
+ }
196
+ }
197
+
198
+ export class PostgresDropPolicy extends PostgresDdlNode {
199
+ readonly kind = 'drop-policy' as const;
200
+ readonly schema: string;
201
+ readonly table: string;
202
+ readonly name: string;
203
+
204
+ constructor(options: { readonly schema: string; readonly table: string; readonly name: string }) {
205
+ super();
206
+ this.schema = options.schema;
207
+ this.table = options.table;
208
+ this.name = options.name;
209
+ this.freeze();
210
+ }
211
+
212
+ override accept<R>(visitor: PostgresDdlVisitor<R>): R {
213
+ return visitor.dropPolicy(this);
214
+ }
215
+ }
216
+
217
+ export type AnyPostgresDdlNode =
218
+ | PostgresCreateTable
219
+ | PostgresCreateSchema
220
+ | PostgresAlterTable
221
+ | PostgresCreatePolicy
222
+ | PostgresDropPolicy;
@@ -1,4 +1,4 @@
1
- import type { ColumnDefault } from '@prisma-next/contract/types';
1
+ import type { ColumnDefault, JsonValue } from '@prisma-next/contract/types';
2
2
 
3
3
  /**
4
4
  * Pre-compiled regex patterns for performance.
@@ -18,6 +18,13 @@ const FALSE_PATTERN = /^false$/i;
18
18
  const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
19
19
  const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d+\))?)?$/;
20
20
 
21
+ /**
22
+ * Matches a Postgres array literal default of the form `'{...}'::elemtype[]`.
23
+ * The literal body is captured in group 1; the cast (including `[]`) is optional.
24
+ * Examples: `'{}'::text[]`, `'{1,2}'::integer[]`, `'{}'`
25
+ */
26
+ const ARRAY_LITERAL_PATTERN = /^'(\{.*\})'(?:::.+\[\])?$/;
27
+
21
28
  /**
22
29
  * Returns the canonical expression for a timestamp default function, or undefined
23
30
  * if the expression is not a recognized timestamp default.
@@ -51,6 +58,108 @@ function canonicalizeTimestampDefault(expr: string): string | undefined {
51
58
  return undefined;
52
59
  }
53
60
 
61
+ type ArrayElementToken = { readonly value: string; readonly quoted: boolean };
62
+
63
+ /**
64
+ * Splits a Postgres array literal body (without the enclosing braces) into its
65
+ * element tokens, honouring quoting. A comma only separates elements when it is
66
+ * outside double quotes; inside a quoted element a doubled quote (`""`) or a
67
+ * backslash-escaped quote (`\"`) is a literal quote, and a backslash escapes the
68
+ * next character. Returns undefined if the body is malformed (e.g. an unbalanced
69
+ * quote).
70
+ */
71
+ function splitArrayElements(inner: string): readonly ArrayElementToken[] | undefined {
72
+ const tokens: ArrayElementToken[] = [];
73
+ let current = '';
74
+ let inQuotes = false;
75
+ let quoted = false;
76
+
77
+ for (let i = 0; i < inner.length; i++) {
78
+ const char = inner[i];
79
+ if (inQuotes) {
80
+ if (char === '\\') {
81
+ const next = inner[i + 1];
82
+ if (next === undefined) return undefined;
83
+ current += next;
84
+ i++;
85
+ continue;
86
+ }
87
+ if (char === '"') {
88
+ if (inner[i + 1] === '"') {
89
+ current += '"';
90
+ i++;
91
+ continue;
92
+ }
93
+ inQuotes = false;
94
+ continue;
95
+ }
96
+ current += char;
97
+ continue;
98
+ }
99
+ if (char === '"') {
100
+ inQuotes = true;
101
+ quoted = true;
102
+ continue;
103
+ }
104
+ if (char === ',') {
105
+ tokens.push({ value: current, quoted });
106
+ current = '';
107
+ quoted = false;
108
+ continue;
109
+ }
110
+ current += char;
111
+ }
112
+
113
+ if (inQuotes) return undefined;
114
+ tokens.push({ value: current, quoted });
115
+ return tokens;
116
+ }
117
+
118
+ /**
119
+ * Parses a Postgres array literal body (`{...}`) into a JS array of primitives.
120
+ * Returns undefined if the body cannot be reliably parsed.
121
+ *
122
+ * Handles:
123
+ * - `{}` → `[]`
124
+ * - `{elem1,elem2,...}` → `[elem1, elem2, ...]` with numeric and string element coercion
125
+ * - quoted elements that contain commas, doubled/escaped quotes, and the literal
126
+ * strings `NULL`/`true`/`false` (a quoted token is always a string)
127
+ */
128
+ function parseArrayLiteralBody(body: string): readonly JsonValue[] | undefined {
129
+ const inner = body.slice(1, -1).trim();
130
+ if (inner === '') return [];
131
+ const tokens = splitArrayElements(inner);
132
+ if (tokens === undefined) return undefined;
133
+ const result: JsonValue[] = [];
134
+ for (const token of tokens) {
135
+ if (token.quoted) {
136
+ // A quoted token is always a string — `"NULL"`, `"true"`, `"1"` are the
137
+ // literal text, never the keyword/number.
138
+ result.push(token.value);
139
+ continue;
140
+ }
141
+ const el = token.value.trim();
142
+ if (el.toUpperCase() === 'NULL') {
143
+ result.push(null);
144
+ continue;
145
+ }
146
+ if (el === 'true') {
147
+ result.push(true);
148
+ continue;
149
+ }
150
+ if (el === 'false') {
151
+ result.push(false);
152
+ continue;
153
+ }
154
+ if (NUMERIC_PATTERN.test(el)) {
155
+ result.push(Number(el));
156
+ continue;
157
+ }
158
+ return undefined;
159
+ }
160
+ return result;
161
+ }
162
+
54
163
  /**
55
164
  * Parses a raw Postgres column default expression into a normalized ColumnDefault.
56
165
  * This enables semantic comparison between contract defaults and introspected schema defaults.
@@ -59,7 +168,7 @@ function canonicalizeTimestampDefault(expr: string): string | undefined {
59
168
  * keeping the introspection layer focused on faithful data capture.
60
169
  *
61
170
  * @param rawDefault - Raw default expression from information_schema.columns.column_default
62
- * @param nativeType - Native column type, used for type-aware parsing (bigint tagging, JSON detection)
171
+ * @param nativeType - Native column type, used for type-aware parsing (array, bigint, JSON)
63
172
  * @returns Normalized ColumnDefault or undefined if the expression cannot be parsed
64
173
  */
65
174
  export function parsePostgresDefault(
@@ -69,11 +178,22 @@ export function parsePostgresDefault(
69
178
  const trimmed = rawDefault.trim();
70
179
  const normalizedType = nativeType?.toLowerCase();
71
180
  const isBigInt = normalizedType === 'bigint' || normalizedType === 'int8';
181
+ const isArrayType = normalizedType?.endsWith('[]') ?? false;
72
182
 
73
183
  if (NEXTVAL_PATTERN.test(trimmed)) {
74
184
  return { kind: 'function', expression: 'autoincrement()' };
75
185
  }
76
186
 
187
+ if (isArrayType) {
188
+ const arrayMatch = trimmed.match(ARRAY_LITERAL_PATTERN);
189
+ if (arrayMatch?.[1] !== undefined) {
190
+ const parsed = parseArrayLiteralBody(arrayMatch[1]);
191
+ if (parsed !== undefined) {
192
+ return { kind: 'literal', value: parsed };
193
+ }
194
+ }
195
+ }
196
+
77
197
  const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);
78
198
  if (canonicalTimestamp) {
79
199
  return { kind: 'function', expression: canonicalTimestamp };
@@ -2,9 +2,11 @@ import type { CodecTypes } from '../exports/codec-types';
2
2
  import {
3
3
  postgresAuthoringEntityTypes,
4
4
  postgresAuthoringFieldPresets,
5
+ postgresAuthoringPslBlockDescriptors,
5
6
  postgresAuthoringTypes,
6
7
  } from './authoring';
7
8
  import { postgresTargetDescriptorMetaRuntime } from './descriptor-meta-runtime';
9
+ import { postgresCreateNamespace } from './postgres-schema';
8
10
 
9
11
  const postgresTargetDescriptorMetaBase = {
10
12
  ...postgresTargetDescriptorMetaRuntime,
@@ -13,6 +15,8 @@ const postgresTargetDescriptorMetaBase = {
13
15
  type: postgresAuthoringTypes,
14
16
  field: postgresAuthoringFieldPresets,
15
17
  entityTypes: postgresAuthoringEntityTypes,
18
+ pslBlockDescriptors: postgresAuthoringPslBlockDescriptors,
19
+ createNamespace: postgresCreateNamespace,
16
20
  },
17
21
  } as const;
18
22
 
@@ -0,0 +1,16 @@
1
+ import type { EntityKindDescriptor } from '@prisma-next/framework-components/ir';
2
+ import { PostgresRlsPolicy, type PostgresRlsPolicyInput } from './postgres-rls-policy';
3
+ import { PostgresRole, type PostgresRoleInput } from './postgres-role';
4
+ import { PostgresRlsPolicySchema, PostgresRoleSchema } from './postgres-validators';
5
+
6
+ export const policyEntityKind: EntityKindDescriptor<PostgresRlsPolicyInput, PostgresRlsPolicy> = {
7
+ kind: 'policy',
8
+ schema: PostgresRlsPolicySchema,
9
+ construct: (input) => new PostgresRlsPolicy(input),
10
+ };
11
+
12
+ export const roleEntityKind: EntityKindDescriptor<PostgresRoleInput, PostgresRole> = {
13
+ kind: 'role',
14
+ schema: PostgresRoleSchema,
15
+ construct: (input) => new PostgresRole(input),
16
+ };
@@ -0,0 +1,10 @@
1
+ import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
2
+
3
+ /**
4
+ * Maps a planner schema name to the contract-free DDL builder's optional
5
+ * `schema` field: the unbound sentinel becomes `undefined` (the builder omits
6
+ * the schema qualifier), every other name passes through.
7
+ */
8
+ export function boundSchema(schemaName: string): string | undefined {
9
+ return schemaName === UNBOUND_NAMESPACE_ID ? undefined : schemaName;
10
+ }