@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
|
@@ -13,28 +13,43 @@ import {
|
|
|
13
13
|
plannerFailure,
|
|
14
14
|
} from '@prisma-next/family-sql/control';
|
|
15
15
|
import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
|
|
16
|
-
import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
|
|
17
16
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
18
17
|
import type {
|
|
19
18
|
MigrationPlanner,
|
|
20
19
|
MigrationPlanWithAuthoringSurface,
|
|
21
20
|
MigrationScaffoldContext,
|
|
22
|
-
|
|
21
|
+
SchemaDiffIssue,
|
|
22
|
+
SchemaOwnership,
|
|
23
23
|
} from '@prisma-next/framework-components/control';
|
|
24
24
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
25
|
+
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
26
|
+
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
25
27
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
29
|
+
import { PostgresRlsPolicy } from '../postgres-rls-policy';
|
|
30
|
+
import { parseRlsPolicyWireName } from '../rls/wire-name';
|
|
31
|
+
import { postgresNodeStorageCoordinate } from '../schema-ir/node-storage-coordinate';
|
|
32
|
+
import { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
|
|
33
|
+
import { PostgresPolicySchemaNode } from '../schema-ir/postgres-policy-schema-node';
|
|
34
|
+
import type { SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';
|
|
28
35
|
import {
|
|
29
|
-
|
|
36
|
+
renderPostgresSuppression,
|
|
37
|
+
resolveNamespaceIdForDdlSchema,
|
|
30
38
|
resolvePostgresCallControlPolicySubject,
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
resolvePostgresNodeIssueControlPolicySubject,
|
|
40
|
+
resolvePostgresNodeIssueCreationFactoryName,
|
|
33
41
|
} from './control-policy';
|
|
34
|
-
import {
|
|
42
|
+
import { buildPostgresPlanDiff } from './diff-database-schema';
|
|
43
|
+
import { coalesceSubtreeIssues, issueNode, issueSchemaName, planIssues } from './issue-planner';
|
|
35
44
|
import type { PostgresOpFactoryCall } from './op-factory-call';
|
|
45
|
+
import {
|
|
46
|
+
CreatePostgresRlsPolicyCall,
|
|
47
|
+
DropPostgresRlsPolicyCall,
|
|
48
|
+
RenamePostgresRlsPolicyCall,
|
|
49
|
+
} from './op-factory-call';
|
|
36
50
|
import { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';
|
|
37
51
|
import { postgresPlannerStrategies } from './planner-strategies';
|
|
52
|
+
import { resolveDdlSchemaForNamespaceStorage } from './resolve-ddl-schema';
|
|
38
53
|
import { verifyPostgresNamespacePresence } from './verify-postgres-namespaces';
|
|
39
54
|
|
|
40
55
|
type PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {
|
|
@@ -47,10 +62,6 @@ type PlannerOptionsWithComponents = SqlMigrationPlannerPlanOptions & {
|
|
|
47
62
|
readonly frameworkComponents: PlannerFrameworkComponents;
|
|
48
63
|
};
|
|
49
64
|
|
|
50
|
-
type VerifySqlSchemaOptionsWithComponents = Parameters<typeof verifySqlSchema>[0] & {
|
|
51
|
-
readonly frameworkComponents: PlannerFrameworkComponents;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
65
|
export function createPostgresMigrationPlanner(
|
|
55
66
|
lowerer: ExecuteRequestLowerer,
|
|
56
67
|
): PostgresMigrationPlanner {
|
|
@@ -75,18 +86,20 @@ export type PostgresPlanResult =
|
|
|
75
86
|
/**
|
|
76
87
|
* Postgres migration planner — a thin wrapper over `planIssues`.
|
|
77
88
|
*
|
|
78
|
-
* `plan()`
|
|
79
|
-
* `
|
|
80
|
-
* `
|
|
81
|
-
* type-change, nullable-tightening, codec-hook
|
|
82
|
-
* component-declared dependency installs, and
|
|
83
|
-
* empty-table-guarded NOT-NULL add-column. The same
|
|
84
|
-
* `migration plan`, `db update`, and `db init`;
|
|
85
|
-
* `policy.allowedOperationClasses` (the
|
|
86
|
-
* when `'data'` is excluded). The issue
|
|
87
|
-
* policy gates and emits a single
|
|
88
|
-
* the runtime-ops view (via
|
|
89
|
-
* authoring surface.
|
|
89
|
+
* `plan()` diffs the target contract against the live schema via the one
|
|
90
|
+
* differ (`buildPostgresPlanDiff`, producing node-typed `SchemaDiffIssue[]`)
|
|
91
|
+
* and delegates to `planIssues` with the unified `postgresPlannerStrategies`
|
|
92
|
+
* list: NOT-NULL backfill, type-change, nullable-tightening, codec-hook
|
|
93
|
+
* storage types, component-declared dependency installs, and
|
|
94
|
+
* shared-temp-default / empty-table-guarded NOT-NULL add-column. The same
|
|
95
|
+
* strategy list runs for `migration plan`, `db update`, and `db init`;
|
|
96
|
+
* behavior diverges purely on `policy.allowedOperationClasses` (the
|
|
97
|
+
* data-safe strategies short-circuit when `'data'` is excluded). The issue
|
|
98
|
+
* planner applies operation-class policy gates and emits a single
|
|
99
|
+
* `PostgresOpFactoryCall[]` that drives both the runtime-ops view (via
|
|
100
|
+
* `renderOps`) and the `renderTypeScript()` authoring surface. RLS policy
|
|
101
|
+
* drift (the structural half of the same one-differ tree) is handled
|
|
102
|
+
* separately via `planPostgresSchemaDiff`.
|
|
90
103
|
*/
|
|
91
104
|
export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {
|
|
92
105
|
readonly #lowerer: ExecuteRequestLowerer | undefined;
|
|
@@ -122,6 +135,11 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
122
135
|
* the marker row by the right space.
|
|
123
136
|
*/
|
|
124
137
|
readonly spaceId: string;
|
|
138
|
+
/**
|
|
139
|
+
* Ownership oracle over the contract-space composition — see
|
|
140
|
+
* {@link SqlMigrationPlannerPlanOptions.ownership}.
|
|
141
|
+
*/
|
|
142
|
+
readonly ownership?: SchemaOwnership;
|
|
125
143
|
}): PostgresPlanResult {
|
|
126
144
|
return this.planSql(options as SqlMigrationPlannerPlanOptions);
|
|
127
145
|
}
|
|
@@ -151,9 +169,73 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
151
169
|
return policyResult;
|
|
152
170
|
}
|
|
153
171
|
|
|
154
|
-
|
|
172
|
+
// The one combined tree diff drives the whole plan: relational findings
|
|
173
|
+
// become structural DDL via `planIssues`, policy findings become RLS ops
|
|
174
|
+
// via `planPostgresSchemaDiff`. Verify runs its own full-tree node diff
|
|
175
|
+
// (`diffSchema`) over the same schema and rejects on a
|
|
176
|
+
// surviving failure.
|
|
177
|
+
PostgresDatabaseSchemaNode.assert(options.schema);
|
|
178
|
+
const { issues: rawIssues } = buildPostgresPlanDiff({
|
|
179
|
+
contract: options.contract,
|
|
180
|
+
actualSchema: options.schema,
|
|
181
|
+
frameworkComponents: options.frameworkComponents,
|
|
182
|
+
});
|
|
183
|
+
const policyDiffIssues = rawIssues.filter((issue) => isPolicyDiffIssue(issue));
|
|
184
|
+
// Role diff issues resolve to the `external` control policy (see
|
|
185
|
+
// `resolvePostgresNodeIssueControlPolicySubject`'s role branch), so the
|
|
186
|
+
// control-policy partition below suppresses them to zero ops on its own,
|
|
187
|
+
// before `mapNodeIssueToCall` ever sees them — no separate exclusion
|
|
188
|
+
// needed here.
|
|
189
|
+
const relationalDiffIssues = rawIssues.filter((issue) => !isPolicyDiffIssue(issue));
|
|
190
|
+
|
|
191
|
+
// The generic differ is total and un-gated: strict-mode extras filtering
|
|
192
|
+
// (dropping `not-expected` findings outside strict mode, mirroring the
|
|
193
|
+
// retired coordinate walk's `if (strict) { ...extra_* } }` guards),
|
|
194
|
+
// subtree coalescing (a missing/extra table also emits an issue for
|
|
195
|
+
// every child under it — redundant once the table-level Create/Drop call
|
|
196
|
+
// already accounts for the whole subtree), and ownership are all post-diff
|
|
197
|
+
// planner steps.
|
|
198
|
+
//
|
|
199
|
+
// Ownership: a live extra is only this plan's to drop when no contract
|
|
200
|
+
// space owns it. The differ ran against THIS space's contract, so a table
|
|
201
|
+
// a sibling space owns surfaces here as `not-expected`; the planner asks
|
|
202
|
+
// the ownership oracle (the passive aggregate) whether any space declares
|
|
203
|
+
// it and, if so, leaves it alone — it is a sibling's table, not an orphan.
|
|
204
|
+
// A table no space owns stays a genuine extra to drop under a destructive
|
|
205
|
+
// policy. Ownership lives in the aggregate; the planner only asks. Absent
|
|
206
|
+
// oracle (single-space, none handed) keeps every extra. Coalescing MUST
|
|
207
|
+
// run before this so a sibling-owned table's child issues have already
|
|
208
|
+
// collapsed into the one table-level issue that carries the table name.
|
|
209
|
+
const strict =
|
|
210
|
+
options.policy.allowedOperationClasses.includes('widening') ||
|
|
211
|
+
options.policy.allowedOperationClasses.includes('destructive');
|
|
212
|
+
const coalesced = coalesceSubtreeIssues(relationalDiffIssues);
|
|
213
|
+
const owned = retainUnownedExtras(coalesced, options.ownership, options.contract);
|
|
214
|
+
const gated = strict ? owned : owned.filter((issue) => issue.reason !== 'not-expected');
|
|
215
|
+
|
|
216
|
+
// Namespace presence (`CREATE SCHEMA`) is a planner-only op-generation
|
|
217
|
+
// concern stitched in here rather than inside the shared diff — verify
|
|
218
|
+
// never needs it (a missing schema already surfaces as a `not-found`
|
|
219
|
+
// table in the relational findings). These synthesized issues are added
|
|
220
|
+
// AFTER coalescing/scoping (never coalesced against the table diff —
|
|
221
|
+
// their path is an ancestor of every table path under that schema, so
|
|
222
|
+
// running them through the same coalesce would swallow the table-level
|
|
223
|
+
// `not-found` issues that drive `CREATE TABLE`) and are NOT subject to
|
|
224
|
+
// sibling-space scoping, matching the retired coordinate walk exactly.
|
|
225
|
+
const namespaceIssues = verifyPostgresNamespacePresence({
|
|
226
|
+
contract: options.contract,
|
|
227
|
+
schema: options.schema,
|
|
228
|
+
});
|
|
229
|
+
const schemaIssues = [...namespaceIssues, ...gated];
|
|
230
|
+
|
|
155
231
|
const codecHooks = extractCodecControlHooks(options.frameworkComponents);
|
|
156
232
|
const storageTypes = options.contract.storage.types ?? {};
|
|
233
|
+
// The strategy layer reads the live schema by bare table name for existence
|
|
234
|
+
// checks (shared-temp-default safety, FK/unique probes), so it takes one
|
|
235
|
+
// per-schema namespace node — never the whole tree root, and never a flat
|
|
236
|
+
// merge of every namespace (which would collide same-named tables across
|
|
237
|
+
// schemas). Probing more than one namespace at once is future work.
|
|
238
|
+
const relationalSchema = relationalNamespaceNode(options.schema, schemaName);
|
|
157
239
|
|
|
158
240
|
// Input-side control-policy partition. `external` / `observed` subjects
|
|
159
241
|
// — and non-creation issues for `tolerated` subjects — are dropped from
|
|
@@ -166,10 +248,8 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
166
248
|
issues: schemaIssues,
|
|
167
249
|
contract: options.contract,
|
|
168
250
|
resolveControlPolicySubject: (issue) =>
|
|
169
|
-
|
|
170
|
-
resolveCreationFactoryName:
|
|
171
|
-
formatSubjectLabel: (factoryName, subject) =>
|
|
172
|
-
formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
|
|
251
|
+
resolvePostgresNodeIssueControlPolicySubject(issue, options.contract),
|
|
252
|
+
resolveCreationFactoryName: resolvePostgresNodeIssueCreationFactoryName,
|
|
173
253
|
});
|
|
174
254
|
|
|
175
255
|
const result = planIssues({
|
|
@@ -179,12 +259,12 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
179
259
|
// `db update` / `db init`, which means data-safety strategies needing
|
|
180
260
|
// from/to comparisons (unsafe type change, nullable tightening) are
|
|
181
261
|
// inapplicable there — reconciliation falls through to
|
|
182
|
-
// `
|
|
262
|
+
// `mapNodeIssueToCall`'s direct destructive handlers.
|
|
183
263
|
fromContract: options.fromContract,
|
|
184
264
|
schemaName,
|
|
185
265
|
codecHooks,
|
|
186
266
|
storageTypes,
|
|
187
|
-
schema
|
|
267
|
+
...ifDefined('schema', relationalSchema),
|
|
188
268
|
policy: options.policy,
|
|
189
269
|
frameworkComponents: options.frameworkComponents,
|
|
190
270
|
strategies: postgresPlannerStrategies,
|
|
@@ -194,6 +274,15 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
194
274
|
return plannerFailure(result.failure);
|
|
195
275
|
}
|
|
196
276
|
|
|
277
|
+
const schemaDiffCalls = this.planPostgresSchemaDiff(options, policyDiffIssues);
|
|
278
|
+
const schemaDiffPartition = partitionCallsByControlPolicy({
|
|
279
|
+
calls: schemaDiffCalls,
|
|
280
|
+
contract: options.contract,
|
|
281
|
+
resolveControlPolicySubject: (call) =>
|
|
282
|
+
resolvePostgresCallControlPolicySubject(call, options.contract),
|
|
283
|
+
resolveFactoryName: (call) => call.factoryName,
|
|
284
|
+
});
|
|
285
|
+
|
|
197
286
|
// Inline `onFieldEvent`-emitted ops after structural DDL. The fixed
|
|
198
287
|
// ordering is `structural → added → dropped → altered`, with
|
|
199
288
|
// within-group sorting by `(tableName, fieldName)` so re-emits are
|
|
@@ -216,14 +305,13 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
216
305
|
resolveControlPolicySubject: (call) =>
|
|
217
306
|
resolvePostgresCallControlPolicySubject(call, options.contract),
|
|
218
307
|
resolveFactoryName: (call) => call.factoryName,
|
|
219
|
-
formatSubjectLabel: (factoryName, subject) =>
|
|
220
|
-
formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
|
|
221
308
|
});
|
|
222
|
-
const calls = [...result.value.calls, ...fieldEventPartition.kept];
|
|
309
|
+
const calls = [...result.value.calls, ...schemaDiffPartition.kept, ...fieldEventPartition.kept];
|
|
223
310
|
const warnings: SqlPlannerConflict[] = [
|
|
224
|
-
...issuePartition.
|
|
225
|
-
...
|
|
226
|
-
|
|
311
|
+
...issuePartition.suppressions,
|
|
312
|
+
...schemaDiffPartition.suppressions,
|
|
313
|
+
...fieldEventPartition.suppressions,
|
|
314
|
+
].map((record) => renderPostgresSuppression(record, options.contract));
|
|
227
315
|
|
|
228
316
|
return Object.freeze({
|
|
229
317
|
kind: 'success' as const,
|
|
@@ -240,6 +328,142 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
240
328
|
});
|
|
241
329
|
}
|
|
242
330
|
|
|
331
|
+
/**
|
|
332
|
+
* Maps the RLS policy presence findings of the one combined tree diff
|
|
333
|
+
* (`buildPostgresPlanDiff`, already ownership-filtered) into
|
|
334
|
+
* `CREATE POLICY` / `DROP POLICY` / `ALTER POLICY … RENAME TO` ops. It
|
|
335
|
+
* does not re-diff — it consumes exactly the policy-node subset of the
|
|
336
|
+
* shared diff's issues. Enablement is NOT decided here: `ENABLE`/`DISABLE
|
|
337
|
+
* ROW LEVEL SECURITY` derive from the table's marker-driven `rlsEnabled`
|
|
338
|
+
* attribute diff on the relational side.
|
|
339
|
+
*
|
|
340
|
+
* Rename post-pass: a `not-found` and a `not-expected` policy on the SAME
|
|
341
|
+
* table whose wire-name content hashes match but prefixes differ are one
|
|
342
|
+
* prefix-only rename, collapsed into a single non-destructive
|
|
343
|
+
* `RenamePostgresRlsPolicyCall`. Multi-candidate hash groups pair
|
|
344
|
+
* deterministically by sorted wire name; leftovers proceed as
|
|
345
|
+
* create/drop. Unparseable wire names never pair.
|
|
346
|
+
*
|
|
347
|
+
* The pairing runs only when the policy allows `widening` (rename's
|
|
348
|
+
* class). Without it (db-init's additive-only set), pairing degrades
|
|
349
|
+
* deliberately to the additive half: the new name is CREATEd and the old
|
|
350
|
+
* policy survives live until a widening/destructive-allowed plan runs —
|
|
351
|
+
* emitting an ungated widening rename would only fail at the runner's
|
|
352
|
+
* class re-enforcement.
|
|
353
|
+
*/
|
|
354
|
+
private planPostgresSchemaDiff(
|
|
355
|
+
options: PlannerOptionsWithComponents,
|
|
356
|
+
filteredDiffIssues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],
|
|
357
|
+
): readonly PostgresOpFactoryCall[] {
|
|
358
|
+
const allowsDestructive = options.policy.allowedOperationClasses.includes('destructive');
|
|
359
|
+
const allowsWidening = options.policy.allowedOperationClasses.includes('widening');
|
|
360
|
+
|
|
361
|
+
interface PolicyFinding {
|
|
362
|
+
readonly node: PostgresPolicySchemaNode;
|
|
363
|
+
readonly schemaForTable: string;
|
|
364
|
+
}
|
|
365
|
+
const missing: PolicyFinding[] = [];
|
|
366
|
+
const extra: PolicyFinding[] = [];
|
|
367
|
+
|
|
368
|
+
for (const issue of filteredDiffIssues) {
|
|
369
|
+
// 'not-equal' is unreachable for content-addressed policies: the wire name
|
|
370
|
+
// encodes the body hash, so two policies sharing a local key (same name)
|
|
371
|
+
// are always equal and isEqualTo never returns false.
|
|
372
|
+
if (issue.reason === 'not-found') {
|
|
373
|
+
const expected = issue.expected;
|
|
374
|
+
PostgresPolicySchemaNode.assert(expected);
|
|
375
|
+
// expected.namespaceId is the DDL schema name (resolved during projection);
|
|
376
|
+
// this re-resolution is a no-op as long as PostgresSchema.ddlSchemaName() returns this.id.
|
|
377
|
+
missing.push({
|
|
378
|
+
node: expected,
|
|
379
|
+
schemaForTable: resolveDdlSchemaForNamespaceStorage(
|
|
380
|
+
options.contract.storage,
|
|
381
|
+
expected.namespaceId,
|
|
382
|
+
),
|
|
383
|
+
});
|
|
384
|
+
} else if (issue.reason === 'not-expected') {
|
|
385
|
+
const actual = issue.actual;
|
|
386
|
+
PostgresPolicySchemaNode.assert(actual);
|
|
387
|
+
extra.push({
|
|
388
|
+
node: actual,
|
|
389
|
+
schemaForTable: resolveDdlSchemaForNamespaceStorage(
|
|
390
|
+
options.contract.storage,
|
|
391
|
+
actual.namespaceId,
|
|
392
|
+
),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const calls: PostgresOpFactoryCall[] = [];
|
|
398
|
+
const renamedExtras = new Set<PolicyFinding>();
|
|
399
|
+
const renamedMissing = new Set<PolicyFinding>();
|
|
400
|
+
const pairingKey = (finding: PolicyFinding, hash: string): string =>
|
|
401
|
+
JSON.stringify([finding.schemaForTable, finding.node.tableName, hash]);
|
|
402
|
+
|
|
403
|
+
if (allowsWidening) {
|
|
404
|
+
const extrasByGroup = new Map<string, PolicyFinding[]>();
|
|
405
|
+
for (const finding of extra) {
|
|
406
|
+
const parsed = parseRlsPolicyWireName(finding.node.name);
|
|
407
|
+
if (parsed === undefined) continue;
|
|
408
|
+
const key = pairingKey(finding, parsed.hash);
|
|
409
|
+
const group = extrasByGroup.get(key) ?? [];
|
|
410
|
+
group.push(finding);
|
|
411
|
+
extrasByGroup.set(key, group);
|
|
412
|
+
}
|
|
413
|
+
for (const group of extrasByGroup.values()) {
|
|
414
|
+
group.sort((a, b) => (a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const sortedMissing = [...missing].sort((a, b) =>
|
|
418
|
+
a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0,
|
|
419
|
+
);
|
|
420
|
+
for (const missingFinding of sortedMissing) {
|
|
421
|
+
const parsed = parseRlsPolicyWireName(missingFinding.node.name);
|
|
422
|
+
if (parsed === undefined) continue;
|
|
423
|
+
const candidates = extrasByGroup.get(pairingKey(missingFinding, parsed.hash));
|
|
424
|
+
const candidate = candidates?.shift();
|
|
425
|
+
if (candidate === undefined) continue;
|
|
426
|
+
// Same name would never surface as missing+extra (the differ pairs by
|
|
427
|
+
// name), so a matched candidate always differs in prefix only.
|
|
428
|
+
renamedExtras.add(candidate);
|
|
429
|
+
renamedMissing.add(missingFinding);
|
|
430
|
+
calls.push(
|
|
431
|
+
new RenamePostgresRlsPolicyCall(
|
|
432
|
+
missingFinding.schemaForTable,
|
|
433
|
+
missingFinding.node.tableName,
|
|
434
|
+
candidate.node.name,
|
|
435
|
+
missingFinding.node.name,
|
|
436
|
+
),
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
for (const finding of missing) {
|
|
442
|
+
if (renamedMissing.has(finding)) continue;
|
|
443
|
+
calls.push(
|
|
444
|
+
new CreatePostgresRlsPolicyCall(
|
|
445
|
+
finding.schemaForTable,
|
|
446
|
+
finding.node.tableName,
|
|
447
|
+
policyNodeToContractPolicy(finding.node),
|
|
448
|
+
),
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
if (allowsDestructive) {
|
|
452
|
+
for (const finding of extra) {
|
|
453
|
+
if (renamedExtras.has(finding)) continue;
|
|
454
|
+
calls.push(
|
|
455
|
+
new DropPostgresRlsPolicyCall(
|
|
456
|
+
finding.schemaForTable,
|
|
457
|
+
finding.node.tableName,
|
|
458
|
+
finding.node.name,
|
|
459
|
+
),
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return calls;
|
|
465
|
+
}
|
|
466
|
+
|
|
243
467
|
private ensureAdditivePolicy(policy: MigrationOperationPolicy) {
|
|
244
468
|
if (!policy.allowedOperationClasses.includes('additive')) {
|
|
245
469
|
return plannerFailure([
|
|
@@ -252,35 +476,101 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
252
476
|
}
|
|
253
477
|
return null;
|
|
254
478
|
}
|
|
479
|
+
}
|
|
255
480
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
481
|
+
/**
|
|
482
|
+
* A diff issue whose node is an RLS policy — the structural half of the one
|
|
483
|
+
* combined tree diff, routed to `planPostgresSchemaDiff` instead of
|
|
484
|
+
* `planIssues`.
|
|
485
|
+
*/
|
|
486
|
+
function isPolicyDiffIssue(issue: SchemaDiffIssue<SqlSchemaDiffNode>): boolean {
|
|
487
|
+
const node = issue.expected ?? issue.actual;
|
|
488
|
+
return node !== undefined && PostgresPolicySchemaNode.is(node);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Drops a `not-expected` issue when it is a whole extra storage entity (a table
|
|
493
|
+
* or a native enum) that some space in the composition owns. Each such node
|
|
494
|
+
* yields its own storage coordinate (see {@link postgresNodeStorageCoordinate}),
|
|
495
|
+
* so `declaresEntity` answers over the whole composition on one uniform
|
|
496
|
+
* coordinate: a positive answer means a sibling owns this entity here — leave
|
|
497
|
+
* it; a negative answer means a genuine orphan — drop it. A node with no storage
|
|
498
|
+
* coordinate (a namespace, or a deeper column/constraint drift on an owned
|
|
499
|
+
* table) is this space's own and is always kept. No oracle ⇒ keep everything.
|
|
500
|
+
*/
|
|
501
|
+
function retainUnownedExtras(
|
|
502
|
+
issues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],
|
|
503
|
+
ownership: SchemaOwnership | undefined,
|
|
504
|
+
contract: Contract<SqlStorage>,
|
|
505
|
+
): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {
|
|
506
|
+
if (ownership === undefined) return issues;
|
|
507
|
+
return issues.filter((issue) => {
|
|
508
|
+
if (issue.reason !== 'not-expected') return true;
|
|
509
|
+
const node = issueNode(issue);
|
|
510
|
+
if (node === undefined) return true;
|
|
511
|
+
const coordinate = postgresNodeStorageCoordinate(node);
|
|
512
|
+
if (coordinate === undefined) return true;
|
|
513
|
+
const ddlSchemaName = issueSchemaName(issue);
|
|
514
|
+
if (ddlSchemaName === undefined) return true;
|
|
515
|
+
const namespaceId = resolveNamespaceIdForDdlSchema(contract, ddlSchemaName);
|
|
516
|
+
return !ownership.declaresEntity({ namespaceId, ...coordinate });
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Returns the one namespace node the relational strategy layer probes for
|
|
522
|
+
* live-table existence and reads codec-hook context off — the namespace
|
|
523
|
+
* matching the planner's resolved schema name, or the first namespace when
|
|
524
|
+
* none matches. `undefined` when the tree has no namespaces, so the strategy
|
|
525
|
+
* context uses its empty-schema default.
|
|
526
|
+
*
|
|
527
|
+
* The relational strategies key tables by bare name, so they can only probe one
|
|
528
|
+
* namespace at a time; probing across every namespace at once is future work.
|
|
529
|
+
*
|
|
530
|
+
* Returns the real `PostgresNamespaceSchemaNode` reference rather than a
|
|
531
|
+
* projection: `storageTypePlanCallStrategy` hands this same value to codec
|
|
532
|
+
* `planTypeOperations` hooks as `schema`, and hooks read the Postgres-specific
|
|
533
|
+
* `nativeEnums` field off it (via `PostgresNamespaceSchemaNode.is`) to decide
|
|
534
|
+
* whether a native enum type already exists — a projection that only copies
|
|
535
|
+
* `tables` would silently drop that signal. `StrategyContext.schema`'s
|
|
536
|
+
* declared type (`SqlSchemaIR`, shared with SQLite's flat shape) doesn't
|
|
537
|
+
* capture this, so the return is `blindCast` the same way `namespaceSchemaNodes`
|
|
538
|
+
* in the family's relational walk already treats a namespace node as a
|
|
539
|
+
* structurally-`SqlSchemaIR`-shaped value.
|
|
540
|
+
*/
|
|
541
|
+
function relationalNamespaceNode(
|
|
542
|
+
schema: PostgresDatabaseSchemaNode,
|
|
543
|
+
schemaName: string,
|
|
544
|
+
): SqlSchemaIR | undefined {
|
|
545
|
+
const namespaceNodes = Object.values(schema.namespaces);
|
|
546
|
+
const namespaceNode =
|
|
547
|
+
namespaceNodes.find((node) => node.schemaName === schemaName) ?? namespaceNodes[0];
|
|
548
|
+
if (namespaceNode === undefined) return undefined;
|
|
549
|
+
return blindCast<
|
|
550
|
+
SqlSchemaIR,
|
|
551
|
+
'PostgresNamespaceSchemaNode carries tables (+ nativeEnums, read by codec hooks via PostgresNamespaceSchemaNode.is) structurally compatible with the SqlSchemaIR shape the strategy layer declares'
|
|
552
|
+
>(namespaceNode);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Rebuilds the `PostgresRlsPolicy` contract entity `CreatePostgresRlsPolicyCall`
|
|
557
|
+
* carries (its `renderTypeScript`/`createRlsPolicy` paths serialize the whole
|
|
558
|
+
* entity, `namespaceId` included). This reconstructs rather than looking the
|
|
559
|
+
* original up in the contract on purpose: the diff node's `namespaceId` is the
|
|
560
|
+
* *resolved DDL schema* (set when the expected tree was built), which is the
|
|
561
|
+
* value the emitted op must carry; the contract-stored entity holds the raw,
|
|
562
|
+
* pre-resolution coordinate, so a lookup would change the migration output.
|
|
563
|
+
*/
|
|
564
|
+
function policyNodeToContractPolicy(node: PostgresPolicySchemaNode): PostgresRlsPolicy {
|
|
565
|
+
return new PostgresRlsPolicy({
|
|
566
|
+
name: node.name,
|
|
567
|
+
prefix: node.prefix,
|
|
568
|
+
tableName: node.tableName,
|
|
569
|
+
namespaceId: node.namespaceId,
|
|
570
|
+
operation: node.operation,
|
|
571
|
+
roles: [...node.roles],
|
|
572
|
+
...ifDefined('using', node.using),
|
|
573
|
+
...ifDefined('withCheck', node.withCheck),
|
|
574
|
+
permissive: node.permissive,
|
|
575
|
+
});
|
|
286
576
|
}
|