@prisma-next/target-postgres 0.14.0-dev.8 → 0.14.0-dev.80
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-Bi9aa8zG.mjs +574 -0
- package/dist/authoring-Bi9aa8zG.mjs.map +1 -0
- package/dist/canonicalize-CAbXtVtB.d.mts +37 -0
- package/dist/canonicalize-CAbXtVtB.d.mts.map +1 -0
- package/dist/{codec-ids-CnXu9Qy3.d.mts → codec-ids-BzrFF-I4.d.mts} +3 -2
- package/dist/codec-ids-BzrFF-I4.d.mts.map +1 -0
- package/dist/{codec-ids-BvytN2P8.mjs → codec-ids-C_-Hj6bL.mjs} +3 -2
- package/dist/codec-ids-C_-Hj6bL.mjs.map +1 -0
- package/dist/codec-ids.d.mts +2 -2
- package/dist/codec-ids.mjs +2 -2
- package/dist/{codec-types-DHCkwPKE.d.mts → codec-types-BiIWziRO.d.mts} +3 -2
- package/dist/codec-types-BiIWziRO.d.mts.map +1 -0
- package/dist/codec-types.d.mts +1 -1
- package/dist/codecs-BemGS69L.mjs +927 -0
- package/dist/codecs-BemGS69L.mjs.map +1 -0
- package/dist/{codecs--0A5_4Bq.d.mts → codecs-Cm-nS4mQ.d.mts} +111 -4
- package/dist/codecs-Cm-nS4mQ.d.mts.map +1 -0
- package/dist/codecs.d.mts +2 -2
- package/dist/codecs.mjs +3 -757
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.d.mts +33 -3
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/contract-free.mjs +23 -7
- package/dist/contract-free.mjs.map +1 -1
- package/dist/control-policy-5LE2kwfb.mjs +1285 -0
- package/dist/control-policy-5LE2kwfb.mjs.map +1 -0
- package/dist/control.d.mts +2 -2
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +866 -36
- 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-DPzwBMhW.d.mts} +3 -3
- package/dist/{data-transform-DDgWdB5o.d.mts.map → data-transform-DPzwBMhW.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/{ddl-QDyOSeLc.mjs → ddl-BQzITB_e.mjs} +128 -6
- package/dist/ddl-BQzITB_e.mjs.map +1 -0
- package/dist/ddl.d.mts +3 -2
- package/dist/ddl.mjs +2 -2
- package/dist/default-normalizer.d.mts +1 -1
- package/dist/default-normalizer.d.mts.map +1 -1
- package/dist/default-normalizer.mjs +247 -1
- package/dist/default-normalizer.mjs.map +1 -0
- package/dist/descriptor-meta-DzL6vXAz.mjs +22 -0
- package/dist/descriptor-meta-DzL6vXAz.mjs.map +1 -0
- package/dist/descriptor-meta-runtime-UwYdV8fD.mjs +12 -0
- package/dist/descriptor-meta-runtime-UwYdV8fD.mjs.map +1 -0
- package/dist/diff-database-schema-DULhiCNM.mjs +305 -0
- package/dist/diff-database-schema-DULhiCNM.mjs.map +1 -0
- package/dist/diff-database-schema.d.mts +46 -0
- package/dist/diff-database-schema.d.mts.map +1 -0
- package/dist/diff-database-schema.mjs +2 -0
- package/dist/errors-DO-w0EUS.mjs +35 -0
- package/dist/errors-DO-w0EUS.mjs.map +1 -0
- package/dist/errors.d.mts +11 -9
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/issue-planner.d.mts +35 -11
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +2 -2
- package/dist/migration.d.mts +5 -5
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +4 -4
- package/dist/namespace-ids-xtp_ZY86.mjs +7 -0
- package/dist/namespace-ids-xtp_ZY86.mjs.map +1 -0
- package/dist/native-type-normalizer.mjs +37 -1
- package/dist/native-type-normalizer.mjs.map +1 -0
- package/dist/nodes-Bc2N3tMy.d.mts +170 -0
- package/dist/nodes-Bc2N3tMy.d.mts.map +1 -0
- package/dist/nodes-DJC5B8Id.mjs +192 -0
- package/dist/nodes-DJC5B8Id.mjs.map +1 -0
- package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-Bn9zDx4_.d.mts} +114 -15
- package/dist/op-factory-call-Bn9zDx4_.d.mts.map +1 -0
- package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-D6yu-PlS.mjs} +469 -32
- package/dist/op-factory-call-D6yu-PlS.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/pack.d.mts +300 -3
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/planner-DwDxdYxi.mjs +390 -0
- package/dist/planner-DwDxdYxi.mjs.map +1 -0
- package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-BKlmGDJl.mjs} +17 -28
- package/dist/planner-ddl-builders-BKlmGDJl.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +4 -6
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-ddl-builders.mjs +2 -2
- package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -1
- package/dist/planner-identity-values.d.mts +8 -2
- package/dist/planner-identity-values.d.mts.map +1 -1
- package/dist/planner-identity-values.mjs +2 -2
- package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-BEY1T0Xm.d.mts} +4 -4
- package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-BEY1T0Xm.d.mts.map} +1 -1
- package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-BGPpq56_.mjs} +3 -3
- package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-BGPpq56_.mjs.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-CDXn2uaS.mjs} +5 -5
- package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-CDXn2uaS.mjs.map} +1 -1
- package/dist/planner-sql-checks.d.mts +2 -2
- package/dist/planner-sql-checks.d.mts.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 +72 -17
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +3 -2
- package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-C3LPCLP_.mjs} +45 -41
- package/dist/postgres-contract-view-C3LPCLP_.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-CJv5bfbs.d.mts +262 -0
- package/dist/postgres-database-schema-node-CJv5bfbs.d.mts.map +1 -0
- package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-DbckK1su.d.mts} +58 -9
- package/dist/postgres-migration-DbckK1su.d.mts.map +1 -0
- package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-et1td40f.mjs} +78 -45
- package/dist/postgres-migration-et1td40f.mjs.map +1 -0
- package/dist/postgres-native-enum-BwVNf0Ku.mjs +45 -0
- package/dist/postgres-native-enum-BwVNf0Ku.mjs.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-role-schema-node-Cm-j0ZGM.mjs +190 -0
- package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs.map +1 -0
- package/dist/postgres-schema-DKq6s1P3.d.mts +269 -0
- package/dist/postgres-schema-DKq6s1P3.d.mts.map +1 -0
- package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-DYATroNx.mjs} +200 -11
- package/dist/postgres-schema-DYATroNx.mjs.map +1 -0
- package/dist/postgres-table-schema-node-D6LvInCe.mjs +216 -0
- package/dist/postgres-table-schema-node-D6LvInCe.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-DpGte50u.mjs +22 -0
- package/dist/resolve-ddl-schema-DpGte50u.mjs.map +1 -0
- package/dist/rls-canonicalize.d.mts +20 -0
- package/dist/rls-canonicalize.d.mts.map +1 -0
- package/dist/rls-canonicalize.mjs +2 -0
- package/dist/runtime.d.mts +6 -8
- 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 +15 -0
- package/dist/schema-ir-annotations.d.mts.map +1 -0
- package/dist/schema-ir-annotations.mjs +2 -0
- package/dist/{sql-utils-DcfMz4MQ.mjs → sql-utils-SU4FDvIV.mjs} +12 -3
- package/dist/{sql-utils-DcfMz4MQ.mjs.map → sql-utils-SU4FDvIV.mjs.map} +1 -1
- package/dist/sql-utils.d.mts +8 -1
- package/dist/sql-utils.d.mts.map +1 -1
- package/dist/sql-utils.mjs +2 -2
- package/dist/types.d.mts +4 -140
- package/dist/types.mjs +5 -2
- package/dist/wire-name-rHHtr1h0.mjs +75 -0
- package/dist/wire-name-rHHtr1h0.mjs.map +1 -0
- package/package.json +26 -20
- package/src/contract-free/checks.ts +153 -0
- package/src/contract-free/control-bootstrap.ts +20 -3
- package/src/contract-free/ddl.ts +98 -1
- package/src/core/authoring.ts +509 -2
- package/src/core/codec-helpers.ts +33 -7
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codec-type-map.ts +2 -0
- package/src/core/codecs.ts +193 -12
- package/src/core/ddl/nodes.ts +185 -2
- package/src/core/default-normalizer.ts +122 -2
- package/src/core/descriptor-meta.ts +10 -1
- package/src/core/entity-kinds.ts +41 -0
- package/src/core/errors.ts +14 -12
- package/src/core/migrations/bound-schema.ts +10 -0
- package/src/core/migrations/column-ddl-rendering.ts +117 -0
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +189 -0
- package/src/core/migrations/control-policy.ts +217 -65
- package/src/core/migrations/diff-database-schema.ts +252 -0
- package/src/core/migrations/issue-planner.ts +817 -656
- package/src/core/migrations/op-factory-call.ts +383 -23
- package/src/core/migrations/operations/columns.ts +24 -12
- package/src/core/migrations/operations/constraints.ts +1 -1
- package/src/core/migrations/operations/data-transform.ts +6 -0
- package/src/core/migrations/operations/dependencies.ts +2 -1
- package/src/core/migrations/operations/native-enum-types.ts +62 -0
- package/src/core/migrations/operations/rls.ts +187 -0
- package/src/core/migrations/operations/shared.ts +0 -30
- package/src/core/migrations/planner-ddl-builders.ts +31 -59
- package/src/core/migrations/planner-identity-values.ts +1 -1
- package/src/core/migrations/planner-recipes.ts +31 -13
- package/src/core/migrations/planner-sql-checks.ts +1 -1
- package/src/core/migrations/planner-strategies.ts +248 -216
- package/src/core/migrations/planner-target-details.ts +3 -1
- package/src/core/migrations/planner.ts +357 -67
- package/src/core/migrations/postgres-migration.ts +118 -86
- package/src/core/migrations/render-typescript.ts +42 -15
- package/src/core/migrations/resolve-ddl-schema.ts +26 -0
- package/src/core/migrations/runner.ts +11 -16
- package/src/core/migrations/verify-postgres-namespaces.ts +46 -31
- package/src/core/namespace-ids.ts +3 -0
- package/src/core/postgres-contract-serializer.ts +46 -71
- package/src/core/postgres-contract-view.ts +48 -0
- package/src/core/postgres-native-enum.ts +61 -0
- package/src/core/postgres-rls-enablement.ts +34 -0
- package/src/core/postgres-rls-policy.ts +64 -0
- package/src/core/postgres-role.ts +59 -0
- package/src/core/postgres-schema-verifier.ts +10 -7
- package/src/core/postgres-schema.ts +85 -15
- package/src/core/postgres-validators.ts +34 -0
- package/src/core/psl-infer/infer-psl-contract.ts +1273 -0
- package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
- package/src/core/psl-infer/postgres-type-map.ts +128 -0
- package/src/core/rls/canonicalize.ts +48 -0
- package/src/core/rls/wire-name.ts +33 -0
- package/src/core/schema-ir/node-storage-coordinate.ts +26 -0
- package/src/core/schema-ir/postgres-database-schema-node.ts +61 -0
- package/src/core/schema-ir/postgres-namespace-schema-node.ts +70 -0
- package/src/core/schema-ir/postgres-native-enum-schema-node.ts +83 -0
- package/src/core/schema-ir/postgres-policy-schema-node.ts +90 -0
- package/src/core/schema-ir/postgres-role-schema-node.ts +65 -0
- package/src/core/schema-ir/postgres-table-schema-node.ts +140 -0
- package/src/core/schema-ir/schema-node-kinds.ts +122 -0
- package/src/core/sql-utils.ts +15 -2
- package/src/exports/codecs.ts +3 -0
- package/src/exports/contract-free.ts +11 -1
- package/src/exports/control.ts +27 -33
- package/src/exports/ddl.ts +8 -0
- package/src/exports/diff-database-schema.ts +7 -0
- package/src/exports/issue-planner.ts +1 -1
- package/src/exports/migration.ts +1 -0
- package/src/exports/op-factory-call.ts +4 -0
- package/src/exports/planner-ddl-builders.ts +0 -2
- package/src/exports/planner-identity-values.ts +4 -1
- package/src/exports/planner.ts +1 -0
- package/src/exports/rls-canonicalize.ts +7 -0
- package/src/exports/runtime.ts +1 -0
- package/src/exports/schema-ir-annotations.ts +1 -0
- package/src/exports/sql-utils.ts +1 -0
- package/src/exports/types.ts +37 -0
- package/dist/codec-ids-BvytN2P8.mjs.map +0 -1
- package/dist/codec-ids-CnXu9Qy3.d.mts.map +0 -1
- package/dist/codec-types-DHCkwPKE.d.mts.map +0 -1
- package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
- package/dist/ddl-QDyOSeLc.mjs.map +0 -1
- package/dist/default-normalizer-DyyCHQWs.mjs +0 -131
- 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/errors-CUk87ByX.mjs +0 -33
- package/dist/errors-CUk87ByX.mjs.map +0 -1
- package/dist/issue-planner-DL6g3CmE.mjs +0 -824
- package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
- package/dist/native-type-normalizer-Bc9XJzWC.mjs +0 -38
- package/dist/native-type-normalizer-Bc9XJzWC.mjs.map +0 -1
- package/dist/nodes-Bbhs2rwj.mjs +0 -76
- 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/core/postgres-enum-type-schema.ts +0 -17
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
|
|
2
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
3
|
+
import { rlsEnabledAst, rlsPolicyExistsAst } from '../../../contract-free/checks';
|
|
4
|
+
import {
|
|
5
|
+
alterPolicyRename,
|
|
6
|
+
createPolicy,
|
|
7
|
+
disableRowLevelSecurity as disableRowLevelSecurityDdl,
|
|
8
|
+
dropPolicy,
|
|
9
|
+
} from '../../../contract-free/ddl';
|
|
10
|
+
import type { PostgresRlsPolicy } from '../../postgres-rls-policy';
|
|
11
|
+
import { qualifyTableName } from '../planner-sql-checks';
|
|
12
|
+
import { type Op, step, targetDetails } from './shared';
|
|
13
|
+
|
|
14
|
+
const PLAIN_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
15
|
+
|
|
16
|
+
function validateRoleName(role: string): string {
|
|
17
|
+
if (!PLAIN_IDENTIFIER.test(role)) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Invalid role name ${JSON.stringify(role)}: role names must be plain SQL identifiers matching ^[A-Za-z_][A-Za-z0-9_$]*$`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return role;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function createRlsPolicy(
|
|
26
|
+
schemaName: string,
|
|
27
|
+
tableName: string,
|
|
28
|
+
policy: PostgresRlsPolicy,
|
|
29
|
+
lowerer: ExecuteRequestLowerer,
|
|
30
|
+
): Promise<Op> {
|
|
31
|
+
const validatedRoles = policy.roles.map(validateRoleName);
|
|
32
|
+
const ddlNode = createPolicy({
|
|
33
|
+
schema: schemaName,
|
|
34
|
+
table: tableName,
|
|
35
|
+
name: policy.name,
|
|
36
|
+
permissive: policy.permissive,
|
|
37
|
+
operation: policy.operation,
|
|
38
|
+
roles: validatedRoles,
|
|
39
|
+
...ifDefined('using', policy.using),
|
|
40
|
+
...ifDefined('withCheck', policy.withCheck),
|
|
41
|
+
});
|
|
42
|
+
const checks = rlsPolicyExistsAst({
|
|
43
|
+
schema: schemaName,
|
|
44
|
+
table: tableName,
|
|
45
|
+
policyName: policy.name,
|
|
46
|
+
});
|
|
47
|
+
const absent = await lowerer.lowerToExecuteRequest(checks.policyAbsent());
|
|
48
|
+
const execute = await lowerer.lowerToExecuteRequest(ddlNode);
|
|
49
|
+
const present = await lowerer.lowerToExecuteRequest(checks.policyPresent());
|
|
50
|
+
return {
|
|
51
|
+
id: `rlsPolicy.${schemaName}.${tableName}.${policy.name}`,
|
|
52
|
+
label: `Create RLS policy "${policy.name}" on "${tableName}"`,
|
|
53
|
+
operationClass: 'additive',
|
|
54
|
+
target: targetDetails('rlsPolicy', policy.name, schemaName, tableName),
|
|
55
|
+
precheck: [
|
|
56
|
+
step(`ensure RLS policy "${policy.name}" does not exist`, absent.sql, absent.params),
|
|
57
|
+
],
|
|
58
|
+
execute: [step(`create RLS policy "${policy.name}"`, execute.sql, execute.params)],
|
|
59
|
+
postcheck: [step(`verify RLS policy "${policy.name}" exists`, present.sql, present.params)],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function dropRlsPolicy(
|
|
64
|
+
schemaName: string,
|
|
65
|
+
tableName: string,
|
|
66
|
+
policyName: string,
|
|
67
|
+
lowerer: ExecuteRequestLowerer,
|
|
68
|
+
): Promise<Op> {
|
|
69
|
+
const ddlNode = dropPolicy({ schema: schemaName, table: tableName, name: policyName });
|
|
70
|
+
const checks = rlsPolicyExistsAst({ schema: schemaName, table: tableName, policyName });
|
|
71
|
+
const present = await lowerer.lowerToExecuteRequest(checks.policyPresent());
|
|
72
|
+
const execute = await lowerer.lowerToExecuteRequest(ddlNode);
|
|
73
|
+
const absent = await lowerer.lowerToExecuteRequest(checks.policyAbsent());
|
|
74
|
+
return {
|
|
75
|
+
id: `rlsPolicy.${schemaName}.${tableName}.${policyName}.drop`,
|
|
76
|
+
label: `Drop RLS policy "${policyName}" on "${tableName}"`,
|
|
77
|
+
operationClass: 'destructive',
|
|
78
|
+
target: targetDetails('rlsPolicy', policyName, schemaName, tableName),
|
|
79
|
+
precheck: [step(`ensure RLS policy "${policyName}" exists`, present.sql, present.params)],
|
|
80
|
+
execute: [step(`drop RLS policy "${policyName}"`, execute.sql, execute.params)],
|
|
81
|
+
postcheck: [step(`verify RLS policy "${policyName}" is absent`, absent.sql, absent.params)],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function enableRowLevelSecurity(
|
|
86
|
+
schemaName: string,
|
|
87
|
+
tableName: string,
|
|
88
|
+
lowerer: ExecuteRequestLowerer,
|
|
89
|
+
): Promise<Op> {
|
|
90
|
+
const checks = rlsEnabledAst(schemaName, tableName);
|
|
91
|
+
const disabled = await lowerer.lowerToExecuteRequest(checks.rlsDisabled());
|
|
92
|
+
const enabled = await lowerer.lowerToExecuteRequest(checks.rlsEnabled());
|
|
93
|
+
return {
|
|
94
|
+
id: `rowLevelSecurity.${schemaName}.${tableName}`,
|
|
95
|
+
label: `Enable row-level security on "${tableName}"`,
|
|
96
|
+
operationClass: 'additive',
|
|
97
|
+
target: targetDetails('rowLevelSecurity', tableName, schemaName),
|
|
98
|
+
precheck: [
|
|
99
|
+
step(`check RLS is not already enabled on "${tableName}"`, disabled.sql, disabled.params),
|
|
100
|
+
],
|
|
101
|
+
execute: [
|
|
102
|
+
step(
|
|
103
|
+
`enable row-level security on "${tableName}"`,
|
|
104
|
+
`ALTER TABLE ${qualifyTableName(schemaName, tableName)} ENABLE ROW LEVEL SECURITY`,
|
|
105
|
+
),
|
|
106
|
+
],
|
|
107
|
+
postcheck: [
|
|
108
|
+
step(`verify row-level security is enabled on "${tableName}"`, enabled.sql, enabled.params),
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function disableRowLevelSecurity(
|
|
114
|
+
schemaName: string,
|
|
115
|
+
tableName: string,
|
|
116
|
+
lowerer: ExecuteRequestLowerer,
|
|
117
|
+
): Promise<Op> {
|
|
118
|
+
const ddlNode = disableRowLevelSecurityDdl({ schema: schemaName, table: tableName });
|
|
119
|
+
const checks = rlsEnabledAst(schemaName, tableName);
|
|
120
|
+
const enabled = await lowerer.lowerToExecuteRequest(checks.rlsEnabled());
|
|
121
|
+
const execute = await lowerer.lowerToExecuteRequest(ddlNode);
|
|
122
|
+
const disabled = await lowerer.lowerToExecuteRequest(checks.rlsDisabled());
|
|
123
|
+
return {
|
|
124
|
+
id: `rowLevelSecurity.${schemaName}.${tableName}.disable`,
|
|
125
|
+
label: `Disable row-level security on "${tableName}"`,
|
|
126
|
+
operationClass: 'destructive',
|
|
127
|
+
target: targetDetails('rowLevelSecurity', tableName, schemaName),
|
|
128
|
+
precheck: [
|
|
129
|
+
step(`check RLS is currently enabled on "${tableName}"`, enabled.sql, enabled.params),
|
|
130
|
+
],
|
|
131
|
+
execute: [step(`disable row-level security on "${tableName}"`, execute.sql, execute.params)],
|
|
132
|
+
postcheck: [
|
|
133
|
+
step(
|
|
134
|
+
`verify row-level security is disabled on "${tableName}"`,
|
|
135
|
+
disabled.sql,
|
|
136
|
+
disabled.params,
|
|
137
|
+
),
|
|
138
|
+
],
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function renameRlsPolicy(
|
|
143
|
+
schemaName: string,
|
|
144
|
+
tableName: string,
|
|
145
|
+
oldPolicyName: string,
|
|
146
|
+
newPolicyName: string,
|
|
147
|
+
lowerer: ExecuteRequestLowerer,
|
|
148
|
+
): Promise<Op> {
|
|
149
|
+
const ddlNode = alterPolicyRename({
|
|
150
|
+
schema: schemaName,
|
|
151
|
+
table: tableName,
|
|
152
|
+
name: oldPolicyName,
|
|
153
|
+
newName: newPolicyName,
|
|
154
|
+
});
|
|
155
|
+
const oldChecks = rlsPolicyExistsAst({
|
|
156
|
+
schema: schemaName,
|
|
157
|
+
table: tableName,
|
|
158
|
+
policyName: oldPolicyName,
|
|
159
|
+
});
|
|
160
|
+
const newChecks = rlsPolicyExistsAst({
|
|
161
|
+
schema: schemaName,
|
|
162
|
+
table: tableName,
|
|
163
|
+
policyName: newPolicyName,
|
|
164
|
+
});
|
|
165
|
+
const oldPresent = await lowerer.lowerToExecuteRequest(oldChecks.policyPresent());
|
|
166
|
+
const execute = await lowerer.lowerToExecuteRequest(ddlNode);
|
|
167
|
+
const newPresent = await lowerer.lowerToExecuteRequest(newChecks.policyPresent());
|
|
168
|
+
return {
|
|
169
|
+
id: `rlsPolicy.${schemaName}.${tableName}.${oldPolicyName}.rename`,
|
|
170
|
+
label: `Rename RLS policy "${oldPolicyName}" to "${newPolicyName}" on "${tableName}"`,
|
|
171
|
+
operationClass: 'widening',
|
|
172
|
+
target: targetDetails('rlsPolicy', newPolicyName, schemaName, tableName),
|
|
173
|
+
precheck: [
|
|
174
|
+
step(`ensure RLS policy "${oldPolicyName}" exists`, oldPresent.sql, oldPresent.params),
|
|
175
|
+
],
|
|
176
|
+
execute: [
|
|
177
|
+
step(
|
|
178
|
+
`rename RLS policy "${oldPolicyName}" to "${newPolicyName}"`,
|
|
179
|
+
execute.sql,
|
|
180
|
+
execute.params,
|
|
181
|
+
),
|
|
182
|
+
],
|
|
183
|
+
postcheck: [
|
|
184
|
+
step(`verify RLS policy "${newPolicyName}" exists`, newPresent.sql, newPresent.params),
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -1,30 +1,10 @@
|
|
|
1
1
|
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
2
2
|
import type { ReferentialAction } from '@prisma-next/sql-contract/types';
|
|
3
3
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
4
|
-
import { quoteIdentifier } from '../../sql-utils';
|
|
5
4
|
import type { OperationClass, PostgresPlanTargetDetails } from '../planner-target-details';
|
|
6
5
|
|
|
7
6
|
export type Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
|
|
8
7
|
|
|
9
|
-
/**
|
|
10
|
-
* Literal-args shape for a column definition consumed by `addColumn` and
|
|
11
|
-
* similar operations. Fully materialized: codec expansion and default
|
|
12
|
-
* rendering have already happened in the wrapper.
|
|
13
|
-
*
|
|
14
|
-
* - `typeSql` is the column's DDL type string (e.g. `"integer"`, `"SERIAL"`,
|
|
15
|
-
* `"varchar(100)"`), already produced by `buildColumnTypeSql` in the
|
|
16
|
-
* call-factory wrapper.
|
|
17
|
-
* - `defaultSql` is the full `DEFAULT …` clause (e.g. `"DEFAULT 42"`) or an
|
|
18
|
-
* empty string when the column has no default, matching
|
|
19
|
-
* `buildColumnDefaultSql`'s output.
|
|
20
|
-
*/
|
|
21
|
-
export interface ColumnSpec {
|
|
22
|
-
readonly name: string;
|
|
23
|
-
readonly typeSql: string;
|
|
24
|
-
readonly defaultSql: string;
|
|
25
|
-
readonly nullable: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
8
|
/**
|
|
29
9
|
* Literal-args shape for a foreign key definition. `references.schema`
|
|
30
10
|
* carries the target table's namespace (schema) coordinate so the rendered
|
|
@@ -57,13 +37,3 @@ export function targetDetails(
|
|
|
57
37
|
details: { schema, objectType, name, ...ifDefined('table', table) },
|
|
58
38
|
};
|
|
59
39
|
}
|
|
60
|
-
|
|
61
|
-
export function renderColumnDefinition(column: ColumnSpec): string {
|
|
62
|
-
const parts = [
|
|
63
|
-
quoteIdentifier(column.name),
|
|
64
|
-
column.typeSql,
|
|
65
|
-
column.defaultSql,
|
|
66
|
-
column.nullable ? '' : 'NOT NULL',
|
|
67
|
-
].filter(Boolean);
|
|
68
|
-
return parts.join(' ');
|
|
69
|
-
}
|
|
@@ -1,43 +1,10 @@
|
|
|
1
1
|
import type { CodecControlHooks } from '@prisma-next/family-sql/control';
|
|
2
|
-
import type {
|
|
3
|
-
StorageColumn,
|
|
4
|
-
StorageTable,
|
|
5
|
-
StorageTypeInstance,
|
|
6
|
-
} from '@prisma-next/sql-contract/types';
|
|
2
|
+
import type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
7
3
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
8
|
-
import { escapeLiteral, quoteIdentifier } from '../sql-utils';
|
|
4
|
+
import { escapeLiteral, quoteIdentifier, quoteQualifiedName } from '../sql-utils';
|
|
9
5
|
import type { PostgresColumnDefault } from '../types';
|
|
10
6
|
import { resolveColumnTypeMetadata } from './planner-type-resolution';
|
|
11
7
|
|
|
12
|
-
export function buildCreateTableSql(
|
|
13
|
-
qualifiedTableName: string,
|
|
14
|
-
table: StorageTable,
|
|
15
|
-
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
16
|
-
storageTypes: Record<string, StorageTypeInstance> = {},
|
|
17
|
-
): string {
|
|
18
|
-
const columnDefinitions = Object.entries(table.columns).map(
|
|
19
|
-
([columnName, column]: [string, StorageColumn]) => {
|
|
20
|
-
const parts = [
|
|
21
|
-
quoteIdentifier(columnName),
|
|
22
|
-
buildColumnTypeSql(column, codecHooks, storageTypes),
|
|
23
|
-
buildColumnDefaultSql(column.default, column),
|
|
24
|
-
column.nullable ? '' : 'NOT NULL',
|
|
25
|
-
].filter(Boolean);
|
|
26
|
-
return parts.join(' ');
|
|
27
|
-
},
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const constraintDefinitions: string[] = [];
|
|
31
|
-
if (table.primaryKey) {
|
|
32
|
-
constraintDefinitions.push(
|
|
33
|
-
`PRIMARY KEY (${table.primaryKey.columns.map(quoteIdentifier).join(', ')})`,
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const allDefinitions = [...columnDefinitions, ...constraintDefinitions];
|
|
38
|
-
return `CREATE TABLE ${qualifiedTableName} (\n ${allDefinitions.join(',\n ')}\n)`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
8
|
/**
|
|
42
9
|
* Pattern for safe PostgreSQL type names.
|
|
43
10
|
* Allows letters, digits, underscores, spaces (for "double precision", "character varying"),
|
|
@@ -98,17 +65,28 @@ export function buildColumnTypeSql(
|
|
|
98
65
|
}
|
|
99
66
|
}
|
|
100
67
|
|
|
68
|
+
// A column whose codec supplied a `typeParams.typeName` references a named
|
|
69
|
+
// database type (e.g. a native enum), not a parameterized builtin: render it
|
|
70
|
+
// as its quoted, schema-qualified type-name identifier. DDL-render only — the
|
|
71
|
+
// verify comparison value (`resolvedNativeType`) stays the bare name the
|
|
72
|
+
// family expander produces, matching introspection.
|
|
73
|
+
if (typeof resolved.typeParams?.['typeName'] === 'string') {
|
|
74
|
+
const quoted = quoteQualifiedName(resolved.nativeType);
|
|
75
|
+
return column.many ? `${quoted}[]` : quoted;
|
|
76
|
+
}
|
|
77
|
+
|
|
101
78
|
const expanded = expandParameterizedTypeSql(resolved, codecHooks);
|
|
102
79
|
if (expanded !== null) {
|
|
103
|
-
return expanded;
|
|
80
|
+
return column.many ? `${expanded}[]` : expanded;
|
|
104
81
|
}
|
|
105
82
|
|
|
106
83
|
if (column.typeRef) {
|
|
107
|
-
|
|
84
|
+
const base = quoteQualifiedName(resolved.nativeType);
|
|
85
|
+
return column.many ? `${base}[]` : base;
|
|
108
86
|
}
|
|
109
87
|
|
|
110
88
|
assertSafeNativeType(resolved.nativeType);
|
|
111
|
-
return resolved.nativeType;
|
|
89
|
+
return column.many ? `${resolved.nativeType}[]` : resolved.nativeType;
|
|
112
90
|
}
|
|
113
91
|
|
|
114
92
|
function expandParameterizedTypeSql(
|
|
@@ -150,7 +128,7 @@ function expandParameterizedTypeSql(
|
|
|
150
128
|
/** Autoincrement columns use SERIAL types, so this returns empty for them. */
|
|
151
129
|
export function buildColumnDefaultSql(
|
|
152
130
|
columnDefault: PostgresColumnDefault | undefined,
|
|
153
|
-
column?: StorageColumn,
|
|
131
|
+
column?: Pick<StorageColumn, 'many' | 'nativeType'>,
|
|
154
132
|
): string {
|
|
155
133
|
if (!columnDefault) {
|
|
156
134
|
return '';
|
|
@@ -171,9 +149,16 @@ export function buildColumnDefaultSql(
|
|
|
171
149
|
}
|
|
172
150
|
}
|
|
173
151
|
|
|
174
|
-
export function renderDefaultLiteral(
|
|
152
|
+
export function renderDefaultLiteral(
|
|
153
|
+
value: unknown,
|
|
154
|
+
column?: Pick<StorageColumn, 'many' | 'nativeType'>,
|
|
155
|
+
): string {
|
|
175
156
|
const isJsonColumn = column?.nativeType === 'json' || column?.nativeType === 'jsonb';
|
|
176
157
|
|
|
158
|
+
if (column?.many && Array.isArray(value)) {
|
|
159
|
+
return renderArrayLiteralDefault(value);
|
|
160
|
+
}
|
|
161
|
+
|
|
177
162
|
if (value instanceof Date) {
|
|
178
163
|
return `'${escapeLiteral(value.toISOString())}'`;
|
|
179
164
|
}
|
|
@@ -193,23 +178,10 @@ export function renderDefaultLiteral(value: unknown, column?: StorageColumn): st
|
|
|
193
178
|
return `'${escapeLiteral(json)}'`;
|
|
194
179
|
}
|
|
195
180
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
storageTypes: Record<string, StorageTypeInstance> = {},
|
|
203
|
-
): string {
|
|
204
|
-
const typeSql = buildColumnTypeSql(column, codecHooks, storageTypes);
|
|
205
|
-
const defaultSql =
|
|
206
|
-
buildColumnDefaultSql(column.default, column) ||
|
|
207
|
-
(temporaryDefault ? `DEFAULT ${temporaryDefault}` : '');
|
|
208
|
-
const parts = [
|
|
209
|
-
`ALTER TABLE ${qualifiedTableName}`,
|
|
210
|
-
`ADD COLUMN ${quoteIdentifier(columnName)} ${typeSql}`,
|
|
211
|
-
defaultSql,
|
|
212
|
-
column.nullable ? '' : 'NOT NULL',
|
|
213
|
-
].filter(Boolean);
|
|
214
|
-
return parts.join(' ');
|
|
181
|
+
function renderArrayLiteralDefault(elements: unknown[]): string {
|
|
182
|
+
if (elements.length === 0) {
|
|
183
|
+
return "'{}'";
|
|
184
|
+
}
|
|
185
|
+
const rendered = elements.map((el) => renderDefaultLiteral(el)).join(', ');
|
|
186
|
+
return `ARRAY[${rendered}]`;
|
|
215
187
|
}
|
|
@@ -9,7 +9,7 @@ import { ifDefined } from '@prisma-next/utils/defined';
|
|
|
9
9
|
*/
|
|
10
10
|
export function resolveIdentityValue(
|
|
11
11
|
column: StorageColumn,
|
|
12
|
-
codecHooks:
|
|
12
|
+
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
13
13
|
storageTypes: Record<string, StorageTypeInstance> = {},
|
|
14
14
|
): string | null {
|
|
15
15
|
const referencedType = column.typeRef ? storageTypes[column.typeRef] : undefined;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type { CodecControlHooks, SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
2
2
|
import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
|
|
3
3
|
import type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
4
|
+
import { FunctionColumnDefault } from '@prisma-next/sql-relational-core/ast';
|
|
5
|
+
import { col } from '@prisma-next/sql-relational-core/contract-free';
|
|
6
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
4
7
|
import {
|
|
5
8
|
columnDefaultAst,
|
|
6
9
|
columnExistsAst,
|
|
7
10
|
columnNullabilityAst,
|
|
8
11
|
} from '../../contract-free/checks';
|
|
9
|
-
import
|
|
12
|
+
import * as contractFreeDdl from '../../contract-free/ddl';
|
|
13
|
+
import { boundSchema } from './bound-schema';
|
|
10
14
|
import { step } from './operations/shared';
|
|
11
|
-
import {
|
|
12
|
-
import { qualifyTableName } from './planner-sql-checks';
|
|
15
|
+
import { buildColumnTypeSql } from './planner-ddl-builders';
|
|
13
16
|
import { buildTargetDetails, type PostgresPlanTargetDetails } from './planner-target-details';
|
|
14
17
|
|
|
15
18
|
export function buildAddColumnOperationIdentity(
|
|
@@ -51,7 +54,29 @@ export async function buildAddNotNullColumnWithTemporaryDefaultOperation(options
|
|
|
51
54
|
temporaryDefault,
|
|
52
55
|
lowerer,
|
|
53
56
|
} = options;
|
|
54
|
-
|
|
57
|
+
|
|
58
|
+
// The recipe handles NOT NULL columns that carry no contract default, so the
|
|
59
|
+
// temporary backfill value is the only default. It is a pre-rendered SQL
|
|
60
|
+
// fragment (e.g. `''`, `0`, `'{}'::jsonb`), carried verbatim as a
|
|
61
|
+
// `FunctionColumnDefault` so the adapter emits it as a `DEFAULT (...)` clause.
|
|
62
|
+
const ddlColumn = col(columnName, buildColumnTypeSql(column, codecHooks, storageTypes), {
|
|
63
|
+
notNull: true,
|
|
64
|
+
default: new FunctionColumnDefault(temporaryDefault),
|
|
65
|
+
});
|
|
66
|
+
const addColumn = await lowerer.lowerToExecuteRequest(
|
|
67
|
+
contractFreeDdl.alterTable({
|
|
68
|
+
...ifDefined('schema', boundSchema(schema)),
|
|
69
|
+
table: tableName,
|
|
70
|
+
actions: [contractFreeDdl.addColumnAction(ddlColumn)],
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
73
|
+
const dropTempDefault = await lowerer.lowerToExecuteRequest(
|
|
74
|
+
contractFreeDdl.alterTable({
|
|
75
|
+
...ifDefined('schema', boundSchema(schema)),
|
|
76
|
+
table: tableName,
|
|
77
|
+
actions: [contractFreeDdl.dropDefaultAction(columnName)],
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
55
80
|
|
|
56
81
|
const absent = await lowerer.lowerToExecuteRequest(
|
|
57
82
|
columnExistsAst({ schema, table: tableName, column: columnName }).columnAbsent(),
|
|
@@ -73,18 +98,11 @@ export async function buildAddNotNullColumnWithTemporaryDefaultOperation(options
|
|
|
73
98
|
execute: [
|
|
74
99
|
{
|
|
75
100
|
description: `add column "${columnName}"`,
|
|
76
|
-
sql:
|
|
77
|
-
qualified,
|
|
78
|
-
columnName,
|
|
79
|
-
column,
|
|
80
|
-
codecHooks,
|
|
81
|
-
temporaryDefault,
|
|
82
|
-
storageTypes,
|
|
83
|
-
),
|
|
101
|
+
sql: addColumn.sql,
|
|
84
102
|
},
|
|
85
103
|
{
|
|
86
104
|
description: `drop temporary default from column "${columnName}"`,
|
|
87
|
-
sql:
|
|
105
|
+
sql: dropTempDefault.sql,
|
|
88
106
|
},
|
|
89
107
|
],
|
|
90
108
|
postcheck: [
|
|
@@ -145,7 +145,7 @@ function formatUserDefinedTypeName(identifier: string): string {
|
|
|
145
145
|
|
|
146
146
|
export function buildExpectedFormatType(
|
|
147
147
|
column: StorageColumn,
|
|
148
|
-
codecHooks:
|
|
148
|
+
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
149
149
|
storageTypes: Record<string, StorageTypeInstance> = {},
|
|
150
150
|
): string {
|
|
151
151
|
const resolved = resolveColumnTypeMetadata(column, storageTypes);
|