@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.
- package/dist/authoring-BX1WHIdN.mjs +220 -0
- package/dist/authoring-BX1WHIdN.mjs.map +1 -0
- package/dist/canonicalize-Bn3BM1Cn.mjs +46 -0
- package/dist/canonicalize-Bn3BM1Cn.mjs.map +1 -0
- package/dist/canonicalize-CAbXtVtB.d.mts +37 -0
- package/dist/canonicalize-CAbXtVtB.d.mts.map +1 -0
- package/dist/{codec-types-DHCkwPKE.d.mts → codec-types-CueCoGD0.d.mts} +2 -2
- package/dist/{codec-types-DHCkwPKE.d.mts.map → codec-types-CueCoGD0.d.mts.map} +1 -1
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs--0A5_4Bq.d.mts → codecs-Ca8upop6.d.mts} +12 -1
- package/dist/codecs-Ca8upop6.d.mts.map +1 -0
- package/dist/codecs.d.mts +1 -1
- package/dist/codecs.mjs +34 -1
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.d.mts +8 -3
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/contract-free.mjs +3 -3
- package/dist/control.d.mts +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +639 -21
- package/dist/control.mjs.map +1 -1
- package/dist/data-transform-BOWpliq8.mjs.map +1 -1
- package/dist/{data-transform-DDgWdB5o.d.mts → data-transform-qKy1U5V9.d.mts} +2 -2
- package/dist/{data-transform-DDgWdB5o.d.mts.map → data-transform-qKy1U5V9.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/{ddl-QDyOSeLc.mjs → ddl-BmLIe1z_.mjs} +62 -5
- package/dist/ddl-BmLIe1z_.mjs.map +1 -0
- package/dist/ddl.d.mts +3 -2
- package/dist/ddl.mjs +2 -2
- package/dist/{default-normalizer-DyyCHQWs.mjs → default-normalizer-Dug8Fez9.mjs} +119 -2
- package/dist/default-normalizer-Dug8Fez9.mjs.map +1 -0
- package/dist/default-normalizer.d.mts +1 -1
- package/dist/default-normalizer.d.mts.map +1 -1
- package/dist/default-normalizer.mjs +1 -1
- package/dist/descriptor-meta-runtime-UwYdV8fD.mjs +12 -0
- package/dist/descriptor-meta-runtime-UwYdV8fD.mjs.map +1 -0
- package/dist/descriptor-meta-tjatyhtZ.mjs +18 -0
- package/dist/descriptor-meta-tjatyhtZ.mjs.map +1 -0
- package/dist/{issue-planner-DL6g3CmE.mjs → issue-planner-DbFvaAgu.mjs} +35 -10
- package/dist/issue-planner-DbFvaAgu.mjs.map +1 -0
- package/dist/issue-planner.d.mts +3 -3
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +5 -5
- package/dist/migration.mjs +4 -4
- package/dist/nodes-CSkPX3rI.d.mts +120 -0
- package/dist/nodes-CSkPX3rI.d.mts.map +1 -0
- package/dist/{nodes-Bbhs2rwj.mjs → nodes-Dh__NS58.mjs} +56 -2
- package/dist/nodes-Dh__NS58.mjs.map +1 -0
- package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-CJWUxyUW.d.mts} +44 -13
- package/dist/op-factory-call-CJWUxyUW.d.mts.map +1 -0
- package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-t65c4jyY.mjs} +201 -28
- package/dist/op-factory-call-t65c4jyY.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.d.mts +74 -2
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/planner-CG2pLHk-.mjs +640 -0
- package/dist/planner-CG2pLHk-.mjs.map +1 -0
- package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-B8Nn6nHN.mjs} +12 -27
- package/dist/planner-ddl-builders-B8Nn6nHN.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +2 -4
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-ddl-builders.mjs +2 -2
- package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-BolD0Mvc.mjs} +3 -3
- package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-BolD0Mvc.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-Cz9--XOT.d.mts} +4 -4
- package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-Cz9--XOT.d.mts.map} +1 -1
- package/dist/planner-produced-postgres-migration.d.mts +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/{planner-sql-checks-jqUUGyQR.mjs → planner-sql-checks-DE9c4519.mjs} +2 -2
- package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-DE9c4519.mjs.map} +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/{planner-target-details-CIY6tLeo.d.mts → planner-target-details-HkP4RrRO.d.mts} +2 -2
- package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -0
- package/dist/planner-target-details.d.mts +1 -1
- package/dist/planner.d.mts +82 -4
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +2 -2
- package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-BegduLr6.mjs} +50 -23
- package/dist/postgres-contract-view-BegduLr6.mjs.map +1 -0
- package/dist/postgres-contract-view-C9j5cqP0.d.mts +34 -0
- package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +1 -0
- package/dist/postgres-database-schema-node-os8ogEap.d.mts +183 -0
- package/dist/postgres-database-schema-node-os8ogEap.d.mts.map +1 -0
- package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-BfMmK6tv.mjs} +21 -2
- package/dist/postgres-migration-BfMmK6tv.mjs.map +1 -0
- package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-D7kNVWVG.d.mts} +19 -6
- package/dist/postgres-migration-D7kNVWVG.d.mts.map +1 -0
- package/dist/postgres-rls-policy--CSddvMR.d.mts +52 -0
- package/dist/postgres-rls-policy--CSddvMR.d.mts.map +1 -0
- package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-BLIHBEfX.mjs} +108 -5
- package/dist/postgres-schema-BLIHBEfX.mjs.map +1 -0
- package/dist/postgres-schema-BywoeKlt.d.mts +189 -0
- package/dist/postgres-schema-BywoeKlt.d.mts.map +1 -0
- package/dist/postgres-table-schema-node-1nNc8XDT.mjs +248 -0
- package/dist/postgres-table-schema-node-1nNc8XDT.mjs.map +1 -0
- package/dist/render-ops.d.mts +1 -1
- package/dist/{render-typescript-KMgosran.mjs → render-typescript-7yqILcwr.mjs} +45 -16
- package/dist/render-typescript-7yqILcwr.mjs.map +1 -0
- package/dist/render-typescript.mjs +1 -1
- package/dist/resolve-ddl-schema-CL1RR1mx.mjs +20 -0
- package/dist/resolve-ddl-schema-CL1RR1mx.mjs.map +1 -0
- package/dist/rls-canonicalize.d.mts +2 -0
- package/dist/rls-canonicalize.mjs +2 -0
- package/dist/runtime.d.mts +7 -6
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +3 -3
- package/dist/runtime.mjs.map +1 -1
- package/dist/schema-ir-annotations.d.mts +14 -0
- package/dist/schema-ir-annotations.d.mts.map +1 -0
- package/dist/schema-ir-annotations.mjs +2 -0
- package/dist/types.d.mts +4 -140
- package/dist/types.mjs +3 -2
- package/package.json +22 -17
- package/src/contract-free/checks.ts +73 -0
- package/src/contract-free/ddl.ts +45 -1
- package/src/core/authoring.ts +115 -1
- package/src/core/codecs.ts +35 -1
- package/src/core/ddl/nodes.ts +94 -2
- package/src/core/default-normalizer.ts +122 -2
- package/src/core/descriptor-meta.ts +4 -0
- package/src/core/entity-kinds.ts +16 -0
- package/src/core/migrations/bound-schema.ts +10 -0
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +125 -0
- package/src/core/migrations/control-policy.ts +3 -0
- package/src/core/migrations/diff-database-schema.ts +191 -0
- package/src/core/migrations/issue-planner.ts +44 -3
- package/src/core/migrations/op-factory-call.ts +109 -21
- package/src/core/migrations/operations/columns.ts +24 -12
- package/src/core/migrations/operations/data-transform.ts +6 -0
- package/src/core/migrations/operations/rls.ts +106 -0
- package/src/core/migrations/operations/shared.ts +0 -30
- package/src/core/migrations/planner-ddl-builders.ts +15 -56
- package/src/core/migrations/planner-recipes.ts +31 -13
- package/src/core/migrations/planner-strategies.ts +3 -11
- package/src/core/migrations/planner-target-details.ts +3 -1
- package/src/core/migrations/planner.ts +165 -33
- package/src/core/migrations/postgres-migration.ts +34 -4
- package/src/core/migrations/render-typescript.ts +42 -15
- package/src/core/migrations/resolve-ddl-schema.ts +24 -0
- package/src/core/migrations/runner.ts +13 -16
- package/src/core/migrations/verify-postgres-namespaces.ts +24 -19
- package/src/core/postgres-contract-serializer.ts +50 -33
- package/src/core/postgres-contract-view.ts +48 -0
- package/src/core/postgres-rls-policy.ts +64 -0
- package/src/core/postgres-role.ts +37 -0
- package/src/core/postgres-schema.ts +37 -13
- package/src/core/postgres-validators.ts +20 -0
- package/src/core/psl-infer/infer-psl-contract.ts +834 -0
- package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
- package/src/core/psl-infer/postgres-type-map.ts +157 -0
- package/src/core/rls/canonicalize.ts +48 -0
- package/src/core/schema-ir/postgres-database-schema-node.ts +63 -0
- package/src/core/schema-ir/postgres-namespace-schema-node.ts +61 -0
- package/src/core/schema-ir/postgres-policy-schema-node.ts +93 -0
- package/src/core/schema-ir/postgres-role-schema-node.ts +66 -0
- package/src/core/schema-ir/postgres-table-schema-node.ts +107 -0
- package/src/core/schema-ir/schema-node-kinds.ts +28 -0
- package/src/exports/contract-free.ts +7 -1
- package/src/exports/control.ts +39 -12
- package/src/exports/ddl.ts +4 -0
- package/src/exports/migration.ts +1 -0
- package/src/exports/planner-ddl-builders.ts +0 -2
- package/src/exports/planner.ts +2 -0
- package/src/exports/rls-canonicalize.ts +6 -0
- package/src/exports/runtime.ts +1 -0
- package/src/exports/schema-ir-annotations.ts +1 -0
- package/src/exports/types.ts +28 -0
- package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
- package/dist/ddl-QDyOSeLc.mjs.map +0 -1
- package/dist/default-normalizer-DyyCHQWs.mjs.map +0 -1
- package/dist/descriptor-meta-CpGygXpI.mjs +0 -140
- package/dist/descriptor-meta-CpGygXpI.mjs.map +0 -1
- package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
- package/dist/nodes-Bbhs2rwj.mjs.map +0 -1
- package/dist/nodes-pLeLgdis.d.mts +0 -67
- package/dist/nodes-pLeLgdis.d.mts.map +0 -1
- package/dist/op-factory-call-D_p5vxwt.mjs.map +0 -1
- package/dist/op-factory-call-DmQEc3XV.d.mts.map +0 -1
- package/dist/planner-Bs_baQax.mjs +0 -324
- package/dist/planner-Bs_baQax.mjs.map +0 -1
- package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +0 -1
- package/dist/planner-target-details-CIY6tLeo.d.mts.map +0 -1
- package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +0 -1
- package/dist/postgres-migration-B5jKrXv3.mjs.map +0 -1
- package/dist/postgres-migration-Y4YBJqkS.d.mts.map +0 -1
- package/dist/postgres-schema-COGZ1ark.mjs.map +0 -1
- package/dist/render-typescript-KMgosran.mjs.map +0 -1
- package/dist/types.d.mts.map +0 -1
package/src/contract-free/ddl.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/core/authoring.ts
CHANGED
|
@@ -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
|
|
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',
|
package/src/core/codecs.ts
CHANGED
|
@@ -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
|
|
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
|
}
|
package/src/core/ddl/nodes.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
+
}
|