@prisma-next/target-postgres 0.14.0-dev.54 → 0.14.0-dev.56
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-Bd9Tt3E3.mjs → authoring-WkqG_MkU.mjs} +38 -6
- package/dist/authoring-WkqG_MkU.mjs.map +1 -0
- package/dist/contract-free.d.mts +27 -2
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/contract-free.mjs +3 -3
- package/dist/{control-policy-CafkzSUC.mjs → control-policy-BtOZBVxL.mjs} +38 -13
- package/dist/control-policy-BtOZBVxL.mjs.map +1 -0
- package/dist/control.mjs +6 -6
- package/dist/{ddl-CZNFMoCp.mjs → ddl-B-krEXY1.mjs} +18 -4
- package/dist/{ddl-CZNFMoCp.mjs.map → ddl-B-krEXY1.mjs.map} +1 -1
- package/dist/ddl.d.mts +2 -2
- package/dist/ddl.mjs +2 -2
- package/dist/{descriptor-meta-_pn08mka.mjs → descriptor-meta-BOcKPaLE.mjs} +4 -3
- package/dist/descriptor-meta-BOcKPaLE.mjs.map +1 -0
- package/dist/{diff-database-schema-CUSoT1Dk.mjs → diff-database-schema-CWb-jeLy.mjs} +19 -11
- package/dist/diff-database-schema-CWb-jeLy.mjs.map +1 -0
- package/dist/diff-database-schema.d.mts +1 -1
- package/dist/diff-database-schema.d.mts.map +1 -1
- package/dist/diff-database-schema.mjs +1 -1
- package/dist/issue-planner.d.mts +1 -1
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +2 -2
- package/dist/migration.mjs +2 -2
- package/dist/{nodes-Dh__NS58.mjs → nodes-B815pj_X.mjs} +34 -2
- package/dist/{nodes-Dh__NS58.mjs.map → nodes-B815pj_X.mjs.map} +1 -1
- package/dist/{nodes-CSkPX3rI.d.mts → nodes-BtQyZha6.d.mts} +29 -3
- package/dist/nodes-BtQyZha6.d.mts.map +1 -0
- package/dist/{op-factory-call-Dt-Jx5JS.d.mts → op-factory-call-D6_7-7Vc.d.mts} +24 -2
- package/dist/{op-factory-call-Dt-Jx5JS.d.mts.map → op-factory-call-D6_7-7Vc.d.mts.map} +1 -1
- package/dist/{op-factory-call-zo3HqJiO.mjs → op-factory-call-DxNNKUeZ.mjs} +99 -4
- package/dist/op-factory-call-DxNNKUeZ.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 +29 -2
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-ChE2d2-k.mjs → planner-BryLk0Ie.mjs} +80 -24
- package/dist/planner-BryLk0Ie.mjs.map +1 -0
- package/dist/{planner-produced-postgres-migration-qTr4KVlt.mjs → planner-produced-postgres-migration-BLJH1zIc.mjs} +2 -2
- package/dist/{planner-produced-postgres-migration-qTr4KVlt.mjs.map → planner-produced-postgres-migration-BLJH1zIc.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-C0a7I1-e.d.mts → planner-produced-postgres-migration-CGifB6VH.d.mts} +2 -2
- package/dist/{planner-produced-postgres-migration-C0a7I1-e.d.mts.map → planner-produced-postgres-migration-CGifB6VH.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-q58sWl7M.mjs → planner-sql-checks-AXoxB1Jl.mjs} +2 -2
- package/dist/{planner-sql-checks-q58sWl7M.mjs.map → planner-sql-checks-AXoxB1Jl.mjs.map} +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/planner.d.mts +23 -6
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +2 -2
- package/dist/{postgres-contract-view-BUjK3NeM.mjs → postgres-contract-view-Dg-N7KA7.mjs} +4 -3
- package/dist/postgres-contract-view-Dg-N7KA7.mjs.map +1 -0
- package/dist/{postgres-database-schema-node-UpzA0Ug5.d.mts → postgres-database-schema-node-CfdTY-Qs.d.mts} +18 -3
- package/dist/postgres-database-schema-node-CfdTY-Qs.d.mts.map +1 -0
- package/dist/{postgres-migration-DqGd8mAu.mjs → postgres-migration-BahMHTbj.mjs} +3 -3
- package/dist/{postgres-migration-DqGd8mAu.mjs.map → postgres-migration-BahMHTbj.mjs.map} +1 -1
- package/dist/{postgres-migration-DFaxuRyI.d.mts → postgres-migration-cyBe2Ee0.d.mts} +2 -2
- package/dist/{postgres-migration-DFaxuRyI.d.mts.map → postgres-migration-cyBe2Ee0.d.mts.map} +1 -1
- package/dist/{postgres-table-schema-node-BZWWEo7B.mjs → postgres-role-schema-node-BiSTCTNg.mjs} +4 -69
- package/dist/postgres-role-schema-node-BiSTCTNg.mjs.map +1 -0
- package/dist/{postgres-schema-9vFZLwGo.d.mts → postgres-schema-CU4gF6QZ.d.mts} +30 -2
- package/dist/postgres-schema-CU4gF6QZ.d.mts.map +1 -0
- package/dist/{postgres-schema-CsOBpCwV.mjs → postgres-schema-DTLA_aRi.mjs} +43 -13
- package/dist/postgres-schema-DTLA_aRi.mjs.map +1 -0
- package/dist/postgres-table-schema-node-9FCtCUz2.mjs +153 -0
- package/dist/postgres-table-schema-node-9FCtCUz2.mjs.map +1 -0
- package/dist/{resolve-ddl-schema-gmgUaHK3.mjs → resolve-ddl-schema-Ca88Tg6W.mjs} +2 -2
- package/dist/{resolve-ddl-schema-gmgUaHK3.mjs.map → resolve-ddl-schema-Ca88Tg6W.mjs.map} +1 -1
- package/dist/rls-canonicalize.d.mts +19 -1
- package/dist/rls-canonicalize.d.mts.map +1 -0
- package/dist/rls-canonicalize.mjs +2 -2
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/schema-ir-annotations.mjs +1 -1
- package/dist/types.d.mts +3 -3
- package/dist/types.mjs +4 -3
- package/dist/{canonicalize-Bn3BM1Cn.mjs → wire-name-rHHtr1h0.mjs} +31 -2
- package/dist/wire-name-rHHtr1h0.mjs.map +1 -0
- package/package.json +20 -20
- package/src/contract-free/ddl.ts +26 -0
- package/src/core/authoring.ts +44 -1
- package/src/core/ddl/nodes.ts +48 -1
- package/src/core/descriptor-meta.ts +2 -0
- package/src/core/entity-kinds.ts +11 -0
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +9 -0
- package/src/core/migrations/control-policy.ts +31 -1
- package/src/core/migrations/diff-database-schema.ts +1 -0
- package/src/core/migrations/issue-planner.ts +49 -4
- package/src/core/migrations/op-factory-call.ts +81 -1
- package/src/core/migrations/operations/rls.ts +82 -1
- package/src/core/migrations/planner.ts +110 -26
- package/src/core/postgres-contract-serializer.ts +9 -4
- package/src/core/postgres-rls-enablement.ts +34 -0
- package/src/core/postgres-schema.ts +19 -21
- package/src/core/postgres-validators.ts +6 -0
- package/src/core/rls/wire-name.ts +33 -0
- package/src/core/schema-ir/postgres-table-schema-node.ts +25 -3
- package/src/exports/contract-free.ts +4 -0
- package/src/exports/ddl.ts +2 -0
- package/src/exports/rls-canonicalize.ts +1 -0
- package/src/exports/types.ts +4 -0
- package/dist/authoring-Bd9Tt3E3.mjs.map +0 -1
- package/dist/canonicalize-Bn3BM1Cn.mjs.map +0 -1
- package/dist/control-policy-CafkzSUC.mjs.map +0 -1
- package/dist/descriptor-meta-_pn08mka.mjs.map +0 -1
- package/dist/diff-database-schema-CUSoT1Dk.mjs.map +0 -1
- package/dist/nodes-CSkPX3rI.d.mts.map +0 -1
- package/dist/op-factory-call-zo3HqJiO.mjs.map +0 -1
- package/dist/planner-ChE2d2-k.mjs.map +0 -1
- package/dist/postgres-contract-view-BUjK3NeM.mjs.map +0 -1
- package/dist/postgres-database-schema-node-UpzA0Ug5.d.mts.map +0 -1
- package/dist/postgres-schema-9vFZLwGo.d.mts.map +0 -1
- package/dist/postgres-schema-CsOBpCwV.mjs.map +0 -1
- package/dist/postgres-table-schema-node-BZWWEo7B.mjs.map +0 -1
- package/dist/schema-node-kinds-ClScchhi.mjs +0 -76
- package/dist/schema-node-kinds-ClScchhi.mjs.map +0 -1
|
@@ -19,8 +19,14 @@ import { blindCast } from '@prisma-next/utils/casts';
|
|
|
19
19
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
20
20
|
import { PostgresTableSource } from './ast/table-source';
|
|
21
21
|
import { PG_TEXT_CODEC_ID } from './codec-ids';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
nativeEnumEntityKind,
|
|
24
|
+
policyEntityKind,
|
|
25
|
+
rlsEnablementEntityKind,
|
|
26
|
+
roleEntityKind,
|
|
27
|
+
} from './entity-kinds';
|
|
23
28
|
import type { PostgresNativeEnum } from './postgres-native-enum';
|
|
29
|
+
import type { PostgresRlsEnablement } from './postgres-rls-enablement';
|
|
24
30
|
import type { PostgresRlsPolicy } from './postgres-rls-policy';
|
|
25
31
|
import type { PostgresRole } from './postgres-role';
|
|
26
32
|
import { escapeLiteral } from './sql-utils';
|
|
@@ -30,6 +36,7 @@ export type PostgresContract = Contract<SqlStorage> & { readonly target: 'postgr
|
|
|
30
36
|
export type PostgresNamespaceEntries = SqlNamespaceEntries & {
|
|
31
37
|
readonly policy?: Readonly<Record<string, PostgresRlsPolicy>>;
|
|
32
38
|
readonly role?: Readonly<Record<string, PostgresRole>>;
|
|
39
|
+
readonly rls?: Readonly<Record<string, PostgresRlsEnablement>>;
|
|
33
40
|
readonly native_enum?: Readonly<Record<string, PostgresNativeEnum>>;
|
|
34
41
|
};
|
|
35
42
|
|
|
@@ -72,7 +79,12 @@ export class PostgresSchema extends SqlNamespaceBase {
|
|
|
72
79
|
|
|
73
80
|
const dispatched = hydrateNamespaceEntities(
|
|
74
81
|
input.entries,
|
|
75
|
-
composeSqlEntityKinds([
|
|
82
|
+
composeSqlEntityKinds([
|
|
83
|
+
policyEntityKind,
|
|
84
|
+
roleEntityKind,
|
|
85
|
+
rlsEnablementEntityKind,
|
|
86
|
+
nativeEnumEntityKind,
|
|
87
|
+
]),
|
|
76
88
|
'carry',
|
|
77
89
|
);
|
|
78
90
|
|
|
@@ -83,32 +95,14 @@ export class PostgresSchema extends SqlNamespaceBase {
|
|
|
83
95
|
? { ...dispatched, valueSet: undefined }
|
|
84
96
|
: dispatched;
|
|
85
97
|
|
|
86
|
-
// `native_enum` is authoring-time-only (`PostgresContractSerializer`
|
|
87
|
-
// never re-emits it; its member values live on via the `valueSet`
|
|
88
|
-
// entry it derives). Carried as a non-enumerable property — like
|
|
89
|
-
// `kind` below — so `JSON.stringify` (the hashing pipeline's
|
|
90
|
-
// canonicalization step, `computeStorageHash` via `hashContract`)
|
|
91
|
-
// walks past it and the storage hash matches what actually gets
|
|
92
|
-
// serialized. Direct property access (`ns.entries.native_enum`)
|
|
93
|
-
// still resolves normally; only enumeration is affected.
|
|
94
|
-
const nativeEnumRaw = dispatched['native_enum'];
|
|
95
98
|
const entriesInput: Record<string, Readonly<Record<string, unknown>> | undefined> = {
|
|
96
99
|
...withPresence,
|
|
97
100
|
};
|
|
98
|
-
delete entriesInput['native_enum'];
|
|
99
|
-
if (nativeEnumRaw !== undefined) {
|
|
100
|
-
Object.defineProperty(entriesInput, 'native_enum', {
|
|
101
|
-
value: nativeEnumRaw,
|
|
102
|
-
enumerable: false,
|
|
103
|
-
writable: false,
|
|
104
|
-
configurable: true,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
101
|
|
|
108
102
|
this.entries = Object.freeze(
|
|
109
103
|
blindCast<
|
|
110
104
|
PostgresNamespaceEntries,
|
|
111
|
-
'composeSqlEntityKinds([policyEntityKind, roleEntityKind, nativeEnumEntityKind]) supplies table→StorageTable, valueSet→StorageValueSet, policy→PostgresRlsPolicy, role→PostgresRole, native_enum→PostgresNativeEnum descriptors'
|
|
105
|
+
'composeSqlEntityKinds([policyEntityKind, roleEntityKind, rlsEnablementEntityKind, nativeEnumEntityKind]) supplies table→StorageTable, valueSet→StorageValueSet, policy→PostgresRlsPolicy, role→PostgresRole, rls→PostgresRlsEnablement, native_enum→PostgresNativeEnum descriptors'
|
|
112
106
|
>(entriesInput),
|
|
113
107
|
);
|
|
114
108
|
Object.defineProperty(this, 'kind', {
|
|
@@ -136,6 +130,10 @@ export class PostgresSchema extends SqlNamespaceBase {
|
|
|
136
130
|
return this.entries.role ?? Object.freeze({});
|
|
137
131
|
}
|
|
138
132
|
|
|
133
|
+
get rls(): Readonly<Record<string, PostgresRlsEnablement>> {
|
|
134
|
+
return this.entries.rls ?? Object.freeze({});
|
|
135
|
+
}
|
|
136
|
+
|
|
139
137
|
/**
|
|
140
138
|
* The bare schema qualifier as it would appear in a rendered SQL
|
|
141
139
|
* fragment (already quoted). The unbound-schema singleton overrides
|
|
@@ -19,6 +19,12 @@ export const PostgresRlsPolicySchema = type({
|
|
|
19
19
|
permissive: 'boolean',
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
export const PostgresRlsEnablementSchema = type({
|
|
23
|
+
kind: "'rls'",
|
|
24
|
+
tableName: 'string',
|
|
25
|
+
namespaceId: 'string',
|
|
26
|
+
});
|
|
27
|
+
|
|
22
28
|
export const PostgresNativeEnumSchema = type({
|
|
23
29
|
kind: "'postgres-enum'",
|
|
24
30
|
typeName: 'string',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface RlsPolicyWireName {
|
|
2
|
+
/** The user-supplied part before the `_<8hex>` suffix. */
|
|
3
|
+
readonly prefix: string;
|
|
4
|
+
/** The 8-lowercase-hex content-hash suffix. */
|
|
5
|
+
readonly hash: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const WIRE_NAME_PATTERN = /^(.+)_([0-9a-f]{8})$/;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Assembles an RLS policy wire name from its user-supplied prefix and its
|
|
12
|
+
* 8-hex content-hash suffix. This module owns the `<prefix>_<hash>` format
|
|
13
|
+
* on both sides — construction here and parsing in
|
|
14
|
+
* {@link parseRlsPolicyWireName} — so the two never drift.
|
|
15
|
+
*/
|
|
16
|
+
export function formatRlsPolicyWireName(prefix: string, hash: string): string {
|
|
17
|
+
return `${prefix}_${hash}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Splits an RLS policy wire name (`<prefix>_<8hex>`) into its prefix and
|
|
22
|
+
* content-hash suffix. Returns `undefined` when the name does not follow the
|
|
23
|
+
* wire-name shape (e.g. a policy created outside the toolchain) — callers
|
|
24
|
+
* treat such names as all-prefix. Consumed by introspection (prefix
|
|
25
|
+
* extraction) and by rename pairing (same hash, different prefix).
|
|
26
|
+
*/
|
|
27
|
+
export function parseRlsPolicyWireName(name: string): RlsPolicyWireName | undefined {
|
|
28
|
+
const match = WIRE_NAME_PATTERN.exec(name);
|
|
29
|
+
const prefix = match?.[1];
|
|
30
|
+
const hash = match?.[2];
|
|
31
|
+
if (prefix === undefined || hash === undefined) return undefined;
|
|
32
|
+
return { prefix, hash };
|
|
33
|
+
}
|
|
@@ -12,11 +12,20 @@ import {
|
|
|
12
12
|
type SqlTableIRInput,
|
|
13
13
|
SqlUniqueIR,
|
|
14
14
|
} from '@prisma-next/sql-schema-ir/types';
|
|
15
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
15
16
|
import type { PostgresPolicySchemaNode } from './postgres-policy-schema-node';
|
|
16
17
|
import { PostgresSchemaNodeKind } from './schema-node-kinds';
|
|
17
18
|
|
|
18
19
|
export interface PostgresTableSchemaNodeInput extends SqlTableIRInput {
|
|
19
20
|
readonly policies?: readonly PostgresPolicySchemaNode[];
|
|
21
|
+
/**
|
|
22
|
+
* Whether row-level security is enabled on this table. Expected side:
|
|
23
|
+
* stamped from the contract's `entries.rls` marker (never from the
|
|
24
|
+
* policy set). Actual side: stamped from `pg_class.relrowsecurity` at
|
|
25
|
+
* introspection. Required with no default so every construction site
|
|
26
|
+
* supplies a deliberate value.
|
|
27
|
+
*/
|
|
28
|
+
readonly rlsEnabled: boolean;
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
/**
|
|
@@ -28,8 +37,8 @@ export interface PostgresTableSchemaNodeInput extends SqlTableIRInput {
|
|
|
28
37
|
* `SqlTableIR` calls `freezeNode` in its own constructor, which prevents
|
|
29
38
|
* subclass field initialisation.
|
|
30
39
|
*
|
|
31
|
-
* `id` is the table name. `isEqualTo`
|
|
32
|
-
*
|
|
40
|
+
* `id` is the table name. `isEqualTo` compares id + `rlsEnabled` — the
|
|
41
|
+
* table's one own diffable attribute; all other structural drift is
|
|
33
42
|
* expressed by its children. `children()` returns every column, the primary
|
|
34
43
|
* key (when present), every foreign key, unique, index, and check constraint,
|
|
35
44
|
* plus the policy nodes — one flat list, so a drifted column and a drifted
|
|
@@ -49,10 +58,12 @@ export class PostgresTableSchemaNode extends SqlSchemaIRNode implements Diffable
|
|
|
49
58
|
declare readonly annotations?: SqlAnnotations;
|
|
50
59
|
declare readonly checks?: ReadonlyArray<SqlCheckConstraintIR>;
|
|
51
60
|
readonly policies: readonly PostgresPolicySchemaNode[];
|
|
61
|
+
readonly rlsEnabled: boolean;
|
|
52
62
|
|
|
53
63
|
constructor(input: PostgresTableSchemaNodeInput) {
|
|
54
64
|
super();
|
|
55
65
|
this.name = input.name;
|
|
66
|
+
this.rlsEnabled = input.rlsEnabled;
|
|
56
67
|
this.columns = Object.freeze(
|
|
57
68
|
Object.fromEntries(
|
|
58
69
|
Object.entries(input.columns).map(([key, col]) => [
|
|
@@ -92,8 +103,19 @@ export class PostgresTableSchemaNode extends SqlSchemaIRNode implements Diffable
|
|
|
92
103
|
return this.name;
|
|
93
104
|
}
|
|
94
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Equal iff the ids (names) match AND `rlsEnabled` matches — the table's
|
|
108
|
+
* one own attribute in the diff; all other structural drift is expressed
|
|
109
|
+
* by children. A paired `not-equal` therefore always means enablement
|
|
110
|
+
* drift, which the planner maps to ENABLE/DISABLE ROW LEVEL SECURITY.
|
|
111
|
+
*/
|
|
95
112
|
isEqualTo(other: DiffableNode): boolean {
|
|
96
|
-
|
|
113
|
+
const node = blindCast<
|
|
114
|
+
SqlSchemaIRNode,
|
|
115
|
+
'every diff-tree node the differ pairs is a SqlSchemaIRNode'
|
|
116
|
+
>(other);
|
|
117
|
+
PostgresTableSchemaNode.assert(node);
|
|
118
|
+
return this.id === node.id && this.rlsEnabled === node.rlsEnabled;
|
|
97
119
|
}
|
|
98
120
|
|
|
99
121
|
children(): readonly DiffableNode[] {
|
|
@@ -12,6 +12,10 @@ export {
|
|
|
12
12
|
type IndexExistsCheckBuilder,
|
|
13
13
|
indexExistsAst,
|
|
14
14
|
noNullValuesAst,
|
|
15
|
+
type RlsEnabledCheckBuilder,
|
|
16
|
+
type RlsPolicyExistsCheckBuilder,
|
|
17
|
+
rlsEnabledAst,
|
|
18
|
+
rlsPolicyExistsAst,
|
|
15
19
|
type TableExistsCheckBuilder,
|
|
16
20
|
type TablePrimaryKeyCheckBuilder,
|
|
17
21
|
tableExistsAst,
|
package/src/exports/ddl.ts
CHANGED
|
@@ -4,12 +4,14 @@ export {
|
|
|
4
4
|
type AnyAlterTableAction,
|
|
5
5
|
type AnyPostgresDdlNode,
|
|
6
6
|
DropDefaultAction,
|
|
7
|
+
PostgresAlterPolicyRename,
|
|
7
8
|
PostgresAlterTable,
|
|
8
9
|
PostgresCreatePolicy,
|
|
9
10
|
PostgresCreateSchema,
|
|
10
11
|
PostgresCreateTable,
|
|
11
12
|
PostgresDdlNode,
|
|
12
13
|
type PostgresDdlVisitor,
|
|
14
|
+
PostgresDisableRowLevelSecurity,
|
|
13
15
|
PostgresDropPolicy,
|
|
14
16
|
type RlsPolicyOperation,
|
|
15
17
|
} from '../core/ddl/nodes';
|
package/src/exports/types.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export { PostgresNativeEnum, type PostgresNativeEnumInput } from '../core/postgres-native-enum';
|
|
2
|
+
export {
|
|
3
|
+
PostgresRlsEnablement,
|
|
4
|
+
type PostgresRlsEnablementInput,
|
|
5
|
+
} from '../core/postgres-rls-enablement';
|
|
2
6
|
export {
|
|
3
7
|
PostgresRlsPolicy,
|
|
4
8
|
type PostgresRlsPolicyInput,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authoring-Bd9Tt3E3.mjs","names":[],"sources":["../src/core/authoring.ts"],"sourcesContent":["import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';\nimport type {\n AuthoringEntityContext,\n AuthoringEntityTypeFactoryOutput,\n AuthoringEntityTypeNamespace,\n AuthoringFieldNamespace,\n AuthoringPslBlockDescriptorNamespace,\n AuthoringTypeNamespace,\n PslExtensionBlock,\n} from '@prisma-next/framework-components/authoring';\nimport type { SqlValueSetDerivingEntityTypeOutput } from '@prisma-next/sql-contract/value-set-derivation-hook';\nimport { PG_ENUM_CODEC_ID } from './codec-ids';\nimport { PostgresNativeEnum } from './postgres-native-enum';\nimport { PostgresRlsPolicy } from './postgres-rls-policy';\nimport { PostgresRole, type PostgresRoleInput } from './postgres-role';\nimport {\n PostgresNativeEnumSchema,\n PostgresRlsPolicySchema,\n PostgresRoleSchema,\n} from './postgres-validators';\nimport { computeContentHash, normalizePredicate } from './rls/canonicalize';\n\n/**\n * `pg.enum(<ref>)` registers as an ordinary type constructor whose sole\n * positional argument names a `native_enum` entity instead of carrying a\n * literal value. The interpreter resolves the ref to the `native_enum`\n * entity generically (driven by `entityRefArg`); the `pg/enum@1` codec\n * descriptor's `columnFromEntity` hook (see `codecs.ts`) converts that\n * entity into the column's `typeParams` and native type.\n */\nexport const postgresAuthoringTypes = {\n pg: {\n enum: {\n kind: 'typeConstructor',\n entityRefArg: { index: 0, entityKind: 'native_enum' },\n output: {\n codecId: PG_ENUM_CODEC_ID,\n },\n },\n },\n} as const satisfies AuthoringTypeNamespace;\n\nexport interface RlsPolicyExtensionBlock extends PslExtensionBlock {\n readonly namespaceId: string;\n}\n\nfunction readRefParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'ref' ? param.identifier : undefined;\n}\n\nfunction readValueParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'value' ? param.raw : undefined;\n}\n\nfunction readListRefParams(block: PslExtensionBlock, key: string): string[] {\n const param = block.parameters[key];\n if (param?.kind !== 'list') return [];\n return param.items.flatMap((item) => (item.kind === 'ref' ? [item.identifier] : []));\n}\n\n/**\n * Unwraps a quoted PSL string argument, inverting the printer's\n * `escapePslString` escapes (`\\\\`, `\\\"`, `\\n`, `\\r`). An unknown escape\n * sequence is kept verbatim, matching the printer-side `unescapePslString`\n * convention.\n */\nfunction unwrapQuotedString(raw: string): string {\n if (!(raw.startsWith('\"') && raw.endsWith('\"') && raw.length >= 2)) {\n return raw;\n }\n const inner = raw.slice(1, -1);\n let result = '';\n for (let i = 0; i < inner.length; i++) {\n if (inner[i] !== '\\\\' || i + 1 >= inner.length) {\n result += inner[i];\n continue;\n }\n const next = inner[i + 1];\n if (next === '\\\\' || next === '\"') {\n result += next;\n } else if (next === 'n') {\n result += '\\n';\n } else if (next === 'r') {\n result += '\\r';\n } else {\n result += '\\\\';\n result += next;\n }\n i++;\n }\n return result;\n}\n\nfunction lowerRlsPolicyFromBlock(\n block: RlsPolicyExtensionBlock,\n _ctx: AuthoringEntityContext,\n): PostgresRlsPolicy {\n const prefix = block.name;\n const targetModelName = readRefParam(block, 'target') ?? '';\n const tableName = targetModelName.charAt(0).toLowerCase() + targetModelName.slice(1);\n const roles = [...readListRefParams(block, 'roles')].sort();\n const using = unwrapQuotedString(readValueParam(block, 'using') ?? '');\n\n const wireHash = computeContentHash({\n using: normalizePredicate(using),\n roles,\n operation: 'select',\n permissive: true,\n });\n const wireName = `${prefix}_${wireHash}`;\n\n return new PostgresRlsPolicy({\n name: wireName,\n prefix,\n tableName,\n namespaceId: block.namespaceId,\n operation: 'select',\n roles,\n using,\n permissive: true,\n });\n}\n\n/**\n * Lowers a `native_enum { memberName = \"value\" … @@map(\"type_name\") }` block\n * into a {@link PostgresNativeEnum}. Members must be authored as explicit\n * `key = \"value\"` pairs — a bare (value-less) member is a diagnostic, not\n * accepted (authoring-design.md §2.1). The parsed `memberName` is only used\n * to duplicate-check and report diagnostics; the lowered entity carries just\n * the member values (a native enum is value-only — the member \"name\" isn't\n * a separate authoring concept from the value). `typeName` comes from\n * `@@map` or defaults to the block name verbatim.\n */\nfunction lowerNativeEnumFromBlock(\n block: PslExtensionBlock,\n ctx: AuthoringEntityContext,\n): PostgresNativeEnum | undefined {\n const sourceId = ctx.sourceId ?? 'unknown';\n const diagnostics = ctx.diagnostics;\n\n const mapAttr = block.blockAttributes.find((a) => a.name === 'map');\n let typeName = block.name;\n if (mapAttr) {\n const rawArg = mapAttr.args[0]?.value;\n const mapped = rawArg !== undefined ? unwrapQuotedString(rawArg) : undefined;\n if (mapped === undefined) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_INVALID_MAP',\n message: `native_enum \"${block.name}\" @@map attribute must have a quoted type-name argument`,\n sourceId,\n span: mapAttr.span,\n });\n return undefined;\n }\n typeName = mapped;\n }\n\n let memberError = false;\n const seenValues = new Set<string>();\n const members: string[] = [];\n for (const [memberName, paramValue] of Object.entries(block.parameters)) {\n if (paramValue.kind === 'bare') {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_BARE_MEMBER',\n message: `native_enum \"${block.name}\" member \"${memberName}\" has no value; members must be authored as \"${memberName} = \\\\\"value\\\\\"\"`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (paramValue.kind !== 'value') continue;\n\n let jsonValue: unknown;\n try {\n jsonValue = JSON.parse(paramValue.raw);\n } catch {\n diagnostics?.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `native_enum \"${block.name}\" member \"${memberName}\" value \"${paramValue.raw}\" is not valid JSON`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (typeof jsonValue !== 'string') {\n diagnostics?.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `native_enum \"${block.name}\" member \"${memberName}\" value must be a string`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (seenValues.has(jsonValue)) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE',\n message: `native_enum \"${block.name}\": duplicate member value \"${jsonValue}\"`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n seenValues.add(jsonValue);\n members.push(jsonValue);\n }\n\n if (memberError) return undefined;\n\n if (members.length === 0) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_MISSING_MEMBERS',\n message: `native_enum \"${block.name}\" must have at least one member`,\n sourceId,\n span: block.span,\n });\n return undefined;\n }\n\n // `control` stays unset — the effective grade is resolved at read time via `effectiveControlPolicy`, like `StorageTable`/`StorageColumn`.\n return new PostgresNativeEnum({ typeName, members });\n}\n\n/**\n * `native_enum`'s entity-type factory output, checked separately from the assembled\n * `postgresAuthoringEntityTypes` map below: `deriveValueSet` is SQL-family surface\n * ({@link SqlValueSetDerivingEntityTypeOutput}), not part of the framework\n * `AuthoringEntityTypeFactoryOutput` shape, so folding it directly into the map's single\n * `satisfies AuthoringEntityTypeNamespace` check would trip an excess-property error. Checking it\n * here against the intersection of both shapes keeps it structurally valid against each without\n * widening the map's own check.\n */\nconst nativeEnumEntityTypeOutput = {\n factory: lowerNativeEnumFromBlock,\n deriveValueSet: (entity: PostgresNativeEnum) => ({\n kind: 'valueSet' as const,\n values: [...entity.members],\n }),\n} satisfies AuthoringEntityTypeFactoryOutput<PslExtensionBlock, PostgresNativeEnum | undefined> &\n SqlValueSetDerivingEntityTypeOutput;\n\nexport const postgresAuthoringEntityTypes = {\n role: {\n kind: 'entity',\n discriminator: 'role',\n validatorSchema: PostgresRoleSchema,\n output: {\n factory: (input: PostgresRoleInput): PostgresRole => new PostgresRole(input),\n },\n },\n policy: {\n kind: 'entity',\n discriminator: 'policy',\n validatorSchema: PostgresRlsPolicySchema,\n output: {\n factory: lowerRlsPolicyFromBlock,\n },\n },\n native_enum: {\n kind: 'entity',\n discriminator: 'native_enum',\n validatorSchema: PostgresNativeEnumSchema,\n output: nativeEnumEntityTypeOutput,\n },\n} as const satisfies AuthoringEntityTypeNamespace;\n\n/**\n * Field presets contributed by the Postgres target pack.\n *\n * These mirror the PSL scalar-to-codec mapping used by the Postgres adapter\n * (see `createPostgresPslScalarTypeDescriptors`), so that authoring a field\n * via the TS callback surface (e.g. `field.int()`) and via the PSL scalar\n * surface (e.g. `Int`) lowers to byte-identical contracts.\n *\n * The `uuidNative` / `id.uuidv4Native` / `id.uuidv7Native` presets use the\n * native Postgres `uuid` type (codecId `pg/uuid@1`). For cross-target\n * portability use `uuidString` / `id.uuidv4String` / `id.uuidv7String` from\n * the family pack instead.\n */\n/**\n * PSL block descriptor for `policy_select`.\n *\n * The parser learns the block shape from this descriptor; lowering from\n * `PslExtensionBlock` to `PostgresRlsPolicy` is wired in the PSL\n * interpreter (a later dispatch). The `discriminator` matches\n * `PostgresRlsPolicy.kind` so the parsed block node carries the same\n * discriminant as the IR class it will lower to.\n *\n * The `roles` list uses `scope:'cross-space'` because same-namespace\n * role ref resolution requires PSL namespace entries keyed by `refKind`\n * (i.e. `'role'`), which in turn requires the role block discriminator to\n * equal `'role'`. Aligning discriminator with refKind is tracked for\n * slice 4 (cross-space roles). Until then cross-space passes validation\n * unconditionally and the authored role names flow through unchanged.\n */\nexport const postgresAuthoringPslBlockDescriptors = {\n policy_select: {\n kind: 'pslBlock',\n keyword: 'policy_select',\n discriminator: 'policy',\n name: { required: true },\n parameters: {\n target: { kind: 'ref', refKind: 'model', scope: 'same-namespace', required: true },\n roles: {\n kind: 'list',\n of: { kind: 'ref', refKind: 'role', scope: 'cross-space' },\n },\n using: { kind: 'value', codecId: 'pg/text@1', required: true },\n },\n },\n /**\n * PSL block descriptor for `native_enum`.\n *\n * Reuses the existing variadic-block mechanism (the same shape the SQL\n * family's `enum` block ships): the body is an open `memberName = \"value\"`\n * list. `variadicParameters: true` opens the block to arbitrary keys\n * beyond the declared (empty) `parameters` set — the lowering factory\n * (`lowerNativeEnumFromBlock`) turns the variadic entries into ordered\n * members and rejects a bare (value-less) member.\n */\n native_enum: {\n kind: 'pslBlock',\n keyword: 'native_enum',\n discriminator: 'native_enum',\n name: { required: true },\n parameters: {},\n variadicParameters: true,\n },\n} as const satisfies AuthoringPslBlockDescriptorNamespace;\n\nexport const postgresAuthoringFieldPresets = {\n text: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/text@1',\n nativeType: 'text',\n },\n },\n int: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int4@1',\n nativeType: 'int4',\n },\n },\n bigint: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int8@1',\n nativeType: 'int8',\n },\n },\n float: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/float8@1',\n nativeType: 'float8',\n },\n },\n decimal: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/numeric@1',\n nativeType: 'numeric',\n },\n },\n boolean: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bool@1',\n nativeType: 'bool',\n },\n },\n json: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/jsonb@1',\n nativeType: 'jsonb',\n },\n },\n bytes: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bytea@1',\n nativeType: 'bytea',\n },\n },\n dateTime: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n },\n },\n temporal: /* @__PURE__ */ temporalAuthoringPresets({\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n }),\n uuidNative: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n },\n },\n id: {\n uuidv4Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv4',\n },\n },\n id: true,\n },\n },\n uuidv7Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv7',\n },\n },\n id: true,\n },\n },\n },\n} as const satisfies AuthoringFieldNamespace;\n"],"mappings":"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AgC;CAC3C,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,KAAK;EACH,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,QAAQ;EACN,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAAU;EACR,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAA0B,yCAAyB;EACjD,SAAS;EACT,YAAY;CACd,CAAC;CACD,YAAY;EACV,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,IAAI;EACF,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;EACA,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;CACF;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canonicalize-Bn3BM1Cn.mjs","names":[],"sources":["../src/core/rls/canonicalize.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nexport type RlsPolicyOperation = 'select' | 'insert' | 'update' | 'delete' | 'all';\n\nexport interface ContentHashParts {\n readonly using?: string;\n readonly withCheck?: string;\n readonly roles: readonly string[];\n readonly operation: RlsPolicyOperation;\n readonly permissive: boolean;\n}\n\n/**\n * Stabilizes an authored predicate for hashing: trim, and collapse runs of\n * internal whitespace to a single space.\n *\n * This is deliberately minimal. The content hash is the equivalence relation\n * for a policy, and the wire name (prefix + hash) is the only thing ever\n * compared — we never recompute the hash from an introspected policy body, so\n * there is no need to match Postgres's reprinted form. Minimal normalization\n * also protects the no-collision property: aggressive rewriting (lowercasing,\n * paren-stripping, cast-alias folding) risks collapsing two distinct predicates\n * onto one hash. Out-of-band alteration of a hashed policy is unsupported.\n *\n * The normalizer is a stability commitment: any change re-suffixes all wire names.\n */\nexport function normalizePredicate(sql: string): string {\n return sql.replace(/\\s+/g, ' ').trim();\n}\n\n/**\n * Returns the first 8 lowercase hex characters of the SHA-256 digest over the\n * canonical content tuple for an RLS policy:\n *\n * [normalize(using), normalize(withCheck), sortedRoles, operation, permissive]\n *\n * Schema and table are excluded (they are orthogonal to policy equivalence).\n * Uses `JSON.stringify` for a deterministic encoding.\n */\nexport function computeContentHash(parts: ContentHashParts): string {\n const using = normalizePredicate(parts.using ?? '');\n const withCheck = normalizePredicate(parts.withCheck ?? '');\n const roles = [...new Set(parts.roles)].sort();\n const permissive = parts.permissive ? 'permissive' : 'restrictive';\n\n const tuple = JSON.stringify([using, withCheck, roles, parts.operation, permissive]);\n return createHash('sha256').update(tuple).digest('hex').slice(0, 8);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA0BA,SAAgB,mBAAmB,KAAqB;CACtD,OAAO,IAAI,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;AACvC;;;;;;;;;;AAWA,SAAgB,mBAAmB,OAAiC;CAClE,MAAM,QAAQ,mBAAmB,MAAM,SAAS,EAAE;CAClD,MAAM,YAAY,mBAAmB,MAAM,aAAa,EAAE;CAC1D,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK;CAC7C,MAAM,aAAa,MAAM,aAAa,eAAe;CAErD,MAAM,QAAQ,KAAK,UAAU;EAAC;EAAO;EAAW;EAAO,MAAM;EAAW;CAAU,CAAC;CACnF,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;AACpE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"control-policy-CafkzSUC.mjs","names":[],"sources":["../src/core/migrations/column-ddl-rendering.ts","../src/core/migrations/planner-strategies.ts","../src/core/migrations/issue-planner.ts","../src/core/migrations/control-policy.ts"],"sourcesContent":["import type { CodecControlHooks } from '@prisma-next/family-sql/control';\nimport type { StorageColumn } from '@prisma-next/sql-contract/types';\nimport type { DdlColumn } from '@prisma-next/sql-relational-core/ast';\nimport * as contractFree from '@prisma-next/sql-relational-core/contract-free';\nimport type { SqlColumnDefaultIR, SqlColumnIR } from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { postgresDefaultToDdlColumnDefault } from './op-factory-call';\nimport { buildColumnDefaultSql, buildColumnTypeSql } from './planner-ddl-builders';\nimport { resolveIdentityValue } from './planner-identity-values';\nimport { buildExpectedFormatType } from './planner-sql-checks';\n\n/**\n * Reconstructs the `StorageColumn`-shaped fields the DDL builder functions\n * (`buildColumnTypeSql`, `buildExpectedFormatType`, `resolveIdentityValue`)\n * expect, from a column node's own stamped codec identity (`codecRef` /\n * `codecBaseNativeType` / `codecNamedType`, Decision 5) — never the\n * contract. The builders were written against `StorageColumn` and are\n * unchanged here; only the shape feeding them moves from the contract to\n * the node. An empty `storageTypes` catalog is passed alongside: the\n * node's fields are already resolved past any `typeRef` indirection, so no\n * live lookup is needed, and passing a non-empty catalog would risk a\n * false `typeRef` hit against an unrelated storage type.\n */\nfunction columnLike(\n column: SqlColumnIR,\n): Pick<\n StorageColumn,\n 'nativeType' | 'codecId' | 'nullable' | 'many' | 'typeParams' | 'typeRef' | 'default'\n> {\n if (column.codecRef === undefined || column.codecBaseNativeType === undefined) {\n throw new Error(\n `columnLike: expected column \"${column.name}\" carries no codec identity — the expected tree must be derived via contractToSchemaIR for planning`,\n );\n }\n return {\n nativeType: column.codecBaseNativeType,\n codecId: column.codecRef.codecId,\n nullable: column.nullable,\n // `column.many` is unset on contract-derived columns (array-ness rides\n // on the `nativeType` `[]` suffix there instead) — `codecRef.many`\n // carries it. Hand-built/introspected columns set `column.many` directly.\n ...ifDefined('many', column.many ?? column.codecRef.many),\n ...ifDefined(\n 'typeParams',\n column.codecRef.typeParams !== undefined\n ? blindCast<\n Record<string, unknown>,\n 'CodecRef.typeParams is JsonValue-shaped; the DDL builders only ever read it as the Record the contract column originally carried'\n >(column.codecRef.typeParams)\n : undefined,\n ),\n ...(column.codecNamedType ? { typeRef: '<resolved>' } : {}),\n ...ifDefined('default', column.resolvedDefault),\n };\n}\n\n/**\n * Builds the `CREATE TABLE` / `ADD COLUMN` DDL column for an expected column\n * node, resolving type rendering from the node's codec identity against the\n * codec hooks the caller holds — the same builder the pre-`plan(start, end)`\n * op-path called, so the output is byte-identical.\n */\nexport function renderColumnDdl(\n name: string,\n column: SqlColumnIR,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n): DdlColumn {\n const like = columnLike(column);\n const typeSql = buildColumnTypeSql(like, codecHooks, {});\n const ddlDefault = postgresDefaultToDdlColumnDefault(like.default);\n return contractFree.col(name, typeSql, {\n ...(!column.nullable ? { notNull: true } : {}),\n ...ifDefined('default', ddlDefault),\n ...ifDefined('codecRef', column.codecRef),\n });\n}\n\n/**\n * Builds the `ALTER COLUMN … TYPE` operands for an expected column node.\n */\nexport function renderColumnAlterType(\n column: SqlColumnIR,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n): { readonly qualifiedTargetType: string; readonly formatTypeExpected: string } {\n const like = columnLike(column);\n return {\n qualifiedTargetType: buildColumnTypeSql(like, codecHooks, {}, false),\n formatTypeExpected: buildExpectedFormatType(like, codecHooks, {}),\n };\n}\n\n/**\n * Resolves the identity value (monoid neutral element) SQL literal used as\n * the temporary default when adding a NOT-NULL column with no contract\n * default (`notNullAddColumnCallStrategy`'s shared-temp-default backfill).\n * `null` when the column's type has no built-in/codec-provided identity\n * value.\n */\nexport function resolveColumnTemporaryDefault(\n column: SqlColumnIR,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n): string | null {\n return resolveIdentityValue(columnLike(column), codecHooks, {});\n}\n\n/**\n * The column's `SET DEFAULT` clause SQL, resolved from a column-default\n * diff node. `''` when the node carries no resolved default.\n */\nexport function renderColumnDefaultSql(defaultNode: SqlColumnDefaultIR): string {\n if (defaultNode.resolved === undefined) return '';\n return buildColumnDefaultSql(defaultNode.resolved, {\n nativeType: defaultNode.nativeTypeContext ?? '',\n ...ifDefined('many', defaultNode.many),\n });\n}\n","/**\n * Migration strategies.\n *\n * Each strategy examines the node-typed diff-issue list, consumes issues it\n * handles, and returns the `PostgresOpFactoryCall[]` to address them. The\n * issue planner runs each strategy in order and routes whatever's left\n * through `mapNodeIssueToCall`.\n *\n * The full ordered list is exported as `postgresPlannerStrategies` and is\n * used unchanged by both `migration plan` and `db update` / `db init`. The\n * two journeys differ only in `policy.allowedOperationClasses`:\n *\n * - When `'data'` is in the policy, data-safe strategies (NOT NULL backfill,\n * nullability tightening, unsafe type changes) emit\n * `DataTransformCall` placeholders that the user fills in.\n * - When `'data'` is excluded, those strategies short-circuit so the\n * downstream strategies (codec-hook type ops and temp-default backfill)\n * and `mapNodeIssueToCall` defaults emit direct DDL instead.\n *\n * Structural decisions (type/nullability drift, DDL fragments) read the diff\n * node pair and resolve column DDL from the node's `codecRef` (`column-ddl-\n * rendering.ts`). The retained subsystems — codec type-operations\n * (`storageTypePlanCallStrategy`) and the NOT-NULL temp-default deferred DDL\n * (`notNullAddColumnCallStrategy`) — keep reading the contract + codec hooks\n * via `StrategyContext`, per the slice's scope (see `diff-database-schema.ts`\n * / the slice spec).\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n CodecControlHooks,\n MigrationOperationPolicy,\n SqlMigrationPlanOperation,\n} from '@prisma-next/family-sql/control';\nimport { resolveValueSetValues } from '@prisma-next/family-sql/control';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type { SchemaDiffIssue } from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport {\n type SqlStorage,\n StorageTable,\n type StorageTypeInstance,\n} from '@prisma-next/sql-contract/types';\nimport * as contractFree from '@prisma-next/sql-relational-core/contract-free';\nimport {\n RelationalSchemaNodeKind,\n type SqlColumnIR,\n type SqlSchemaIR,\n} from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { isPostgresSchema } from '../postgres-schema';\nimport {\n renderColumnAlterType,\n renderColumnDdl,\n resolveColumnTemporaryDefault,\n} from './column-ddl-rendering';\nimport { resolveNamespaceIdForDdlSchema } from './control-policy';\nimport { emissionSchemaName, issueNode, issueSchemaName, issueTableName } from './issue-planner';\nimport {\n AddCheckConstraintCall,\n AddColumnCall,\n AddNotNullColumnDirectCall,\n AddNotNullColumnWithTempDefaultCall,\n AlterColumnTypeCall,\n DataTransformCall,\n DropCheckConstraintCall,\n DropNotNullCall,\n type PostgresOpFactoryCall,\n RawSqlCall,\n SetNotNullCall,\n} from './op-factory-call';\nimport { buildSchemaLookupMap, hasForeignKey, hasUniqueConstraint } from './planner-schema-lookup';\nimport { buildTargetDetails, type PostgresPlanTargetDetails } from './planner-target-details';\n\n/**\n * Look up a storage table by its explicit namespace coordinate. Returns\n * `undefined` when the namespace has no table by that name (or no such\n * namespace exists). Callers that get `undefined` MUST treat it as an\n * explicit conflict — never silently fall back to a global default\n * schema or a name-only walk, because that footgun would resolve a\n * stale or duplicate table name to whichever namespace the iteration\n * order surfaced first (a real data-loss hazard in multi-namespace\n * contracts where two namespaces can carry the same table name).\n */\nexport function tableAt(\n storage: SqlStorage,\n namespaceId: string,\n tableName: string,\n): StorageTable | undefined {\n const ns = storage.namespaces[namespaceId];\n if (ns === undefined) return undefined;\n return ns.entries.table?.[tableName];\n}\n\n/**\n * Resolve the DDL schema name for a namespace coordinate. Postgres-aware\n * namespaces dispatch to their polymorphic `ddlSchemaName` override —\n * named schemas return their own id; the unbound singleton returns\n * `UNBOUND_NAMESPACE_ID`. Legacy single-namespace contracts whose\n * `__unbound__` slot is the framework-default `SqlUnboundNamespace`\n * (rather than the Postgres-aware `PostgresUnboundSchema`) flow the\n * coordinate through unchanged so downstream `qualifyTableName`\n * resolves polymorphically.\n */\nexport function resolveDdlSchemaForNamespace(ctx: StrategyContext, namespaceId: string): string {\n const namespace = ctx.toContract.storage.namespaces[namespaceId];\n if (isPostgresSchema(namespace)) {\n return namespace.ddlSchemaName(ctx.toContract.storage);\n }\n return namespaceId;\n}\n\n/**\n * Recovers the contract namespace id for a DDL schema name embedded in a\n * diff-issue path (`path[1]`). The strategies need the CONTRACT column/table\n * (for codec-hook reads and eligibility probes the retained subsystems still\n * run) even though the issue itself only carries the resolved DDL schema —\n * this is the reverse of `resolveDdlSchemaForNamespace`.\n */\nfunction namespaceIdForDdlSchema(ctx: StrategyContext, ddlSchemaName: string): string {\n return resolveNamespaceIdForDdlSchema(ctx.toContract, ddlSchemaName);\n}\n\n// ============================================================================\n// Strategy types\n// ============================================================================\n\n/**\n * Context passed to each migration strategy.\n *\n * Strategies read the source (`fromContract`), target (`toContract`), current\n * database state (`schema`), operation policy (`policy`), and component list\n * (`frameworkComponents`) to make planning decisions. `fromContract` is null\n * when no prior contract is available (e.g. `db update`, where the current\n * DB state is approximated via `schema`).\n */\nexport interface StrategyContext {\n readonly toContract: Contract<SqlStorage>;\n readonly fromContract: Contract<SqlStorage> | null;\n readonly schemaName: string;\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n readonly storageTypes: Readonly<Record<string, StorageTypeInstance>>;\n readonly schema: SqlSchemaIR;\n readonly policy: MigrationOperationPolicy;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n}\n\n// ============================================================================\n// Call strategies (for issue planner)\n// ============================================================================\n\n/**\n * Consumes node-typed diff issues (`SchemaDiffIssue`, from the one differ —\n * `buildPostgresPlanDiff`), reading the issue's node pair for structural\n * decisions and resolving column DDL from the node's `codecRef`. The\n * retained subsystems (codec type-operations, the NOT-NULL temp-default\n * backfill) keep reading the contract via `StrategyContext`.\n */\nexport type CallMigrationStrategy = (\n issues: readonly SchemaDiffIssue[],\n context: StrategyContext,\n) =>\n | {\n kind: 'match';\n issues: readonly SchemaDiffIssue[];\n calls: readonly PostgresOpFactoryCall[];\n /**\n * `true` for strategies that emit cohesive sequential recipes whose\n * calls must stay contiguous and in the returned order — e.g.\n * `notNullBackfillCallStrategy` (addColumn → dataTransform → setNotNull).\n * Defaults to `false`, which lets `planIssues` hoist individual calls\n * into their DDL sequencing bucket.\n */\n recipe?: boolean;\n }\n | { kind: 'no_match' };\n\n/** A `not-equal` column issue whose node pair is narrowed to `SqlColumnIR`. */\nfunction columnNodePair(\n issue: SchemaDiffIssue,\n): { readonly expected: SqlColumnIR; readonly actual: SqlColumnIR } | undefined {\n const node = issueNode(issue);\n if (node === undefined || node.nodeKind !== RelationalSchemaNodeKind.column) return undefined;\n if (issue.expected === undefined || issue.actual === undefined) return undefined;\n return {\n expected: blindCast<SqlColumnIR, 'a column diff node is always a SqlColumnIR'>(issue.expected),\n actual: blindCast<SqlColumnIR, 'a column diff node is always a SqlColumnIR'>(issue.actual),\n };\n}\n\nexport const notNullBackfillCallStrategy: CallMigrationStrategy = (issues, ctx) => {\n // `DataTransformCall` is operation class `'data'`. When the policy excludes\n // it (`db update` / `db init`), skip so `notNullAddColumnCallStrategy`\n // (temp-default backfill) or `mapNodeIssueToCall` can take the issue.\n if (!ctx.policy.allowedOperationClasses.includes('data')) return { kind: 'no_match' };\n\n const matched: SchemaDiffIssue[] = [];\n const calls: PostgresOpFactoryCall[] = [];\n\n for (const issue of issues) {\n if (issue.reason !== 'not-found') continue;\n const node = issueNode(issue);\n if (node === undefined || node.nodeKind !== RelationalSchemaNodeKind.column) continue;\n const expected = blindCast<\n SqlColumnIR,\n 'a not-found column issue always carries the expected column node'\n >(issue.expected);\n if (expected.nullable !== false || expected.resolvedDefault !== undefined) continue;\n\n const ddlSchemaName = issueSchemaName(issue);\n const tableName = issueTableName(issue);\n if (ddlSchemaName === undefined || tableName === undefined) continue;\n const schemaName = emissionSchemaName(ctx, ddlSchemaName);\n\n matched.push(issue);\n const ddl = renderColumnDdl(expected.name, expected, ctx.codecHooks);\n const nullableSpec = contractFree.col(ddl.name, ddl.type, {\n ...(ddl.codecRef !== undefined ? { codecRef: ddl.codecRef } : {}),\n });\n calls.push(\n new AddColumnCall(schemaName, tableName, nullableSpec),\n new DataTransformCall(\n `backfill-${tableName}-${expected.name}`,\n `backfill-${tableName}-${expected.name}:check`,\n `backfill-${tableName}-${expected.name}:run`,\n ),\n new SetNotNullCall(schemaName, tableName, expected.name),\n );\n }\n\n if (matched.length === 0) return { kind: 'no_match' };\n return {\n kind: 'match',\n issues: issues.filter((i) => !matched.includes(i)),\n calls,\n recipe: true,\n };\n};\n\nconst SAFE_WIDENINGS = new Set(['int2→int4', 'int2→int8', 'int4→int8', 'float4→float8']);\n\n/**\n * Handles `not-equal` column issues whose TYPE differs. `fromContract` is\n * only supplied by `migration plan` — for reconciliation (`db update` /\n * `db init`, `fromContract === null`) this strategy never fires, mirroring\n * the legacy `typeChangeCallStrategy`'s requirement of a prior contract:\n * `mapNodeIssueToCall`'s in-place ALTER covers reconciliation directly.\n *\n * A single node issue can carry BOTH type and nullability drift (Postgres\n * alters in place, so the differ emits one `not-equal` column issue where\n * the legacy coordinate walk emitted two: `type_mismatch` +\n * `nullability_mismatch`). When this strategy consumes the issue for its\n * type portion, it also emits whatever nullability delta the same node pair\n * carries — using the same construction `nullableTighteningCallStrategy` /\n * the mapper's direct dispatch would have used — so the issue is never\n * partially handled.\n */\nexport const typeChangeCallStrategy: CallMigrationStrategy = (issues, ctx) => {\n if (ctx.fromContract === null) return { kind: 'no_match' };\n const dataAllowed = ctx.policy.allowedOperationClasses.includes('data');\n\n const matched: SchemaDiffIssue[] = [];\n const calls: PostgresOpFactoryCall[] = [];\n\n for (const issue of issues) {\n if (issue.reason !== 'not-equal') continue;\n const pair = columnNodePair(issue);\n if (pair === undefined) continue;\n const { expected, actual } = pair;\n if (!columnTypeChangedNativeOnly(expected, actual)) continue;\n\n const fromType = actual.nativeType;\n const toType = expected.nativeType;\n const isSafeWidening = SAFE_WIDENINGS.has(`${fromType}→${toType}`);\n if (!isSafeWidening && !dataAllowed) continue;\n\n const ddlSchemaName = issueSchemaName(issue);\n const tableName = issueTableName(issue);\n if (ddlSchemaName === undefined || tableName === undefined) continue;\n const schemaName = emissionSchemaName(ctx, ddlSchemaName);\n\n matched.push(issue);\n const { qualifiedTargetType, formatTypeExpected } = renderColumnAlterType(\n expected,\n ctx.codecHooks,\n );\n const alterOpts = {\n qualifiedTargetType,\n formatTypeExpected,\n rawTargetTypeForLabel: qualifiedTargetType,\n };\n if (isSafeWidening) {\n calls.push(new AlterColumnTypeCall(schemaName, tableName, expected.name, alterOpts));\n } else {\n calls.push(\n new DataTransformCall(\n `typechange-${tableName}-${expected.name}`,\n `typechange-${tableName}-${expected.name}:check`,\n `typechange-${tableName}-${expected.name}:run`,\n ),\n new AlterColumnTypeCall(schemaName, tableName, expected.name, alterOpts),\n );\n }\n\n if (expected.nullable !== actual.nullable) {\n if (expected.nullable) {\n calls.push(new DropNotNullCall(schemaName, tableName, expected.name));\n } else if (dataAllowed) {\n calls.push(\n new DataTransformCall(\n `handle-nulls-${tableName}-${expected.name}`,\n `handle-nulls-${tableName}-${expected.name}:check`,\n `handle-nulls-${tableName}-${expected.name}:run`,\n ),\n new SetNotNullCall(schemaName, tableName, expected.name),\n );\n } else {\n calls.push(new SetNotNullCall(schemaName, tableName, expected.name));\n }\n }\n }\n\n if (matched.length === 0) return { kind: 'no_match' };\n return {\n kind: 'match',\n issues: issues.filter((i) => !matched.includes(i)),\n calls,\n recipe: true,\n };\n};\n\n/**\n * Whether the raw (unresolved) native type differs — the SAME comparison\n * `typeChangeCallStrategy` always used (`fromColumn.nativeType !==\n * toColumn.nativeType`), which for the widenable numeric/float types\n * `SAFE_WIDENINGS` lists is identical to the resolved comparison\n * `columnTypeChanged` (in `issue-planner.ts`) performs.\n */\nfunction columnTypeChangedNativeOnly(expected: SqlColumnIR, actual: SqlColumnIR): boolean {\n return expected.nativeType !== actual.nativeType;\n}\n\n/**\n * Handles `not-equal` column issues whose type did NOT change but\n * nullability tightened (contract requires NOT NULL, live column is\n * nullable). A type-changed issue's nullability delta (if any) is already\n * handled by `typeChangeCallStrategy`, which runs first — this strategy\n * only ever sees issues that strategy left behind.\n */\nexport const nullableTighteningCallStrategy: CallMigrationStrategy = (issues, ctx) => {\n // `DataTransformCall` is operation class `'data'`. When the policy excludes\n // it (`db update` / `db init`), skip so `mapNodeIssueToCall` emits a direct\n // `SET NOT NULL` instead.\n if (!ctx.policy.allowedOperationClasses.includes('data')) return { kind: 'no_match' };\n\n const matched: SchemaDiffIssue[] = [];\n const calls: PostgresOpFactoryCall[] = [];\n\n for (const issue of issues) {\n if (issue.reason !== 'not-equal') continue;\n const pair = columnNodePair(issue);\n if (pair === undefined) continue;\n const { expected, actual } = pair;\n if (columnTypeChangedNativeOnly(expected, actual)) continue; // typeChangeCallStrategy's concern\n if (expected.nullable !== false || actual.nullable !== true) continue;\n\n const ddlSchemaName = issueSchemaName(issue);\n const tableName = issueTableName(issue);\n if (ddlSchemaName === undefined || tableName === undefined) continue;\n const schemaName = emissionSchemaName(ctx, ddlSchemaName);\n\n matched.push(issue);\n calls.push(\n new DataTransformCall(\n `handle-nulls-${tableName}-${expected.name}`,\n `handle-nulls-${tableName}-${expected.name}:check`,\n `handle-nulls-${tableName}-${expected.name}:run`,\n ),\n new SetNotNullCall(schemaName, tableName, expected.name),\n );\n }\n\n if (matched.length === 0) return { kind: 'no_match' };\n return {\n kind: 'match',\n issues: issues.filter((i) => !matched.includes(i)),\n calls,\n recipe: true,\n };\n};\n\n/**\n * Collects every check constraint from a table in the contract storage.\n * Returns an empty array when the table has no checks or the table is absent.\n */\nfunction collectContractChecks(\n storage: SqlStorage,\n namespaceId: string,\n tableName: string,\n): ReadonlyArray<{ name: string; column: string; permittedValues: readonly string[] }> {\n const ns = storage.namespaces[namespaceId];\n const tableRaw = ns !== undefined ? ns.entries.table?.[tableName] : undefined;\n if (!(tableRaw instanceof StorageTable)) return [];\n const checks = tableRaw.checks;\n if (!checks || checks.length === 0) return [];\n return checks.map((c) => ({\n name: c.name,\n column: c.column,\n permittedValues: resolveValueSetValues(\n c.valueSet,\n storage,\n `check \"${c.name}\" on \"${tableName}\"`,\n ),\n }));\n}\n\n/**\n * Compares two value arrays as unordered sets.\n */\nfunction checkValueSetsEqual(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false;\n const bSet = new Set(b);\n return a.every((v) => bSet.has(v));\n}\n\n/**\n * Plans check-constraint migrations for `enumType`-authored columns.\n *\n * Walks every namespace's tables in the target contract (the check nodes'\n * resolved `permittedValues` are ultimately sourced from the same\n * contract-declared value sets, so walking the contract directly is the\n * simplest faithful port — the strategy's decisions never depend on which\n * ISSUES happen to be in the input list, only on the contract + live schema\n * shapes). For each table that carries `checks`, diffs the contract-expected\n * checks against the live schema's checks:\n *\n * - Check in contract, absent from live DB → `AddCheckConstraintCall`.\n * - Check in live DB, absent from contract → `DropCheckConstraintCall`.\n * - Check on both sides but value sets differ → `DropCheckConstraintCall`\n * then `AddCheckConstraintCall` (drop + recreate; a check predicate cannot\n * be altered in place).\n *\n * Consumes every `sql-check-constraint` issue on a table this walk handles\n * (not-found/not-expected/not-equal), leaving check issues on tables with\n * NO contract checks to `mapNodeIssueToCall`'s `not-expected` fallback.\n */\nexport const checkConstraintPlanCallStrategy: CallMigrationStrategy = (issues, ctx) => {\n const calls: PostgresOpFactoryCall[] = [];\n const handledIssueKeys = new Set<string>();\n\n for (const [namespaceId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {\n for (const tableName of Object.keys(ns.entries.table ?? {})) {\n const contractChecks = collectContractChecks(ctx.toContract.storage, namespaceId, tableName);\n if (contractChecks.length === 0) continue;\n\n const schemaTable = ctx.schema.tables[tableName];\n const liveChecks = schemaTable?.checks ?? [];\n const ddlSchema = resolveDdlSchemaForNamespace(ctx, namespaceId);\n\n for (const contractCheck of contractChecks) {\n const liveCheck = liveChecks.find((c) => c.name === contractCheck.name);\n const issueKey = `${tableName} ${contractCheck.name}`;\n if (!liveCheck) {\n calls.push(\n new AddCheckConstraintCall(\n ddlSchema,\n tableName,\n contractCheck.name,\n contractCheck.column,\n contractCheck.permittedValues,\n ),\n );\n handledIssueKeys.add(issueKey);\n } else if (!checkValueSetsEqual(contractCheck.permittedValues, liveCheck.permittedValues)) {\n calls.push(\n new DropCheckConstraintCall(ddlSchema, tableName, contractCheck.name),\n new AddCheckConstraintCall(\n ddlSchema,\n tableName,\n contractCheck.name,\n contractCheck.column,\n contractCheck.permittedValues,\n ),\n );\n handledIssueKeys.add(issueKey);\n }\n // else: values match — no op needed, still consume the issue\n else {\n handledIssueKeys.add(issueKey);\n }\n }\n\n // Emit drops for checks that are live but not in the contract.\n for (const liveCheck of liveChecks) {\n const inContract = contractChecks.some((c) => c.name === liveCheck.name);\n if (!inContract) {\n const issueKey = `${tableName} ${liveCheck.name}`;\n calls.push(new DropCheckConstraintCall(ddlSchema, tableName, liveCheck.name));\n handledIssueKeys.add(issueKey);\n }\n }\n }\n }\n\n if (calls.length === 0 && handledIssueKeys.size === 0) return { kind: 'no_match' };\n\n const remaining = issues.filter((issue) => {\n const node = issueNode(issue);\n if (node === undefined || node.nodeKind !== RelationalSchemaNodeKind.check) return true;\n const tableName = issueTableName(issue);\n if (tableName === undefined) return true;\n const checkName = blindCast<{ readonly name: string }, 'a check node always carries a name'>(\n node,\n ).name;\n return !handledIssueKeys.has(`${tableName} ${checkName}`);\n });\n\n return { kind: 'match', issues: remaining, calls };\n};\n\n/**\n * Dispatches codec-typed storage types through their codec's\n * `planTypeOperations` hook (the authoritative source for codec-driven DDL\n * such as custom type creation). Codec extension/type ops are not modeled as\n * diff nodes — this strategy drives entirely off `ctx.toContract.storage.types`\n * + codec hooks, consuming nothing from the node issue list (there is no\n * node-vocabulary equivalent of `type_missing` / `enum_values_changed`).\n */\nexport const storageTypePlanCallStrategy: CallMigrationStrategy = (issues, ctx) => {\n const storageTypes = ctx.toContract.storage.types ?? {};\n if (Object.keys(storageTypes).length === 0) return { kind: 'no_match' };\n\n const calls: PostgresOpFactoryCall[] = [];\n\n for (const [typeName, typeInstance] of Object.entries(storageTypes).sort(([a], [b]) =>\n a.localeCompare(b),\n )) {\n const codecInstance = typeInstance as StorageTypeInstance;\n const hook = ctx.codecHooks.get(codecInstance.codecId);\n if (!hook?.planTypeOperations) continue;\n const planResult = hook.planTypeOperations({\n typeName,\n typeInstance: codecInstance,\n contract: ctx.toContract,\n schema: ctx.schema,\n schemaName: ctx.schemaName,\n policy: ctx.policy,\n });\n if (!planResult) continue;\n for (const op of planResult.operations) {\n calls.push(\n new RawSqlCall({\n ...op,\n target: {\n id: op.target.id,\n details: buildTargetDetails('type', typeName, ctx.schemaName),\n },\n } as SqlMigrationPlanOperation<PostgresPlanTargetDetails>),\n );\n }\n }\n\n if (calls.length === 0) return { kind: 'no_match' };\n return { kind: 'match', issues, calls };\n};\n\n/**\n * Handles `not-found` column issues for NOT NULL columns without a contract\n * default. Replaces the legacy `buildAddColumnItem` non-default branches.\n *\n * Two shapes:\n * - Shared-temp-default safe: emit a single atomic composite op (add\n * nullable → backfill identity value → `SET NOT NULL` → `DROP DEFAULT`).\n * The temp-default value is resolved from the column node's `codecRef`\n * (`resolveColumnTemporaryDefault`, wrapping `resolveIdentityValue`).\n * - Empty-table guarded: emit a hand-built op with a `tableIsEmptyCheck`\n * precheck so the failure message is \"table is not empty\" rather than the\n * raw PG NOT NULL violation.\n *\n * \"Normal\" not-found column cases (nullable or has a contract default) are\n * left for `mapNodeIssueToCall`'s default `AddColumnCall` emission.\n */\nexport const notNullAddColumnCallStrategy: CallMigrationStrategy = (issues, ctx) => {\n const matched: SchemaDiffIssue[] = [];\n const calls: PostgresOpFactoryCall[] = [];\n\n const schemaLookups = buildSchemaLookupMap(ctx.schema);\n\n const mutableCodecHooks = ctx.codecHooks as Map<string, CodecControlHooks>;\n const mutableStorageTypes = ctx.storageTypes as Record<string, StorageTypeInstance>;\n\n for (const issue of issues) {\n if (issue.reason !== 'not-found') continue;\n const node = issueNode(issue);\n if (node === undefined || node.nodeKind !== RelationalSchemaNodeKind.column) continue;\n const expected = blindCast<\n SqlColumnIR,\n 'a not-found column issue always carries the expected column node'\n >(issue.expected);\n if (expected.nullable !== false || expected.resolvedDefault !== undefined) continue;\n\n const ddlSchemaName = issueSchemaName(issue);\n const tableName = issueTableName(issue);\n if (ddlSchemaName === undefined || tableName === undefined) continue;\n\n const namespaceId = namespaceIdForDdlSchema(ctx, ddlSchemaName);\n const schemaName = namespaceId === UNBOUND_NAMESPACE_ID ? UNBOUND_NAMESPACE_ID : ddlSchemaName;\n const contractTable = tableAt(ctx.toContract.storage, namespaceId, tableName);\n const column = contractTable?.columns[expected.name];\n if (!contractTable || !column) continue;\n\n const schemaTable = ctx.schema.tables[tableName];\n if (!schemaTable) continue;\n\n const temporaryDefault = resolveColumnTemporaryDefault(expected, ctx.codecHooks);\n const schemaLookup = schemaLookups.get(tableName);\n const canUseSharedTempDefault =\n temporaryDefault !== null &&\n canUseSharedTemporaryDefaultStrategy({\n table: contractTable,\n schemaTable,\n schemaLookup,\n columnName: expected.name,\n });\n\n matched.push(issue);\n\n if (canUseSharedTempDefault && temporaryDefault !== null) {\n calls.push(\n new AddNotNullColumnWithTempDefaultCall({\n schemaName,\n tableName,\n columnName: expected.name,\n column,\n codecHooks: mutableCodecHooks,\n storageTypes: mutableStorageTypes,\n temporaryDefault,\n }),\n );\n continue;\n }\n\n calls.push(\n new AddNotNullColumnDirectCall(\n schemaName,\n tableName,\n expected.name,\n renderColumnDdl(expected.name, expected, ctx.codecHooks),\n ),\n );\n }\n\n if (matched.length === 0) return { kind: 'no_match' };\n return {\n kind: 'match',\n issues: issues.filter((i) => !matched.includes(i)),\n calls,\n };\n};\n\n// ============================================================================\n// Strategy helpers\n// ============================================================================\n\nfunction canUseSharedTemporaryDefaultStrategy(options: {\n readonly table: StorageTable;\n readonly schemaTable: SqlSchemaIR['tables'][string];\n readonly schemaLookup: ReturnType<typeof buildSchemaLookupMap> extends ReadonlyMap<\n string,\n infer V\n >\n ? V | undefined\n : never;\n readonly columnName: string;\n}): boolean {\n const { table, schemaTable, schemaLookup, columnName } = options;\n\n if (table.primaryKey?.columns.includes(columnName) && !schemaTable.primaryKey) {\n return false;\n }\n\n for (const unique of table.uniques) {\n if (!unique.columns.includes(columnName)) continue;\n if (!schemaLookup || !hasUniqueConstraint(schemaLookup, unique.columns)) return false;\n }\n\n for (const foreignKey of table.foreignKeys) {\n if (foreignKey.constraint === false || !foreignKey.source.columns.includes(columnName))\n continue;\n if (!schemaLookup || !hasForeignKey(schemaLookup, foreignKey)) return false;\n }\n\n return true;\n}\n\n/**\n * Ordered list of Postgres planner strategies, shared by `migration plan`\n * and `db update` / `db init`. The issue planner runs each strategy in\n * order, letting it consume any issues it handles, and routes whatever's\n * left through `mapNodeIssueToCall`. Behavior diverges purely on\n * `policy.allowedOperationClasses`:\n *\n * - When `'data'` is allowed (`migration plan`), the data-safe strategies\n * (`notNullBackfillCallStrategy`, `typeChangeCallStrategy`,\n * `nullableTighteningCallStrategy`) consume their matching issues and emit\n * `DataTransformCall` placeholders or recipe ops.\n *\n * - When `'data'` is not allowed (`db update` / `db init`), the\n * placeholder-emitting strategies short-circuit to `no_match`, leaving\n * the issue for the downstream strategies (`storageTypePlanCallStrategy`,\n * `notNullAddColumnCallStrategy`) or the `mapNodeIssueToCall` default to\n * handle with direct DDL.\n *\n * Codec-typed storage type entries are dispatched through\n * `storageTypePlanCallStrategy`.\n */\nexport const postgresPlannerStrategies: readonly CallMigrationStrategy[] = [\n notNullBackfillCallStrategy,\n typeChangeCallStrategy,\n nullableTighteningCallStrategy,\n checkConstraintPlanCallStrategy,\n storageTypePlanCallStrategy,\n notNullAddColumnCallStrategy,\n];\n","/**\n * Postgres migration issue planner.\n *\n * Takes node-typed schema-diff issues (from the one differ — see\n * `buildPostgresPlanDiff` in `diff-database-schema.ts`) and emits migration\n * IR (`PostgresOpFactoryCall[]`). Strategies consume issues they recognize\n * and produce specialized call sequences (e.g. NOT NULL backfill →\n * addColumn(nullable) + dataTransform + setNotNull); remaining issues flow\n * through `mapNodeIssueToCall` for the default case.\n *\n * Structural op-render (column type/default DDL) resolves the column node's\n * `codecRef` against the codec hooks the caller holds (`column-ddl-\n * rendering.ts`) — never re-derived from the contract. The retained\n * subsystems (codec type-operations, the NOT-NULL temp-default deferred DDL,\n * control-policy disposition) still read the contract via the strategy\n * context, per the slice's scope.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n CodecControlHooks,\n MigrationOperationPolicy,\n SqlPlannerConflict,\n SqlPlannerConflictLocation,\n} from '@prisma-next/family-sql/control';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type { DiffableNode, SchemaDiffIssue } from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';\nimport type { DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';\nimport * as contractFree from '@prisma-next/sql-relational-core/contract-free';\nimport { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';\nimport {\n RelationalSchemaNodeKind,\n type SqlColumnDefaultIR,\n type SqlColumnIR,\n type SqlForeignKeyIR,\n type SqlIndexIR,\n SqlSchemaIR,\n type SqlSchemaIRNode,\n type SqlUniqueIR,\n} from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport type { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';\nimport type { PostgresTableSchemaNode } from '../schema-ir/postgres-table-schema-node';\nimport { PostgresSchemaNodeKind } from '../schema-ir/schema-node-kinds';\nimport { quoteIdentifier } from '../sql-utils';\nimport {\n renderColumnAlterType,\n renderColumnDdl,\n renderColumnDefaultSql,\n} from './column-ddl-rendering';\nimport { resolveNamespaceIdForDdlSchema } from './control-policy';\nimport {\n AddColumnCall,\n AddForeignKeyCall,\n AddPrimaryKeyCall,\n AddUniqueCall,\n AlterColumnTypeCall,\n CreateIndexCall,\n CreateSchemaCall,\n CreateTableCall,\n DropCheckConstraintCall,\n DropColumnCall,\n DropConstraintCall,\n DropDefaultCall,\n DropIndexCall,\n DropNotNullCall,\n DropTableCall,\n type PostgresOpFactoryCall,\n SetDefaultCall,\n SetNotNullCall,\n} from './op-factory-call';\nimport type { ForeignKeySpec } from './operations/shared';\nimport {\n type CallMigrationStrategy,\n postgresPlannerStrategies,\n type StrategyContext,\n} from './planner-strategies';\n\nexport type { CallMigrationStrategy, StrategyContext };\n\n/**\n * Deterministic name for the element-non-null CHECK constraint on a scalar-array\n * column. Distinct `_elem_not_null` suffix avoids collision with the enum\n * value-set `_check` constraints. Re-emitting the same schema produces the same\n * name, so `pg_get_constraintdef`-based verify sees no drift.\n */\nfunction elementNonNullCheckName(tableName: string, columnName: string): string {\n return `${tableName}_${columnName}_elem_not_null`;\n}\n\n/**\n * Predicate enforcing that a scalar-array column carries no NULL element. The\n * array column itself may be NULL (container nullability is the column's NOT NULL\n * clause); `array_position` over a NULL array yields NULL, which a CHECK treats\n * as satisfied, so a nullable array column is unaffected.\n */\nfunction elementNonNullCheckExpression(columnName: string): string {\n return `array_position(${quoteIdentifier(columnName)}, NULL) IS NULL`;\n}\n\n// ============================================================================\n// Conflict helpers\n// ============================================================================\n\nfunction issueConflict(\n kind: SqlPlannerConflict['kind'],\n summary: string,\n location?: SqlPlannerConflict['location'],\n): SqlPlannerConflict {\n return {\n kind,\n summary,\n why: 'Use `migration new` to author a custom migration for this change.',\n ...(location ? { location } : {}),\n };\n}\n\nexport interface IssuePlannerValue {\n readonly calls: readonly PostgresOpFactoryCall[];\n}\n\n/**\n * Classifies calls into dependency order categories for correct DDL sequencing.\n */\ntype CallCategory =\n | 'dep'\n | 'drop'\n | 'table'\n | 'rlsEnable'\n | 'rlsPolicy'\n | 'column'\n | 'alter'\n | 'primaryKey'\n | 'unique'\n | 'index'\n | 'foreignKey';\n\n/**\n * Classifies calls into DDL sequencing buckets. The order matches the\n * legacy walk-schema planner's emission order so `db init` and `db update`\n * produce byte-identical plans for the shared shape (deps → drops → tables\n * → columns → alters → PKs → uniques → indexes → FKs).\n */\nfunction classifyCall(call: PostgresOpFactoryCall): CallCategory {\n switch (call.factoryName) {\n case 'createExtension':\n case 'createSchema':\n return 'dep';\n case 'dropTable':\n case 'dropColumn':\n case 'dropConstraint':\n case 'dropCheckConstraint':\n case 'dropIndex':\n case 'dropDefault':\n return 'drop';\n case 'addCheckConstraint':\n return 'unique'; // after uniques, before indexes\n case 'createTable':\n return 'table';\n case 'enableRowLevelSecurity':\n return 'rlsEnable';\n case 'createRlsPolicy':\n return 'rlsPolicy';\n case 'dropRlsPolicy':\n return 'drop';\n case 'addColumn':\n return 'column';\n case 'alterColumnType':\n case 'setNotNull':\n case 'dropNotNull':\n case 'setDefault':\n return 'alter';\n case 'addPrimaryKey':\n return 'primaryKey';\n case 'addUnique':\n return 'unique';\n case 'createIndex':\n return 'index';\n case 'addForeignKey':\n return 'foreignKey';\n case 'rawSql': {\n // Type ops lifted through `RawSqlCall` by `storageTypePlanCallStrategy`\n // to preserve the codec-emitted label and precheck/postcheck.\n // Classification falls back to inspecting the underlying op's target\n // details (`objectType: 'type'`).\n const op = (\n call as {\n op?: {\n target?: { details?: { objectType?: string } };\n };\n }\n ).op;\n const objectType = op?.target?.details?.objectType;\n if (objectType === 'type') return 'dep';\n return 'alter';\n }\n default:\n return 'alter';\n }\n}\n\n// When no policy is explicitly supplied (test-only path; production callers\n// always pass one), allow every class so strategies that gate on\n// `'data'` (data-safe placeholders) still fire — the test is treated as\n// trusted. Filtering of actual emitted calls only runs when a policy was\n// explicitly provided (see `policyProvided` below).\nconst DEFAULT_POLICY: MigrationOperationPolicy = {\n allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'],\n};\n\nfunction emptySchemaIR(): SqlSchemaIR {\n return new SqlSchemaIR({ tables: {} });\n}\n\nfunction conflictKindForCall(call: PostgresOpFactoryCall): SqlPlannerConflict['kind'] {\n switch (call.factoryName) {\n case 'alterColumnType':\n return 'typeMismatch';\n case 'setNotNull':\n case 'dropNotNull':\n return 'nullabilityConflict';\n case 'addForeignKey':\n case 'dropConstraint':\n return 'foreignKeyConflict';\n case 'createIndex':\n case 'dropIndex':\n return 'indexIncompatible';\n default:\n return 'missingButNonAdditive';\n }\n}\n\nfunction locationForCall(call: PostgresOpFactoryCall): SqlPlannerConflict['location'] | undefined {\n // Most Postgres call classes expose `tableName`/`columnName`/`indexName`/\n // `constraintName` as readonly fields. We avoid `toOp()` here because a\n // `DataTransformCall` intentionally throws from `toOp`.\n const anyCall = call as unknown as {\n tableName?: string;\n columnName?: string;\n indexName?: string;\n constraintName?: string;\n typeName?: string;\n };\n const location: {\n table?: string;\n column?: string;\n index?: string;\n constraint?: string;\n type?: string;\n } = {};\n if (anyCall.tableName) location.table = anyCall.tableName;\n if (anyCall.columnName) location.column = anyCall.columnName;\n if (anyCall.indexName) location.index = anyCall.indexName;\n if (anyCall.constraintName) location.constraint = anyCall.constraintName;\n if (anyCall.typeName) location.type = anyCall.typeName;\n return Object.keys(location).length > 0 ? (location as SqlPlannerConflictLocation) : undefined;\n}\n\nfunction conflictForDisallowedCall(\n call: PostgresOpFactoryCall,\n allowed: readonly string[],\n): SqlPlannerConflict {\n const summary = `Operation \"${call.label}\" requires class \"${call.operationClass}\", but policy allows only: ${allowed.join(', ')}`;\n const location = locationForCall(call);\n return {\n kind: conflictKindForCall(call),\n summary,\n why: 'Use `migration new` to author a custom migration for this change.',\n ...(location ? { location } : {}),\n };\n}\n\n// ============================================================================\n// Node-based issue planner\n// ============================================================================\n//\n// Consumes node-typed `SchemaDiffIssue`s (from the one differ —\n// `buildPostgresPlanDiff`) and reads the diff node each issue carries\n// (`issue.expected` / `issue.actual`). Column DDL (type/default SQL) resolves\n// from the column node's `codecRef` against the codec hooks the caller holds\n// (`column-ddl-rendering.ts`), never the contract. The retained subsystems —\n// codec type-operations, field-lifecycle hooks, the NOT-NULL temp-default\n// deferred DDL, control-policy disposition — keep the contract via the\n// strategy context, per the slice's scope.\n\n/** The diff node an issue concerns — expected when present, else the actual (extra) node. */\nexport function issueNode(issue: SchemaDiffIssue): SqlSchemaIRNode | undefined {\n const node = issue.expected ?? issue.actual;\n if (node === undefined) return undefined;\n return blindCast<\n SqlSchemaIRNode,\n 'every node in a Postgres schema diff tree is a SqlSchemaIRNode; nodeKind is its required discriminant'\n >(node);\n}\n\n/** DDL schema segment of a table-or-descendant issue path: `[database, ddlSchema, table, …]`. */\nexport function issueSchemaName(issue: SchemaDiffIssue): string | undefined {\n return issue.path[1];\n}\n\n/** Table segment of a table-or-descendant issue path: `[database, ddlSchema, table, …]`. */\nexport function issueTableName(issue: SchemaDiffIssue): string | undefined {\n return issue.path[2];\n}\n\n/** Column name embedded in a column/default issue path segment (`column:<name>`). */\nexport function issueColumnName(issue: SchemaDiffIssue): string | undefined {\n const segment = issue.path[3];\n if (segment === undefined || !segment.startsWith('column:')) return undefined;\n return segment.slice('column:'.length);\n}\n\n/**\n * The DDL schema name to use when EMITTING an op against `ddlSchemaName` (the\n * diff tree's resolved physical schema, `issueSchemaName(issue)`). The\n * unbound namespace's diff-tree identity resolves to `public` (a concrete\n * physical default the differ needs in order to compare its tree against\n * introspection — `resolveDdlSchemaForNamespaceStorage`), but DDL EMISSION\n * must stay unqualified so the live connection's `search_path` resolves it\n * at runtime (`boundSchema`). Recovers the logical namespace id via the\n * contract and substitutes the unbound sentinel back in when it resolves\n * there; every other namespace's `ddlSchemaName` already agrees between the\n * two resolution paths, so it passes through unchanged.\n */\nexport function emissionSchemaName(ctx: StrategyContext, ddlSchemaName: string): string {\n const namespaceId = resolveNamespaceIdForDdlSchema(ctx.toContract, ddlSchemaName);\n return namespaceId === UNBOUND_NAMESPACE_ID ? UNBOUND_NAMESPACE_ID : ddlSchemaName;\n}\n\n/**\n * Whether a column node is a scalar-array (`many: true`) column. The family\n * converter (`contractToSchemaIR`'s `convertColumn`) never stamps `many` on\n * the derived node — array-ness is folded into the `[]` suffix on\n * `nativeType` instead — so the node-derived check reads the suffix; `.many`\n * is still checked first for nodes a caller stamps directly (e.g. hand-built\n * test fixtures, or an adapter that populates it at introspection).\n */\nfunction isManyColumn(column: SqlColumnIR): boolean {\n return column.many === true || column.nativeType.endsWith('[]');\n}\n\n/** Whether the expected/actual native type (resolved, or raw+many fallback) differs — mirrors `SqlColumnIR.isEqualTo`'s type comparison. */\nexport function columnTypeChanged(expected: SqlColumnIR, actual: SqlColumnIR): boolean {\n if (expected.resolvedNativeType !== undefined && actual.resolvedNativeType !== undefined) {\n return expected.resolvedNativeType !== actual.resolvedNativeType;\n }\n return (\n expected.nativeType !== actual.nativeType || Boolean(expected.many) !== Boolean(actual.many)\n );\n}\n\n// ----------------------------------------------------------------------------\n// Node-keyed issue ordering (re-keys ISSUE_KIND_ORDER on nodeKind + reason)\n// ----------------------------------------------------------------------------\n\n/**\n * Re-keys the legacy `ISSUE_KIND_ORDER` on `(nodeKind, reason)`, numbers\n * preserved so the dependency intent stays legible. Final emission order is\n * fixed downstream by `classifyCall` bucketing (dep → drop → table → column →\n * recipe → alter → primaryKey → unique → index → foreignKey), so this only\n * breaks ties within a bucket.\n */\nexport function nodeIssueOrder(issue: SchemaDiffIssue): number {\n const node = issueNode(issue);\n if (node === undefined) return 99;\n switch (node.nodeKind) {\n case PostgresSchemaNodeKind.namespace:\n return 1;\n case RelationalSchemaNodeKind.foreignKey:\n return issue.reason === 'not-expected' ? 10 : 60;\n case RelationalSchemaNodeKind.unique:\n return issue.reason === 'not-expected' ? 11 : 51;\n case RelationalSchemaNodeKind.primaryKey:\n return issue.reason === 'not-expected' ? 12 : 50;\n case RelationalSchemaNodeKind.index:\n return issue.reason === 'not-expected' ? 13 : 52;\n case RelationalSchemaNodeKind.columnDefault:\n if (issue.reason === 'not-expected') return 14;\n return issue.reason === 'not-found' ? 42 : 43;\n case RelationalSchemaNodeKind.column:\n if (issue.reason === 'not-expected') return 15;\n return issue.reason === 'not-found' ? 30 : 40;\n case PostgresSchemaNodeKind.table:\n return issue.reason === 'not-expected' ? 16 : 20;\n case RelationalSchemaNodeKind.check:\n if (issue.reason === 'not-found') return 53;\n return issue.reason === 'not-expected' ? 55 : 54;\n default:\n return 99;\n }\n}\n\n/** Deterministic tiebreak within an order bucket: the diff path already encodes schema → table → child. */\nexport function nodeIssueKey(issue: SchemaDiffIssue): string {\n return issue.path.join(' ');\n}\n\n// ----------------------------------------------------------------------------\n// Subtree coalescing (the planner's responsibility per the differ's contract)\n// ----------------------------------------------------------------------------\n\n/**\n * The generic differ is total: a missing/extra table (or column) emits an\n * issue for itself AND for every node in its subtree. `CreateTable`/`DropTable`\n * and `AddColumn`/`DropColumn` already account for the whole subtree, so the\n * nested issues are redundant — coalescing drops any issue whose path is a\n * strict descendant of a `not-found`/`not-expected` issue's path. Run over the\n * relational subset ONLY (policy issues and synthesized namespace issues are\n * handled on their own paths, never coalesced against tables).\n */\nexport function coalesceSubtreeIssues<TNode extends DiffableNode = DiffableNode>(\n issues: readonly SchemaDiffIssue<TNode>[],\n): readonly SchemaDiffIssue<TNode>[] {\n const collapsingPaths = issues\n .filter((issue) => issue.reason === 'not-found' || issue.reason === 'not-expected')\n .map((issue) => issue.path);\n if (collapsingPaths.length === 0) return issues;\n return issues.filter(\n (issue) => !collapsingPaths.some((ancestor) => isStrictDescendantPath(issue.path, ancestor)),\n );\n}\n\nfunction isStrictDescendantPath(path: readonly string[], ancestor: readonly string[]): boolean {\n if (path.length <= ancestor.length) return false;\n for (let i = 0; i < ancestor.length; i += 1) {\n if (path[i] !== ancestor[i]) return false;\n }\n return true;\n}\n\n// ----------------------------------------------------------------------------\n// Node → call construction\n// ----------------------------------------------------------------------------\n\nfunction fkSpecFromNode(fk: SqlForeignKeyIR, tableName: string): ForeignKeySpec {\n const name = fk.name ?? `${tableName}_${fk.columns.join('_')}_fkey`;\n return {\n name,\n columns: [...fk.columns],\n references: {\n // The raw target namespace coordinate, matching the retired coordinate\n // path's `references.schema: fk.target.namespaceId` (the FK node stamps\n // it verbatim). The op renderer qualifies the REFERENCES clause from it.\n schema: fk.referencedSchema ?? '',\n table: fk.referencedTable,\n columns: [...fk.referencedColumns],\n },\n ...ifDefined('onDelete', fk.onDelete),\n ...ifDefined('onUpdate', fk.onUpdate),\n };\n}\n\n/**\n * Builds the `CreateTable` + child `CreateIndex` / `AddForeignKey` / `AddUnique`\n * calls for a newly-expected table, reading only the table node's children. The\n * PK and element-non-null CHECKs go inline as table constraints; indexes\n * (declared + FK-backing, already merged and ordered at derivation) and the\n * FK / unique constraints are separate calls (re-bucketed downstream). Every\n * column's DDL is resolved from its `codecRef` via `renderColumnDdl`.\n */\nfunction buildCreateTableCallsFromNode(\n schemaName: string,\n table: PostgresTableSchemaNode,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n): PostgresOpFactoryCall[] {\n const ddlColumns = Object.values(table.columns).map((c) =>\n renderColumnDdl(c.name, c, codecHooks),\n );\n const primaryKeyConstraints: DdlTableConstraint[] = table.primaryKey\n ? [\n contractFree.primaryKey([...table.primaryKey.columns], {\n ...ifDefined('name', table.primaryKey.name),\n }),\n ]\n : [];\n const elementNonNullChecks: DdlTableConstraint[] = Object.values(table.columns)\n .filter((c) => isManyColumn(c))\n .map((c) =>\n contractFree.checkExpression(\n elementNonNullCheckName(table.name, c.name),\n elementNonNullCheckExpression(c.name),\n ),\n );\n const allTableConstraints = [...primaryKeyConstraints, ...elementNonNullChecks];\n const calls: PostgresOpFactoryCall[] = [\n new CreateTableCall(\n schemaName,\n table.name,\n ddlColumns,\n allTableConstraints.length > 0 ? allTableConstraints : undefined,\n ),\n ];\n for (const index of table.indexes) {\n const indexName = index.name ?? defaultIndexName(table.name, index.columns);\n const extras: { type?: string; options?: Record<string, unknown> } = {};\n if (index.type !== undefined) extras.type = index.type;\n if (index.options !== undefined) extras.options = index.options;\n calls.push(new CreateIndexCall(schemaName, table.name, indexName, [...index.columns], extras));\n }\n for (const fk of table.foreignKeys) {\n calls.push(new AddForeignKeyCall(schemaName, table.name, fkSpecFromNode(fk, table.name)));\n }\n for (const unique of table.uniques) {\n const constraintName = unique.name ?? `${table.name}_${unique.columns.join('_')}_key`;\n calls.push(new AddUniqueCall(schemaName, table.name, constraintName, [...unique.columns]));\n }\n return calls;\n}\n\nfunction nodeConflict(kind: SqlPlannerConflict['kind'], message: string): SqlPlannerConflict {\n return issueConflict(kind, message);\n}\n\nfunction mapTableNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n if (issue.reason === 'not-found') {\n const table = blindCast<\n PostgresTableSchemaNode,\n 'a not-found table issue always carries the expected PostgresTableSchemaNode'\n >(issue.expected);\n return ok(buildCreateTableCallsFromNode(schemaName, table, codecHooks));\n }\n if (issue.reason === 'not-expected') {\n const table = blindCast<\n PostgresTableSchemaNode,\n 'a not-expected table issue always carries the actual PostgresTableSchemaNode'\n >(issue.actual);\n return ok([new DropTableCall(schemaName, table.name)]);\n }\n // Unreachable: PostgresTableSchemaNode.isEqualTo is identity.\n return notOk(nodeConflict('unsupportedOperation', `Unexpected table drift: ${issue.message}`));\n}\n\nfunction mapColumnNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n tableName: string,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n if (issue.reason === 'not-found') {\n const column = blindCast<\n SqlColumnIR,\n 'a not-found column issue always carries the expected column node'\n >(issue.expected);\n return ok([\n new AddColumnCall(schemaName, tableName, renderColumnDdl(column.name, column, codecHooks)),\n ]);\n }\n if (issue.reason === 'not-expected') {\n const column = blindCast<\n SqlColumnIR,\n 'a not-expected column issue always carries the actual column node'\n >(issue.actual);\n return ok([new DropColumnCall(schemaName, tableName, column.name)]);\n }\n // not-equal: Postgres alters in place — type drift and/or nullability drift.\n const expected = blindCast<\n SqlColumnIR,\n 'a not-equal column issue always carries the expected column node'\n >(issue.expected);\n const actual = blindCast<\n SqlColumnIR,\n 'a not-equal column issue always carries the actual column node'\n >(issue.actual);\n const calls: PostgresOpFactoryCall[] = [];\n if (columnTypeChanged(expected, actual)) {\n const { qualifiedTargetType, formatTypeExpected } = renderColumnAlterType(expected, codecHooks);\n calls.push(\n new AlterColumnTypeCall(schemaName, tableName, expected.name, {\n qualifiedTargetType,\n formatTypeExpected,\n rawTargetTypeForLabel: qualifiedTargetType,\n }),\n );\n }\n if (expected.nullable !== actual.nullable) {\n calls.push(\n expected.nullable\n ? new DropNotNullCall(schemaName, tableName, expected.name)\n : new SetNotNullCall(schemaName, tableName, expected.name),\n );\n }\n return ok(calls);\n}\n\nfunction mapColumnDefaultNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n tableName: string,\n columnName: string,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n if (issue.reason === 'not-expected') {\n return ok([new DropDefaultCall(schemaName, tableName, columnName)]);\n }\n // not-found (SET DEFAULT, additive) or not-equal (SET DEFAULT, widening).\n if (issue.expected === undefined) return ok([]);\n const defaultNode = blindCast<\n SqlColumnDefaultIR,\n 'a not-found/not-equal column-default issue always carries the expected default node'\n >(issue.expected);\n const defaultSql = renderColumnDefaultSql(defaultNode);\n if (!defaultSql) return ok([]);\n return ok([\n new SetDefaultCall(\n schemaName,\n tableName,\n columnName,\n defaultSql,\n issue.reason === 'not-equal' ? 'widening' : 'additive',\n ),\n ]);\n}\n\nfunction mapPrimaryKeyNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n tableName: string,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n if (issue.reason === 'not-found') {\n const pk = blindCast<\n { readonly columns: readonly string[]; readonly name?: string },\n 'a not-found primary-key issue always carries the expected PrimaryKey node'\n >(issue.expected);\n const constraintName = pk.name ?? `${tableName}_pkey`;\n return ok([new AddPrimaryKeyCall(schemaName, tableName, constraintName, [...pk.columns])]);\n }\n if (issue.reason === 'not-expected') {\n const pk = blindCast<\n { readonly name?: string },\n 'a not-expected primary-key issue always carries the actual PrimaryKey node'\n >(issue.actual);\n return ok([\n new DropConstraintCall(schemaName, tableName, pk.name ?? `${tableName}_pkey`, 'primaryKey'),\n ]);\n }\n return notOk(nodeConflict('indexIncompatible', issue.message));\n}\n\nfunction mapForeignKeyNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n tableName: string,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n if (issue.reason === 'not-found') {\n const fk = blindCast<\n SqlForeignKeyIR,\n 'a not-found foreign-key issue always carries the expected foreign-key node'\n >(issue.expected);\n return ok([new AddForeignKeyCall(schemaName, tableName, fkSpecFromNode(fk, tableName))]);\n }\n if (issue.reason === 'not-expected') {\n const fk = blindCast<\n SqlForeignKeyIR,\n 'a not-expected foreign-key issue always carries the actual foreign-key node'\n >(issue.actual);\n const name = fk.name ?? `${tableName}_${fk.columns.join('_')}_fkey`;\n return ok([new DropConstraintCall(schemaName, tableName, name, 'foreignKey')]);\n }\n return notOk(nodeConflict('foreignKeyConflict', issue.message));\n}\n\nfunction mapUniqueNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n tableName: string,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n if (issue.reason === 'not-found') {\n const unique = blindCast<\n SqlUniqueIR,\n 'a not-found unique issue always carries the expected unique node'\n >(issue.expected);\n const name = unique.name ?? `${tableName}_${unique.columns.join('_')}_key`;\n return ok([new AddUniqueCall(schemaName, tableName, name, [...unique.columns])]);\n }\n if (issue.reason === 'not-expected') {\n const unique = blindCast<\n SqlUniqueIR,\n 'a not-expected unique issue always carries the actual unique node'\n >(issue.actual);\n const name = unique.name ?? `${tableName}_${unique.columns.join('_')}_key`;\n return ok([new DropConstraintCall(schemaName, tableName, name, 'unique')]);\n }\n return notOk(nodeConflict('indexIncompatible', issue.message));\n}\n\nfunction mapIndexNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n tableName: string,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n if (issue.reason === 'not-found') {\n const index = blindCast<\n SqlIndexIR,\n 'a not-found index issue always carries the expected index node'\n >(issue.expected);\n const indexName = index.name ?? defaultIndexName(tableName, index.columns);\n const extras: { type?: string; options?: Record<string, unknown> } = {};\n if (index.type !== undefined) extras.type = index.type;\n if (index.options !== undefined) extras.options = index.options;\n return ok([new CreateIndexCall(schemaName, tableName, indexName, [...index.columns], extras)]);\n }\n if (issue.reason === 'not-expected') {\n const index = blindCast<\n SqlIndexIR,\n 'a not-expected index issue always carries the actual index node'\n >(issue.actual);\n const indexName = index.name ?? defaultIndexName(tableName, index.columns);\n return ok([new DropIndexCall(schemaName, tableName, indexName)]);\n }\n return notOk(nodeConflict('indexIncompatible', issue.message));\n}\n\nfunction mapCheckNodeIssue(\n issue: SchemaDiffIssue,\n schemaName: string,\n tableName: string,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n // check_removed (extra live check not in contract) is the only check drift\n // the default mapper handles directly; check_missing / check_mismatch are\n // consumed by `checkConstraintPlanCallStrategy` (drop+recreate), so reaching\n // here for them means the strategy did not run — a conflict.\n if (issue.reason === 'not-expected') {\n const check = blindCast<\n { readonly name: string },\n 'a not-expected check issue always carries the actual check node'\n >(issue.actual);\n return ok([new DropCheckConstraintCall(schemaName, tableName, check.name)]);\n }\n return notOk(\n nodeConflict(\n 'unsupportedOperation',\n `Check constraint drift on \"${tableName}\" — handled by checkConstraintPlanCallStrategy: ${issue.message}`,\n ),\n );\n}\n\n/**\n * Maps one node-typed diff issue to its migration call(s), dispatching on the\n * node's `nodeKind` + `issue.reason`, reading nodes and resolving column DDL\n * from `codecRef` via `column-ddl-rendering.ts`.\n */\nexport function mapNodeIssueToCall(\n issue: SchemaDiffIssue,\n ctx: StrategyContext,\n): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {\n const node = issueNode(issue);\n if (node === undefined) {\n return notOk(\n nodeConflict(\n 'unsupportedOperation',\n `Issue carries neither an expected nor an actual node: ${issue.message}`,\n ),\n );\n }\n if (node.nodeKind === PostgresSchemaNodeKind.namespace) {\n if (issue.reason !== 'not-found') {\n return notOk(\n nodeConflict('unsupportedOperation', `Unexpected namespace drift: ${issue.message}`),\n );\n }\n const namespace = blindCast<\n PostgresNamespaceSchemaNode,\n 'a namespace-presence issue always carries a PostgresNamespaceSchemaNode'\n >(issue.expected);\n return ok([new CreateSchemaCall(namespace.schemaName)]);\n }\n\n const ddlSchemaName = issueSchemaName(issue);\n const tableName = issueTableName(issue);\n if (ddlSchemaName === undefined || tableName === undefined) {\n return notOk(\n nodeConflict(\n 'unsupportedOperation',\n `Issue has no schema/table in its path: ${issue.message}`,\n ),\n );\n }\n const schemaName = emissionSchemaName(ctx, ddlSchemaName);\n\n switch (node.nodeKind) {\n case PostgresSchemaNodeKind.table:\n return mapTableNodeIssue(issue, schemaName, ctx.codecHooks);\n case RelationalSchemaNodeKind.column:\n return mapColumnNodeIssue(issue, schemaName, tableName, ctx.codecHooks);\n case RelationalSchemaNodeKind.columnDefault: {\n const columnName = issueColumnName(issue);\n if (columnName === undefined) {\n return notOk(\n nodeConflict(\n 'unsupportedOperation',\n `Default issue has no column in its path: ${issue.message}`,\n ),\n );\n }\n return mapColumnDefaultNodeIssue(issue, schemaName, tableName, columnName);\n }\n case RelationalSchemaNodeKind.primaryKey:\n return mapPrimaryKeyNodeIssue(issue, schemaName, tableName);\n case RelationalSchemaNodeKind.foreignKey:\n return mapForeignKeyNodeIssue(issue, schemaName, tableName);\n case RelationalSchemaNodeKind.unique:\n return mapUniqueNodeIssue(issue, schemaName, tableName);\n case RelationalSchemaNodeKind.index:\n return mapIndexNodeIssue(issue, schemaName, tableName);\n case RelationalSchemaNodeKind.check:\n return mapCheckNodeIssue(issue, schemaName, tableName);\n default:\n return notOk(nodeConflict('unsupportedOperation', `Unhandled node kind: ${node.nodeKind}`));\n }\n}\n\nexport interface IssuePlannerOptions {\n readonly issues: readonly SchemaDiffIssue[];\n readonly toContract: Contract<SqlStorage>;\n readonly fromContract: Contract<SqlStorage> | null;\n readonly schemaName: string;\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n readonly storageTypes: Readonly<Record<string, StorageTypeInstance>>;\n /**\n * Current database schema IR. Strategies read this to detect whether a\n * structure already exists (e.g. `buildSchemaLookupMap` for shared-temp-\n * default safety, extension dependency checks). Defaults to an empty schema\n * when omitted so the planner can still run over \"fresh DB\" contract\n * snapshots.\n */\n readonly schema?: SqlSchemaIR;\n /**\n * Operation-class policy. `planIssues` filters calls whose `operationClass`\n * is not in `policy.allowedOperationClasses` and surfaces them as conflicts\n * instead of emitting disallowed DDL. Defaults to additive-only.\n */\n readonly policy?: MigrationOperationPolicy;\n /**\n * Framework components participating in this composition. Available to\n * future strategies that may consult component metadata at plan time.\n */\n readonly frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n readonly strategies?: readonly CallMigrationStrategy[];\n}\n\n/**\n * Runs the ordered strategy list over the node-typed diff issues, maps\n * leftover issues via {@link mapNodeIssueToCall}, applies operation-class\n * policy gating, and buckets calls into the fixed DDL emission order (dep →\n * drop → table → column → recipe → alter → primaryKey → unique → index →\n * foreignKey).\n */\nexport function planIssues(\n options: IssuePlannerOptions,\n): Result<IssuePlannerValue, readonly SqlPlannerConflict[]> {\n const policyProvided = options.policy !== undefined;\n const policy = options.policy ?? DEFAULT_POLICY;\n const schema = options.schema ?? emptySchemaIR();\n const frameworkComponents = options.frameworkComponents ?? [];\n\n const context: StrategyContext = {\n toContract: options.toContract,\n fromContract: options.fromContract,\n schemaName: options.schemaName,\n codecHooks: options.codecHooks,\n storageTypes: options.storageTypes,\n schema,\n policy,\n frameworkComponents,\n };\n\n const strategies = options.strategies ?? postgresPlannerStrategies;\n\n let remaining = options.issues;\n const recipeCalls: PostgresOpFactoryCall[] = [];\n const bucketablePatternCalls: PostgresOpFactoryCall[] = [];\n\n for (const strategy of strategies) {\n const result = strategy(remaining, context);\n if (result.kind === 'match') {\n remaining = result.issues;\n if (result.recipe) {\n recipeCalls.push(...result.calls);\n } else {\n bucketablePatternCalls.push(...result.calls);\n }\n }\n }\n\n const sorted = [...remaining].sort((a, b) => {\n const kindDelta = nodeIssueOrder(a) - nodeIssueOrder(b);\n if (kindDelta !== 0) return kindDelta;\n const keyA = nodeIssueKey(a);\n const keyB = nodeIssueKey(b);\n return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;\n });\n\n const defaultCalls: PostgresOpFactoryCall[] = [];\n const conflicts: SqlPlannerConflict[] = [];\n\n for (const issue of sorted) {\n const result = mapNodeIssueToCall(issue, context);\n if (result.ok) {\n defaultCalls.push(...result.value);\n } else {\n conflicts.push(result.failure);\n }\n }\n\n const allowed = policy.allowedOperationClasses;\n let gatedDefault = defaultCalls;\n let gatedRecipe = recipeCalls;\n let gatedBucketable = bucketablePatternCalls;\n if (policyProvided) {\n const keepIfAllowed = (bucket: PostgresOpFactoryCall[]) => (call: PostgresOpFactoryCall) => {\n if (allowed.includes(call.operationClass)) {\n bucket.push(call);\n return;\n }\n conflicts.push(conflictForDisallowedCall(call, allowed));\n };\n const gatedDefaultBucket: PostgresOpFactoryCall[] = [];\n const gatedRecipeBucket: PostgresOpFactoryCall[] = [];\n const gatedBucketableBucket: PostgresOpFactoryCall[] = [];\n defaultCalls.forEach(keepIfAllowed(gatedDefaultBucket));\n recipeCalls.forEach(keepIfAllowed(gatedRecipeBucket));\n bucketablePatternCalls.forEach(keepIfAllowed(gatedBucketableBucket));\n gatedDefault = gatedDefaultBucket;\n gatedRecipe = gatedRecipeBucket;\n gatedBucketable = gatedBucketableBucket;\n }\n\n if (conflicts.length > 0) {\n return notOk(conflicts);\n }\n\n const combinedBucketable = [...gatedDefault, ...gatedBucketable];\n const byCategory = (cat: CallCategory) =>\n combinedBucketable.filter((c) => classifyCall(c) === cat);\n\n const calls: PostgresOpFactoryCall[] = [\n ...byCategory('dep'),\n ...byCategory('drop'),\n ...byCategory('table'),\n ...byCategory('column'),\n ...gatedRecipe,\n ...byCategory('alter'),\n ...byCategory('primaryKey'),\n ...byCategory('unique'),\n ...byCategory('index'),\n ...byCategory('foreignKey'),\n ];\n\n return ok({ calls });\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { ControlPolicySubject } from '@prisma-next/family-sql/control';\nimport type { SchemaDiffIssue } from '@prisma-next/framework-components/control';\nimport { entityAt, UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage, StorageTable } from '@prisma-next/sql-contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { isPostgresSchema } from '../postgres-schema';\nimport type { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';\nimport type { SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';\nimport { PostgresSchemaNodeKind } from '../schema-ir/schema-node-kinds';\nimport { issueColumnName } from './issue-planner';\nimport type { PostgresOpFactoryCall } from './op-factory-call';\n\n/**\n * Factory calls that create a whole, previously-absent top-level storage\n * object. Used to decide whether `tolerated` permits a call (it only allows\n * creating absent objects, never modifying existing ones).\n *\n * Deliberately an explicit, closed set rather than a `factoryName`\n * create/alter/drop classification: it answers exactly one yes/no question\n * and is fail-closed. Any call not listed here — including future or\n * extension-contributed factories — is treated as NOT object-creation, so it\n * is suppressed under `tolerated` rather than permissively emitted.\n */\nconst OBJECT_CREATION_FACTORIES: ReadonlySet<string> = new Set<string>([\n 'createTable',\n 'createSchema',\n 'createRlsPolicy',\n 'enableRowLevelSecurity',\n]);\n\nfunction createsNewTopLevelObject(call: PostgresOpFactoryCall): boolean {\n return OBJECT_CREATION_FACTORIES.has(call.factoryName);\n}\n\nfunction ddlSchemaNameForNamespace(contract: Contract<SqlStorage>, namespaceId: string): string {\n const namespace = contract.storage.namespaces[namespaceId];\n return isPostgresSchema(namespace) ? namespace.ddlSchemaName(contract.storage) : namespaceId;\n}\n\nfunction resolveNamespaceIdForTable(\n contract: Contract<SqlStorage>,\n tableName: string,\n ddlSchemaName: string | undefined,\n): string {\n for (const namespaceId of Object.keys(contract.storage.namespaces)) {\n const table = entityAt<StorageTable>(contract.storage, {\n namespaceId,\n entityKind: 'table',\n entityName: tableName,\n });\n if (!table) continue;\n if (\n ddlSchemaName === undefined ||\n ddlSchemaNameForNamespace(contract, namespaceId) === ddlSchemaName\n ) {\n return namespaceId;\n }\n }\n return UNBOUND_NAMESPACE_ID;\n}\n\nexport function resolveNamespaceIdForDdlSchema(\n contract: Contract<SqlStorage>,\n ddlSchemaName: string,\n): string {\n for (const namespaceId of Object.keys(contract.storage.namespaces)) {\n const ns = contract.storage.namespaces[namespaceId];\n if (isPostgresSchema(ns) && ns.ddlSchemaName(contract.storage) === ddlSchemaName) {\n return namespaceId;\n }\n if (namespaceId === ddlSchemaName) {\n return namespaceId;\n }\n }\n return UNBOUND_NAMESPACE_ID;\n}\n\ninterface PostgresCallFields {\n readonly schemaName?: string;\n readonly tableName?: string;\n readonly columnName?: string;\n}\n\nfunction postgresCallFields(call: PostgresOpFactoryCall): PostgresCallFields {\n return {\n ...ifDefined('schemaName', 'schemaName' in call ? call.schemaName : undefined),\n ...ifDefined('tableName', 'tableName' in call ? call.tableName : undefined),\n ...ifDefined('columnName', 'columnName' in call ? call.columnName : undefined),\n };\n}\n\nexport function formatPostgresControlPolicySubjectLabel(\n factoryName: string,\n subject: ControlPolicySubject | undefined,\n contract: Contract<SqlStorage>,\n): string {\n if (subject?.table) {\n const ddlSchema = ddlSchemaNameForNamespace(contract, subject.namespaceId);\n return `${factoryName}(${ddlSchema}.${subject.table})`;\n }\n return factoryName;\n}\n\nexport function resolvePostgresCallControlPolicySubject(\n call: PostgresOpFactoryCall,\n contract: Contract<SqlStorage>,\n): ControlPolicySubject | undefined {\n const callFields = postgresCallFields(call);\n const createsNewObject = createsNewTopLevelObject(call);\n\n if (call.factoryName === 'createSchema' && callFields.schemaName) {\n return {\n namespaceId: resolveNamespaceIdForDdlSchema(contract, callFields.schemaName),\n createsNewObject,\n };\n }\n\n if (callFields.tableName) {\n const namespaceId = resolveNamespaceIdForTable(\n contract,\n callFields.tableName,\n callFields.schemaName,\n );\n const tableControlPolicy = entityAt<StorageTable>(contract.storage, {\n namespaceId,\n entityKind: 'table',\n entityName: callFields.tableName,\n })?.control;\n return {\n namespaceId,\n ...ifDefined('explicitNodeControlPolicy', tableControlPolicy),\n table: callFields.tableName,\n ...ifDefined('column', callFields.columnName),\n createsNewObject,\n };\n }\n\n if (callFields.schemaName) {\n return {\n namespaceId: resolveNamespaceIdForDdlSchema(contract, callFields.schemaName),\n createsNewObject,\n };\n }\n\n return undefined;\n}\n\n/**\n * Node kinds that describe the absence of a whole, top-level Postgres\n * object — the same objects `createsNewTopLevelObject` recognises for calls.\n * Used by {@link resolvePostgresNodeIssueCreationFactoryName} to decide\n * whether a `tolerated` subject permits the issue to flow into the planner\n * (create-if-absent) and to seed the suppressed-subject warning's\n * `factoryName` when the planner is skipped. RLS policy creation is not\n * listed here — policy issues never reach this issue-based partition (they\n * are routed to `planPostgresSchemaDiff` and gated via the call-based\n * {@link resolvePostgresCallControlPolicySubject} instead).\n */\nconst POSTGRES_NODE_CREATION_FACTORY: Readonly<Record<string, string>> = Object.freeze({\n [PostgresSchemaNodeKind.namespace]: 'createSchema',\n [PostgresSchemaNodeKind.table]: 'createTable',\n});\n\nexport function resolvePostgresNodeIssueCreationFactoryName(\n issue: SchemaDiffIssue<SqlSchemaDiffNode>,\n): string | undefined {\n if (issue.reason !== 'not-found') return undefined;\n const node = issue.expected ?? issue.actual;\n if (node === undefined) return undefined;\n return POSTGRES_NODE_CREATION_FACTORY[node.nodeKind];\n}\n\n/**\n * Resolve the control-policy subject coordinate for a single node-typed\n * {@link SchemaDiffIssue}. Mirrors the resolution\n * `resolvePostgresCallControlPolicySubject` performs for a generated DDL\n * call, but works *off the issue* — so the planner can partition issues by\n * effective policy before the diff engine runs. `createsNewObject` is\n * derived from the node kind + reason: a `not-found` schema/table describes\n * a brand-new top-level object; everything else touches an existing object.\n *\n * A `not-expected` table carries no contract namespace coordinate (the live\n * table isn't claimed by any contract namespace), so the subject's\n * `namespaceId` falls back to {@link UNBOUND_NAMESPACE_ID} via\n * `resolveNamespaceIdForTable`'s own fallback — the call-side resolver does\n * the same for the `DropTableCall` it produces.\n */\nexport function resolvePostgresNodeIssueControlPolicySubject(\n issue: SchemaDiffIssue<SqlSchemaDiffNode>,\n contract: Contract<SqlStorage>,\n): ControlPolicySubject | undefined {\n const node = issue.expected ?? issue.actual;\n if (node === undefined) return undefined;\n\n if (node.nodeKind === PostgresSchemaNodeKind.namespace) {\n const namespaceNode = blindCast<\n PostgresNamespaceSchemaNode,\n 'a postgres-namespace diff node is always a PostgresNamespaceSchemaNode'\n >(node);\n return {\n namespaceId: resolveNamespaceIdForDdlSchema(contract, namespaceNode.schemaName),\n createsNewObject: issue.reason === 'not-found',\n };\n }\n\n const tableName = issue.path[2];\n if (tableName === undefined) return undefined;\n const ddlSchemaName = issue.path[1];\n const namespaceId = resolveNamespaceIdForTable(contract, tableName, ddlSchemaName);\n const table = entityAt<StorageTable>(contract.storage, {\n namespaceId,\n entityKind: 'table',\n entityName: tableName,\n });\n const createsNewObject =\n node.nodeKind === PostgresSchemaNodeKind.table && issue.reason === 'not-found';\n\n return {\n namespaceId,\n ...ifDefined('explicitNodeControlPolicy', table?.control),\n table: tableName,\n ...ifDefined('column', issueColumnName(issue)),\n createsNewObject,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"descriptor-meta-_pn08mka.mjs","names":[],"sources":["../src/core/descriptor-meta.ts"],"sourcesContent":["import type { CodecTypes } from '../exports/codec-types';\nimport {\n postgresAuthoringEntityTypes,\n postgresAuthoringFieldPresets,\n postgresAuthoringPslBlockDescriptors,\n postgresAuthoringTypes,\n} from './authoring';\nimport { postgresQualifyColumnType } from './codecs';\nimport { postgresTargetDescriptorMetaRuntime } from './descriptor-meta-runtime';\nimport { DEFAULT_NAMESPACE_ID } from './namespace-ids';\nimport { postgresCreateNamespace } from './postgres-schema';\n\nconst postgresTargetDescriptorMetaBase = {\n ...postgresTargetDescriptorMetaRuntime,\n defaultNamespaceId: DEFAULT_NAMESPACE_ID,\n authoring: {\n type: postgresAuthoringTypes,\n field: postgresAuthoringFieldPresets,\n entityTypes: postgresAuthoringEntityTypes,\n pslBlockDescriptors: postgresAuthoringPslBlockDescriptors,\n createNamespace: postgresCreateNamespace,\n qualifyColumnType: postgresQualifyColumnType,\n },\n} as const;\n\nexport const postgresTargetDescriptorMeta: typeof postgresTargetDescriptorMetaBase & {\n readonly __codecTypes?: CodecTypes;\n} = postgresTargetDescriptorMetaBase;\n"],"mappings":";;;;;AAyBA,MAAa,+BAET;CAdF,GAAG;CACH,oBAAoB;CACpB,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,qBAAqB;EACrB,iBAAiB;EACjB,mBAAmB;CACrB;AAKE"}
|