@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
package/dist/pack.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Y as postgresQualifyColumnType } from "./codecs-Cm-nS4mQ.mjs";
|
|
2
2
|
import { r as CodecTypes } from "./codec-types-BiIWziRO.mjs";
|
|
3
3
|
import { t as PostgresRlsPolicy } from "./postgres-rls-policy--CSddvMR.mjs";
|
|
4
|
-
import { a as postgresCreateNamespace, c as
|
|
4
|
+
import { a as postgresCreateNamespace, c as PostgresRlsEnablement, d as PostgresRoleInput, l as PostgresRlsEnablementInput, o as PostgresNativeEnum, u as PostgresRole } from "./postgres-schema-CU4gF6QZ.mjs";
|
|
5
5
|
import { PslExtensionBlock } from "@prisma-next/framework-components/authoring";
|
|
6
6
|
|
|
7
7
|
//#region src/core/authoring.d.ts
|
|
@@ -172,6 +172,18 @@ declare const postgresTargetDescriptorMetaBase: {
|
|
|
172
172
|
readonly factory: (input: PostgresRoleInput) => PostgresRole;
|
|
173
173
|
};
|
|
174
174
|
};
|
|
175
|
+
readonly rls: {
|
|
176
|
+
readonly kind: "entity";
|
|
177
|
+
readonly discriminator: "rls";
|
|
178
|
+
readonly validatorSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
179
|
+
kind: "rls";
|
|
180
|
+
tableName: string;
|
|
181
|
+
namespaceId: string;
|
|
182
|
+
}, {}>;
|
|
183
|
+
readonly output: {
|
|
184
|
+
readonly factory: (input: PostgresRlsEnablementInput) => PostgresRlsEnablement;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
175
187
|
readonly policy: {
|
|
176
188
|
readonly kind: "entity";
|
|
177
189
|
readonly discriminator: "policy";
|
|
@@ -201,7 +213,7 @@ declare const postgresTargetDescriptorMetaBase: {
|
|
|
201
213
|
control?: "managed" | "tolerated" | "external" | "observed";
|
|
202
214
|
}, {}>;
|
|
203
215
|
readonly output: {
|
|
204
|
-
factory: (block: import("@prisma-next/
|
|
216
|
+
factory: (block: import("@prisma-next/psl-parser").PslExtensionBlock, ctx: import("@prisma-next/framework-components/authoring").AuthoringEntityContext) => PostgresNativeEnum | undefined;
|
|
205
217
|
deriveValueSet: (entity: PostgresNativeEnum) => {
|
|
206
218
|
kind: "valueSet";
|
|
207
219
|
values: string[];
|
|
@@ -238,6 +250,10 @@ declare const postgresTargetDescriptorMetaBase: {
|
|
|
238
250
|
readonly required: true;
|
|
239
251
|
};
|
|
240
252
|
};
|
|
253
|
+
readonly requiresModelAttribute: {
|
|
254
|
+
readonly parameter: "target";
|
|
255
|
+
readonly attribute: "rls";
|
|
256
|
+
};
|
|
241
257
|
};
|
|
242
258
|
readonly native_enum: {
|
|
243
259
|
readonly kind: "pslBlock";
|
|
@@ -250,6 +266,17 @@ declare const postgresTargetDescriptorMetaBase: {
|
|
|
250
266
|
readonly variadicParameters: true;
|
|
251
267
|
};
|
|
252
268
|
};
|
|
269
|
+
readonly modelAttributes: {
|
|
270
|
+
readonly rls: {
|
|
271
|
+
readonly kind: "modelAttribute";
|
|
272
|
+
readonly attribute: "rls";
|
|
273
|
+
readonly spec: import("@prisma-next/psl-parser").AttributeSpec<{}>;
|
|
274
|
+
readonly lower: (_parsed: Record<never, never>, ctx: import("@prisma-next/framework-components/authoring").AuthoringModelAttributeContext) => {
|
|
275
|
+
key: string;
|
|
276
|
+
entity: PostgresRlsEnablement;
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
};
|
|
253
280
|
readonly createNamespace: typeof postgresCreateNamespace;
|
|
254
281
|
readonly qualifyColumnType: typeof postgresQualifyColumnType;
|
|
255
282
|
};
|
package/dist/pack.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pack.d.mts","names":[],"sources":["../src/core/authoring.ts","../src/core/descriptor-meta.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"pack.d.mts","names":[],"sources":["../src/core/authoring.ts","../src/core/descriptor-meta.ts"],"mappings":";;;;;;;UAgDiB,uBAAA,SAAgC,iBAAiB;EAAA,SACvD,WAAW;AAAA;;;cCpChB,gCAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAYI,iBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAEG,4BAAA,SAAqC,gCAAA;EAAA,SACvC,YAAA,GAAe,UAAU;AAAA"}
|
package/dist/pack.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as postgresTargetDescriptorMeta } from "./descriptor-meta-
|
|
1
|
+
import { t as postgresTargetDescriptorMeta } from "./descriptor-meta-BOcKPaLE.mjs";
|
|
2
2
|
export { postgresTargetDescriptorMeta as default };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { t as DEFAULT_NAMESPACE_ID } from "./namespace-ids-xtp_ZY86.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { t as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { t as
|
|
2
|
+
import { h as PostgresRlsPolicy, r as isPostgresSchema } from "./postgres-schema-DTLA_aRi.mjs";
|
|
3
|
+
import { n as parseRlsPolicyWireName } from "./wire-name-rHHtr1h0.mjs";
|
|
4
|
+
import { n as PostgresSchemaNodeKind } from "./postgres-table-schema-node-9FCtCUz2.mjs";
|
|
5
|
+
import { i as PostgresDatabaseSchemaNode, n as PostgresPolicySchemaNode, r as PostgresNamespaceSchemaNode } from "./postgres-role-schema-node-BiSTCTNg.mjs";
|
|
6
|
+
import { t as resolveDdlSchemaForNamespaceStorage } from "./resolve-ddl-schema-Ca88Tg6W.mjs";
|
|
7
|
+
import { t as buildPostgresPlanDiff } from "./diff-database-schema-CWb-jeLy.mjs";
|
|
8
|
+
import { E as RenamePostgresRlsPolicyCall, S as DropPostgresRlsPolicyCall, d as CreatePostgresRlsPolicyCall } from "./op-factory-call-DxNNKUeZ.mjs";
|
|
9
|
+
import { a as resolvePostgresNodeIssueCreationFactoryName, c as issueSchemaName, d as postgresPlannerStrategies, i as resolvePostgresNodeIssueControlPolicySubject, l as issueTableName, n as resolveNamespaceIdForDdlSchema, o as coalesceSubtreeIssues, r as resolvePostgresCallControlPolicySubject, s as issueNode, t as formatPostgresControlPolicySubjectLabel, u as planIssues } from "./control-policy-BtOZBVxL.mjs";
|
|
10
|
+
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-BLJH1zIc.mjs";
|
|
10
11
|
import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
|
|
11
12
|
import { blindCast } from "@prisma-next/utils/casts";
|
|
12
13
|
import { extractCodecControlHooks, partitionCallsByControlPolicy, partitionIssuesByControlPolicy, planFieldEventOperations, plannerFailure } from "@prisma-next/family-sql/control";
|
|
@@ -214,29 +215,84 @@ var PostgresMigrationPlanner = class {
|
|
|
214
215
|
}
|
|
215
216
|
/**
|
|
216
217
|
* Maps the RLS policy presence findings of the one combined tree diff
|
|
217
|
-
* (`buildPostgresPlanDiff`, already ownership-filtered) into
|
|
218
|
-
*
|
|
219
|
-
* exactly the policy-node subset of the
|
|
218
|
+
* (`buildPostgresPlanDiff`, already ownership-filtered) into
|
|
219
|
+
* `CREATE POLICY` / `DROP POLICY` / `ALTER POLICY … RENAME TO` ops. It
|
|
220
|
+
* does not re-diff — it consumes exactly the policy-node subset of the
|
|
221
|
+
* shared diff's issues. Enablement is NOT decided here: `ENABLE`/`DISABLE
|
|
222
|
+
* ROW LEVEL SECURITY` derive from the table's marker-driven `rlsEnabled`
|
|
223
|
+
* attribute diff on the relational side.
|
|
224
|
+
*
|
|
225
|
+
* Rename post-pass: a `not-found` and a `not-expected` policy on the SAME
|
|
226
|
+
* table whose wire-name content hashes match but prefixes differ are one
|
|
227
|
+
* prefix-only rename, collapsed into a single non-destructive
|
|
228
|
+
* `RenamePostgresRlsPolicyCall`. Multi-candidate hash groups pair
|
|
229
|
+
* deterministically by sorted wire name; leftovers proceed as
|
|
230
|
+
* create/drop. Unparseable wire names never pair.
|
|
231
|
+
*
|
|
232
|
+
* The pairing runs only when the policy allows `widening` (rename's
|
|
233
|
+
* class). Without it (db-init's additive-only set), pairing degrades
|
|
234
|
+
* deliberately to the additive half: the new name is CREATEd and the old
|
|
235
|
+
* policy survives live until a widening/destructive-allowed plan runs —
|
|
236
|
+
* emitting an ungated widening rename would only fail at the runner's
|
|
237
|
+
* class re-enforcement.
|
|
220
238
|
*/
|
|
221
239
|
planPostgresSchemaDiff(options, filteredDiffIssues) {
|
|
222
240
|
const allowsDestructive = options.policy.allowedOperationClasses.includes("destructive");
|
|
223
|
-
const
|
|
224
|
-
const
|
|
241
|
+
const allowsWidening = options.policy.allowedOperationClasses.includes("widening");
|
|
242
|
+
const missing = [];
|
|
243
|
+
const extra = [];
|
|
225
244
|
for (const issue of filteredDiffIssues) if (issue.reason === "not-found") {
|
|
226
245
|
const expected = issue.expected;
|
|
227
246
|
PostgresPolicySchemaNode.assert(expected);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
calls.push(new CreatePostgresRlsPolicyCall(schemaForTable, expected.tableName, policyNodeToContractPolicy(expected)));
|
|
235
|
-
} else if (issue.reason === "not-expected" && allowsDestructive) {
|
|
247
|
+
missing.push({
|
|
248
|
+
node: expected,
|
|
249
|
+
schemaForTable: resolveDdlSchemaForNamespaceStorage(options.contract.storage, expected.namespaceId)
|
|
250
|
+
});
|
|
251
|
+
} else if (issue.reason === "not-expected") {
|
|
236
252
|
const actual = issue.actual;
|
|
237
253
|
PostgresPolicySchemaNode.assert(actual);
|
|
238
|
-
|
|
239
|
-
|
|
254
|
+
extra.push({
|
|
255
|
+
node: actual,
|
|
256
|
+
schemaForTable: resolveDdlSchemaForNamespaceStorage(options.contract.storage, actual.namespaceId)
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
const calls = [];
|
|
260
|
+
const renamedExtras = /* @__PURE__ */ new Set();
|
|
261
|
+
const renamedMissing = /* @__PURE__ */ new Set();
|
|
262
|
+
const pairingKey = (finding, hash) => JSON.stringify([
|
|
263
|
+
finding.schemaForTable,
|
|
264
|
+
finding.node.tableName,
|
|
265
|
+
hash
|
|
266
|
+
]);
|
|
267
|
+
if (allowsWidening) {
|
|
268
|
+
const extrasByGroup = /* @__PURE__ */ new Map();
|
|
269
|
+
for (const finding of extra) {
|
|
270
|
+
const parsed = parseRlsPolicyWireName(finding.node.name);
|
|
271
|
+
if (parsed === void 0) continue;
|
|
272
|
+
const key = pairingKey(finding, parsed.hash);
|
|
273
|
+
const group = extrasByGroup.get(key) ?? [];
|
|
274
|
+
group.push(finding);
|
|
275
|
+
extrasByGroup.set(key, group);
|
|
276
|
+
}
|
|
277
|
+
for (const group of extrasByGroup.values()) group.sort((a, b) => a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0);
|
|
278
|
+
const sortedMissing = [...missing].sort((a, b) => a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0);
|
|
279
|
+
for (const missingFinding of sortedMissing) {
|
|
280
|
+
const parsed = parseRlsPolicyWireName(missingFinding.node.name);
|
|
281
|
+
if (parsed === void 0) continue;
|
|
282
|
+
const candidate = extrasByGroup.get(pairingKey(missingFinding, parsed.hash))?.shift();
|
|
283
|
+
if (candidate === void 0) continue;
|
|
284
|
+
renamedExtras.add(candidate);
|
|
285
|
+
renamedMissing.add(missingFinding);
|
|
286
|
+
calls.push(new RenamePostgresRlsPolicyCall(missingFinding.schemaForTable, missingFinding.node.tableName, candidate.node.name, missingFinding.node.name));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
for (const finding of missing) {
|
|
290
|
+
if (renamedMissing.has(finding)) continue;
|
|
291
|
+
calls.push(new CreatePostgresRlsPolicyCall(finding.schemaForTable, finding.node.tableName, policyNodeToContractPolicy(finding.node)));
|
|
292
|
+
}
|
|
293
|
+
if (allowsDestructive) for (const finding of extra) {
|
|
294
|
+
if (renamedExtras.has(finding)) continue;
|
|
295
|
+
calls.push(new DropPostgresRlsPolicyCall(finding.schemaForTable, finding.node.tableName, finding.node.name));
|
|
240
296
|
}
|
|
241
297
|
return calls;
|
|
242
298
|
}
|
|
@@ -364,4 +420,4 @@ function policyNodeToContractPolicy(node) {
|
|
|
364
420
|
//#endregion
|
|
365
421
|
export { createPostgresMigrationPlanner as t };
|
|
366
422
|
|
|
367
|
-
//# sourceMappingURL=planner-
|
|
423
|
+
//# sourceMappingURL=planner-BryLk0Ie.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner-BryLk0Ie.mjs","names":["#lowerer"],"sources":["../src/core/migrations/verify-postgres-namespaces.ts","../src/core/migrations/planner.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport type { SchemaDiffIssue } from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';\nimport { DEFAULT_NAMESPACE_ID } from '../namespace-ids';\nimport { isPostgresSchema } from '../postgres-schema';\nimport { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';\nimport { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';\nimport type { SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';\n\n/**\n * Resolves the live-database schema name for a given namespace\n * coordinate. Mirrors `resolveDdlSchemaForNamespace` in\n * `planner-strategies.ts` so the verifier's projection and the\n * planner's projection always agree — Postgres-aware namespaces (the\n * production path) dispatch to `ddlSchemaName(storage)`, and bare\n * object payloads (used by some tests) fall back to the coordinate\n * itself.\n */\nfunction resolveDdlSchemaName(storage: SqlStorage, namespaceId: string): string {\n const namespace = storage.namespaces[namespaceId];\n if (isPostgresSchema(namespace)) {\n return namespace.ddlSchemaName(storage);\n }\n return namespaceId;\n}\n\n/**\n * Reads the introspected list of schema names from the database-root schema\n * node. `existingSchemas` is database-level, so it lives on the\n * `PostgresDatabaseSchemaNode` root — not on the per-schema namespace nodes.\n *\n * Defaults to the always-present `public` schema when the node is not the\n * database root — a fresh Postgres database always carries `public` (unless an\n * operator dropped it manually), so any verifier path that runs without an\n * enriched introspection still suppresses the redundant `CREATE SCHEMA\n * \"public\"`.\n *\n * Production introspection (`PostgresControlAdapter.introspect`) is the\n * authoritative source: it queries `pg_namespace` and sets `existingSchemas`\n * on the returned root. Tests that want to assert against a richer initial\n * state construct a `PostgresDatabaseSchemaNode` explicitly.\n */\nfunction existingSchemasFromSchema(schema: SqlSchemaIRNode): readonly string[] {\n if (PostgresDatabaseSchemaNode.is(schema)) {\n return schema.existingSchemas;\n }\n return [DEFAULT_NAMESPACE_ID];\n}\n\n/**\n * Emits a `postgres-namespace` `not-found` diff issue for every\n * contract-declared Postgres namespace whose live container does not yet\n * exist. The planner prepends these (node-typed, synthesized) to the\n * relational diff issues so a multi-schema plan emits `CREATE SCHEMA`\n * before the tables that need it — a planner-only concern (verify already\n * rejects via the `not-found` table issues a missing schema already\n * produces), so this is not part of the shared diff.\n *\n * A namespace's live container is the schema returned by its\n * polymorphic `ddlSchemaName(storage)` method — named schemas resolve\n * to their own id; the unbound singleton returns `UNBOUND_NAMESPACE_ID`\n * and is skipped explicitly (late-bound namespaces have no fixed DDL\n * schema). Issues are emitted only when the resolved name is a real,\n * creatable schema (not the unbound sentinel) and is missing from the\n * introspected list. `public` is suppressed implicitly because the\n * introspection (or its sensible default) always carries it.\n *\n * Each emitted issue's path is `['database', ddlName]` — an ancestor of\n * every table path under that schema, so it must never be run through\n * `coalesceSubtreeIssues` alongside the table diff (it would swallow the\n * table-level `not-found` issues that drive `CREATE TABLE`); the planner\n * adds these AFTER coalescing the relational issues, and they are not\n * subject to sibling-space ownership scoping (mirrors the retired\n * coordinate walk, which prepended namespace issues after that filter).\n */\nexport function verifyPostgresNamespacePresence(input: {\n readonly contract: Contract<SqlStorage>;\n readonly schema: SqlSchemaIRNode;\n}): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {\n const { contract, schema } = input;\n const existing = new Set(existingSchemasFromSchema(schema));\n const issues: SchemaDiffIssue<SqlSchemaDiffNode>[] = [];\n const namespaceIds = Object.keys(contract.storage.namespaces).sort();\n for (const namespaceId of namespaceIds) {\n if (namespaceId === UNBOUND_NAMESPACE_ID) continue;\n const ddlName = resolveDdlSchemaName(contract.storage, namespaceId);\n if (ddlName === UNBOUND_NAMESPACE_ID) continue;\n if (existing.has(ddlName)) continue;\n const namespace = new PostgresNamespaceSchemaNode({\n schemaName: ddlName,\n tables: {},\n nativeEnumTypeNames: [],\n });\n issues.push({\n path: ['database', ddlName],\n reason: 'not-found',\n message: `Schema \"${ddlName}\" is missing from database`,\n expected: namespace,\n });\n }\n return issues;\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlMigrationPlannerPlanOptions,\n SqlPlannerConflict,\n SqlPlannerFailureResult,\n} from '@prisma-next/family-sql/control';\nimport {\n extractCodecControlHooks,\n partitionCallsByControlPolicy,\n partitionIssuesByControlPolicy,\n planFieldEventOperations,\n plannerFailure,\n} from '@prisma-next/family-sql/control';\nimport type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n MigrationPlanner,\n MigrationPlanWithAuthoringSurface,\n MigrationScaffoldContext,\n SchemaDiffIssue,\n SchemaOwnership,\n} from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { PostgresRlsPolicy } from '../postgres-rls-policy';\nimport { parseRlsPolicyWireName } from '../rls/wire-name';\nimport { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';\nimport { PostgresPolicySchemaNode } from '../schema-ir/postgres-policy-schema-node';\nimport { PostgresSchemaNodeKind, type SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';\nimport {\n formatPostgresControlPolicySubjectLabel,\n resolveNamespaceIdForDdlSchema,\n resolvePostgresCallControlPolicySubject,\n resolvePostgresNodeIssueControlPolicySubject,\n resolvePostgresNodeIssueCreationFactoryName,\n} from './control-policy';\nimport { buildPostgresPlanDiff } from './diff-database-schema';\nimport {\n coalesceSubtreeIssues,\n issueNode,\n issueSchemaName,\n issueTableName,\n planIssues,\n} from './issue-planner';\nimport type { PostgresOpFactoryCall } from './op-factory-call';\nimport {\n CreatePostgresRlsPolicyCall,\n DropPostgresRlsPolicyCall,\n RenamePostgresRlsPolicyCall,\n} from './op-factory-call';\nimport { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';\nimport { postgresPlannerStrategies } from './planner-strategies';\nimport { resolveDdlSchemaForNamespaceStorage } from './resolve-ddl-schema';\nimport { verifyPostgresNamespacePresence } from './verify-postgres-namespaces';\n\ntype PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {\n readonly frameworkComponents: infer T;\n}\n ? T\n : ReadonlyArray<unknown>;\n\ntype PlannerOptionsWithComponents = SqlMigrationPlannerPlanOptions & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\nexport function createPostgresMigrationPlanner(\n lowerer: ExecuteRequestLowerer,\n): PostgresMigrationPlanner {\n return new PostgresMigrationPlanner(lowerer);\n}\n\n/**\n * Result of `PostgresMigrationPlanner.plan()`. A discriminated union whose\n * success variant carries a `TypeScriptRenderablePostgresMigration` — a\n * migration object that both the CLI (via `renderTypeScript()`) and the\n * SQL-typed callers (via `operations`, `describe()`, etc.) consume\n * uniformly.\n */\nexport type PostgresPlanResult =\n | {\n readonly kind: 'success';\n readonly plan: TypeScriptRenderablePostgresMigration;\n readonly warnings?: readonly SqlPlannerConflict[];\n }\n | SqlPlannerFailureResult;\n\n/**\n * Postgres migration planner — a thin wrapper over `planIssues`.\n *\n * `plan()` diffs the target contract against the live schema via the one\n * differ (`buildPostgresPlanDiff`, producing node-typed `SchemaDiffIssue[]`)\n * and delegates to `planIssues` with the unified `postgresPlannerStrategies`\n * list: NOT-NULL backfill, type-change, nullable-tightening, codec-hook\n * storage types, component-declared dependency installs, and\n * shared-temp-default / empty-table-guarded NOT-NULL add-column. The same\n * strategy list runs for `migration plan`, `db update`, and `db init`;\n * behavior diverges purely on `policy.allowedOperationClasses` (the\n * data-safe strategies short-circuit when `'data'` is excluded). The issue\n * planner applies operation-class policy gates and emits a single\n * `PostgresOpFactoryCall[]` that drives both the runtime-ops view (via\n * `renderOps`) and the `renderTypeScript()` authoring surface. RLS policy\n * drift (the structural half of the same one-differ tree) is handled\n * separately via `planPostgresSchemaDiff`.\n */\nexport class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {\n readonly #lowerer: ExecuteRequestLowerer | undefined;\n\n constructor(lowerer?: ExecuteRequestLowerer) {\n this.#lowerer = lowerer;\n }\n\n plan(options: {\n readonly contract: unknown;\n readonly schema: unknown;\n readonly policy: MigrationOperationPolicy;\n /**\n * The \"from\" contract (state the planner assumes the database starts\n * at), or `null` for reconciliation flows. Only `migration plan` ever\n * supplies a non-null value; `db update` / `db init` reconcile against\n * the live schema and pass `null`. When present alongside the\n * `'data'` operation class, strategies that need from/to column-shape\n * comparisons (unsafe type change, nullability tightening) activate.\n *\n * Typed as the framework `Contract | null` to satisfy the\n * `MigrationPlanner` interface contract; `planSql` narrows to the SQL\n * shape via `SqlMigrationPlannerPlanOptions`. Used to populate\n * `describe().from` on the produced plan as\n * `fromContract?.storage.storageHash ?? null`.\n */\n readonly fromContract: Contract | null;\n readonly schemaName?: string;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n /**\n * Contract space this plan applies to. Stamped onto the produced\n * {@link TypeScriptRenderablePostgresMigration.spaceId} so the runner keys\n * the marker row by the right space.\n */\n readonly spaceId: string;\n /**\n * Ownership oracle over the contract-space composition — see\n * {@link SqlMigrationPlannerPlanOptions.ownership}.\n */\n readonly ownership?: SchemaOwnership;\n }): PostgresPlanResult {\n return this.planSql(options as SqlMigrationPlannerPlanOptions);\n }\n\n emptyMigration(\n context: MigrationScaffoldContext,\n spaceId: string,\n ): MigrationPlanWithAuthoringSurface {\n return new TypeScriptRenderablePostgresMigration(\n [],\n {\n from: context.fromHash,\n to: context.toHash,\n },\n spaceId,\n this.#lowerer,\n );\n }\n\n private planSql(options: SqlMigrationPlannerPlanOptions): PostgresPlanResult {\n const schemaName =\n options.schemaName ??\n Object.keys(options.contract.storage.namespaces).find((id) => id !== UNBOUND_NAMESPACE_ID) ??\n UNBOUND_NAMESPACE_ID;\n const policyResult = this.ensureAdditivePolicy(options.policy);\n if (policyResult) {\n return policyResult;\n }\n\n // The one combined tree diff drives the whole plan: relational findings\n // become structural DDL via `planIssues`, policy findings become RLS ops\n // via `planPostgresSchemaDiff`. Verify runs its own full-tree node diff\n // (`diffSchema`) over the same schema and rejects on a\n // surviving failure.\n PostgresDatabaseSchemaNode.assert(options.schema);\n const { issues: rawIssues } = buildPostgresPlanDiff({\n contract: options.contract,\n actualSchema: options.schema,\n frameworkComponents: options.frameworkComponents,\n });\n const policyDiffIssues = rawIssues.filter((issue) => isPolicyDiffIssue(issue));\n const relationalDiffIssues = rawIssues.filter((issue) => !isPolicyDiffIssue(issue));\n\n // The generic differ is total and un-gated: strict-mode extras filtering\n // (dropping `not-expected` findings outside strict mode, mirroring the\n // retired coordinate walk's `if (strict) { ...extra_* } }` guards),\n // subtree coalescing (a missing/extra table also emits an issue for\n // every child under it — redundant once the table-level Create/Drop call\n // already accounts for the whole subtree), and ownership are all post-diff\n // planner steps.\n //\n // Ownership: a live extra is only this plan's to drop when no contract\n // space owns it. The differ ran against THIS space's contract, so a table\n // a sibling space owns surfaces here as `not-expected`; the planner asks\n // the ownership oracle (the passive aggregate) whether any space declares\n // it and, if so, leaves it alone — it is a sibling's table, not an orphan.\n // A table no space owns stays a genuine extra to drop under a destructive\n // policy. Ownership lives in the aggregate; the planner only asks. Absent\n // oracle (single-space, none handed) keeps every extra. Coalescing MUST\n // run before this so a sibling-owned table's child issues have already\n // collapsed into the one table-level issue that carries the table name.\n const strict =\n options.policy.allowedOperationClasses.includes('widening') ||\n options.policy.allowedOperationClasses.includes('destructive');\n const coalesced = coalesceSubtreeIssues(relationalDiffIssues);\n const owned = retainUnownedExtras(coalesced, options.ownership, options.contract);\n const gated = strict ? owned : owned.filter((issue) => issue.reason !== 'not-expected');\n\n // Namespace presence (`CREATE SCHEMA`) is a planner-only op-generation\n // concern stitched in here rather than inside the shared diff — verify\n // never needs it (a missing schema already surfaces as a `not-found`\n // table in the relational findings). These synthesized issues are added\n // AFTER coalescing/scoping (never coalesced against the table diff —\n // their path is an ancestor of every table path under that schema, so\n // running them through the same coalesce would swallow the table-level\n // `not-found` issues that drive `CREATE TABLE`) and are NOT subject to\n // sibling-space scoping, matching the retired coordinate walk exactly.\n const namespaceIssues = verifyPostgresNamespacePresence({\n contract: options.contract,\n schema: options.schema,\n });\n const schemaIssues = [...namespaceIssues, ...gated];\n\n const codecHooks = extractCodecControlHooks(options.frameworkComponents);\n const storageTypes = options.contract.storage.types ?? {};\n // The strategy layer reads the live schema by bare table name for existence\n // checks (shared-temp-default safety, FK/unique probes), so it takes one\n // per-schema namespace node — never the whole tree root, and never a flat\n // merge of every namespace (which would collide same-named tables across\n // schemas). Probing more than one namespace at once is future work.\n const relationalSchema = relationalNamespaceNode(options.schema, schemaName);\n\n // Input-side control-policy partition. `external` / `observed` subjects\n // — and non-creation issues for `tolerated` subjects — are dropped from\n // the planner's input entirely; the planner never observes them, never\n // diffs them, never generates DDL for them. Suppression warnings are\n // built directly from the suppressed partition (one per subject), so the\n // user-visible message survives even when the planner would have failed\n // to model the subject's live shape.\n const issuePartition = partitionIssuesByControlPolicy({\n issues: schemaIssues,\n contract: options.contract,\n resolveControlPolicySubject: (issue) =>\n resolvePostgresNodeIssueControlPolicySubject(issue, options.contract),\n resolveCreationFactoryName: resolvePostgresNodeIssueCreationFactoryName,\n formatSubjectLabel: (factoryName, subject) =>\n formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),\n });\n\n const result = planIssues({\n issues: issuePartition.plannable,\n toContract: options.contract,\n // `fromContract` is only supplied by `migration plan`. It is `null` for\n // `db update` / `db init`, which means data-safety strategies needing\n // from/to comparisons (unsafe type change, nullable tightening) are\n // inapplicable there — reconciliation falls through to\n // `mapNodeIssueToCall`'s direct destructive handlers.\n fromContract: options.fromContract,\n schemaName,\n codecHooks,\n storageTypes,\n ...ifDefined('schema', relationalSchema),\n policy: options.policy,\n frameworkComponents: options.frameworkComponents,\n strategies: postgresPlannerStrategies,\n });\n\n if (!result.ok) {\n return plannerFailure(result.failure);\n }\n\n const schemaDiffCalls = this.planPostgresSchemaDiff(options, policyDiffIssues);\n const schemaDiffPartition = partitionCallsByControlPolicy({\n calls: schemaDiffCalls,\n contract: options.contract,\n resolveControlPolicySubject: (call) =>\n resolvePostgresCallControlPolicySubject(call, options.contract),\n resolveFactoryName: (call) => call.factoryName,\n formatSubjectLabel: (factoryName, subject) =>\n formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),\n });\n\n // Inline `onFieldEvent`-emitted ops after structural DDL. The fixed\n // ordering is `structural → added → dropped → altered`, with\n // within-group sorting by `(tableName, fieldName)` so re-emits are\n // byte-stable. The hook fires only at the application emitter —\n // extension-space planning never reaches this helper.\n const fieldEventOps = planFieldEventOperations({\n priorContract: options.fromContract,\n newContract: options.contract,\n codecHooks,\n });\n // Codec hook ops are target-agnostic `OpFactoryCall`; Postgres planning\n // lifts them at this integration boundary (see field-event-planner JSDoc).\n const fieldEventPostgresCalls = blindCast<\n readonly PostgresOpFactoryCall[],\n 'Codec hook ops conform to PostgresOpFactoryCall at the app emitter boundary'\n >(fieldEventOps);\n const fieldEventPartition = partitionCallsByControlPolicy({\n calls: fieldEventPostgresCalls,\n contract: options.contract,\n resolveControlPolicySubject: (call) =>\n resolvePostgresCallControlPolicySubject(call, options.contract),\n resolveFactoryName: (call) => call.factoryName,\n formatSubjectLabel: (factoryName, subject) =>\n formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),\n });\n const calls = [...result.value.calls, ...schemaDiffPartition.kept, ...fieldEventPartition.kept];\n const warnings: SqlPlannerConflict[] = [\n ...issuePartition.warnings,\n ...schemaDiffPartition.warnings,\n ...fieldEventPartition.warnings,\n ];\n\n return Object.freeze({\n kind: 'success' as const,\n plan: new TypeScriptRenderablePostgresMigration(\n calls,\n {\n from: options.fromContract?.storage.storageHash ?? null,\n to: options.contract.storage.storageHash,\n },\n options.spaceId,\n this.#lowerer,\n ),\n ...(warnings.length > 0 ? { warnings: Object.freeze(warnings) } : {}),\n });\n }\n\n /**\n * Maps the RLS policy presence findings of the one combined tree diff\n * (`buildPostgresPlanDiff`, already ownership-filtered) into\n * `CREATE POLICY` / `DROP POLICY` / `ALTER POLICY … RENAME TO` ops. It\n * does not re-diff — it consumes exactly the policy-node subset of the\n * shared diff's issues. Enablement is NOT decided here: `ENABLE`/`DISABLE\n * ROW LEVEL SECURITY` derive from the table's marker-driven `rlsEnabled`\n * attribute diff on the relational side.\n *\n * Rename post-pass: a `not-found` and a `not-expected` policy on the SAME\n * table whose wire-name content hashes match but prefixes differ are one\n * prefix-only rename, collapsed into a single non-destructive\n * `RenamePostgresRlsPolicyCall`. Multi-candidate hash groups pair\n * deterministically by sorted wire name; leftovers proceed as\n * create/drop. Unparseable wire names never pair.\n *\n * The pairing runs only when the policy allows `widening` (rename's\n * class). Without it (db-init's additive-only set), pairing degrades\n * deliberately to the additive half: the new name is CREATEd and the old\n * policy survives live until a widening/destructive-allowed plan runs —\n * emitting an ungated widening rename would only fail at the runner's\n * class re-enforcement.\n */\n private planPostgresSchemaDiff(\n options: PlannerOptionsWithComponents,\n filteredDiffIssues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],\n ): readonly PostgresOpFactoryCall[] {\n const allowsDestructive = options.policy.allowedOperationClasses.includes('destructive');\n const allowsWidening = options.policy.allowedOperationClasses.includes('widening');\n\n interface PolicyFinding {\n readonly node: PostgresPolicySchemaNode;\n readonly schemaForTable: string;\n }\n const missing: PolicyFinding[] = [];\n const extra: PolicyFinding[] = [];\n\n for (const issue of filteredDiffIssues) {\n // 'not-equal' is unreachable for content-addressed policies: the wire name\n // encodes the body hash, so two policies sharing a local key (same name)\n // are always equal and isEqualTo never returns false.\n if (issue.reason === 'not-found') {\n const expected = issue.expected;\n PostgresPolicySchemaNode.assert(expected);\n // expected.namespaceId is the DDL schema name (resolved during projection);\n // this re-resolution is a no-op as long as PostgresSchema.ddlSchemaName() returns this.id.\n missing.push({\n node: expected,\n schemaForTable: resolveDdlSchemaForNamespaceStorage(\n options.contract.storage,\n expected.namespaceId,\n ),\n });\n } else if (issue.reason === 'not-expected') {\n const actual = issue.actual;\n PostgresPolicySchemaNode.assert(actual);\n extra.push({\n node: actual,\n schemaForTable: resolveDdlSchemaForNamespaceStorage(\n options.contract.storage,\n actual.namespaceId,\n ),\n });\n }\n }\n\n const calls: PostgresOpFactoryCall[] = [];\n const renamedExtras = new Set<PolicyFinding>();\n const renamedMissing = new Set<PolicyFinding>();\n const pairingKey = (finding: PolicyFinding, hash: string): string =>\n JSON.stringify([finding.schemaForTable, finding.node.tableName, hash]);\n\n if (allowsWidening) {\n const extrasByGroup = new Map<string, PolicyFinding[]>();\n for (const finding of extra) {\n const parsed = parseRlsPolicyWireName(finding.node.name);\n if (parsed === undefined) continue;\n const key = pairingKey(finding, parsed.hash);\n const group = extrasByGroup.get(key) ?? [];\n group.push(finding);\n extrasByGroup.set(key, group);\n }\n for (const group of extrasByGroup.values()) {\n group.sort((a, b) => (a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0));\n }\n\n const sortedMissing = [...missing].sort((a, b) =>\n a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0,\n );\n for (const missingFinding of sortedMissing) {\n const parsed = parseRlsPolicyWireName(missingFinding.node.name);\n if (parsed === undefined) continue;\n const candidates = extrasByGroup.get(pairingKey(missingFinding, parsed.hash));\n const candidate = candidates?.shift();\n if (candidate === undefined) continue;\n // Same name would never surface as missing+extra (the differ pairs by\n // name), so a matched candidate always differs in prefix only.\n renamedExtras.add(candidate);\n renamedMissing.add(missingFinding);\n calls.push(\n new RenamePostgresRlsPolicyCall(\n missingFinding.schemaForTable,\n missingFinding.node.tableName,\n candidate.node.name,\n missingFinding.node.name,\n ),\n );\n }\n }\n\n for (const finding of missing) {\n if (renamedMissing.has(finding)) continue;\n calls.push(\n new CreatePostgresRlsPolicyCall(\n finding.schemaForTable,\n finding.node.tableName,\n policyNodeToContractPolicy(finding.node),\n ),\n );\n }\n if (allowsDestructive) {\n for (const finding of extra) {\n if (renamedExtras.has(finding)) continue;\n calls.push(\n new DropPostgresRlsPolicyCall(\n finding.schemaForTable,\n finding.node.tableName,\n finding.node.name,\n ),\n );\n }\n }\n\n return calls;\n }\n\n private ensureAdditivePolicy(policy: MigrationOperationPolicy) {\n if (!policy.allowedOperationClasses.includes('additive')) {\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: 'Migration planner requires additive operations be allowed',\n why: 'The planner requires the \"additive\" operation class to be allowed in the policy.',\n },\n ]);\n }\n return null;\n }\n}\n\n/**\n * A diff issue whose node is an RLS policy — the structural half of the one\n * combined tree diff, routed to `planPostgresSchemaDiff` instead of\n * `planIssues`.\n */\nfunction isPolicyDiffIssue(issue: SchemaDiffIssue<SqlSchemaDiffNode>): boolean {\n const node = issue.expected ?? issue.actual;\n return node !== undefined && PostgresPolicySchemaNode.is(node);\n}\n\n/**\n * Drops a `not-expected` issue when it is a whole extra TABLE that some\n * contract space owns, asking the ownership oracle per node.\n *\n * The consultation applies ONLY to table-level extras — a live table this\n * space's contract lacks — identified by asking the issue's own node\n * (`nodeKind === table`), never by counting path segments. `declaresEntity`\n * answers over the whole composition (self included), keyed on the schema-IR\n * entity coordinate so a genuine orphan in one namespace is never conflated\n * with a same-named table a sibling space declares in another, or with a\n * same-named non-table entity (an enum, an RLS policy) a sibling declares in\n * the SAME namespace: a positive answer means another space owns THIS table\n * in THIS namespace (a table this space owned would be in its expected tree,\n * never an extra) — leave it. A negative answer means no space owns it — a\n * genuine orphan to drop. `entityKind` is the literal `'table'` here: this\n * function only ever asks about a node already confirmed to be\n * `PostgresSchemaNodeKind.table` (checked just above), and the diff tree's\n * `nodeKind` vocabulary (`'postgres-table'`) is distinct from the storage\n * `entries` vocabulary `elementCoordinates` walks (`'table'`) — the literal\n * is that storage-entries spelling, not the node kind.\n *\n * The issue path carries the *resolved DDL schema* (e.g. `public`), but a\n * contract space's own declared namespace id can be the unbound sentinel\n * (`__unbound__`) that resolves to that schema — the two spellings would\n * never string-match. `resolveNamespaceIdForDdlSchema` recovers the raw\n * namespace id THIS space's own contract would use for that DDL schema, so\n * a table this space's own unbound namespace declares (and any sibling\n * whose own unbound namespace resolves the same way) is compared on the\n * same coordinate the aggregate's `elementCoordinates` walk yields.\n *\n * A DEEPER extra (an extra column/constraint on a table this space DOES own —\n * only the child drifted, so the table is in the expected tree) is this\n * space's own drift and is always kept for dropping; asking the oracle there\n * would wrongly suppress it, because the owned table answers `true`. Shallower\n * issues (namespace/root) are never ownership-scoped here. No oracle ⇒ every\n * extra is kept (single-space plan).\n */\nfunction retainUnownedExtras(\n issues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],\n ownership: SchemaOwnership | undefined,\n contract: Contract<SqlStorage>,\n): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {\n if (ownership === undefined) return issues;\n return issues.filter((issue) => {\n if (issue.reason !== 'not-expected') return true;\n const node = issueNode(issue);\n if (node === undefined || node.nodeKind !== PostgresSchemaNodeKind.table) return true;\n const ddlSchemaName = issueSchemaName(issue);\n const tableName = issueTableName(issue);\n if (ddlSchemaName === undefined || tableName === undefined) return true;\n const namespaceId = resolveNamespaceIdForDdlSchema(contract, ddlSchemaName);\n return !ownership.declaresEntity({ namespaceId, entityKind: 'table', entityName: tableName });\n });\n}\n\n/**\n * Returns the one namespace node the relational strategy layer probes for\n * live-table existence and reads codec-hook context off — the namespace\n * matching the planner's resolved schema name, or the first namespace when\n * none matches. `undefined` when the tree has no namespaces, so the strategy\n * context uses its empty-schema default.\n *\n * The relational strategies key tables by bare name, so they can only probe one\n * namespace at a time; probing across every namespace at once is future work.\n *\n * Returns the real `PostgresNamespaceSchemaNode` reference rather than a\n * projection: `storageTypePlanCallStrategy` hands this same value to codec\n * `planTypeOperations` hooks as `schema`, and hooks read the Postgres-specific\n * `nativeEnumTypeNames` field off it (via `PostgresNamespaceSchemaNode.is`) to\n * decide whether a native enum type already exists — a projection that only\n * copies `tables` would silently drop that signal. `StrategyContext.schema`'s\n * declared type (`SqlSchemaIR`, shared with SQLite's flat shape) doesn't\n * capture this, so the return is `blindCast` the same way `namespaceSchemaNodes`\n * in the family's relational walk already treats a namespace node as a\n * structurally-`SqlSchemaIR`-shaped value.\n */\nfunction relationalNamespaceNode(\n schema: PostgresDatabaseSchemaNode,\n schemaName: string,\n): SqlSchemaIR | undefined {\n const namespaceNodes = Object.values(schema.namespaces);\n const namespaceNode =\n namespaceNodes.find((node) => node.schemaName === schemaName) ?? namespaceNodes[0];\n if (namespaceNode === undefined) return undefined;\n return blindCast<\n SqlSchemaIR,\n 'PostgresNamespaceSchemaNode carries tables (+ nativeEnumTypeNames, read by codec hooks via PostgresNamespaceSchemaNode.is) structurally compatible with the SqlSchemaIR shape the strategy layer declares'\n >(namespaceNode);\n}\n\n/**\n * Rebuilds the `PostgresRlsPolicy` contract entity `CreatePostgresRlsPolicyCall`\n * carries (its `renderTypeScript`/`createRlsPolicy` paths serialize the whole\n * entity, `namespaceId` included). This reconstructs rather than looking the\n * original up in the contract on purpose: the diff node's `namespaceId` is the\n * *resolved DDL schema* (set when the expected tree was built), which is the\n * value the emitted op must carry; the contract-stored entity holds the raw,\n * pre-resolution coordinate, so a lookup would change the migration output.\n */\nfunction policyNodeToContractPolicy(node: PostgresPolicySchemaNode): PostgresRlsPolicy {\n return new PostgresRlsPolicy({\n name: node.name,\n prefix: node.prefix,\n tableName: node.tableName,\n namespaceId: node.namespaceId,\n operation: node.operation,\n roles: [...node.roles],\n ...ifDefined('using', node.using),\n ...ifDefined('withCheck', node.withCheck),\n permissive: node.permissive,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,qBAAqB,SAAqB,aAA6B;CAC9E,MAAM,YAAY,QAAQ,WAAW;CACrC,IAAI,iBAAiB,SAAS,GAC5B,OAAO,UAAU,cAAc,OAAO;CAExC,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,SAAS,0BAA0B,QAA4C;CAC7E,IAAI,2BAA2B,GAAG,MAAM,GACtC,OAAO,OAAO;CAEhB,OAAO,CAAC,oBAAoB;AAC9B;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,gCAAgC,OAGE;CAChD,MAAM,EAAE,UAAU,WAAW;CAC7B,MAAM,WAAW,IAAI,IAAI,0BAA0B,MAAM,CAAC;CAC1D,MAAM,SAA+C,CAAC;CACtD,MAAM,eAAe,OAAO,KAAK,SAAS,QAAQ,UAAU,CAAC,CAAC,KAAK;CACnE,KAAK,MAAM,eAAe,cAAc;EACtC,IAAI,gBAAgB,sBAAsB;EAC1C,MAAM,UAAU,qBAAqB,SAAS,SAAS,WAAW;EAClE,IAAI,YAAY,sBAAsB;EACtC,IAAI,SAAS,IAAI,OAAO,GAAG;EAC3B,MAAM,YAAY,IAAI,4BAA4B;GAChD,YAAY;GACZ,QAAQ,CAAC;GACT,qBAAqB,CAAC;EACxB,CAAC;EACD,OAAO,KAAK;GACV,MAAM,CAAC,YAAY,OAAO;GAC1B,QAAQ;GACR,SAAS,WAAW,QAAQ;GAC5B,UAAU;EACZ,CAAC;CACH;CACA,OAAO;AACT;;;AClCA,SAAgB,+BACd,SAC0B;CAC1B,OAAO,IAAI,yBAAyB,OAAO;AAC7C;;;;;;;;;;;;;;;;;;;AAmCA,IAAa,2BAAb,MAAqF;CACnF;CAEA,YAAY,SAAiC;EAC3C,KAAKA,WAAW;CAClB;CAEA,KAAK,SAgCkB;EACrB,OAAO,KAAK,QAAQ,OAAyC;CAC/D;CAEA,eACE,SACA,SACmC;EACnC,OAAO,IAAI,sCACT,CAAC,GACD;GACE,MAAM,QAAQ;GACd,IAAI,QAAQ;EACd,GACA,SACA,KAAKA,QACP;CACF;CAEA,QAAgB,SAA6D;EAC3E,MAAM,aACJ,QAAQ,cACR,OAAO,KAAK,QAAQ,SAAS,QAAQ,UAAU,CAAC,CAAC,MAAM,OAAO,OAAO,oBAAoB,KACzF;EACF,MAAM,eAAe,KAAK,qBAAqB,QAAQ,MAAM;EAC7D,IAAI,cACF,OAAO;EAQT,2BAA2B,OAAO,QAAQ,MAAM;EAChD,MAAM,EAAE,QAAQ,cAAc,sBAAsB;GAClD,UAAU,QAAQ;GAClB,cAAc,QAAQ;GACtB,qBAAqB,QAAQ;EAC/B,CAAC;EACD,MAAM,mBAAmB,UAAU,QAAQ,UAAU,kBAAkB,KAAK,CAAC;EAC7E,MAAM,uBAAuB,UAAU,QAAQ,UAAU,CAAC,kBAAkB,KAAK,CAAC;EAoBlF,MAAM,SACJ,QAAQ,OAAO,wBAAwB,SAAS,UAAU,KAC1D,QAAQ,OAAO,wBAAwB,SAAS,aAAa;EAE/D,MAAM,QAAQ,oBADI,sBAAsB,oBACE,GAAG,QAAQ,WAAW,QAAQ,QAAQ;EAChF,MAAM,QAAQ,SAAS,QAAQ,MAAM,QAAQ,UAAU,MAAM,WAAW,cAAc;EAetF,MAAM,eAAe,CAAC,GAJE,gCAAgC;GACtD,UAAU,QAAQ;GAClB,QAAQ,QAAQ;EAClB,CACuC,GAAG,GAAG,KAAK;EAElD,MAAM,aAAa,yBAAyB,QAAQ,mBAAmB;EACvE,MAAM,eAAe,QAAQ,SAAS,QAAQ,SAAS,CAAC;EAMxD,MAAM,mBAAmB,wBAAwB,QAAQ,QAAQ,UAAU;EAS3E,MAAM,iBAAiB,+BAA+B;GACpD,QAAQ;GACR,UAAU,QAAQ;GAClB,8BAA8B,UAC5B,6CAA6C,OAAO,QAAQ,QAAQ;GACtE,4BAA4B;GAC5B,qBAAqB,aAAa,YAChC,wCAAwC,aAAa,SAAS,QAAQ,QAAQ;EAClF,CAAC;EAED,MAAM,SAAS,WAAW;GACxB,QAAQ,eAAe;GACvB,YAAY,QAAQ;GAMpB,cAAc,QAAQ;GACtB;GACA;GACA;GACA,GAAG,UAAU,UAAU,gBAAgB;GACvC,QAAQ,QAAQ;GAChB,qBAAqB,QAAQ;GAC7B,YAAY;EACd,CAAC;EAED,IAAI,CAAC,OAAO,IACV,OAAO,eAAe,OAAO,OAAO;EAItC,MAAM,sBAAsB,8BAA8B;GACxD,OAFsB,KAAK,uBAAuB,SAAS,gBAEtC;GACrB,UAAU,QAAQ;GAClB,8BAA8B,SAC5B,wCAAwC,MAAM,QAAQ,QAAQ;GAChE,qBAAqB,SAAS,KAAK;GACnC,qBAAqB,aAAa,YAChC,wCAAwC,aAAa,SAAS,QAAQ,QAAQ;EAClF,CAAC;EAkBD,MAAM,sBAAsB,8BAA8B;GACxD,OAL8B,UAPV,yBAAyB;IAC7C,eAAe,QAAQ;IACvB,aAAa,QAAQ;IACrB;GACF,CAMc,CAEiB;GAC7B,UAAU,QAAQ;GAClB,8BAA8B,SAC5B,wCAAwC,MAAM,QAAQ,QAAQ;GAChE,qBAAqB,SAAS,KAAK;GACnC,qBAAqB,aAAa,YAChC,wCAAwC,aAAa,SAAS,QAAQ,QAAQ;EAClF,CAAC;EACD,MAAM,QAAQ;GAAC,GAAG,OAAO,MAAM;GAAO,GAAG,oBAAoB;GAAM,GAAG,oBAAoB;EAAI;EAC9F,MAAM,WAAiC;GACrC,GAAG,eAAe;GAClB,GAAG,oBAAoB;GACvB,GAAG,oBAAoB;EACzB;EAEA,OAAO,OAAO,OAAO;GACnB,MAAM;GACN,MAAM,IAAI,sCACR,OACA;IACE,MAAM,QAAQ,cAAc,QAAQ,eAAe;IACnD,IAAI,QAAQ,SAAS,QAAQ;GAC/B,GACA,QAAQ,SACR,KAAKA,QACP;GACA,GAAI,SAAS,SAAS,IAAI,EAAE,UAAU,OAAO,OAAO,QAAQ,EAAE,IAAI,CAAC;EACrE,CAAC;CACH;;;;;;;;;;;;;;;;;;;;;;;;CAyBA,uBACE,SACA,oBACkC;EAClC,MAAM,oBAAoB,QAAQ,OAAO,wBAAwB,SAAS,aAAa;EACvF,MAAM,iBAAiB,QAAQ,OAAO,wBAAwB,SAAS,UAAU;EAMjF,MAAM,UAA2B,CAAC;EAClC,MAAM,QAAyB,CAAC;EAEhC,KAAK,MAAM,SAAS,oBAIlB,IAAI,MAAM,WAAW,aAAa;GAChC,MAAM,WAAW,MAAM;GACvB,yBAAyB,OAAO,QAAQ;GAGxC,QAAQ,KAAK;IACX,MAAM;IACN,gBAAgB,oCACd,QAAQ,SAAS,SACjB,SAAS,WACX;GACF,CAAC;EACH,OAAO,IAAI,MAAM,WAAW,gBAAgB;GAC1C,MAAM,SAAS,MAAM;GACrB,yBAAyB,OAAO,MAAM;GACtC,MAAM,KAAK;IACT,MAAM;IACN,gBAAgB,oCACd,QAAQ,SAAS,SACjB,OAAO,WACT;GACF,CAAC;EACH;EAGF,MAAM,QAAiC,CAAC;EACxC,MAAM,gCAAgB,IAAI,IAAmB;EAC7C,MAAM,iCAAiB,IAAI,IAAmB;EAC9C,MAAM,cAAc,SAAwB,SAC1C,KAAK,UAAU;GAAC,QAAQ;GAAgB,QAAQ,KAAK;GAAW;EAAI,CAAC;EAEvE,IAAI,gBAAgB;GAClB,MAAM,gCAAgB,IAAI,IAA6B;GACvD,KAAK,MAAM,WAAW,OAAO;IAC3B,MAAM,SAAS,uBAAuB,QAAQ,KAAK,IAAI;IACvD,IAAI,WAAW,KAAA,GAAW;IAC1B,MAAM,MAAM,WAAW,SAAS,OAAO,IAAI;IAC3C,MAAM,QAAQ,cAAc,IAAI,GAAG,KAAK,CAAC;IACzC,MAAM,KAAK,OAAO;IAClB,cAAc,IAAI,KAAK,KAAK;GAC9B;GACA,KAAK,MAAM,SAAS,cAAc,OAAO,GACvC,MAAM,MAAM,GAAG,MAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,KAAK,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,IAAI,CAAE;GAG3F,MAAM,gBAAgB,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,MAC1C,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,KAAK,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,IAAI,CACnE;GACA,KAAK,MAAM,kBAAkB,eAAe;IAC1C,MAAM,SAAS,uBAAuB,eAAe,KAAK,IAAI;IAC9D,IAAI,WAAW,KAAA,GAAW;IAE1B,MAAM,YADa,cAAc,IAAI,WAAW,gBAAgB,OAAO,IAAI,CAChD,CAAC,EAAE,MAAM;IACpC,IAAI,cAAc,KAAA,GAAW;IAG7B,cAAc,IAAI,SAAS;IAC3B,eAAe,IAAI,cAAc;IACjC,MAAM,KACJ,IAAI,4BACF,eAAe,gBACf,eAAe,KAAK,WACpB,UAAU,KAAK,MACf,eAAe,KAAK,IACtB,CACF;GACF;EACF;EAEA,KAAK,MAAM,WAAW,SAAS;GAC7B,IAAI,eAAe,IAAI,OAAO,GAAG;GACjC,MAAM,KACJ,IAAI,4BACF,QAAQ,gBACR,QAAQ,KAAK,WACb,2BAA2B,QAAQ,IAAI,CACzC,CACF;EACF;EACA,IAAI,mBACF,KAAK,MAAM,WAAW,OAAO;GAC3B,IAAI,cAAc,IAAI,OAAO,GAAG;GAChC,MAAM,KACJ,IAAI,0BACF,QAAQ,gBACR,QAAQ,KAAK,WACb,QAAQ,KAAK,IACf,CACF;EACF;EAGF,OAAO;CACT;CAEA,qBAA6B,QAAkC;EAC7D,IAAI,CAAC,OAAO,wBAAwB,SAAS,UAAU,GACrD,OAAO,eAAe,CACpB;GACE,MAAM;GACN,SAAS;GACT,KAAK;EACP,CACF,CAAC;EAEH,OAAO;CACT;AACF;;;;;;AAOA,SAAS,kBAAkB,OAAoD;CAC7E,MAAM,OAAO,MAAM,YAAY,MAAM;CACrC,OAAO,SAAS,KAAA,KAAa,yBAAyB,GAAG,IAAI;AAC/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAS,oBACP,QACA,WACA,UAC+C;CAC/C,IAAI,cAAc,KAAA,GAAW,OAAO;CACpC,OAAO,OAAO,QAAQ,UAAU;EAC9B,IAAI,MAAM,WAAW,gBAAgB,OAAO;EAC5C,MAAM,OAAO,UAAU,KAAK;EAC5B,IAAI,SAAS,KAAA,KAAa,KAAK,aAAa,uBAAuB,OAAO,OAAO;EACjF,MAAM,gBAAgB,gBAAgB,KAAK;EAC3C,MAAM,YAAY,eAAe,KAAK;EACtC,IAAI,kBAAkB,KAAA,KAAa,cAAc,KAAA,GAAW,OAAO;EACnE,MAAM,cAAc,+BAA+B,UAAU,aAAa;EAC1E,OAAO,CAAC,UAAU,eAAe;GAAE;GAAa,YAAY;GAAS,YAAY;EAAU,CAAC;CAC9F,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAS,wBACP,QACA,YACyB;CACzB,MAAM,iBAAiB,OAAO,OAAO,OAAO,UAAU;CACtD,MAAM,gBACJ,eAAe,MAAM,SAAS,KAAK,eAAe,UAAU,KAAK,eAAe;CAClF,IAAI,kBAAkB,KAAA,GAAW,OAAO,KAAA;CACxC,OAAO,UAGL,aAAa;AACjB;;;;;;;;;;AAWA,SAAS,2BAA2B,MAAmD;CACrF,OAAO,IAAI,kBAAkB;EAC3B,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,WAAW,KAAK;EAChB,aAAa,KAAK;EAClB,WAAW,KAAK;EAChB,OAAO,CAAC,GAAG,KAAK,KAAK;EACrB,GAAG,UAAU,SAAS,KAAK,KAAK;EAChC,GAAG,UAAU,aAAa,KAAK,SAAS;EACxC,YAAY,KAAK;CACnB,CAAC;AACH"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as PostgresMigration } from "./postgres-migration-
|
|
1
|
+
import { t as PostgresMigration } from "./postgres-migration-BahMHTbj.mjs";
|
|
2
2
|
import { t as renderOps } from "./render-ops-BREh1kHe.mjs";
|
|
3
3
|
import { t as renderCallsToTypeScript } from "./render-typescript-7yqILcwr.mjs";
|
|
4
4
|
//#region src/core/migrations/planner-produced-postgres-migration.ts
|
|
@@ -40,4 +40,4 @@ var TypeScriptRenderablePostgresMigration = class extends PostgresMigration {
|
|
|
40
40
|
//#endregion
|
|
41
41
|
export { TypeScriptRenderablePostgresMigration as t };
|
|
42
42
|
|
|
43
|
-
//# sourceMappingURL=planner-produced-postgres-migration-
|
|
43
|
+
//# sourceMappingURL=planner-produced-postgres-migration-BLJH1zIc.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner-produced-postgres-migration-
|
|
1
|
+
{"version":3,"file":"planner-produced-postgres-migration-BLJH1zIc.mjs","names":["#calls","#meta","#spaceId","#lowerer","#operationsCache"],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"sourcesContent":["/**\n * Planner-produced Postgres migration.\n *\n * Returned by `PostgresMigrationPlanner.plan(...)` and `emptyMigration(...)`.\n * Holds the migration IR (`PostgresOpFactoryCall[]`) alongside\n * `MigrationMeta` and exposes both the runtime-ops view (`get operations`)\n * and the TypeScript authoring view (`renderTypeScript()`). Satisfies\n * `MigrationPlanWithAuthoringSurface` so the CLI can uniformly serialize any\n * planner result back to `migration.ts`.\n *\n * Extends the family-level `SqlMigration` alias rather than the target-local\n * migration base directly — mirrors Mongo's `PlannerProducedMongoMigration`\n * shape and keeps CLI wiring one step removed from target internals.\n *\n * Placeholder-bearing plans: `renderTypeScript()` always succeeds and embeds\n * `() => placeholder(\"slot\")` at each stub. `operations`, in contrast, is\n * _not safe to enumerate_ on a stub-bearing plan — `DataTransformCall.toOp()`\n * throws `PN-MIG-2001` because a planner-stubbed closure cannot be lowered\n * to a runtime op. Callers that know a plan may carry stubs must render to\n * `migration.ts`, let the user fill the slots, and re-load the edited\n * migration before enumerating ops. The walk-schema planner does not emit\n * `DataTransformCall`s today, so this asymmetry is invisible until the\n * issue-planner integration lands in Phase 2.\n */\n\nimport type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';\nimport type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';\nimport type {\n MigrationPlanWithAuthoringSurface,\n OpFactoryCall,\n} from '@prisma-next/framework-components/control';\nimport type { MigrationMeta } from '@prisma-next/migration-tools/migration';\nimport type { PostgresPlanTargetDetails } from './planner-target-details';\nimport { PostgresMigration } from './postgres-migration';\nimport { renderOps } from './render-ops';\nimport { renderCallsToTypeScript } from './render-typescript';\n\nexport class TypeScriptRenderablePostgresMigration\n extends PostgresMigration\n implements MigrationPlanWithAuthoringSurface\n{\n readonly #calls: readonly OpFactoryCall[];\n readonly #meta: MigrationMeta;\n readonly #spaceId: string;\n readonly #lowerer: ExecuteRequestLowerer | undefined;\n #operationsCache:\n | readonly (\n | SqlMigrationPlanOperation<PostgresPlanTargetDetails>\n | Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>>\n )[]\n | undefined;\n\n constructor(\n calls: readonly OpFactoryCall[],\n meta: MigrationMeta,\n spaceId: string,\n lowerer?: ExecuteRequestLowerer,\n ) {\n super();\n this.#calls = calls;\n this.#meta = meta;\n this.#spaceId = spaceId;\n this.#lowerer = lowerer;\n }\n\n override get operations(): readonly (\n | SqlMigrationPlanOperation<PostgresPlanTargetDetails>\n | Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>>\n )[] {\n this.#operationsCache ??= renderOps(this.#calls, this.#lowerer);\n return this.#operationsCache;\n }\n\n override describe(): MigrationMeta {\n return this.#meta;\n }\n\n /**\n * Contract space this planner-produced plan applies to. Threaded\n * from the planner options so the runner keys the marker row by\n * the right space when executing the plan.\n */\n get spaceId(): string {\n return this.#spaceId;\n }\n\n renderTypeScript(): string {\n return renderCallsToTypeScript(this.#calls, { from: this.#meta.from, to: this.#meta.to });\n }\n}\n"],"mappings":";;;;AAqCA,IAAa,wCAAb,cACU,kBAEV;CACE;CACA;CACA;CACA;CACA;CAOA,YACE,OACA,MACA,SACA,SACA;EACA,MAAM;EACN,KAAKA,SAAS;EACd,KAAKC,QAAQ;EACb,KAAKC,WAAW;EAChB,KAAKC,WAAW;CAClB;CAEA,IAAa,aAGT;EACF,KAAKC,qBAAqB,UAAU,KAAKJ,QAAQ,KAAKG,QAAQ;EAC9D,OAAO,KAAKC;CACd;CAEA,WAAmC;EACjC,OAAO,KAAKH;CACd;;;;;;CAOA,IAAI,UAAkB;EACpB,OAAO,KAAKC;CACd;CAEA,mBAA2B;EACzB,OAAO,wBAAwB,KAAKF,QAAQ;GAAE,MAAM,KAAKC,MAAM;GAAM,IAAI,KAAKA,MAAM;EAAG,CAAC;CAC1F;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as PostgresPlanTargetDetails } from "./planner-target-details-HkP4RrRO.mjs";
|
|
2
|
-
import { t as PostgresMigration } from "./postgres-migration-
|
|
2
|
+
import { t as PostgresMigration } from "./postgres-migration-cyBe2Ee0.mjs";
|
|
3
3
|
import { SqlMigrationPlanOperation } from "@prisma-next/family-sql/control";
|
|
4
4
|
import { MigrationPlanWithAuthoringSurface, OpFactoryCall } from "@prisma-next/framework-components/control";
|
|
5
5
|
import { MigrationMeta } from "@prisma-next/migration-tools/migration";
|
|
@@ -21,4 +21,4 @@ declare class TypeScriptRenderablePostgresMigration extends PostgresMigration im
|
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
|
23
23
|
export { TypeScriptRenderablePostgresMigration as t };
|
|
24
|
-
//# sourceMappingURL=planner-produced-postgres-migration-
|
|
24
|
+
//# sourceMappingURL=planner-produced-postgres-migration-CGifB6VH.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner-produced-postgres-migration-
|
|
1
|
+
{"version":3,"file":"planner-produced-postgres-migration-CGifB6VH.d.mts","names":[],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"mappings":";;;;;;;;cAqCa,qCAAA,SACH,iBAAA,YACG,iCAAA;EAAA;cAcT,KAAA,WAAgB,aAAA,IAChB,IAAA,EAAM,aAAA,EACN,OAAA,UACA,OAAA,GAAU,qBAAA;EAAA,IASC,UAAA,cACT,yBAAA,CAA0B,yBAAA,IAC1B,OAAA,CAAQ,yBAAA,CAA0B,yBAAA;EAM7B,QAAA,IAAY,aAAA;EARR;;;;;EAAA,IAiBT,OAAA;EAIJ,gBAAA;AAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-
|
|
1
|
+
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-CGifB6VH.mjs";
|
|
2
2
|
export { TypeScriptRenderablePostgresMigration };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-
|
|
1
|
+
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-BLJH1zIc.mjs";
|
|
2
2
|
export { TypeScriptRenderablePostgresMigration };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as postgresCreateNamespace } from "./postgres-schema-
|
|
1
|
+
import { i as postgresCreateNamespace } from "./postgres-schema-DTLA_aRi.mjs";
|
|
2
2
|
import { i as quoteIdentifier } from "./sql-utils-DcfMz4MQ.mjs";
|
|
3
3
|
import { t as resolveColumnTypeMetadata } from "./planner-type-resolution-Bt2f_q-F.mjs";
|
|
4
4
|
//#region src/core/migrations/planner-sql-checks.ts
|
|
@@ -149,4 +149,4 @@ function buildExpectedFormatType(column, codecHooks, storageTypes = {}) {
|
|
|
149
149
|
//#endregion
|
|
150
150
|
export { qualifyTableName as n, buildExpectedFormatType as t };
|
|
151
151
|
|
|
152
|
-
//# sourceMappingURL=planner-sql-checks-
|
|
152
|
+
//# sourceMappingURL=planner-sql-checks-AXoxB1Jl.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner-sql-checks-
|
|
1
|
+
{"version":3,"file":"planner-sql-checks-AXoxB1Jl.mjs","names":[],"sources":["../src/core/migrations/planner-sql-checks.ts"],"sourcesContent":["import type { CodecControlHooks } from '@prisma-next/family-sql/control';\nimport type { StorageColumn, StorageTypeInstance } from '@prisma-next/sql-contract/types';\nimport { postgresCreateNamespace } from '../postgres-schema';\nimport { quoteIdentifier } from '../sql-utils';\nimport { resolveColumnTypeMetadata } from './planner-type-resolution';\n\n/**\n * String-keyed entry points the migration ops use to render\n * schema-qualified DDL and catalog checks. The `schema` argument is\n * interpreted as a namespace coordinate: the framework `__unbound__`\n * sentinel resolves to the late-bound `PostgresUnboundSchema` singleton\n * (which elides the qualifier so `search_path` decides at runtime); any\n * other id materialises a `PostgresSchema(id)` whose qualifier is the\n * named schema. Helpers route through these `Namespace` concretions so\n * the unbound branch lives in the polymorphic override, not the call\n * site.\n */\nexport function qualifyTableName(schema: string, table: string): string {\n return postgresCreateNamespace({ id: schema, entries: { table: {} } }).qualifyTable(table);\n}\n\nconst FORMAT_TYPE_DISPLAY: ReadonlyMap<string, string> = new Map([\n ['int2', 'smallint'],\n ['int4', 'integer'],\n ['int8', 'bigint'],\n ['float4', 'real'],\n ['float8', 'double precision'],\n ['bool', 'boolean'],\n ['timestamp', 'timestamp without time zone'],\n ['timestamptz', 'timestamp with time zone'],\n ['time', 'time without time zone'],\n ['timetz', 'time with time zone'],\n]);\n\nconst UNQUOTED_POSTGRES_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_$]*$/;\n\nconst POSTGRES_RESERVED_IDENTIFIER_WORDS = new Set([\n 'all',\n 'analyse',\n 'analyze',\n 'and',\n 'any',\n 'array',\n 'as',\n 'asc',\n 'asymmetric',\n 'authorization',\n 'between',\n 'binary',\n 'both',\n 'case',\n 'cast',\n 'check',\n 'collate',\n 'column',\n 'constraint',\n 'create',\n 'current_catalog',\n 'current_date',\n 'current_role',\n 'current_time',\n 'current_timestamp',\n 'current_user',\n 'default',\n 'deferrable',\n 'desc',\n 'distinct',\n 'do',\n 'else',\n 'end',\n 'except',\n 'false',\n 'fetch',\n 'for',\n 'foreign',\n 'freeze',\n 'from',\n 'full',\n 'grant',\n 'group',\n 'having',\n 'ilike',\n 'in',\n 'initially',\n 'inner',\n 'intersect',\n 'into',\n 'is',\n 'isnull',\n 'join',\n 'lateral',\n 'leading',\n 'left',\n 'like',\n 'limit',\n 'localtime',\n 'localtimestamp',\n 'natural',\n 'not',\n 'notnull',\n 'null',\n 'offset',\n 'on',\n 'only',\n 'or',\n 'order',\n 'outer',\n 'overlaps',\n 'placing',\n 'primary',\n 'references',\n 'right',\n 'select',\n 'session_user',\n 'similar',\n 'some',\n 'symmetric',\n 'table',\n 'then',\n 'to',\n 'trailing',\n 'true',\n 'union',\n 'unique',\n 'user',\n 'using',\n 'variadic',\n 'verbose',\n 'when',\n 'where',\n 'window',\n 'with',\n]);\n\nfunction formatUserDefinedTypeName(identifier: string): string {\n if (\n UNQUOTED_POSTGRES_IDENTIFIER_PATTERN.test(identifier) &&\n !POSTGRES_RESERVED_IDENTIFIER_WORDS.has(identifier)\n ) {\n return identifier;\n }\n\n return quoteIdentifier(identifier);\n}\n\nexport function buildExpectedFormatType(\n column: StorageColumn,\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n storageTypes: Record<string, StorageTypeInstance> = {},\n): string {\n const resolved = resolveColumnTypeMetadata(column, storageTypes);\n\n if (resolved.typeParams && resolved.codecId) {\n const hooks = codecHooks.get(resolved.codecId);\n if (hooks?.expandNativeType) {\n return hooks.expandNativeType({\n nativeType: resolved.nativeType,\n codecId: resolved.codecId,\n typeParams: resolved.typeParams,\n });\n }\n }\n\n if (column.typeRef) {\n return formatUserDefinedTypeName(resolved.nativeType);\n }\n\n return FORMAT_TYPE_DISPLAY.get(resolved.nativeType) ?? resolved.nativeType;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAgB,iBAAiB,QAAgB,OAAuB;CACtE,OAAO,wBAAwB;EAAE,IAAI;EAAQ,SAAS,EAAE,OAAO,CAAC,EAAE;CAAE,CAAC,CAAC,CAAC,aAAa,KAAK;AAC3F;AAEA,MAAM,sBAAmD,IAAI,IAAI;CAC/D,CAAC,QAAQ,UAAU;CACnB,CAAC,QAAQ,SAAS;CAClB,CAAC,QAAQ,QAAQ;CACjB,CAAC,UAAU,MAAM;CACjB,CAAC,UAAU,kBAAkB;CAC7B,CAAC,QAAQ,SAAS;CAClB,CAAC,aAAa,6BAA6B;CAC3C,CAAC,eAAe,0BAA0B;CAC1C,CAAC,QAAQ,wBAAwB;CACjC,CAAC,UAAU,qBAAqB;AAClC,CAAC;AAED,MAAM,uCAAuC;AAE7C,MAAM,qCAAqC,IAAI,IAAI;CACjD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,0BAA0B,YAA4B;CAC7D,IACE,qCAAqC,KAAK,UAAU,KACpD,CAAC,mCAAmC,IAAI,UAAU,GAElD,OAAO;CAGT,OAAO,gBAAgB,UAAU;AACnC;AAEA,SAAgB,wBACd,QACA,YACA,eAAoD,CAAC,GAC7C;CACR,MAAM,WAAW,0BAA0B,QAAQ,YAAY;CAE/D,IAAI,SAAS,cAAc,SAAS,SAAS;EAC3C,MAAM,QAAQ,WAAW,IAAI,SAAS,OAAO;EAC7C,IAAI,OAAO,kBACT,OAAO,MAAM,iBAAiB;GAC5B,YAAY,SAAS;GACrB,SAAS,SAAS;GAClB,YAAY,SAAS;EACvB,CAAC;CAEL;CAEA,IAAI,OAAO,SACT,OAAO,0BAA0B,SAAS,UAAU;CAGtD,OAAO,oBAAoB,IAAI,SAAS,UAAU,KAAK,SAAS;AAClE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as qualifyTableName, t as buildExpectedFormatType } from "./planner-sql-checks-
|
|
1
|
+
import { n as qualifyTableName, t as buildExpectedFormatType } from "./planner-sql-checks-AXoxB1Jl.mjs";
|
|
2
2
|
export { buildExpectedFormatType, qualifyTableName };
|
package/dist/planner.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as PostgresDatabaseSchemaNode } from "./postgres-database-schema-node-
|
|
2
|
-
import { t as PostgresContract } from "./postgres-schema-
|
|
3
|
-
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-
|
|
1
|
+
import { t as PostgresDatabaseSchemaNode } from "./postgres-database-schema-node-CfdTY-Qs.mjs";
|
|
2
|
+
import { t as PostgresContract } from "./postgres-schema-CU4gF6QZ.mjs";
|
|
3
|
+
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-CGifB6VH.mjs";
|
|
4
4
|
import { ContractToSchemaIROptions, MigrationOperationPolicy, SqlPlannerConflict, SqlPlannerFailureResult } from "@prisma-next/family-sql/control";
|
|
5
5
|
import { MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationScaffoldContext, SchemaOwnership } from "@prisma-next/framework-components/control";
|
|
6
6
|
import { Contract } from "@prisma-next/contract/types";
|
|
@@ -102,9 +102,26 @@ declare class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postg
|
|
|
102
102
|
private planSql;
|
|
103
103
|
/**
|
|
104
104
|
* Maps the RLS policy presence findings of the one combined tree diff
|
|
105
|
-
* (`buildPostgresPlanDiff`, already ownership-filtered) into
|
|
106
|
-
*
|
|
107
|
-
* exactly the policy-node subset of the
|
|
105
|
+
* (`buildPostgresPlanDiff`, already ownership-filtered) into
|
|
106
|
+
* `CREATE POLICY` / `DROP POLICY` / `ALTER POLICY … RENAME TO` ops. It
|
|
107
|
+
* does not re-diff — it consumes exactly the policy-node subset of the
|
|
108
|
+
* shared diff's issues. Enablement is NOT decided here: `ENABLE`/`DISABLE
|
|
109
|
+
* ROW LEVEL SECURITY` derive from the table's marker-driven `rlsEnabled`
|
|
110
|
+
* attribute diff on the relational side.
|
|
111
|
+
*
|
|
112
|
+
* Rename post-pass: a `not-found` and a `not-expected` policy on the SAME
|
|
113
|
+
* table whose wire-name content hashes match but prefixes differ are one
|
|
114
|
+
* prefix-only rename, collapsed into a single non-destructive
|
|
115
|
+
* `RenamePostgresRlsPolicyCall`. Multi-candidate hash groups pair
|
|
116
|
+
* deterministically by sorted wire name; leftovers proceed as
|
|
117
|
+
* create/drop. Unparseable wire names never pair.
|
|
118
|
+
*
|
|
119
|
+
* The pairing runs only when the policy allows `widening` (rename's
|
|
120
|
+
* class). Without it (db-init's additive-only set), pairing degrades
|
|
121
|
+
* deliberately to the additive half: the new name is CREATEd and the old
|
|
122
|
+
* policy survives live until a widening/destructive-allowed plan runs —
|
|
123
|
+
* emitting an ungated widening rename would only fail at the runner's
|
|
124
|
+
* class re-enforcement.
|
|
108
125
|
*/
|
|
109
126
|
private planPostgresSchemaDiff;
|
|
110
127
|
private ensureAdditivePolicy;
|
package/dist/planner.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner.d.mts","names":[],"sources":["../src/core/migrations/contract-to-postgres-database-schema-node.ts","../src/core/migrations/planner.ts"],"mappings":";;;;;;;;;;;;;;;;;AAiDA;;;;;;;;;;;;;iBAAgB,oCAAA,CACd,QAAA,EAAU,gBAAA,SACV,OAAA,EAAS,yBAAA,GACR,0BAAA;;;
|
|
1
|
+
{"version":3,"file":"planner.d.mts","names":[],"sources":["../src/core/migrations/contract-to-postgres-database-schema-node.ts","../src/core/migrations/planner.ts"],"mappings":";;;;;;;;;;;;;;;;;AAiDA;;;;;;;;;;;;;iBAAgB,oCAAA,CACd,QAAA,EAAU,gBAAA,SACV,OAAA,EAAS,yBAAA,GACR,0BAAA;;;iBCiBa,8BAAA,CACd,OAAA,EAAS,qBAAA,GACR,wBAAwB;;;;ADtB3B;;;;KCiCY,kBAAA;EAAA,SAEG,IAAA;EAAA,SACA,IAAA,EAAM,qCAAA;EAAA,SACN,QAAA,YAAoB,kBAAA;AAAA,IAE/B,uBAAA;;;;;;ADpCyB;;;;ACiB7B;;;;;;;;AAE2B;cAqCd,wBAAA,YAAoC,gBAAA;EAAA;cAGnC,OAAA,GAAU,qBAAA;EAItB,IAAA,CAAK,OAAA;IAAA,SACM,QAAA;IAAA,SACA,MAAA;IAAA,SACA,MAAA,EAAQ,wBAAA;IA9BM;;;;;;;;AAAA;AAoB3B;;;;;IApB2B,SA6Cd,YAAA,EAAc,QAAA;IAAA,SACd,UAAA;IAAA,SACA,mBAAA,EAAqB,aAAA,CAAc,8BAAA;IAWvB;;;;;IAAA,SALZ,OAAA;IAjCoD;;;;IAAA,SAsCpD,SAAA,GAAY,eAAA;EAAA,IACnB,kBAAA;EAIJ,cAAA,CACE,OAAA,EAAS,wBAAA,EACT,OAAA,WACC,iCAAA;EAAA,QAYK,OAAA;EAjDG;;;;;;;;;;;;;;;;;;;;;;;EAAA,QAkPH,sBAAA;EAAA,QAiHA,oBAAA;AAAA"}
|
package/dist/planner.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { r as contractToPostgresDatabaseSchemaNode } from "./diff-database-schema-
|
|
2
|
-
import { t as createPostgresMigrationPlanner } from "./planner-
|
|
1
|
+
import { r as contractToPostgresDatabaseSchemaNode } from "./diff-database-schema-CWb-jeLy.mjs";
|
|
2
|
+
import { t as createPostgresMigrationPlanner } from "./planner-BryLk0Ie.mjs";
|
|
3
3
|
export { contractToPostgresDatabaseSchemaNode, createPostgresMigrationPlanner };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { p as PG_INT_CODEC_ID, v as PG_TEXT_CODEC_ID } from "./codec-ids-C_-Hj6bL.mjs";
|
|
2
|
-
import { a as nativeEnumEntityKind, o as policyEntityKind, s as
|
|
3
|
-
import { t as postgresAuthoringEntityTypes } from "./authoring-
|
|
2
|
+
import { a as nativeEnumEntityKind, c as roleEntityKind, o as policyEntityKind, s as rlsEnablementEntityKind, t as PostgresSchema } from "./postgres-schema-DTLA_aRi.mjs";
|
|
3
|
+
import { t as postgresAuthoringEntityTypes } from "./authoring-WkqG_MkU.mjs";
|
|
4
4
|
import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
|
|
5
5
|
import { blindCast } from "@prisma-next/utils/casts";
|
|
6
6
|
import { buildSqlSchemaQualifiedView } from "@prisma-next/sql-contract/contract-view";
|
|
@@ -47,6 +47,7 @@ var PostgresContractSerializer = class extends SqlContractSerializerBase {
|
|
|
47
47
|
super(storageTypesHydrators, [
|
|
48
48
|
policyEntityKind,
|
|
49
49
|
roleEntityKind,
|
|
50
|
+
rlsEnablementEntityKind,
|
|
50
51
|
nativeEnumEntityKind,
|
|
51
52
|
...extraPackEntityKinds
|
|
52
53
|
]);
|
|
@@ -107,4 +108,4 @@ const PostgresContractView = {
|
|
|
107
108
|
//#endregion
|
|
108
109
|
export { PostgresContractSerializer as n, PostgresContractView as t };
|
|
109
110
|
|
|
110
|
-
//# sourceMappingURL=postgres-contract-view-
|
|
111
|
+
//# sourceMappingURL=postgres-contract-view-Dg-N7KA7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-contract-view-Dg-N7KA7.mjs","names":[],"sources":["../src/core/postgres-contract-serializer.ts","../src/core/postgres-contract-view.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n SqlContractSerializerBase,\n type SqlEntityHydrationFactory,\n} from '@prisma-next/family-sql/ir';\nimport {\n type AuthoringEntityContext,\n type AuthoringEntityTypeFactoryOutput,\n type AuthoringEntityTypeNamespace,\n isAuthoringEntityTypeDescriptor,\n} from '@prisma-next/framework-components/authoring';\nimport {\n type AnyEntityKindDescriptor,\n type Namespace,\n UNBOUND_NAMESPACE_ID,\n} from '@prisma-next/framework-components/ir';\nimport type { SqlNamespaceInput, SqlStorage } from '@prisma-next/sql-contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { JsonObject } from '@prisma-next/utils/json';\nimport { postgresAuthoringEntityTypes } from './authoring';\nimport { PG_INT_CODEC_ID, PG_TEXT_CODEC_ID } from './codec-ids';\nimport {\n nativeEnumEntityKind,\n policyEntityKind,\n rlsEnablementEntityKind,\n roleEntityKind,\n} from './entity-kinds';\nimport { PostgresSchema } from './postgres-schema';\n\nconst POSTGRES_AUTHORING_CTX: AuthoringEntityContext = {\n family: 'sql',\n target: 'postgres',\n enumInferenceCodecs: { text: PG_TEXT_CODEC_ID, int: PG_INT_CODEC_ID },\n};\n\nfunction isAuthoringEntityTypeFactoryOutput(\n output: unknown,\n): output is AuthoringEntityTypeFactoryOutput<unknown, unknown> {\n return (\n typeof output === 'object' &&\n output !== null &&\n 'factory' in output &&\n typeof output.factory === 'function'\n );\n}\n\n/**\n * Walks a pack's entity-type namespace tree and emits hydration factories\n * keyed by the descriptor's `discriminator`. Used for `storage.types`\n * (codec-triple hydration). Namespace entries hydration dispatches by\n * entries key, not discriminator — handled by `hydrateNamespaceEntities`.\n */\nfunction collectStorageTypesHydrators(\n namespace: AuthoringEntityTypeNamespace,\n): ReadonlyMap<string, SqlEntityHydrationFactory> {\n const registry = new Map<string, SqlEntityHydrationFactory>();\n const walk = (node: AuthoringEntityTypeNamespace): void => {\n for (const value of Object.values(node)) {\n if (isAuthoringEntityTypeDescriptor(value)) {\n if (isAuthoringEntityTypeFactoryOutput(value.output)) {\n const { factory } = value.output;\n registry.set(value.discriminator, (raw) => factory(raw, POSTGRES_AUTHORING_CTX));\n }\n continue;\n }\n if (typeof value === 'object' && value !== null) {\n walk(value);\n }\n }\n };\n walk(namespace);\n return registry;\n}\n\nexport class PostgresContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {\n constructor(extraPackEntityKinds: readonly AnyEntityKindDescriptor[] = []) {\n const storageTypesHydrators = collectStorageTypesHydrators(postgresAuthoringEntityTypes);\n super(storageTypesHydrators, [\n policyEntityKind,\n roleEntityKind,\n rlsEnablementEntityKind,\n nativeEnumEntityKind,\n ...extraPackEntityKinds,\n ]);\n }\n\n protected override hydrateSqlNamespaceEntry(\n nsId: string,\n raw: Record<string, unknown>,\n ): Namespace | SqlNamespaceInput {\n const hydrated = blindCast<\n SqlNamespaceInput,\n 'raw is always plain JSON, so super.hydrateSqlNamespaceEntry returns SqlNamespaceInput'\n >(super.hydrateSqlNamespaceEntry(nsId, raw));\n const { id, entries } = hydrated;\n\n const allSlotsEmpty = Object.values(entries).every(\n (slot) => slot === undefined || Object.keys(slot).length === 0,\n );\n if (id === UNBOUND_NAMESPACE_ID && allSlotsEmpty) {\n return PostgresSchema.unbound;\n }\n const valueSetSlot = entries['valueSet'];\n const hasValueSets = valueSetSlot !== undefined && Object.keys(valueSetSlot).length > 0;\n return new PostgresSchema({\n id,\n entries: {\n ...entries,\n table: entries['table'] ?? {},\n ...(hasValueSets ? { valueSet: valueSetSlot } : {}),\n },\n });\n }\n\n override serializeContract(contract: Contract<SqlStorage>): JsonObject {\n const { storage, ...rest } = contract;\n const namespacesJson: Record<string, JsonObject> = {};\n // Each namespace serializes to its id, its schema-kind tag, and the\n // base's generic entries walk — every enumerable kind on\n // `PostgresSchema.entries`, including `native_enum`.\n for (const [nsId, ns] of Object.entries(storage.namespaces)) {\n const isUnboundSlot = ns.id === UNBOUND_NAMESPACE_ID;\n namespacesJson[nsId] = {\n id: ns.id,\n kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',\n entries: this.serializeNamespaceEntries(ns.entries),\n };\n }\n const storageOut: Record<string, unknown> = {\n storageHash: String(storage.storageHash),\n namespaces: namespacesJson,\n };\n if (storage.types !== undefined) {\n const typesOut: Record<string, JsonObject> = {};\n for (const [name, entry] of Object.entries(storage.types)) {\n typesOut[name] = this.serializeJsonObject(entry);\n }\n storageOut['types'] = typesOut;\n }\n return blindCast<\n JsonObject,\n 'contract minus storage plus a JSON-shaped storageOut is a JsonObject'\n >({\n ...rest,\n storage: storageOut,\n });\n }\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport {\n buildSqlSchemaQualifiedView,\n type SqlSchemaQualifiedView,\n} from '@prisma-next/sql-contract/contract-view';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { PostgresContractSerializer } from './postgres-contract-serializer';\n\n/**\n * A schema-qualified Postgres contract view: the deserialized contract\n * intersected with a single `namespace` member holding every schema by id. It is\n * substitutable for `Contract` (carries `storage`, `domain`, …) and reaches each\n * schema's entities through `view.namespace.<schema>`:\n *\n * ```ts\n * const view = PostgresContractView.fromJson<Contract>(contractJson);\n * view.namespace.public.table.users // typed table leaf in the public schema\n * view.namespace.auth.table.users // the auth schema's own users table\n * view.namespace.public.entries.policy.X // pack-contributed kind (RLS / #771 path)\n * view.namespace.__unbound__.table.X // default schema, keyed by its raw id\n * view.storage // the full contract is still present\n * ```\n *\n * This mirrors the runtime `db.enums.<ns>` keying exactly (the default schema\n * keeps its literal `__unbound__` id). Schema names are NOT promoted to the\n * contract root, so there is no collision with contract envelope fields — a\n * schema named `storage` is `view.namespace.storage`, while `view.storage`\n * stays the contract's `storage`.\n */\nexport type PostgresContractView<TContract extends Contract<SqlStorage> = Contract<SqlStorage>> =\n SqlSchemaQualifiedView<TContract>;\n\nexport const PostgresContractView = {\n /** Wrap an already-deserialized Postgres contract in a schema-qualified view. */\n from<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n ): PostgresContractView<TContract> {\n return buildSqlSchemaQualifiedView(contract);\n },\n\n /** Deserialize a Postgres contract JSON envelope and wrap it in a view. */\n fromJson<TContract extends Contract<SqlStorage> = Contract<SqlStorage>>(\n json: unknown,\n ): PostgresContractView<TContract> {\n const contract = new PostgresContractSerializer().deserializeContract<TContract>(json);\n return buildSqlSchemaQualifiedView(contract);\n },\n};\n"],"mappings":";;;;;;;;;AA6BA,MAAM,yBAAiD;CACrD,QAAQ;CACR,QAAQ;CACR,qBAAqB;EAAE,MAAM;EAAkB,KAAK;CAAgB;AACtE;AAEA,SAAS,mCACP,QAC8D;CAC9D,OACE,OAAO,WAAW,YAClB,WAAW,QACX,aAAa,UACb,OAAO,OAAO,YAAY;AAE9B;;;;;;;AAQA,SAAS,6BACP,WACgD;CAChD,MAAM,2BAAW,IAAI,IAAuC;CAC5D,MAAM,QAAQ,SAA6C;EACzD,KAAK,MAAM,SAAS,OAAO,OAAO,IAAI,GAAG;GACvC,IAAI,gCAAgC,KAAK,GAAG;IAC1C,IAAI,mCAAmC,MAAM,MAAM,GAAG;KACpD,MAAM,EAAE,YAAY,MAAM;KAC1B,SAAS,IAAI,MAAM,gBAAgB,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;IACjF;IACA;GACF;GACA,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,KAAK,KAAK;EAEd;CACF;CACA,KAAK,SAAS;CACd,OAAO;AACT;AAEA,IAAa,6BAAb,cAAgD,0BAAgD;CAC9F,YAAY,uBAA2D,CAAC,GAAG;EACzE,MAAM,wBAAwB,6BAA6B,4BAA4B;EACvF,MAAM,uBAAuB;GAC3B;GACA;GACA;GACA;GACA,GAAG;EACL,CAAC;CACH;CAEA,yBACE,MACA,KAC+B;EAK/B,MAAM,EAAE,IAAI,YAJK,UAGf,MAAM,yBAAyB,MAAM,GAAG,CACX;EAE/B,MAAM,gBAAgB,OAAO,OAAO,OAAO,CAAC,CAAC,OAC1C,SAAS,SAAS,KAAA,KAAa,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,CAC/D;EACA,IAAI,OAAO,wBAAwB,eACjC,OAAO,eAAe;EAExB,MAAM,eAAe,QAAQ;EAC7B,MAAM,eAAe,iBAAiB,KAAA,KAAa,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS;EACtF,OAAO,IAAI,eAAe;GACxB;GACA,SAAS;IACP,GAAG;IACH,OAAO,QAAQ,YAAY,CAAC;IAC5B,GAAI,eAAe,EAAE,UAAU,aAAa,IAAI,CAAC;GACnD;EACF,CAAC;CACH;CAEA,kBAA2B,UAA4C;EACrE,MAAM,EAAE,SAAS,GAAG,SAAS;EAC7B,MAAM,iBAA6C,CAAC;EAIpD,KAAK,MAAM,CAAC,MAAM,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAAG;GAC3D,MAAM,gBAAgB,GAAG,OAAO;GAChC,eAAe,QAAQ;IACrB,IAAI,GAAG;IACP,MAAM,gBAAgB,4BAA4B;IAClD,SAAS,KAAK,0BAA0B,GAAG,OAAO;GACpD;EACF;EACA,MAAM,aAAsC;GAC1C,aAAa,OAAO,QAAQ,WAAW;GACvC,YAAY;EACd;EACA,IAAI,QAAQ,UAAU,KAAA,GAAW;GAC/B,MAAM,WAAuC,CAAC;GAC9C,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,QAAQ,KAAK,GACtD,SAAS,QAAQ,KAAK,oBAAoB,KAAK;GAEjD,WAAW,WAAW;EACxB;EACA,OAAO,UAGL;GACA,GAAG;GACH,SAAS;EACX,CAAC;CACH;AACF;;;ACnHA,MAAa,uBAAuB;;CAElC,KACE,UACiC;EACjC,OAAO,4BAA4B,QAAQ;CAC7C;;CAGA,SACE,MACiC;EAEjC,OAAO,4BADU,IAAI,2BAA2B,CAAC,CAAC,oBAA+B,IACvC,CAAC;CAC7C;AACF"}
|
|
@@ -55,6 +55,14 @@ declare class PostgresPolicySchemaNode extends SqlSchemaIRNode implements Diffab
|
|
|
55
55
|
//#region src/core/schema-ir/postgres-table-schema-node.d.ts
|
|
56
56
|
interface PostgresTableSchemaNodeInput extends SqlTableIRInput {
|
|
57
57
|
readonly policies?: readonly PostgresPolicySchemaNode[];
|
|
58
|
+
/**
|
|
59
|
+
* Whether row-level security is enabled on this table. Expected side:
|
|
60
|
+
* stamped from the contract's `entries.rls` marker (never from the
|
|
61
|
+
* policy set). Actual side: stamped from `pg_class.relrowsecurity` at
|
|
62
|
+
* introspection. Required with no default so every construction site
|
|
63
|
+
* supplies a deliberate value.
|
|
64
|
+
*/
|
|
65
|
+
readonly rlsEnabled: boolean;
|
|
58
66
|
}
|
|
59
67
|
/**
|
|
60
68
|
* Postgres-specific table schema-diff node. Carries all `SqlTableIR` fields
|
|
@@ -65,8 +73,8 @@ interface PostgresTableSchemaNodeInput extends SqlTableIRInput {
|
|
|
65
73
|
* `SqlTableIR` calls `freezeNode` in its own constructor, which prevents
|
|
66
74
|
* subclass field initialisation.
|
|
67
75
|
*
|
|
68
|
-
* `id` is the table name. `isEqualTo`
|
|
69
|
-
*
|
|
76
|
+
* `id` is the table name. `isEqualTo` compares id + `rlsEnabled` — the
|
|
77
|
+
* table's one own diffable attribute; all other structural drift is
|
|
70
78
|
* expressed by its children. `children()` returns every column, the primary
|
|
71
79
|
* key (when present), every foreign key, unique, index, and check constraint,
|
|
72
80
|
* plus the policy nodes — one flat list, so a drifted column and a drifted
|
|
@@ -85,8 +93,15 @@ declare class PostgresTableSchemaNode extends SqlSchemaIRNode implements Diffabl
|
|
|
85
93
|
readonly annotations?: SqlAnnotations;
|
|
86
94
|
readonly checks?: ReadonlyArray<SqlCheckConstraintIR>;
|
|
87
95
|
readonly policies: readonly PostgresPolicySchemaNode[];
|
|
96
|
+
readonly rlsEnabled: boolean;
|
|
88
97
|
constructor(input: PostgresTableSchemaNodeInput);
|
|
89
98
|
get id(): string;
|
|
99
|
+
/**
|
|
100
|
+
* Equal iff the ids (names) match AND `rlsEnabled` matches — the table's
|
|
101
|
+
* one own attribute in the diff; all other structural drift is expressed
|
|
102
|
+
* by children. A paired `not-equal` therefore always means enablement
|
|
103
|
+
* drift, which the planner maps to ENABLE/DISABLE ROW LEVEL SECURITY.
|
|
104
|
+
*/
|
|
90
105
|
isEqualTo(other: DiffableNode): boolean;
|
|
91
106
|
children(): readonly DiffableNode[];
|
|
92
107
|
static is(node: SqlSchemaIRNode): node is PostgresTableSchemaNode;
|
|
@@ -200,4 +215,4 @@ declare class PostgresDatabaseSchemaNode extends SqlSchemaIRNode implements Diff
|
|
|
200
215
|
}
|
|
201
216
|
//#endregion
|
|
202
217
|
export { PostgresNamespaceSchemaNode as a, PostgresTableSchemaNode as c, PostgresPolicySchemaNodeInput as d, PostgresRoleSchemaNodeInput as i, PostgresTableSchemaNodeInput as l, PostgresDatabaseSchemaNodeInput as n, PostgresNamespaceSchemaNodeInput as o, PostgresRoleSchemaNode as r, PostgresNativeEnumIntrospection as s, PostgresDatabaseSchemaNode as t, PostgresPolicySchemaNode as u };
|
|
203
|
-
//# sourceMappingURL=postgres-database-schema-node-
|
|
218
|
+
//# sourceMappingURL=postgres-database-schema-node-CfdTY-Qs.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-database-schema-node-CfdTY-Qs.d.mts","names":[],"sources":["../src/core/schema-ir/postgres-policy-schema-node.ts","../src/core/schema-ir/postgres-table-schema-node.ts","../src/core/schema-ir/postgres-namespace-schema-node.ts","../src/core/schema-ir/postgres-role-schema-node.ts","../src/core/schema-ir/postgres-database-schema-node.ts"],"mappings":"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"}
|