@prisma/orm-target-sqlite 8.0.0-rc.14-dev.11 → 8.0.0-rc.14-dev.13
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/{migration-Y6M_R3GK.mjs → migration-BQaFOngL.mjs} +2 -2
- package/dist/{migration-Y6M_R3GK.mjs.map → migration-BQaFOngL.mjs.map} +1 -1
- package/dist/{migration-dc58fySD.d.mts → migration-LE8F9qcM.d.mts} +2 -2
- package/dist/{migration-dc58fySD.d.mts.map → migration-LE8F9qcM.d.mts.map} +1 -1
- package/dist/{op-factory-call-4FJxPMyx.d.mts → op-factory-call-B_WuATMN.d.mts} +15 -3
- package/dist/op-factory-call-B_WuATMN.d.mts.map +1 -0
- package/dist/{op-factory-call-Dv_ma_mw-BtLqNmZI.mjs → op-factory-call-DFDt6p_b-CN07t9pu.mjs} +114 -15
- package/dist/op-factory-call-DFDt6p_b-CN07t9pu.mjs.map +1 -0
- package/dist/{planner-Bsjn1MTX.d.mts → planner-B37W4Kaw.d.mts} +2 -2
- package/dist/{planner-Bsjn1MTX.d.mts.map → planner-B37W4Kaw.d.mts.map} +1 -1
- package/dist/{planner-produced-sqlite-migration-BQ8vBitH-DlquRDZ4.d.mts → planner-produced-sqlite-migration-C6t5lWDq-DXm-Vkhf.d.mts} +4 -4
- package/dist/planner-produced-sqlite-migration-C6t5lWDq-DXm-Vkhf.d.mts.map +1 -0
- package/dist/planner-produced-sqlite-migration-D7O3_r38.d.mts +1 -0
- package/dist/{planner-produced-sqlite-migration-D1iuFT1l-BSFCXgJD.mjs → planner-produced-sqlite-migration-v5i-Qz6p-D2ezVWv0.mjs} +3 -3
- package/dist/{planner-produced-sqlite-migration-D1iuFT1l-BSFCXgJD.mjs.map → planner-produced-sqlite-migration-v5i-Qz6p-D2ezVWv0.mjs.map} +1 -1
- package/dist/planner-rTeVmEl6-EkIM6GZa.mjs +191 -0
- package/dist/planner-rTeVmEl6-EkIM6GZa.mjs.map +1 -0
- package/dist/{sqlite-migration-Du67NG7r-CqcA5XBz.d.mts → sqlite-migration-2IEGvjRm-BQfd6NLr.d.mts} +11 -3
- package/dist/sqlite-migration-2IEGvjRm-BQfd6NLr.d.mts.map +1 -0
- package/dist/{planner-CWfPzOwZ-DVj6Tm5a.mjs → sqlite-migration-D1Zk_YEy-BRKDlY8h.mjs} +173 -165
- package/dist/sqlite-migration-D1Zk_YEy-BRKDlY8h.mjs.map +1 -0
- package/dist/target.d.mts +7 -7
- package/dist/target.mjs +7 -7
- package/dist/target__control.mjs +2 -1
- package/dist/target__control.mjs.map +1 -1
- package/dist/target__migration.d.mts +2 -2
- package/dist/target__migration.mjs +2 -2
- package/dist/target__op-factory-call.d.mts +2 -2
- package/dist/target__op-factory-call.mjs +2 -2
- package/dist/target__planner-produced-sqlite-migration.d.mts +2 -2
- package/dist/target__planner-produced-sqlite-migration.mjs +1 -1
- package/dist/target__planner.d.mts +1 -1
- package/dist/target__planner.mjs +1 -1
- package/package.json +9 -9
- package/dist/op-factory-call-4FJxPMyx.d.mts.map +0 -1
- package/dist/op-factory-call-Dv_ma_mw-BtLqNmZI.mjs.map +0 -1
- package/dist/planner-CWfPzOwZ-DVj6Tm5a.mjs.map +0 -1
- package/dist/planner-produced-sqlite-migration-BQ8vBitH-DlquRDZ4.d.mts.map +0 -1
- package/dist/planner-produced-sqlite-migration-BfFAqrKj.d.mts +0 -1
- package/dist/sqlite-migration-Du67NG7r-CqcA5XBz.d.mts.map +0 -1
- package/dist/sqlite-migration-DuQG9WLW-BqHx4fMJ.mjs +0 -94
- package/dist/sqlite-migration-DuQG9WLW-BqHx4fMJ.mjs.map +0 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { m as renameTableSteps, u as RenameTableCall } from "./op-factory-call-DFDt6p_b-CN07t9pu.mjs";
|
|
2
|
+
import { c as pairIndexReplacements, d as sqlitePlannerStrategies, i as conflictForDisallowedCall, l as planIssues, n as buildSqlitePlanDiff, o as indexNameCaseChange, r as coalesceSubtreeIssues, s as issueNode } from "./sqlite-migration-D1Zk_YEy-BRKDlY8h.mjs";
|
|
3
|
+
import { t as TypeScriptRenderableSqliteMigration } from "./planner-produced-sqlite-migration-v5i-Qz6p-D2ezVWv0.mjs";
|
|
4
|
+
import { issueOutcome } from "@prisma/orm-framework/components/control";
|
|
5
|
+
import { UNBOUND_NAMESPACE_ID } from "@prisma/orm-framework/components/ir";
|
|
6
|
+
import { RelationalSchemaNodeKind, SqlTableIR } from "@prisma/orm-family-sql/schema-ir/types";
|
|
7
|
+
import { detectTableNameCaseChanges, extractCodecControlHooks, planFieldEventOperations, plannerFailure } from "@prisma/orm-family-sql/family/control";
|
|
8
|
+
//#region ../../../3-targets/3-targets/sqlite/dist/planner-rTeVmEl6.mjs
|
|
9
|
+
function createSqliteMigrationPlanner(lowerer) {
|
|
10
|
+
return new SqliteMigrationPlanner(lowerer);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* SQLite migration planner — a thin wrapper over `planIssues`.
|
|
14
|
+
*
|
|
15
|
+
* `plan()` diffs the live schema against the target contract via the one
|
|
16
|
+
* differ (`buildSqlitePlanDiff`, producing node-typed `SchemaDiffIssue[]`)
|
|
17
|
+
* and delegates to `planIssues` with the registered strategies. Strategies
|
|
18
|
+
* absorb groups of related issues into composite recipes (e.g. recreating a
|
|
19
|
+
* table to apply type/nullability/default/constraint changes at once);
|
|
20
|
+
* anything not absorbed by a strategy flows through `mapNodeIssueToCall` in
|
|
21
|
+
* the issue planner as a one-off call.
|
|
22
|
+
*
|
|
23
|
+
* FK-backing indexes are already merged into the expected table node's
|
|
24
|
+
* `indexes` at derivation (`contractToSchemaIR`'s `convertTable`), so
|
|
25
|
+
* `mapNodeIssueToCall` handles them uniformly alongside user-declared
|
|
26
|
+
* indexes — no separate expansion step in the planner.
|
|
27
|
+
*/
|
|
28
|
+
var SqliteMigrationPlanner = class {
|
|
29
|
+
#lowerer;
|
|
30
|
+
constructor(lowerer) {
|
|
31
|
+
this.#lowerer = lowerer;
|
|
32
|
+
}
|
|
33
|
+
plan(options) {
|
|
34
|
+
return this.planSql(options);
|
|
35
|
+
}
|
|
36
|
+
emptyMigration(context, spaceId) {
|
|
37
|
+
return new TypeScriptRenderableSqliteMigration([], {
|
|
38
|
+
from: context.fromHash,
|
|
39
|
+
to: context.toHash
|
|
40
|
+
}, spaceId, context.snapshotsImportPath, void 0, this.#lowerer);
|
|
41
|
+
}
|
|
42
|
+
planSql(options) {
|
|
43
|
+
const policyResult = this.ensureAdditivePolicy(options.policy);
|
|
44
|
+
if (policyResult) return policyResult;
|
|
45
|
+
const { expected, actual, issues: diffIssues } = this.collectSchemaIssues(options);
|
|
46
|
+
const replacedIndexes = pairIndexReplacements(diffIssues, indexNameCaseChange);
|
|
47
|
+
const disallowedIndexCalls = replacedIndexes.calls.filter((call) => !options.policy.allowedOperationClasses.includes(call.operationClass));
|
|
48
|
+
if (disallowedIndexCalls.length > 0) return plannerFailure(disallowedIndexCalls.map((call) => conflictForDisallowedCall(call, options.policy.allowedOperationClasses)));
|
|
49
|
+
const issues = diffIssues.filter((issue) => !replacedIndexes.consumed.has(issue));
|
|
50
|
+
const caseChangeConflicts = detectTableNameCaseChanges({
|
|
51
|
+
issues,
|
|
52
|
+
tableOf: (issue) => {
|
|
53
|
+
const node = issueNode(issue);
|
|
54
|
+
return node instanceof SqlTableIR ? node : void 0;
|
|
55
|
+
},
|
|
56
|
+
namespaceIdOf: () => UNBOUND_NAMESPACE_ID,
|
|
57
|
+
renameByHandStatements: (rename) => renameTableSteps(rename.from, rename.to).map((renameStep) => renameStep.sql),
|
|
58
|
+
renameTableCall: (rename) => new RenameTableCall(rename.from, rename.to).renderTypeScript(),
|
|
59
|
+
contract: options.contract,
|
|
60
|
+
defaultNamespaceId: UNBOUND_NAMESPACE_ID
|
|
61
|
+
});
|
|
62
|
+
if (caseChangeConflicts.length > 0) return plannerFailure(caseChangeConflicts);
|
|
63
|
+
const codecHooks = extractCodecControlHooks(options.frameworkComponents);
|
|
64
|
+
const result = planIssues({
|
|
65
|
+
issues,
|
|
66
|
+
expected,
|
|
67
|
+
actual,
|
|
68
|
+
policy: options.policy,
|
|
69
|
+
frameworkComponents: options.frameworkComponents,
|
|
70
|
+
strategies: sqlitePlannerStrategies
|
|
71
|
+
});
|
|
72
|
+
if (!result.ok) return plannerFailure(result.failure);
|
|
73
|
+
const fieldEventOps = planFieldEventOperations({
|
|
74
|
+
priorContract: options.fromContract,
|
|
75
|
+
newContract: options.contract,
|
|
76
|
+
codecHooks
|
|
77
|
+
});
|
|
78
|
+
const calls = [
|
|
79
|
+
...replacedIndexes.calls,
|
|
80
|
+
...result.value.calls,
|
|
81
|
+
...fieldEventOps
|
|
82
|
+
];
|
|
83
|
+
const destination = {
|
|
84
|
+
storageHash: options.contract.storage.storageHash,
|
|
85
|
+
...options.contract.profileHash !== void 0 ? { profileHash: options.contract.profileHash } : {}
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
kind: "success",
|
|
89
|
+
plan: new TypeScriptRenderableSqliteMigration(calls, {
|
|
90
|
+
from: options.fromContract?.storage.storageHash ?? null,
|
|
91
|
+
to: options.contract.storage.storageHash
|
|
92
|
+
}, options.spaceId, options.snapshotsImportPath, destination, this.#lowerer)
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
ensureAdditivePolicy(policy) {
|
|
96
|
+
if (!policy.allowedOperationClasses.includes("additive")) return plannerFailure([{
|
|
97
|
+
kind: "unsupportedOperation",
|
|
98
|
+
summary: "Migration planner requires additive operations be allowed",
|
|
99
|
+
why: "The planner requires the \"additive\" operation class to be allowed in the policy."
|
|
100
|
+
}]);
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Diffs the target contract against the live schema via the one differ
|
|
105
|
+
* (the same tree-building `diffSqliteSchema` uses, plus the
|
|
106
|
+
* op-render stamper) and prepares the issue list `planIssues` consumes.
|
|
107
|
+
*
|
|
108
|
+
* Three passes, in order:
|
|
109
|
+
* 1. Subtree coalescing — the differ is total (a missing/extra table also
|
|
110
|
+
* emits an issue for every column/constraint under it); those nested
|
|
111
|
+
* issues are redundant once the table-level `CreateTable`/`DropTable`
|
|
112
|
+
* call already accounts for the whole subtree. Runs FIRST, over the
|
|
113
|
+
* complete diff: a sibling-owned extra table's column issues must
|
|
114
|
+
* collapse into its one table-level issue before the ownership pass,
|
|
115
|
+
* because a bare column node carries no table reference — if coalescing
|
|
116
|
+
* ran after ownership dropped the table-level issue, the orphaned column
|
|
117
|
+
* issues would survive and the planner would emit drops against a
|
|
118
|
+
* sibling space's table.
|
|
119
|
+
* 2. Ownership — a live extra is only this plan's to drop when no contract
|
|
120
|
+
* space owns it. The differ ran against THIS space's contract, so a
|
|
121
|
+
* table a sibling owns surfaces here as `not-expected`; the planner asks
|
|
122
|
+
* the ownership oracle (the passive aggregate) whether any space declares
|
|
123
|
+
* it and, if so, leaves it alone. A table no space owns stays a genuine
|
|
124
|
+
* extra. Ownership lives in the aggregate; the planner only asks. No
|
|
125
|
+
* oracle (single-space) keeps every extra.
|
|
126
|
+
* 3. Strict-mode extras gating — `not-expected` (extra table/column/
|
|
127
|
+
* constraint) issues are dropped entirely outside strict mode, mirroring
|
|
128
|
+
* the retired coordinate walk's `if (strict) { ...extra_* } }` guards:
|
|
129
|
+
* an additive-only plan must never even consider dropping an unclaimed
|
|
130
|
+
* object, not just refuse to emit the drop.
|
|
131
|
+
*/
|
|
132
|
+
collectSchemaIssues(options) {
|
|
133
|
+
const allowed = options.policy.allowedOperationClasses;
|
|
134
|
+
const strict = allowed.includes("widening") || allowed.includes("destructive");
|
|
135
|
+
const { expected, actual, issues: rawIssues } = buildSqlitePlanDiff({
|
|
136
|
+
contract: options.contract,
|
|
137
|
+
actualSchema: options.schema,
|
|
138
|
+
frameworkComponents: options.frameworkComponents
|
|
139
|
+
});
|
|
140
|
+
const owned = retainUnownedExtras(coalesceSubtreeIssues(rawIssues), options.ownership);
|
|
141
|
+
return {
|
|
142
|
+
expected,
|
|
143
|
+
actual,
|
|
144
|
+
issues: strict ? owned : owned.filter((issue) => issueOutcome(issue) !== "not-expected")
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Drops a `not-expected` issue when it is a whole extra TABLE that some
|
|
150
|
+
* contract space owns, asking the ownership oracle per node.
|
|
151
|
+
*
|
|
152
|
+
* The consultation applies ONLY to table-level extras — a live table this
|
|
153
|
+
* space's contract lacks — identified by asking the issue's own node
|
|
154
|
+
* (`nodeKind === table`), never by counting path segments. SQLite is a
|
|
155
|
+
* single-namespace target, so every coordinate is qualified with the shared
|
|
156
|
+
* `UNBOUND_NAMESPACE_ID` sentinel (the same one the aggregate's declared
|
|
157
|
+
* entities carry for this target). `entityKind` is the literal `'table'`:
|
|
158
|
+
* this function only ever asks about a node already confirmed to be
|
|
159
|
+
* `RelationalSchemaNodeKind.table` (checked just above), and that's a
|
|
160
|
+
* diff-tree `nodeKind` spelling (`'sql-table'`) distinct from the storage
|
|
161
|
+
* `entries` vocabulary `elementCoordinates` walks (`'table'`) — the literal
|
|
162
|
+
* is that storage-entries spelling. `declaresEntity` answers over the whole
|
|
163
|
+
* composition (self included), so a positive answer on such a table means
|
|
164
|
+
* another space owns it (a table this space owned would be in its expected
|
|
165
|
+
* tree, never an extra): leave it. A negative answer means no space owns
|
|
166
|
+
* it — a genuine orphan to drop.
|
|
167
|
+
*
|
|
168
|
+
* A DEEPER extra (an extra column/constraint on a table this space DOES own —
|
|
169
|
+
* only the child drifted, so the table is in the expected tree) is this
|
|
170
|
+
* space's own drift and is always kept for dropping; asking the oracle there
|
|
171
|
+
* would wrongly suppress it, because the owned table answers `true`. No oracle
|
|
172
|
+
* ⇒ every extra is kept (single-space plan).
|
|
173
|
+
*/
|
|
174
|
+
function retainUnownedExtras(issues, ownership) {
|
|
175
|
+
if (ownership === void 0) return issues;
|
|
176
|
+
return issues.filter((issue) => {
|
|
177
|
+
if (issueOutcome(issue) !== "not-expected") return true;
|
|
178
|
+
const node = issueNode(issue);
|
|
179
|
+
if (node === void 0 || node.nodeKind !== RelationalSchemaNodeKind.table) return true;
|
|
180
|
+
const tableName = issue.path[1];
|
|
181
|
+
return tableName === void 0 || !ownership.declaresEntity({
|
|
182
|
+
namespaceId: UNBOUND_NAMESPACE_ID,
|
|
183
|
+
entityKind: "table",
|
|
184
|
+
entityName: tableName
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { createSqliteMigrationPlanner as n, SqliteMigrationPlanner as t };
|
|
190
|
+
|
|
191
|
+
//# sourceMappingURL=planner-rTeVmEl6-EkIM6GZa.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner-rTeVmEl6-EkIM6GZa.mjs","names":["#lowerer"],"sources":["../../../../3-targets/3-targets/sqlite/dist/planner-rTeVmEl6.mjs"],"sourcesContent":["import { p as renameTableSteps, u as RenameTableCall } from \"./op-factory-call-DFDt6p_b.mjs\";\nimport { a as conflictForDisallowedCall, c as sqlitePlannerStrategies, i as coalesceSubtreeIssues, l as buildSqlitePlanDiff, n as indexNameCaseChange, o as issueNode, r as pairIndexReplacements, s as planIssues } from \"./sqlite-migration-D1Zk_YEy.mjs\";\nimport { t as TypeScriptRenderableSqliteMigration } from \"./planner-produced-sqlite-migration-v5i-Qz6p.mjs\";\nimport { issueOutcome } from \"@internal/framework-components/control\";\nimport { detectTableNameCaseChanges, extractCodecControlHooks, planFieldEventOperations, plannerFailure } from \"@internal/family-sql/control\";\nimport { RelationalSchemaNodeKind, SqlTableIR } from \"@internal/sql-schema-ir/types\";\nimport { UNBOUND_NAMESPACE_ID } from \"@internal/framework-components/ir\";\n//#region src/core/migrations/planner.ts\nfunction createSqliteMigrationPlanner(lowerer) {\n\treturn new SqliteMigrationPlanner(lowerer);\n}\n/**\n* SQLite migration planner — a thin wrapper over `planIssues`.\n*\n* `plan()` diffs the live schema against the target contract via the one\n* differ (`buildSqlitePlanDiff`, producing node-typed `SchemaDiffIssue[]`)\n* and delegates to `planIssues` with the registered strategies. Strategies\n* absorb groups of related issues into composite recipes (e.g. recreating a\n* table to apply type/nullability/default/constraint changes at once);\n* anything not absorbed by a strategy flows through `mapNodeIssueToCall` in\n* the issue planner as a one-off call.\n*\n* FK-backing indexes are already merged into the expected table node's\n* `indexes` at derivation (`contractToSchemaIR`'s `convertTable`), so\n* `mapNodeIssueToCall` handles them uniformly alongside user-declared\n* indexes — no separate expansion step in the planner.\n*/\nvar SqliteMigrationPlanner = class {\n\t#lowerer;\n\tconstructor(lowerer) {\n\t\tthis.#lowerer = lowerer;\n\t}\n\tplan(options) {\n\t\treturn this.planSql(options);\n\t}\n\temptyMigration(context, spaceId) {\n\t\treturn new TypeScriptRenderableSqliteMigration([], {\n\t\t\tfrom: context.fromHash,\n\t\t\tto: context.toHash\n\t\t}, spaceId, context.snapshotsImportPath, void 0, this.#lowerer);\n\t}\n\tplanSql(options) {\n\t\tconst policyResult = this.ensureAdditivePolicy(options.policy);\n\t\tif (policyResult) return policyResult;\n\t\tconst { expected, actual, issues: diffIssues } = this.collectSchemaIssues(options);\n\t\tconst replacedIndexes = pairIndexReplacements(diffIssues, indexNameCaseChange);\n\t\tconst disallowedIndexCalls = replacedIndexes.calls.filter((call) => !options.policy.allowedOperationClasses.includes(call.operationClass));\n\t\tif (disallowedIndexCalls.length > 0) return plannerFailure(disallowedIndexCalls.map((call) => conflictForDisallowedCall(call, options.policy.allowedOperationClasses)));\n\t\tconst issues = diffIssues.filter((issue) => !replacedIndexes.consumed.has(issue));\n\t\tconst caseChangeConflicts = detectTableNameCaseChanges({\n\t\t\tissues,\n\t\t\ttableOf: (issue) => {\n\t\t\t\tconst node = issueNode(issue);\n\t\t\t\treturn node instanceof SqlTableIR ? node : void 0;\n\t\t\t},\n\t\t\tnamespaceIdOf: () => UNBOUND_NAMESPACE_ID,\n\t\t\trenameByHandStatements: (rename) => renameTableSteps(rename.from, rename.to).map((renameStep) => renameStep.sql),\n\t\t\trenameTableCall: (rename) => new RenameTableCall(rename.from, rename.to).renderTypeScript(),\n\t\t\tcontract: options.contract,\n\t\t\tdefaultNamespaceId: UNBOUND_NAMESPACE_ID\n\t\t});\n\t\tif (caseChangeConflicts.length > 0) return plannerFailure(caseChangeConflicts);\n\t\tconst codecHooks = extractCodecControlHooks(options.frameworkComponents);\n\t\tconst result = planIssues({\n\t\t\tissues,\n\t\t\texpected,\n\t\t\tactual,\n\t\t\tpolicy: options.policy,\n\t\t\tframeworkComponents: options.frameworkComponents,\n\t\t\tstrategies: sqlitePlannerStrategies\n\t\t});\n\t\tif (!result.ok) return plannerFailure(result.failure);\n\t\tconst fieldEventOps = planFieldEventOperations({\n\t\t\tpriorContract: options.fromContract,\n\t\t\tnewContract: options.contract,\n\t\t\tcodecHooks\n\t\t});\n\t\tconst calls = [\n\t\t\t...replacedIndexes.calls,\n\t\t\t...result.value.calls,\n\t\t\t...fieldEventOps\n\t\t];\n\t\tconst destination = {\n\t\t\tstorageHash: options.contract.storage.storageHash,\n\t\t\t...options.contract.profileHash !== void 0 ? { profileHash: options.contract.profileHash } : {}\n\t\t};\n\t\treturn {\n\t\t\tkind: \"success\",\n\t\t\tplan: new TypeScriptRenderableSqliteMigration(calls, {\n\t\t\t\tfrom: options.fromContract?.storage.storageHash ?? null,\n\t\t\t\tto: options.contract.storage.storageHash\n\t\t\t}, options.spaceId, options.snapshotsImportPath, destination, this.#lowerer)\n\t\t};\n\t}\n\tensureAdditivePolicy(policy) {\n\t\tif (!policy.allowedOperationClasses.includes(\"additive\")) return plannerFailure([{\n\t\t\tkind: \"unsupportedOperation\",\n\t\t\tsummary: \"Migration planner requires additive operations be allowed\",\n\t\t\twhy: \"The planner requires the \\\"additive\\\" operation class to be allowed in the policy.\"\n\t\t}]);\n\t\treturn null;\n\t}\n\t/**\n\t* Diffs the target contract against the live schema via the one differ\n\t* (the same tree-building `diffSqliteSchema` uses, plus the\n\t* op-render stamper) and prepares the issue list `planIssues` consumes.\n\t*\n\t* Three passes, in order:\n\t* 1. Subtree coalescing — the differ is total (a missing/extra table also\n\t* emits an issue for every column/constraint under it); those nested\n\t* issues are redundant once the table-level `CreateTable`/`DropTable`\n\t* call already accounts for the whole subtree. Runs FIRST, over the\n\t* complete diff: a sibling-owned extra table's column issues must\n\t* collapse into its one table-level issue before the ownership pass,\n\t* because a bare column node carries no table reference — if coalescing\n\t* ran after ownership dropped the table-level issue, the orphaned column\n\t* issues would survive and the planner would emit drops against a\n\t* sibling space's table.\n\t* 2. Ownership — a live extra is only this plan's to drop when no contract\n\t* space owns it. The differ ran against THIS space's contract, so a\n\t* table a sibling owns surfaces here as `not-expected`; the planner asks\n\t* the ownership oracle (the passive aggregate) whether any space declares\n\t* it and, if so, leaves it alone. A table no space owns stays a genuine\n\t* extra. Ownership lives in the aggregate; the planner only asks. No\n\t* oracle (single-space) keeps every extra.\n\t* 3. Strict-mode extras gating — `not-expected` (extra table/column/\n\t* constraint) issues are dropped entirely outside strict mode, mirroring\n\t* the retired coordinate walk's `if (strict) { ...extra_* } }` guards:\n\t* an additive-only plan must never even consider dropping an unclaimed\n\t* object, not just refuse to emit the drop.\n\t*/\n\tcollectSchemaIssues(options) {\n\t\tconst allowed = options.policy.allowedOperationClasses;\n\t\tconst strict = allowed.includes(\"widening\") || allowed.includes(\"destructive\");\n\t\tconst { expected, actual, issues: rawIssues } = buildSqlitePlanDiff({\n\t\t\tcontract: options.contract,\n\t\t\tactualSchema: options.schema,\n\t\t\tframeworkComponents: options.frameworkComponents\n\t\t});\n\t\tconst owned = retainUnownedExtras(coalesceSubtreeIssues(rawIssues), options.ownership);\n\t\treturn {\n\t\t\texpected,\n\t\t\tactual,\n\t\t\tissues: strict ? owned : owned.filter((issue) => issueOutcome(issue) !== \"not-expected\")\n\t\t};\n\t}\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. SQLite is a\n* single-namespace target, so every coordinate is qualified with the shared\n* `UNBOUND_NAMESPACE_ID` sentinel (the same one the aggregate's declared\n* entities carry for this target). `entityKind` is the literal `'table'`:\n* this function only ever asks about a node already confirmed to be\n* `RelationalSchemaNodeKind.table` (checked just above), and that's a\n* diff-tree `nodeKind` spelling (`'sql-table'`) distinct from the storage\n* `entries` vocabulary `elementCoordinates` walks (`'table'`) — the literal\n* is that storage-entries spelling. `declaresEntity` answers over the whole\n* composition (self included), so a positive answer on such a table means\n* another space owns it (a table this space owned would be in its expected\n* tree, never an extra): leave it. A negative answer means no space owns\n* it — a genuine orphan to drop.\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`. No oracle\n* ⇒ every extra is kept (single-space plan).\n*/\nfunction retainUnownedExtras(issues, ownership) {\n\tif (ownership === void 0) return issues;\n\treturn issues.filter((issue) => {\n\t\tif (issueOutcome(issue) !== \"not-expected\") return true;\n\t\tconst node = issueNode(issue);\n\t\tif (node === void 0 || node.nodeKind !== RelationalSchemaNodeKind.table) return true;\n\t\tconst tableName = issue.path[1];\n\t\treturn tableName === void 0 || !ownership.declaresEntity({\n\t\t\tnamespaceId: UNBOUND_NAMESPACE_ID,\n\t\t\tentityKind: \"table\",\n\t\t\tentityName: tableName\n\t\t});\n\t});\n}\n//#endregion\nexport { createSqliteMigrationPlanner as n, SqliteMigrationPlanner as t };\n\n//# sourceMappingURL=planner-rTeVmEl6.mjs.map"],"mappings":"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"}
|
package/dist/{sqlite-migration-Du67NG7r-CqcA5XBz.d.mts → sqlite-migration-2IEGvjRm-BQfd6NLr.d.mts}
RENAMED
|
@@ -4,11 +4,11 @@ import { t as SqliteContractView } from "./sqlite-contract-view-BpNMaU2m-COMDaGa
|
|
|
4
4
|
import { DdlColumn, DdlTableConstraint } from "@prisma/orm-family-sql/relational-core/ast";
|
|
5
5
|
import { ControlStack } from "@prisma/orm-framework/components/control";
|
|
6
6
|
import { SqlStorage } from "@prisma/orm-family-sql/contract/types";
|
|
7
|
-
import { Migration } from "@prisma/orm-family-sql/family/migration";
|
|
8
7
|
import { MigrationOperationClass, SqlMigrationPlanOperation } from "@prisma/orm-family-sql/family/control";
|
|
8
|
+
import { Migration } from "@prisma/orm-family-sql/family/migration";
|
|
9
9
|
import { Contract } from "@prisma/orm-framework/contract/types";
|
|
10
10
|
import { SqlControlAdapter } from "@prisma/orm-family-sql/family/control-adapter";
|
|
11
|
-
//#region ../../../3-targets/3-targets/sqlite/dist/sqlite-migration-
|
|
11
|
+
//#region ../../../3-targets/3-targets/sqlite/dist/sqlite-migration-2IEGvjRm.d.mts
|
|
12
12
|
//#region src/core/migrations/sqlite-migration.d.ts
|
|
13
13
|
type Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;
|
|
14
14
|
/**
|
|
@@ -44,6 +44,7 @@ declare abstract class SqliteMigration<Start extends Contract<SqlStorage> = Cont
|
|
|
44
44
|
*/
|
|
45
45
|
protected readonly controlAdapter: SqlControlAdapter<'sqlite'> | undefined;
|
|
46
46
|
constructor(stack?: ControlStack<'sql', 'sqlite'>);
|
|
47
|
+
private frameworkComponents;
|
|
47
48
|
/**
|
|
48
49
|
* Returns the materialized control adapter, or throws a MIGRATION.SQLITE_CONTROL_STACK_MISSING naming
|
|
49
50
|
* `operation` when the migration was constructed without a `ControlStack`.
|
|
@@ -70,6 +71,13 @@ declare abstract class SqliteMigration<Start extends Contract<SqlStorage> = Cont
|
|
|
70
71
|
protected dropTable(options: {
|
|
71
72
|
readonly table: string;
|
|
72
73
|
}): Promise<Op>;
|
|
74
|
+
/**
|
|
75
|
+
* Emit the operations that rename a table: the table rename, then a drop and a create under the new name of each index whose name was derived from the old table name, read from this migration's start and end contracts. Spread the result into `operations`: `...this.renameTable({ table: 'userProfile', to: 'UserProfile' })`. Throws `MIGRATION.TABLE_RENAME_UNMATCHED` when the start contract lacks the table or the end contract lacks the new name.
|
|
76
|
+
*/
|
|
77
|
+
protected renameTable(options: {
|
|
78
|
+
readonly table: string;
|
|
79
|
+
readonly to: string;
|
|
80
|
+
}): readonly Promise<Op>[];
|
|
73
81
|
protected addColumn(options: {
|
|
74
82
|
readonly table: string;
|
|
75
83
|
readonly column: SqliteColumnSpec;
|
|
@@ -99,4 +107,4 @@ declare abstract class SqliteMigration<Start extends Contract<SqlStorage> = Cont
|
|
|
99
107
|
}
|
|
100
108
|
//#endregion
|
|
101
109
|
export { SqliteMigration as t };
|
|
102
|
-
//# sourceMappingURL=sqlite-migration-
|
|
110
|
+
//# sourceMappingURL=sqlite-migration-2IEGvjRm-BQfd6NLr.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-migration-2IEGvjRm-BQfd6NLr.d.mts","names":[],"sources":["../../../../3-targets/3-targets/sqlite/dist/sqlite-migration-2IEGvjRm.d.mts"],"mappings":";;;;;;;;;;;;KAWK,KAAK,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;uBAuBb,gBAAgB,cAAc,SAAS,cAAc,SAAS,aAAa,YAAY,SAAS,cAAc,SAAS,qBAAqB,UAAU,mCAAmC,OAAO;;WAE5M;;;;;;;qBAOU,gBAAgB;EACnC,YAAY,QAAQ;UACZ;;;;;;UAMA;;;;;;MAMJ,eAAe,mBAAmB;;;;;MAKlC,iBAAiB,mBAAmB;YAC9B,YAAY;aACX;aACA;aACA,kBAAkB;aAClB,uBAAuB;MAC9B,QAAQ;YACF,UAAU;aACT;MACP,QAAQ;;;;YAIF,YAAY;aACX;aACA;eACE,QAAQ;YACX,UAAU;aACT;aACA,QAAQ;MACf,QAAQ;YACF,WAAW;aACV;aACA;MACP,QAAQ;YACF,YAAY;aACX;aACA;aACA;MACP,QAAQ;YACF,UAAU;aACT;aACA;MACP,QAAQ;YACF,cAAc;aACb;aACA,eAAe;aACf;aACA,kBAAkB;aAClB;aACA,qBAAqB;aACrB,gBAAgB;MACvB,QAAQ"}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import { n as sqliteError } from "./errors-DnR-sMHS-KkMLIP2U.mjs";
|
|
1
|
+
import { n as sqliteError, t as errorSqliteMigrationStackMissing } from "./errors-DnR-sMHS-KkMLIP2U.mjs";
|
|
2
2
|
import { n as sqliteResolveDefault } from "./default-normalizer-Bbo6WzxJ-MgaICRCQ.mjs";
|
|
3
|
-
import { a as DropColumnCall, d as
|
|
3
|
+
import { _ as sqliteIdentifiersCollide, a as DropColumnCall, d as buildColumnTypeSql, f as buildRecreatePostchecks, g as sqliteDefaultToDdlColumnDefault, h as renderDefaultLiteral, i as DataTransformCall, l as RecreateTableCall, n as CreateIndexCall, o as DropIndexCall, p as buildRecreateSummary, r as CreateTableCall, s as DropTableCall, t as AddColumnCall, u as RenameTableCall } from "./op-factory-call-DFDt6p_b-CN07t9pu.mjs";
|
|
4
4
|
import { t as CONTROL_TABLE_NAMES } from "./control-tables-D_o8dKRB-BXi43noL.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { n as SqliteContractView } from "./sqlite-contract-view-BYR10usg-BteDAUZr.mjs";
|
|
6
6
|
import { DdlColumn, ForeignKeyConstraint, PrimaryKeyConstraint, UniqueConstraint } from "@prisma/orm-family-sql/relational-core/ast";
|
|
7
7
|
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
8
8
|
import { blindCast } from "@prisma/orm-framework/utils/casts";
|
|
9
9
|
import { diffSchemas, issueOutcome, orderIssuesByDependencies } from "@prisma/orm-framework/components/control";
|
|
10
|
-
import {
|
|
11
|
-
import { RelationalSchemaNodeKind,
|
|
10
|
+
import { entityAt } from "@prisma/orm-framework/components/ir";
|
|
11
|
+
import { RelationalSchemaNodeKind, SqlIndexIR, SqlSchemaIR, contractDefaultRefusal, relationalNodeGranularity } from "@prisma/orm-family-sql/schema-ir/types";
|
|
12
12
|
import { InternalError } from "@prisma/orm-framework/utils/internal-error";
|
|
13
|
-
import { buildDataTypeResolver, buildNativeTypeExpander, contractToSchemaIR
|
|
13
|
+
import { applyTableRename, buildDataTypeResolver, buildNativeTypeExpander, contractToSchemaIR } from "@prisma/orm-family-sql/family/control";
|
|
14
14
|
import { verifySqlSchemaByDiff } from "@prisma/orm-family-sql/family/diff";
|
|
15
|
+
import { parseWireName } from "@prisma/orm-family-sql/schema-ir/naming";
|
|
15
16
|
import { notOk, ok } from "@prisma/orm-framework/utils/result";
|
|
16
|
-
|
|
17
|
+
import { Migration } from "@prisma/orm-family-sql/family/migration";
|
|
18
|
+
import { MigrationContractViews } from "@prisma/orm-toolchain/migration-tools/migration";
|
|
19
|
+
//#region ../../../3-targets/3-targets/sqlite/dist/sqlite-migration-D1Zk_YEy.mjs
|
|
17
20
|
/** Renders a column default for the SQLite dialect. */
|
|
18
21
|
function sqliteRenderDefault(def, column) {
|
|
19
22
|
if (def.kind === "function") {
|
|
@@ -672,174 +675,179 @@ function locationForCall(call) {
|
|
|
672
675
|
if ("indexName" in call) location.index = call.indexName;
|
|
673
676
|
return Object.keys(location).length > 0 ? location : void 0;
|
|
674
677
|
}
|
|
675
|
-
function
|
|
676
|
-
return
|
|
678
|
+
function indexFindings(issues, outcome) {
|
|
679
|
+
return issues.flatMap((issue) => {
|
|
680
|
+
const node = issueNode(issue);
|
|
681
|
+
const tableName = issue.path[1];
|
|
682
|
+
if (node === void 0 || !SqlIndexIR.is(node) || tableName === void 0) return [];
|
|
683
|
+
return issueOutcome(issue) === outcome ? [{
|
|
684
|
+
issue,
|
|
685
|
+
index: node,
|
|
686
|
+
tableName
|
|
687
|
+
}] : [];
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* An index on a renamed table whose wire name derives from the table name: the old and the new index share their content hash and differ in name.
|
|
692
|
+
*/
|
|
693
|
+
function renamedTableIndex(renamedTables) {
|
|
694
|
+
return (old, replacement) => {
|
|
695
|
+
const oldWire = parseWireName(old.index.name);
|
|
696
|
+
const replacementWire = parseWireName(replacement.index.name);
|
|
697
|
+
return renamedTables.has(old.tableName) && old.tableName === replacement.tableName && oldWire !== void 0 && oldWire.hash === replacementWire?.hash && old.index.name !== replacement.index.name;
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* An index on the same table whose new name SQLite takes for the old one, as after a table renamed by hand. Its content is not compared: the old index must be dropped before the new one can be created whatever either defines, and the new one is created from its own definition.
|
|
702
|
+
*/
|
|
703
|
+
const indexNameCaseChange = (old, replacement) => old.tableName === replacement.tableName && old.index.name !== replacement.index.name && sqliteIdentifiersCollide(old.index.name, replacement.index.name);
|
|
704
|
+
/**
|
|
705
|
+
* Pairs each index the plan drops with the index that replaces it, and plans every paired drop before every paired create. SQLite cannot rename an index, and it compares index names without regard to the case of ASCII letters, so a replacement whose name differs from the old one only in that case would otherwise collide with it. The paired issues are returned as consumed so the ordinary diff does not plan them again.
|
|
706
|
+
*/
|
|
707
|
+
function pairIndexReplacements(issues, matches) {
|
|
708
|
+
const missing = indexFindings(issues, "not-found");
|
|
709
|
+
const pairs = indexFindings(issues, "not-expected").flatMap((old) => {
|
|
710
|
+
const replacement = missing.find((candidate) => matches(old, candidate));
|
|
711
|
+
if (replacement === void 0) return [];
|
|
712
|
+
missing.splice(missing.indexOf(replacement), 1);
|
|
713
|
+
return [{
|
|
714
|
+
old,
|
|
715
|
+
replacement
|
|
716
|
+
}];
|
|
717
|
+
});
|
|
718
|
+
return {
|
|
719
|
+
calls: [...pairs.map(({ old }) => new DropIndexCall(old.tableName, old.index.name)), ...pairs.map(({ replacement }) => new CreateIndexCall(replacement.tableName, replacement.index.name, replacement.index.columns ?? []))],
|
|
720
|
+
consumed: new Set(pairs.flatMap(({ old, replacement }) => [old.issue, replacement.issue]))
|
|
721
|
+
};
|
|
677
722
|
}
|
|
678
723
|
/**
|
|
679
|
-
*
|
|
724
|
+
* The calls a migration's `renameTable` emits: the table rename, then a drop of each wire-named index whose prefix derives from the old table name and a create of it under the new name, since SQLite cannot rename an index. SQLite names no primary key, unique constraint or foreign key the contract leaves unnamed, so those need nothing. Throws `MIGRATION.TABLE_RENAME_UNMATCHED` when the start contract lacks the table or the end contract lacks the new name.
|
|
725
|
+
*/
|
|
726
|
+
function sqliteTableRenameCalls(input) {
|
|
727
|
+
const applied = applyTableRename({
|
|
728
|
+
startContract: input.startContract,
|
|
729
|
+
endContract: input.endContract,
|
|
730
|
+
rename: input.rename,
|
|
731
|
+
renameTableReferences: void 0
|
|
732
|
+
});
|
|
733
|
+
if (!applied.ok) throw applied.failure;
|
|
734
|
+
const { rename } = applied.value;
|
|
735
|
+
const { issues } = buildSqlitePlanDiff({
|
|
736
|
+
contract: input.endContract,
|
|
737
|
+
actualSchema: sqliteContractToSchema(applied.value.contract),
|
|
738
|
+
frameworkComponents: input.frameworkComponents
|
|
739
|
+
});
|
|
740
|
+
return [new RenameTableCall(rename.from, rename.to), ...pairIndexReplacements(coalesceSubtreeIssues(issues), renamedTableIndex(/* @__PURE__ */ new Set([rename.to]))).calls];
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Target-owned base class for SQLite migrations. Fixes the `SqlMigration`
|
|
744
|
+
* generic to `SqlitePlanTargetDetails` and the abstract `targetId` to the
|
|
745
|
+
* SQLite literal, so both user-authored migrations and renderer-generated
|
|
746
|
+
* scaffolds can extend `SqliteMigration` directly without redeclaring
|
|
747
|
+
* target-local identity.
|
|
680
748
|
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
* anything not absorbed by a strategy flows through `mapNodeIssueToCall` in
|
|
687
|
-
* the issue planner as a one-off call.
|
|
749
|
+
* The constructor materializes a single SQLite `SqlControlAdapter` from
|
|
750
|
+
* `stack.adapter.create(stack)` and stores it; the protected instance methods
|
|
751
|
+
* forward to the corresponding `*Call` with that stored adapter, so user
|
|
752
|
+
* migrations can write `this.createTable({...})` without threading the adapter
|
|
753
|
+
* through every call.
|
|
688
754
|
*
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
* `
|
|
692
|
-
*
|
|
755
|
+
* Binds the framework base's `Start` / `End` contract generics so a subclass
|
|
756
|
+
* that assigns its snapshot-store `contract.json` imports to
|
|
757
|
+
* `startContractJson` / `endContractJson` gets fully-typed view accessors:
|
|
758
|
+
* `this.endContract` is a `SqliteContractView<End>`
|
|
759
|
+
* (sole namespace unwrapped to the root — `this.endContract.table.<name>`),
|
|
760
|
+
* built lazily from the JSON fields via the shared `MigrationContractViews`
|
|
761
|
+
* helper. Mirrors `MongoMigration`'s view getters; the framework base derives
|
|
762
|
+
* `describe()` from the same JSON.
|
|
693
763
|
*/
|
|
694
|
-
var
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
planSql(options) {
|
|
709
|
-
const policyResult = this.ensureAdditivePolicy(options.policy);
|
|
710
|
-
if (policyResult) return policyResult;
|
|
711
|
-
const { expected, actual, issues } = this.collectSchemaIssues(options);
|
|
712
|
-
const caseChangeConflicts = detectTableNameCaseChanges({
|
|
713
|
-
issues,
|
|
714
|
-
tableOf: (issue) => {
|
|
715
|
-
const node = issueNode(issue);
|
|
716
|
-
return node instanceof SqlTableIR ? node : void 0;
|
|
717
|
-
},
|
|
718
|
-
namespaceIdOf: () => UNBOUND_NAMESPACE_ID
|
|
719
|
-
});
|
|
720
|
-
if (caseChangeConflicts.length > 0) return plannerFailure(caseChangeConflicts);
|
|
721
|
-
const codecHooks = extractCodecControlHooks(options.frameworkComponents);
|
|
722
|
-
const result = planIssues({
|
|
723
|
-
issues,
|
|
724
|
-
expected,
|
|
725
|
-
actual,
|
|
726
|
-
policy: options.policy,
|
|
727
|
-
frameworkComponents: options.frameworkComponents,
|
|
728
|
-
strategies: sqlitePlannerStrategies
|
|
729
|
-
});
|
|
730
|
-
if (!result.ok) return plannerFailure(result.failure);
|
|
731
|
-
const fieldEventOps = planFieldEventOperations({
|
|
732
|
-
priorContract: options.fromContract,
|
|
733
|
-
newContract: options.contract,
|
|
734
|
-
codecHooks
|
|
735
|
-
});
|
|
736
|
-
const calls = [...result.value.calls, ...fieldEventOps];
|
|
737
|
-
const destination = {
|
|
738
|
-
storageHash: options.contract.storage.storageHash,
|
|
739
|
-
...options.contract.profileHash !== void 0 ? { profileHash: options.contract.profileHash } : {}
|
|
740
|
-
};
|
|
741
|
-
return {
|
|
742
|
-
kind: "success",
|
|
743
|
-
plan: new TypeScriptRenderableSqliteMigration(calls, {
|
|
744
|
-
from: options.fromContract?.storage.storageHash ?? null,
|
|
745
|
-
to: options.contract.storage.storageHash
|
|
746
|
-
}, options.spaceId, options.snapshotsImportPath, destination, this.#lowerer)
|
|
747
|
-
};
|
|
764
|
+
var SqliteMigration = class extends Migration {
|
|
765
|
+
targetId = "sqlite";
|
|
766
|
+
/**
|
|
767
|
+
* Materialized SQLite control adapter, created once per migration
|
|
768
|
+
* instance from the injected stack. `undefined` only when the migration
|
|
769
|
+
* was instantiated without a stack (test fixtures); `controlAdapterFor`
|
|
770
|
+
* throws a MIGRATION.SQLITE_CONTROL_STACK_MISSING in that case to surface the misuse.
|
|
771
|
+
*/
|
|
772
|
+
controlAdapter;
|
|
773
|
+
#endView = new MigrationContractViews(this, "SqliteMigration", (json) => SqliteContractView.fromJson(json));
|
|
774
|
+
#startView = new MigrationContractViews(this, "SqliteMigration", (json) => SqliteContractView.fromJson(json));
|
|
775
|
+
constructor(stack) {
|
|
776
|
+
super(stack);
|
|
777
|
+
this.controlAdapter = stack?.adapter ? blindCast(stack.adapter.create(stack)) : void 0;
|
|
748
778
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
779
|
+
frameworkComponents() {
|
|
780
|
+
const stack = this.stack;
|
|
781
|
+
if (stack === void 0) return [];
|
|
782
|
+
return [
|
|
783
|
+
stack.target,
|
|
784
|
+
...stack.adapter === void 0 ? [] : [stack.adapter],
|
|
785
|
+
...stack.extensions
|
|
786
|
+
];
|
|
756
787
|
}
|
|
757
788
|
/**
|
|
758
|
-
*
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
* Three passes, in order:
|
|
763
|
-
* 1. Subtree coalescing — the differ is total (a missing/extra table also
|
|
764
|
-
* emits an issue for every column/constraint under it); those nested
|
|
765
|
-
* issues are redundant once the table-level `CreateTable`/`DropTable`
|
|
766
|
-
* call already accounts for the whole subtree. Runs FIRST, over the
|
|
767
|
-
* complete diff: a sibling-owned extra table's column issues must
|
|
768
|
-
* collapse into its one table-level issue before the ownership pass,
|
|
769
|
-
* because a bare column node carries no table reference — if coalescing
|
|
770
|
-
* ran after ownership dropped the table-level issue, the orphaned column
|
|
771
|
-
* issues would survive and the planner would emit drops against a
|
|
772
|
-
* sibling space's table.
|
|
773
|
-
* 2. Ownership — a live extra is only this plan's to drop when no contract
|
|
774
|
-
* space owns it. The differ ran against THIS space's contract, so a
|
|
775
|
-
* table a sibling owns surfaces here as `not-expected`; the planner asks
|
|
776
|
-
* the ownership oracle (the passive aggregate) whether any space declares
|
|
777
|
-
* it and, if so, leaves it alone. A table no space owns stays a genuine
|
|
778
|
-
* extra. Ownership lives in the aggregate; the planner only asks. No
|
|
779
|
-
* oracle (single-space) keeps every extra.
|
|
780
|
-
* 3. Strict-mode extras gating — `not-expected` (extra table/column/
|
|
781
|
-
* constraint) issues are dropped entirely outside strict mode, mirroring
|
|
782
|
-
* the retired coordinate walk's `if (strict) { ...extra_* } }` guards:
|
|
783
|
-
* an additive-only plan must never even consider dropping an unclaimed
|
|
784
|
-
* object, not just refuse to emit the drop.
|
|
789
|
+
* Returns the materialized control adapter, or throws a MIGRATION.SQLITE_CONTROL_STACK_MISSING naming
|
|
790
|
+
* `operation` when the migration was constructed without a `ControlStack`.
|
|
791
|
+
* Single home for the null-check that every DDL/DML method shares.
|
|
785
792
|
*/
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
793
|
+
controlAdapterFor(operation) {
|
|
794
|
+
if (!this.controlAdapter) throw errorSqliteMigrationStackMissing(operation);
|
|
795
|
+
return this.controlAdapter;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* The typed SQLite view over this migration's end-state contract — sole
|
|
799
|
+
* namespace unwrapped to the root, so `this.endContract.table.<name>` etc.
|
|
800
|
+
* Throws if no `endContractJson` was provided.
|
|
801
|
+
*/
|
|
802
|
+
get endContract() {
|
|
803
|
+
return this.#endView.endContract;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* The typed SQLite view over this migration's start-state contract, or
|
|
807
|
+
* `null` for a baseline migration (no `startContractJson`).
|
|
808
|
+
*/
|
|
809
|
+
get startContract() {
|
|
810
|
+
return this.#startView.startContract;
|
|
811
|
+
}
|
|
812
|
+
createTable(options) {
|
|
813
|
+
return new CreateTableCall(options.table, options.columns, options.constraints).toOp(this.controlAdapterFor("createTable"));
|
|
814
|
+
}
|
|
815
|
+
dropTable(options) {
|
|
816
|
+
return new DropTableCall(options.table).toOp(this.controlAdapterFor("dropTable"));
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Emit the operations that rename a table: the table rename, then a drop and a create under the new name of each index whose name was derived from the old table name, read from this migration's start and end contracts. Spread the result into `operations`: `...this.renameTable({ table: 'userProfile', to: 'UserProfile' })`. Throws `MIGRATION.TABLE_RENAME_UNMATCHED` when the start contract lacks the table or the end contract lacks the new name.
|
|
820
|
+
*/
|
|
821
|
+
renameTable(options) {
|
|
822
|
+
const adapter = this.controlAdapterFor("renameTable");
|
|
823
|
+
return sqliteTableRenameCalls({
|
|
824
|
+
startContract: this.startContract,
|
|
825
|
+
endContract: this.endContract,
|
|
826
|
+
rename: {
|
|
827
|
+
namespaceId: void 0,
|
|
828
|
+
from: options.table,
|
|
829
|
+
to: options.to
|
|
830
|
+
},
|
|
831
|
+
frameworkComponents: this.frameworkComponents()
|
|
832
|
+
}).map(async (call) => call.toOp(adapter));
|
|
833
|
+
}
|
|
834
|
+
addColumn(options) {
|
|
835
|
+
return new AddColumnCall(options.table, options.column).toOp(this.controlAdapterFor("addColumn"));
|
|
836
|
+
}
|
|
837
|
+
dropColumn(options) {
|
|
838
|
+
return new DropColumnCall(options.table, options.column).toOp(this.controlAdapterFor("dropColumn"));
|
|
839
|
+
}
|
|
840
|
+
createIndex(options) {
|
|
841
|
+
return new CreateIndexCall(options.table, options.index, options.columns).toOp(this.controlAdapterFor("createIndex"));
|
|
842
|
+
}
|
|
843
|
+
dropIndex(options) {
|
|
844
|
+
return new DropIndexCall(options.table, options.index).toOp(this.controlAdapterFor("dropIndex"));
|
|
845
|
+
}
|
|
846
|
+
recreateTable(options) {
|
|
847
|
+
return new RecreateTableCall(options).toOp(this.controlAdapterFor("recreateTable"));
|
|
800
848
|
}
|
|
801
849
|
};
|
|
802
|
-
/**
|
|
803
|
-
* Drops a `not-expected` issue when it is a whole extra TABLE that some
|
|
804
|
-
* contract space owns, asking the ownership oracle per node.
|
|
805
|
-
*
|
|
806
|
-
* The consultation applies ONLY to table-level extras — a live table this
|
|
807
|
-
* space's contract lacks — identified by asking the issue's own node
|
|
808
|
-
* (`nodeKind === table`), never by counting path segments. SQLite is a
|
|
809
|
-
* single-namespace target, so every coordinate is qualified with the shared
|
|
810
|
-
* `UNBOUND_NAMESPACE_ID` sentinel (the same one the aggregate's declared
|
|
811
|
-
* entities carry for this target). `entityKind` is the literal `'table'`:
|
|
812
|
-
* this function only ever asks about a node already confirmed to be
|
|
813
|
-
* `RelationalSchemaNodeKind.table` (checked just above), and that's a
|
|
814
|
-
* diff-tree `nodeKind` spelling (`'sql-table'`) distinct from the storage
|
|
815
|
-
* `entries` vocabulary `elementCoordinates` walks (`'table'`) — the literal
|
|
816
|
-
* is that storage-entries spelling. `declaresEntity` answers over the whole
|
|
817
|
-
* composition (self included), so a positive answer on such a table means
|
|
818
|
-
* another space owns it (a table this space owned would be in its expected
|
|
819
|
-
* tree, never an extra): leave it. A negative answer means no space owns
|
|
820
|
-
* it — a genuine orphan to drop.
|
|
821
|
-
*
|
|
822
|
-
* A DEEPER extra (an extra column/constraint on a table this space DOES own —
|
|
823
|
-
* only the child drifted, so the table is in the expected tree) is this
|
|
824
|
-
* space's own drift and is always kept for dropping; asking the oracle there
|
|
825
|
-
* would wrongly suppress it, because the owned table answers `true`. No oracle
|
|
826
|
-
* ⇒ every extra is kept (single-space plan).
|
|
827
|
-
*/
|
|
828
|
-
function retainUnownedExtras(issues, ownership) {
|
|
829
|
-
if (ownership === void 0) return issues;
|
|
830
|
-
return issues.filter((issue) => {
|
|
831
|
-
if (issueOutcome(issue) !== "not-expected") return true;
|
|
832
|
-
const node = issueNode(issue);
|
|
833
|
-
if (node === void 0 || node.nodeKind !== RelationalSchemaNodeKind.table) return true;
|
|
834
|
-
const tableName = issue.path[1];
|
|
835
|
-
return tableName === void 0 || !ownership.declaresEntity({
|
|
836
|
-
namespaceId: UNBOUND_NAMESPACE_ID,
|
|
837
|
-
entityKind: "table",
|
|
838
|
-
entityName: tableName
|
|
839
|
-
});
|
|
840
|
-
});
|
|
841
|
-
}
|
|
842
850
|
//#endregion
|
|
843
|
-
export {
|
|
851
|
+
export { diffSqliteSchema as a, pairIndexReplacements as c, sqlitePlannerStrategies as d, verifySqliteDatabaseSchema as f, conflictForDisallowedCall as i, planIssues as l, buildSqlitePlanDiff as n, indexNameCaseChange as o, coalesceSubtreeIssues as r, issueNode as s, SqliteMigration as t, sqliteContractToSchema as u };
|
|
844
852
|
|
|
845
|
-
//# sourceMappingURL=
|
|
853
|
+
//# sourceMappingURL=sqlite-migration-D1Zk_YEy-BRKDlY8h.mjs.map
|