@prisma-next/target-postgres 0.12.0-dev.27 → 0.12.0-dev.28
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/control.mjs +1 -1
- package/dist/{data-transform-4QL41_vQ.mjs → data-transform-DIYwbe4S.mjs} +1 -1
- package/dist/{data-transform-4QL41_vQ.mjs.map → data-transform-DIYwbe4S.mjs.map} +1 -1
- package/dist/data-transform.mjs +1 -1
- package/dist/{errors-BhiZYTWZ.mjs → errors-De185dnO.mjs} +1 -1
- package/dist/{errors-BhiZYTWZ.mjs.map → errors-De185dnO.mjs.map} +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/{issue-planner-BrqTKeZa.mjs → issue-planner-ttX4mOiF.mjs} +16 -103
- package/dist/issue-planner-ttX4mOiF.mjs.map +1 -0
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.mjs +2 -2
- package/dist/{planner-produced-postgres-migration-x3hafaGC.mjs → planner-produced-postgres-migration-D6KXC2DH.mjs} +4 -4
- package/dist/{planner-produced-postgres-migration-x3hafaGC.mjs.map → planner-produced-postgres-migration-D6KXC2DH.mjs.map} +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/{planner-schema-lookup-DLJbkU7-.mjs → planner-schema-lookup-Bm4S3LvB.mjs} +1 -1
- package/dist/{planner-schema-lookup-DLJbkU7-.mjs.map → planner-schema-lookup-Bm4S3LvB.mjs.map} +1 -1
- package/dist/planner-schema-lookup.mjs +1 -1
- package/dist/planner-y-bVvDFR.mjs +342 -0
- package/dist/planner-y-bVvDFR.mjs.map +1 -0
- package/dist/planner.d.mts +2 -1
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/{postgres-migration-BDaWGYDu.mjs → postgres-migration-BnDg_Nj0.mjs} +3 -3
- package/dist/{postgres-migration-BDaWGYDu.mjs.map → postgres-migration-BnDg_Nj0.mjs.map} +1 -1
- package/dist/{render-ops-Da7bQcyv.mjs → render-ops-BpU-Qv06.mjs} +1 -1
- package/dist/{render-ops-Da7bQcyv.mjs.map → render-ops-BpU-Qv06.mjs.map} +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/{render-typescript-DTpTcoNZ.mjs → render-typescript-D9O7aOS_.mjs} +1 -1
- package/dist/{render-typescript-DTpTcoNZ.mjs.map → render-typescript-D9O7aOS_.mjs.map} +1 -1
- package/dist/render-typescript.mjs +1 -1
- package/package.json +17 -17
- package/src/core/migrations/control-policy.ts +91 -0
- package/src/core/migrations/issue-planner.ts +1 -12
- package/src/core/migrations/planner.ts +38 -5
- package/dist/issue-planner-BrqTKeZa.mjs.map +0 -1
- package/dist/planner-C_fLowcn.mjs +0 -184
- package/dist/planner-C_fLowcn.mjs.map +0 -1
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { t as postgresColumnsCompatible } from "./column-type-compatibility-Dzxz_CkP.mjs";
|
|
2
|
-
import { r as isPostgresSchema } from "./postgres-schema-Dky_Jff8.mjs";
|
|
3
|
-
import { t as createResolveExistingEnumValues } from "./enum-planning-DHQE3zSH.mjs";
|
|
4
|
-
import { t as parsePostgresDefault } from "./default-normalizer-DFHtpCPH.mjs";
|
|
5
|
-
import { t as normalizeSchemaNativeType } from "./native-type-normalizer-BUUe8USD.mjs";
|
|
6
|
-
import { n as postgresPlannerStrategies, r as resolvePostgresCallControlPolicySubject, t as planIssues } from "./issue-planner-BrqTKeZa.mjs";
|
|
7
|
-
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-x3hafaGC.mjs";
|
|
8
|
-
import { extractCodecControlHooks, filterCallsByControlPolicy, planFieldEventOperations, plannerFailure } from "@prisma-next/family-sql/control";
|
|
9
|
-
import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
|
|
10
|
-
import { verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
|
|
11
|
-
import { blindCast } from "@prisma-next/utils/casts";
|
|
12
|
-
//#region src/core/migrations/verify-postgres-namespaces.ts
|
|
13
|
-
/**
|
|
14
|
-
* Resolves the live-database schema name for a given namespace
|
|
15
|
-
* coordinate. Mirrors `resolveDdlSchemaForNamespace` in
|
|
16
|
-
* `planner-strategies.ts` so the verifier's projection and the
|
|
17
|
-
* planner's projection always agree — Postgres-aware namespaces (the
|
|
18
|
-
* production path) dispatch to `ddlSchemaName(storage)`, and bare
|
|
19
|
-
* object payloads (used by some tests) fall back to the coordinate
|
|
20
|
-
* itself.
|
|
21
|
-
*/
|
|
22
|
-
function resolveDdlSchemaName(storage, namespaceId) {
|
|
23
|
-
const namespace = storage.namespaces[namespaceId];
|
|
24
|
-
if (isPostgresSchema(namespace)) return namespace.ddlSchemaName(storage);
|
|
25
|
-
return namespaceId;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Reads the introspected list of schema names from the Postgres-flavoured
|
|
29
|
-
* annotations slot on the schema IR. Defaults to the always-present
|
|
30
|
-
* `public` schema when introspection did not populate the slot — a fresh
|
|
31
|
-
* Postgres database always carries `public` (unless an operator dropped
|
|
32
|
-
* it manually), so any verifier path that runs without an enriched
|
|
33
|
-
* introspection still suppresses the redundant `CREATE SCHEMA "public"`.
|
|
34
|
-
*
|
|
35
|
-
* Production introspection (`PostgresControlAdapter.introspect`) is the
|
|
36
|
-
* authoritative source: it queries `pg_namespace` and writes every
|
|
37
|
-
* non-system schema into `annotations.pg.existingSchemas`. Tests that
|
|
38
|
-
* want to assert against a richer initial state pass the slot
|
|
39
|
-
* explicitly via the schema IR.
|
|
40
|
-
*/
|
|
41
|
-
function existingSchemasFromSchema(schema) {
|
|
42
|
-
const slot = schema.annotations?.pg?.existingSchemas;
|
|
43
|
-
if (Array.isArray(slot)) return slot.filter((s) => typeof s === "string");
|
|
44
|
-
return ["public"];
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Emits a `missing_schema` issue for every contract-declared Postgres
|
|
48
|
-
* namespace whose live container does not yet exist.
|
|
49
|
-
*
|
|
50
|
-
* A namespace's live container is the schema returned by its
|
|
51
|
-
* polymorphic `ddlSchemaName(storage)` method — named schemas resolve
|
|
52
|
-
* to their own id; the unbound singleton returns `UNBOUND_NAMESPACE_ID`
|
|
53
|
-
* and is skipped explicitly (late-bound namespaces have no fixed DDL
|
|
54
|
-
* schema). Issues are emitted only when the resolved name is a real,
|
|
55
|
-
* creatable schema (not the unbound sentinel) and is missing from the
|
|
56
|
-
* introspected list. `public` is suppressed implicitly because the
|
|
57
|
-
* introspection (or its sensible default) always carries it.
|
|
58
|
-
*
|
|
59
|
-
* Each emitted issue stamps `namespaceId` with the contract namespace
|
|
60
|
-
* coordinate so the downstream `mapIssueToCall` re-resolves the DDL
|
|
61
|
-
* schema name through the same polymorphic path — keeping the
|
|
62
|
-
* coordinate, not the resolved name, as the issue's stable identity.
|
|
63
|
-
*/
|
|
64
|
-
function verifyPostgresNamespacePresence(input) {
|
|
65
|
-
const { contract, schema } = input;
|
|
66
|
-
const existing = new Set(existingSchemasFromSchema(schema));
|
|
67
|
-
const issues = [];
|
|
68
|
-
const namespaceIds = Object.keys(contract.storage.namespaces).sort();
|
|
69
|
-
for (const namespaceId of namespaceIds) {
|
|
70
|
-
if (namespaceId === UNBOUND_NAMESPACE_ID) continue;
|
|
71
|
-
const ddlName = resolveDdlSchemaName(contract.storage, namespaceId);
|
|
72
|
-
if (ddlName === UNBOUND_NAMESPACE_ID) continue;
|
|
73
|
-
if (existing.has(ddlName)) continue;
|
|
74
|
-
issues.push({
|
|
75
|
-
kind: "missing_schema",
|
|
76
|
-
namespaceId,
|
|
77
|
-
message: `Schema "${ddlName}" is missing from database`
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
return issues;
|
|
81
|
-
}
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region src/core/migrations/planner.ts
|
|
84
|
-
function createPostgresMigrationPlanner() {
|
|
85
|
-
return new PostgresMigrationPlanner();
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Postgres migration planner — a thin wrapper over `planIssues`.
|
|
89
|
-
*
|
|
90
|
-
* `plan()` verifies the live schema against the target contract (producing
|
|
91
|
-
* `SchemaIssue[]`) and delegates to `planIssues` with the unified
|
|
92
|
-
* `postgresPlannerStrategies` list: enum-change, NOT-NULL backfill,
|
|
93
|
-
* type-change, nullable-tightening, codec-hook storage types,
|
|
94
|
-
* component-declared dependency installs, and shared-temp-default /
|
|
95
|
-
* empty-table-guarded NOT-NULL add-column. The same strategy list runs for
|
|
96
|
-
* `migration plan`, `db update`, and `db init`; behavior diverges purely on
|
|
97
|
-
* `policy.allowedOperationClasses` (the data-safe strategies short-circuit
|
|
98
|
-
* when `'data'` is excluded). The issue planner applies operation-class
|
|
99
|
-
* policy gates and emits a single `PostgresOpFactoryCall[]` that drives both
|
|
100
|
-
* the runtime-ops view (via `renderOps`) and the `renderTypeScript()`
|
|
101
|
-
* authoring surface.
|
|
102
|
-
*/
|
|
103
|
-
var PostgresMigrationPlanner = class {
|
|
104
|
-
plan(options) {
|
|
105
|
-
return this.planSql(options);
|
|
106
|
-
}
|
|
107
|
-
emptyMigration(context, spaceId) {
|
|
108
|
-
return new TypeScriptRenderablePostgresMigration([], {
|
|
109
|
-
from: context.fromHash,
|
|
110
|
-
to: context.toHash
|
|
111
|
-
}, spaceId);
|
|
112
|
-
}
|
|
113
|
-
planSql(options) {
|
|
114
|
-
const schemaName = options.schemaName ?? Object.keys(options.contract.storage.namespaces).find((id) => id !== UNBOUND_NAMESPACE_ID) ?? UNBOUND_NAMESPACE_ID;
|
|
115
|
-
const policyResult = this.ensureAdditivePolicy(options.policy);
|
|
116
|
-
if (policyResult) return policyResult;
|
|
117
|
-
const schemaIssues = this.collectSchemaIssues(options);
|
|
118
|
-
const codecHooks = extractCodecControlHooks(options.frameworkComponents);
|
|
119
|
-
const storageTypes = options.contract.storage.types ?? {};
|
|
120
|
-
const result = planIssues({
|
|
121
|
-
issues: schemaIssues,
|
|
122
|
-
toContract: options.contract,
|
|
123
|
-
fromContract: options.fromContract,
|
|
124
|
-
schemaName,
|
|
125
|
-
codecHooks,
|
|
126
|
-
storageTypes,
|
|
127
|
-
schema: options.schema,
|
|
128
|
-
policy: options.policy,
|
|
129
|
-
frameworkComponents: options.frameworkComponents,
|
|
130
|
-
strategies: postgresPlannerStrategies
|
|
131
|
-
});
|
|
132
|
-
if (!result.ok) return plannerFailure(result.failure);
|
|
133
|
-
const filteredFieldEvents = filterCallsByControlPolicy({
|
|
134
|
-
calls: blindCast(planFieldEventOperations({
|
|
135
|
-
priorContract: options.fromContract,
|
|
136
|
-
newContract: options.contract,
|
|
137
|
-
codecHooks
|
|
138
|
-
})),
|
|
139
|
-
contract: options.contract,
|
|
140
|
-
resolveControlPolicySubject: (call) => resolvePostgresCallControlPolicySubject(call, options.contract)
|
|
141
|
-
});
|
|
142
|
-
const calls = [...result.value.calls, ...filteredFieldEvents];
|
|
143
|
-
return Object.freeze({
|
|
144
|
-
kind: "success",
|
|
145
|
-
plan: new TypeScriptRenderablePostgresMigration(calls, {
|
|
146
|
-
from: options.fromContract?.storage.storageHash ?? null,
|
|
147
|
-
to: options.contract.storage.storageHash
|
|
148
|
-
}, options.spaceId)
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
ensureAdditivePolicy(policy) {
|
|
152
|
-
if (!policy.allowedOperationClasses.includes("additive")) return plannerFailure([{
|
|
153
|
-
kind: "unsupportedOperation",
|
|
154
|
-
summary: "Migration planner requires additive operations be allowed",
|
|
155
|
-
why: "The planner requires the \"additive\" operation class to be allowed in the policy."
|
|
156
|
-
}]);
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
collectSchemaIssues(options) {
|
|
160
|
-
const allowed = options.policy.allowedOperationClasses;
|
|
161
|
-
const strict = allowed.includes("widening") || allowed.includes("destructive");
|
|
162
|
-
const verifyResult = verifySqlSchema({
|
|
163
|
-
contract: options.contract,
|
|
164
|
-
schema: options.schema,
|
|
165
|
-
strict,
|
|
166
|
-
typeMetadataRegistry: /* @__PURE__ */ new Map(),
|
|
167
|
-
frameworkComponents: options.frameworkComponents,
|
|
168
|
-
normalizeDefault: parsePostgresDefault,
|
|
169
|
-
normalizeNativeType: normalizeSchemaNativeType,
|
|
170
|
-
columnsCompatible: postgresColumnsCompatible,
|
|
171
|
-
resolveExistingEnumValues: createResolveExistingEnumValues(options.contract.storage)
|
|
172
|
-
});
|
|
173
|
-
const namespaceIssues = verifyPostgresNamespacePresence({
|
|
174
|
-
contract: options.contract,
|
|
175
|
-
schema: options.schema
|
|
176
|
-
});
|
|
177
|
-
if (namespaceIssues.length === 0) return verifyResult.schema.issues;
|
|
178
|
-
return [...namespaceIssues, ...verifyResult.schema.issues];
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
//#endregion
|
|
182
|
-
export { createPostgresMigrationPlanner as t };
|
|
183
|
-
|
|
184
|
-
//# sourceMappingURL=planner-C_fLowcn.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"planner-C_fLowcn.mjs","names":[],"sources":["../src/core/migrations/verify-postgres-namespaces.ts","../src/core/migrations/planner.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport type { SchemaIssue } 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 { isPostgresSchema } from '../postgres-schema';\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 Postgres-flavoured\n * annotations slot on the schema IR. Defaults to the always-present\n * `public` schema when introspection did not populate the slot — a fresh\n * Postgres database always carries `public` (unless an operator dropped\n * it manually), so any verifier path that runs without an enriched\n * introspection still suppresses the redundant `CREATE SCHEMA \"public\"`.\n *\n * Production introspection (`PostgresControlAdapter.introspect`) is the\n * authoritative source: it queries `pg_namespace` and writes every\n * non-system schema into `annotations.pg.existingSchemas`. Tests that\n * want to assert against a richer initial state pass the slot\n * explicitly via the schema IR.\n */\nfunction existingSchemasFromSchema(schema: SqlSchemaIR): readonly string[] {\n const annotations = (schema as { annotations?: { pg?: { existingSchemas?: unknown } } })\n .annotations;\n const slot = annotations?.pg?.existingSchemas;\n if (Array.isArray(slot)) {\n return slot.filter((s): s is string => typeof s === 'string');\n }\n return ['public'];\n}\n\n/**\n * Emits a `missing_schema` issue for every contract-declared Postgres\n * namespace whose live container does not yet exist.\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 stamps `namespaceId` with the contract namespace\n * coordinate so the downstream `mapIssueToCall` re-resolves the DDL\n * schema name through the same polymorphic path — keeping the\n * coordinate, not the resolved name, as the issue's stable identity.\n */\nexport function verifyPostgresNamespacePresence(input: {\n readonly contract: Contract<SqlStorage>;\n readonly schema: SqlSchemaIR;\n}): readonly SchemaIssue[] {\n const { contract, schema } = input;\n const existing = new Set(existingSchemasFromSchema(schema));\n const issues: SchemaIssue[] = [];\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 issues.push({\n kind: 'missing_schema',\n namespaceId,\n message: `Schema \"${ddlName}\" is missing from database`,\n });\n }\n return issues;\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlMigrationPlannerPlanOptions,\n SqlPlannerFailureResult,\n} from '@prisma-next/family-sql/control';\nimport {\n extractCodecControlHooks,\n filterCallsByControlPolicy,\n planFieldEventOperations,\n plannerFailure,\n} from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n MigrationPlanner,\n MigrationPlanWithAuthoringSurface,\n MigrationScaffoldContext,\n SchemaIssue,\n} from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { postgresColumnsCompatible } from '../column-type-compatibility';\nimport { parsePostgresDefault } from '../default-normalizer';\nimport { normalizeSchemaNativeType } from '../native-type-normalizer';\nimport { resolvePostgresCallControlPolicySubject } from './control-policy';\nimport { createResolveExistingEnumValues } from './enum-planning';\nimport { planIssues } from './issue-planner';\nimport type { PostgresOpFactoryCall } from './op-factory-call';\nimport { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';\nimport { postgresPlannerStrategies } from './planner-strategies';\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\ntype VerifySqlSchemaOptionsWithComponents = Parameters<typeof verifySqlSchema>[0] & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\nexport function createPostgresMigrationPlanner(): PostgresMigrationPlanner {\n return new PostgresMigrationPlanner();\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 }\n | SqlPlannerFailureResult;\n\n/**\n * Postgres migration planner — a thin wrapper over `planIssues`.\n *\n * `plan()` verifies the live schema against the target contract (producing\n * `SchemaIssue[]`) and delegates to `planIssues` with the unified\n * `postgresPlannerStrategies` list: enum-change, NOT-NULL backfill,\n * type-change, nullable-tightening, codec-hook storage types,\n * component-declared dependency installs, and shared-temp-default /\n * empty-table-guarded NOT-NULL add-column. The same strategy list runs for\n * `migration plan`, `db update`, and `db init`; behavior diverges purely on\n * `policy.allowedOperationClasses` (the data-safe strategies short-circuit\n * when `'data'` is excluded). The issue planner applies operation-class\n * policy gates and emits a single `PostgresOpFactoryCall[]` that drives both\n * the runtime-ops view (via `renderOps`) and the `renderTypeScript()`\n * authoring surface.\n */\nexport class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {\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 }): 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 );\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 const schemaIssues = this.collectSchemaIssues(options);\n const codecHooks = extractCodecControlHooks(options.frameworkComponents);\n const storageTypes = options.contract.storage.types ?? {};\n\n const result = planIssues({\n issues: schemaIssues,\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 // `mapIssueToCall`'s direct destructive handlers.\n fromContract: options.fromContract,\n schemaName,\n codecHooks,\n storageTypes,\n schema: options.schema,\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 // 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 filteredFieldEvents = filterCallsByControlPolicy({\n calls: fieldEventPostgresCalls,\n contract: options.contract,\n resolveControlPolicySubject: (call) =>\n resolvePostgresCallControlPolicySubject(call, options.contract),\n });\n const calls = [...result.value.calls, ...filteredFieldEvents];\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 ),\n });\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 private collectSchemaIssues(options: PlannerOptionsWithComponents): readonly SchemaIssue[] {\n // `db init` uses additive-only policy and intentionally ignores extra\n // schema objects. Any reconciliation-capable policy (widening or\n // destructive) must inspect extras to reconcile strict equality.\n const allowed = options.policy.allowedOperationClasses;\n const strict = allowed.includes('widening') || allowed.includes('destructive');\n const verifyOptions: VerifySqlSchemaOptionsWithComponents = {\n contract: options.contract,\n schema: options.schema,\n strict,\n typeMetadataRegistry: new Map(),\n frameworkComponents: options.frameworkComponents,\n normalizeDefault: parsePostgresDefault,\n normalizeNativeType: normalizeSchemaNativeType,\n columnsCompatible: postgresColumnsCompatible,\n resolveExistingEnumValues: createResolveExistingEnumValues(options.contract.storage),\n };\n const verifyResult = verifySqlSchema(verifyOptions);\n // Schema presence is a Postgres-specific concern (no equivalent in\n // SQLite / Mongo), so the issue emission lives in the target layer\n // rather than in the family verifier. Stitch it in here so a single\n // `SchemaIssue[]` flows through `planIssues` and the planner emits\n // CREATE SCHEMA in the dep bucket before any CreateTableCall.\n const namespaceIssues = verifyPostgresNamespacePresence({\n contract: options.contract,\n schema: options.schema,\n });\n if (namespaceIssues.length === 0) {\n return verifyResult.schema.issues;\n }\n return [...namespaceIssues, ...verifyResult.schema.issues];\n }\n}\n"],"mappings":"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"}
|