@prisma-next/target-sqlite 0.5.0-dev.67 → 0.5.0-dev.68
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 +120 -52
- package/dist/control.mjs.map +1 -1
- package/dist/migration.d.mts +11 -1
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +13 -1
- package/dist/migration.mjs.map +1 -1
- package/dist/{op-factory-call-DvewDQ7a.mjs → op-factory-call-DRKKURAO.mjs} +30 -2
- package/dist/{op-factory-call-DvewDQ7a.mjs.map → op-factory-call-DRKKURAO.mjs.map} +1 -1
- package/dist/{op-factory-call-DzKIrTLj.d.mts → op-factory-call-FrU2vXqw.d.mts} +21 -3
- package/dist/{op-factory-call-DzKIrTLj.d.mts.map → op-factory-call-FrU2vXqw.d.mts.map} +1 -1
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/{planner-CIjeXa04.mjs → planner-C94LJeIM.mjs} +11 -5
- package/dist/{planner-CIjeXa04.mjs.map → planner-C94LJeIM.mjs.map} +1 -1
- package/dist/{planner-produced-sqlite-migration-IZZt7TRg.d.mts → planner-produced-sqlite-migration-BblR19lI.d.mts} +2 -2
- package/dist/{planner-produced-sqlite-migration-IZZt7TRg.d.mts.map → planner-produced-sqlite-migration-BblR19lI.d.mts.map} +1 -1
- package/dist/planner-produced-sqlite-migration.d.mts +1 -1
- package/dist/planner.d.mts +1 -1
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/render-ops.d.mts +1 -1
- package/dist/{statement-builders-DMT4ltXR.mjs → statement-builders-Dne-LkAV.mjs} +4 -4
- package/dist/statement-builders-Dne-LkAV.mjs.map +1 -0
- package/dist/statement-builders.mjs +1 -1
- package/package.json +15 -15
- package/src/core/migrations/op-factory-call.ts +38 -1
- package/src/core/migrations/operations/raw.ts +12 -0
- package/src/core/migrations/planner.ts +30 -2
- package/src/core/migrations/runner.ts +164 -75
- package/src/exports/migration.ts +1 -0
- package/src/exports/op-factory-call.ts +1 -0
- package/dist/statement-builders-DMT4ltXR.mjs.map +0 -1
package/dist/control.mjs
CHANGED
|
@@ -2,12 +2,13 @@ import { t as sqliteTargetDescriptorMeta } from "./descriptor-meta-CE2Kbn9b.mjs"
|
|
|
2
2
|
import { t as parseSqliteDefault } from "./default-normalizer-3Fccw7yw.mjs";
|
|
3
3
|
import { t as normalizeSqliteNativeType } from "./native-type-normalizer-BlN5XfD-.mjs";
|
|
4
4
|
import { d as renderDefaultLiteral } from "./tables-D84zfPZI.mjs";
|
|
5
|
-
import { n as createSqliteMigrationPlanner } from "./planner-
|
|
6
|
-
import { a as buildLedgerInsertStatement, c as ensureMarkerTableStatement, i as MARKER_TABLE_NAME, l as readMarkerStatement, o as buildWriteMarkerStatements, s as ensureLedgerTableStatement } from "./statement-builders-
|
|
5
|
+
import { n as createSqliteMigrationPlanner } from "./planner-C94LJeIM.mjs";
|
|
6
|
+
import { a as buildLedgerInsertStatement, c as ensureMarkerTableStatement, i as MARKER_TABLE_NAME, l as readMarkerStatement, o as buildWriteMarkerStatements, s as ensureLedgerTableStatement } from "./statement-builders-Dne-LkAV.mjs";
|
|
7
7
|
import { contractToSchemaIR, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
|
|
8
8
|
import { verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
|
|
9
|
-
import { ok, okVoid } from "@prisma-next/utils/result";
|
|
9
|
+
import { notOk, ok, okVoid } from "@prisma-next/utils/result";
|
|
10
10
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
11
|
+
import { APP_SPACE_ID } from "@prisma-next/framework-components/control";
|
|
11
12
|
import { parseContractMarkerRow } from "@prisma-next/family-sql/verify";
|
|
12
13
|
//#region src/core/migrations/runner.ts
|
|
13
14
|
function createSqliteMigrationRunner(family) {
|
|
@@ -30,60 +31,127 @@ var SqliteMigrationRunner = class {
|
|
|
30
31
|
await this.beginExclusiveTransaction(driver);
|
|
31
32
|
let committed = false;
|
|
32
33
|
try {
|
|
33
|
-
const
|
|
34
|
-
if (!
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);
|
|
39
|
-
const isSelfEdge = options.plan.origin?.storageHash === options.plan.destination.storageHash;
|
|
40
|
-
const skipOperations = markerAtDestination && options.plan.origin != null && !isSelfEdge;
|
|
41
|
-
let operationsExecuted;
|
|
42
|
-
let executedOperations;
|
|
43
|
-
if (skipOperations) {
|
|
44
|
-
operationsExecuted = 0;
|
|
45
|
-
executedOperations = [];
|
|
46
|
-
} else {
|
|
47
|
-
const applyResult = await this.applyPlan(driver, options);
|
|
48
|
-
if (!applyResult.ok) return applyResult;
|
|
49
|
-
operationsExecuted = applyResult.value.operationsExecuted;
|
|
50
|
-
executedOperations = applyResult.value.executedOperations;
|
|
34
|
+
const result = await this.executeOnConnection(options);
|
|
35
|
+
if (!result.ok) return result;
|
|
36
|
+
if (fkWasEnabled) {
|
|
37
|
+
const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);
|
|
38
|
+
if (!fkIntegrityCheck.ok) return fkIntegrityCheck;
|
|
51
39
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
40
|
+
await this.commitTransaction(driver);
|
|
41
|
+
committed = true;
|
|
42
|
+
return result;
|
|
43
|
+
} finally {
|
|
44
|
+
if (!committed) await this.rollbackTransaction(driver);
|
|
45
|
+
}
|
|
46
|
+
} finally {
|
|
47
|
+
if (fkWasEnabled) await driver.query("PRAGMA foreign_keys = ON");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Apply the plan against an already-open connection without managing
|
|
52
|
+
* the transaction lifecycle. The caller owns BEGIN/COMMIT/ROLLBACK
|
|
53
|
+
* and any connection-level setup (FK pragma toggle, FK integrity
|
|
54
|
+
* check). Used by the per-space runner orchestration to fan out
|
|
55
|
+
* across contract spaces inside one outer transaction.
|
|
56
|
+
*/
|
|
57
|
+
async executeOnConnection(options) {
|
|
58
|
+
const driver = options.driver;
|
|
59
|
+
if (options.space !== void 0 && options.space !== options.plan.spaceId) throw new Error(`SqlMigrationRunner: options.space (${options.space}) does not match plan.spaceId (${options.plan.spaceId})`);
|
|
60
|
+
const space = options.plan.spaceId;
|
|
61
|
+
const destinationCheck = this.ensurePlanMatchesDestinationContract(options.plan.destination, options.destinationContract);
|
|
62
|
+
if (!destinationCheck.ok) return destinationCheck;
|
|
63
|
+
const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);
|
|
64
|
+
if (!policyCheck.ok) return policyCheck;
|
|
65
|
+
const ensureResult = await this.ensureControlTables(driver);
|
|
66
|
+
if (!ensureResult.ok) return ensureResult;
|
|
67
|
+
const existingMarker = await this.readMarker(driver, space);
|
|
68
|
+
const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);
|
|
69
|
+
if (!markerCheck.ok) return markerCheck;
|
|
70
|
+
const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);
|
|
71
|
+
const isSelfEdge = options.plan.origin?.storageHash === options.plan.destination.storageHash;
|
|
72
|
+
const skipOperations = markerAtDestination && options.plan.origin != null && !isSelfEdge;
|
|
73
|
+
let operationsExecuted;
|
|
74
|
+
let executedOperations;
|
|
75
|
+
if (skipOperations) {
|
|
76
|
+
operationsExecuted = 0;
|
|
77
|
+
executedOperations = [];
|
|
78
|
+
} else {
|
|
79
|
+
const applyResult = await this.applyPlan(driver, options);
|
|
80
|
+
if (!applyResult.ok) return applyResult;
|
|
81
|
+
operationsExecuted = applyResult.value.operationsExecuted;
|
|
82
|
+
executedOperations = applyResult.value.executedOperations;
|
|
83
|
+
}
|
|
84
|
+
if (space === APP_SPACE_ID) {
|
|
85
|
+
const schemaIR = await this.family.introspect({
|
|
86
|
+
driver,
|
|
87
|
+
contract: options.destinationContract
|
|
88
|
+
});
|
|
89
|
+
const schemaVerifyResult = verifySqlSchema({
|
|
90
|
+
contract: options.destinationContract,
|
|
91
|
+
schema: schemaIR,
|
|
92
|
+
strict: options.strictVerification ?? true,
|
|
93
|
+
context: options.context ?? {},
|
|
94
|
+
typeMetadataRegistry: this.family.typeMetadataRegistry,
|
|
95
|
+
frameworkComponents: options.frameworkComponents,
|
|
96
|
+
normalizeDefault: parseSqliteDefault,
|
|
97
|
+
normalizeNativeType: normalizeSqliteNativeType
|
|
98
|
+
});
|
|
99
|
+
if (!schemaVerifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", schemaVerifyResult.summary, {
|
|
100
|
+
why: "The resulting database schema does not satisfy the destination contract.",
|
|
101
|
+
meta: { issues: schemaVerifyResult.schema.issues }
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const incomingInvariants = options.plan.providedInvariants;
|
|
105
|
+
const existingInvariants = new Set(existingMarker?.invariants ?? []);
|
|
106
|
+
const incomingIsSubsetOfExisting = incomingInvariants.every((id) => existingInvariants.has(id));
|
|
107
|
+
if (!(isSelfEdge && operationsExecuted === 0 && incomingIsSubsetOfExisting)) {
|
|
108
|
+
await this.upsertMarker(driver, options, existingMarker, space);
|
|
109
|
+
await this.recordLedgerEntry(driver, options, existingMarker, executedOperations);
|
|
110
|
+
}
|
|
111
|
+
return runnerSuccess({
|
|
112
|
+
operationsPlanned: options.plan.operations.length,
|
|
113
|
+
operationsExecuted
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async executeAcrossSpaces(options) {
|
|
117
|
+
const driver = options.driver;
|
|
118
|
+
const perSpaceOptions = options.perSpaceOptions;
|
|
119
|
+
if (perSpaceOptions.length === 0) return ok({ perSpaceResults: [] });
|
|
120
|
+
const fkWasEnabled = await this.readForeignKeysEnabled(driver);
|
|
121
|
+
if (fkWasEnabled) await driver.query("PRAGMA foreign_keys = OFF");
|
|
122
|
+
try {
|
|
123
|
+
await this.beginExclusiveTransaction(driver);
|
|
124
|
+
let committed = false;
|
|
125
|
+
try {
|
|
126
|
+
const perSpaceResults = [];
|
|
127
|
+
let lastProcessedSpace;
|
|
128
|
+
for (const spaceOptions of perSpaceOptions) {
|
|
129
|
+
const space = spaceOptions.space ?? spaceOptions.plan.spaceId;
|
|
130
|
+
const result = await this.executeOnConnection({
|
|
131
|
+
...spaceOptions,
|
|
132
|
+
driver,
|
|
133
|
+
space
|
|
134
|
+
});
|
|
135
|
+
if (!result.ok) return notOk({
|
|
136
|
+
...result.failure,
|
|
137
|
+
failingSpace: space
|
|
138
|
+
});
|
|
139
|
+
perSpaceResults.push({
|
|
140
|
+
space,
|
|
141
|
+
value: result.value
|
|
142
|
+
});
|
|
143
|
+
lastProcessedSpace = space;
|
|
76
144
|
}
|
|
77
145
|
if (fkWasEnabled) {
|
|
78
146
|
const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);
|
|
79
|
-
if (!fkIntegrityCheck.ok) return
|
|
147
|
+
if (!fkIntegrityCheck.ok) return notOk({
|
|
148
|
+
...fkIntegrityCheck.failure,
|
|
149
|
+
failingSpace: lastProcessedSpace ?? APP_SPACE_ID
|
|
150
|
+
});
|
|
80
151
|
}
|
|
81
152
|
await this.commitTransaction(driver);
|
|
82
153
|
committed = true;
|
|
83
|
-
return
|
|
84
|
-
operationsPlanned: options.plan.operations.length,
|
|
85
|
-
operationsExecuted
|
|
86
|
-
});
|
|
154
|
+
return ok({ perSpaceResults });
|
|
87
155
|
} finally {
|
|
88
156
|
if (!committed) await this.rollbackTransaction(driver);
|
|
89
157
|
}
|
|
@@ -282,12 +350,12 @@ var SqliteMigrationRunner = class {
|
|
|
282
350
|
} });
|
|
283
351
|
return okVoid();
|
|
284
352
|
}
|
|
285
|
-
async upsertMarker(driver, options, existingMarker) {
|
|
353
|
+
async upsertMarker(driver, options, existingMarker, space) {
|
|
286
354
|
const merged = new Set(existingMarker?.invariants ?? []);
|
|
287
355
|
for (const inv of options.plan.providedInvariants) merged.add(inv);
|
|
288
356
|
const invariants = Array.from(merged).sort();
|
|
289
357
|
const writeStatements = buildWriteMarkerStatements({
|
|
290
|
-
space
|
|
358
|
+
space,
|
|
291
359
|
storageHash: options.plan.destination.storageHash,
|
|
292
360
|
profileHash: options.plan.destination.profileHash ?? options.destinationContract.profileHash ?? options.plan.destination.storageHash,
|
|
293
361
|
contractJson: options.destinationContract,
|
package/dist/control.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.mjs","names":[],"sources":["../src/core/migrations/runner.ts","../src/core/control-target.ts"],"sourcesContent":["import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlControlFamilyInstance,\n SqlMigrationPlanContractInfo,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationRunner,\n SqlMigrationRunnerExecuteOptions,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerResult,\n} from '@prisma-next/family-sql/control';\nimport { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport { type ContractMarkerRow, parseContractMarkerRow } from '@prisma-next/family-sql/verify';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Result } from '@prisma-next/utils/result';\nimport { ok, okVoid } from '@prisma-next/utils/result';\nimport { parseSqliteDefault } from '../default-normalizer';\nimport { normalizeSqliteNativeType } from '../native-type-normalizer';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\nimport {\n buildLedgerInsertStatement,\n buildWriteMarkerStatements,\n ensureLedgerTableStatement,\n ensureMarkerTableStatement,\n MARKER_TABLE_NAME,\n readMarkerStatement,\n type SqlStatement,\n} from './statement-builders';\n\nexport function createSqliteMigrationRunner(\n family: SqlControlFamilyInstance,\n): SqlMigrationRunner<SqlitePlanTargetDetails> {\n return new SqliteMigrationRunner(family);\n}\n\nclass SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetails> {\n constructor(private readonly family: SqlControlFamilyInstance) {}\n\n async execute(\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<SqlMigrationRunnerResult> {\n const driver = options.driver;\n\n const destinationCheck = this.ensurePlanMatchesDestinationContract(\n options.plan.destination,\n options.destinationContract,\n );\n if (!destinationCheck.ok) {\n return destinationCheck;\n }\n\n const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);\n if (!policyCheck.ok) {\n return policyCheck;\n }\n\n // SQLite recreate-table drops and rebuilds the table. If foreign_keys is ON,\n // dropping a referenced parent cascade-deletes child rows; we must disable FK\n // enforcement for the duration of the migration and validate integrity before\n // committing. PRAGMA foreign_keys is a no-op inside a transaction, so toggle\n // around BEGIN/COMMIT.\n const fkWasEnabled = await this.readForeignKeysEnabled(driver);\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = OFF');\n }\n\n try {\n await this.beginExclusiveTransaction(driver);\n let committed = false;\n try {\n const ensureResult = await this.ensureControlTables(driver);\n if (!ensureResult.ok) {\n return ensureResult;\n }\n const existingMarker = await this.readMarker(driver, options.plan.spaceId);\n\n const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);\n if (!markerCheck.ok) {\n return markerCheck;\n }\n\n const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);\n const isSelfEdge =\n options.plan.origin?.storageHash === options.plan.destination.storageHash;\n const skipOperations = markerAtDestination && options.plan.origin != null && !isSelfEdge;\n\n let operationsExecuted: number;\n let executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[];\n\n if (skipOperations) {\n operationsExecuted = 0;\n executedOperations = [];\n } else {\n const applyResult = await this.applyPlan(driver, options);\n if (!applyResult.ok) {\n return applyResult;\n }\n operationsExecuted = applyResult.value.operationsExecuted;\n executedOperations = applyResult.value.executedOperations;\n }\n\n const schemaIR = await this.family.introspect({\n driver,\n contract: options.destinationContract,\n });\n\n const schemaVerifyResult = verifySqlSchema({\n contract: options.destinationContract,\n schema: schemaIR,\n strict: options.strictVerification ?? true,\n context: options.context ?? {},\n typeMetadataRegistry: this.family.typeMetadataRegistry,\n frameworkComponents: options.frameworkComponents,\n normalizeDefault: parseSqliteDefault,\n normalizeNativeType: normalizeSqliteNativeType,\n });\n if (!schemaVerifyResult.ok) {\n return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {\n why: 'The resulting database schema does not satisfy the destination contract.',\n meta: {\n issues: schemaVerifyResult.schema.issues,\n },\n });\n }\n\n // Self-edge no-op detection: a self-edge migration whose ops had no\n // ops to begin with and brings no new invariants produced no\n // observable change. Skip the marker + ledger writes so an idempotent\n // re-apply of a self-edge data transform doesn't churn updatedAt or\n // pile up empty ledger entries. db update no-ops still write a\n // ledger entry as audit trail.\n const incomingInvariants = options.plan.providedInvariants;\n const existingInvariants = new Set(existingMarker?.invariants ?? []);\n const incomingIsSubsetOfExisting = incomingInvariants.every((id) =>\n existingInvariants.has(id),\n );\n const isSelfEdgeNoOp = isSelfEdge && operationsExecuted === 0 && incomingIsSubsetOfExisting;\n\n if (!isSelfEdgeNoOp) {\n await this.upsertMarker(driver, options, existingMarker);\n await this.recordLedgerEntry(driver, options, existingMarker, executedOperations);\n }\n\n if (fkWasEnabled) {\n const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);\n if (!fkIntegrityCheck.ok) {\n return fkIntegrityCheck;\n }\n }\n\n await this.commitTransaction(driver);\n committed = true;\n return runnerSuccess({\n operationsPlanned: options.plan.operations.length,\n operationsExecuted,\n });\n } finally {\n if (!committed) {\n await this.rollbackTransaction(driver);\n }\n }\n } finally {\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = ON');\n }\n }\n }\n\n private async readForeignKeysEnabled(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<boolean> {\n const result = await driver.query<{ foreign_keys: number }>('PRAGMA foreign_keys');\n const row = result.rows[0];\n return row?.foreign_keys === 1;\n }\n\n private async verifyForeignKeyIntegrity(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n const result = await driver.query<Record<string, unknown>>('PRAGMA foreign_key_check');\n if (result.rows.length === 0) {\n return okVoid();\n }\n return runnerFailure(\n 'FOREIGN_KEY_VIOLATION',\n `Foreign key integrity check failed after migration: ${result.rows.length} violation(s).`,\n {\n why: 'PRAGMA foreign_key_check reported violations after applying recreate-table operations.',\n meta: { violations: result.rows },\n },\n );\n }\n\n private async applyPlan(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<\n Result<\n {\n readonly operationsExecuted: number;\n readonly executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[];\n },\n SqlMigrationRunnerFailure\n >\n > {\n const checks = options.executionChecks;\n const runPrechecks = checks?.prechecks !== false;\n const runPostchecks = checks?.postchecks !== false;\n const runIdempotency = checks?.idempotencyChecks !== false;\n\n let operationsExecuted = 0;\n const executedOperations: Array<SqlMigrationPlanOperation<SqlitePlanTargetDetails>> = [];\n\n for (const operation of options.plan.operations) {\n options.callbacks?.onOperationStart?.(operation);\n try {\n if (runPostchecks && runIdempotency) {\n const postcheckAlreadySatisfied = await this.expectationsAreSatisfied(\n driver,\n operation.postcheck,\n );\n if (postcheckAlreadySatisfied) {\n executedOperations.push(this.createSkipRecord(operation));\n continue;\n }\n }\n\n if (runPrechecks) {\n const precheckResult = await this.runExpectationSteps(\n driver,\n operation.precheck,\n operation,\n 'precheck',\n );\n if (!precheckResult.ok) {\n return precheckResult;\n }\n }\n\n const executeResult = await this.runExecuteSteps(driver, operation.execute, operation);\n if (!executeResult.ok) {\n return executeResult;\n }\n\n if (runPostchecks) {\n const postcheckResult = await this.runExpectationSteps(\n driver,\n operation.postcheck,\n operation,\n 'postcheck',\n );\n if (!postcheckResult.ok) {\n return postcheckResult;\n }\n }\n\n executedOperations.push(operation);\n operationsExecuted += 1;\n } finally {\n options.callbacks?.onOperationComplete?.(operation);\n }\n }\n return ok({ operationsExecuted, executedOperations });\n }\n\n private async ensureControlTables(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n // Pre-1.0 zero-range guardrail: detect a pre-cleanup single-row\n // marker table (no `space` column) and surface a structured failure\n // rather than silently rebuilding the table into the per-space\n // shape. See `specs/framework-mechanism.spec.md § 2`.\n const legacyDetection = await this.detectLegacyMarkerShape(driver);\n if (!legacyDetection.ok) {\n return legacyDetection;\n }\n await this.executeStatement(driver, ensureMarkerTableStatement);\n await this.executeStatement(driver, ensureLedgerTableStatement);\n return okVoid();\n }\n\n private async detectLegacyMarkerShape(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n const tableInfo = await driver.query<{ name: string }>(\n `PRAGMA table_info(\"${MARKER_TABLE_NAME}\")`,\n );\n if (tableInfo.rows.length === 0) {\n return okVoid();\n }\n const columns = new Set(tableInfo.rows.map((row) => row.name));\n if (columns.has('space')) {\n return okVoid();\n }\n return runnerFailure(\n 'LEGACY_MARKER_SHAPE',\n `Legacy marker-table shape detected on ${MARKER_TABLE_NAME} (no \\`space\\` column). ` +\n 'Prisma Next is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. ' +\n `Drop \\`${MARKER_TABLE_NAME}\\` and re-run \\`dbInit\\` to reinitialise from a clean baseline.`,\n {\n meta: {\n table: MARKER_TABLE_NAME,\n columns: [...columns].sort(),\n },\n },\n );\n }\n\n private async readMarker(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n space: string,\n ): Promise<ContractMarkerRecord | null> {\n const stmt = readMarkerStatement(space);\n try {\n const result = await driver.query<ContractMarkerRow>(stmt.sql, stmt.params);\n const row = result.rows[0];\n if (!row) return null;\n // SQLite stores arrays as JSON-encoded TEXT (no native array type), so\n // the driver returns `invariants` as a string. Decode before delegating\n // to the shared row schema, which expects `string[]`.\n const invariants =\n typeof row.invariants === 'string'\n ? (JSON.parse(row.invariants) as unknown)\n : row.invariants;\n return parseContractMarkerRow({ ...row, invariants });\n } catch (error) {\n // Table might not exist yet\n if (error instanceof Error && error.message.includes('no such table')) {\n return null;\n }\n throw error;\n }\n }\n\n private async runExpectationSteps(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n phase: 'precheck' | 'postcheck',\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n const result = await driver.query(step.sql, step.params ?? []);\n if (!this.stepResultIsTrue(result.rows)) {\n const code = phase === 'precheck' ? 'PRECHECK_FAILED' : 'POSTCHECK_FAILED';\n return runnerFailure(\n code,\n `Operation ${operation.id} failed during ${phase}: ${step.description}`,\n {\n meta: {\n operationId: operation.id,\n phase,\n stepDescription: step.description,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private async runExecuteSteps(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n try {\n await driver.query(step.sql, step.params ?? []);\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return runnerFailure(\n 'EXECUTION_FAILED',\n `Operation ${operation.id} failed during execution: ${step.description}`,\n {\n why: message,\n meta: {\n operationId: operation.id,\n stepDescription: step.description,\n sql: step.sql,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private stepResultIsTrue(rows: readonly Record<string, unknown>[]): boolean {\n if (!rows || rows.length === 0) {\n return false;\n }\n const firstRow = rows[0];\n const firstValue = firstRow ? Object.values(firstRow)[0] : undefined;\n if (typeof firstValue === 'number') {\n return firstValue !== 0;\n }\n if (typeof firstValue === 'boolean') {\n return firstValue;\n }\n if (typeof firstValue === 'string') {\n const lower = firstValue.toLowerCase();\n if (lower === 'true' || lower === '1') return true;\n if (lower === 'false' || lower === '0') return false;\n return firstValue.length > 0;\n }\n return Boolean(firstValue);\n }\n\n private async expectationsAreSatisfied(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n ): Promise<boolean> {\n if (steps.length === 0) {\n return false;\n }\n for (const step of steps) {\n const result = await driver.query(step.sql, step.params ?? []);\n if (!this.stepResultIsTrue(result.rows)) {\n return false;\n }\n }\n return true;\n }\n\n private createSkipRecord(\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n ): SqlMigrationPlanOperation<SqlitePlanTargetDetails> {\n return Object.freeze({\n id: operation.id,\n label: operation.label,\n ...ifDefined('summary', operation.summary),\n operationClass: operation.operationClass,\n target: operation.target,\n precheck: Object.freeze([]),\n execute: Object.freeze([]),\n postcheck: Object.freeze([...operation.postcheck]),\n meta: Object.freeze({\n ...(operation.meta ?? {}),\n runner: Object.freeze({ skipped: true, reason: 'postcheck_pre_satisfied' }),\n }),\n });\n }\n\n private markerMatchesDestination(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['plan'],\n ): boolean {\n if (!marker) return false;\n if (marker.storageHash !== plan.destination.storageHash) return false;\n if (plan.destination.profileHash && marker.profileHash !== plan.destination.profileHash) {\n return false;\n }\n return true;\n }\n\n private enforcePolicyCompatibility(\n policy: MigrationOperationPolicy,\n operations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[],\n ): Result<void, SqlMigrationRunnerFailure> {\n const allowedClasses = new Set(policy.allowedOperationClasses);\n for (const operation of operations) {\n if (!allowedClasses.has(operation.operationClass)) {\n return runnerFailure(\n 'POLICY_VIOLATION',\n `Operation ${operation.id} has class \"${operation.operationClass}\" which is not allowed by policy.`,\n {\n why: `Policy only allows: ${policy.allowedOperationClasses.join(', ')}.`,\n meta: {\n operationId: operation.id,\n operationClass: operation.operationClass,\n allowedClasses: policy.allowedOperationClasses,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private ensureMarkerCompatibility(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['plan'],\n ): Result<void, SqlMigrationRunnerFailure> {\n const origin = plan.origin ?? null;\n if (!origin) {\n return okVoid();\n }\n if (!marker) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Missing contract marker: expected origin storage hash ${origin.storageHash}.`,\n { meta: { expectedOriginStorageHash: origin.storageHash } },\n );\n }\n if (marker.storageHash !== origin.storageHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker (${marker.storageHash}) does not match plan origin (${origin.storageHash}).`,\n {\n meta: {\n markerStorageHash: marker.storageHash,\n expectedOriginStorageHash: origin.storageHash,\n },\n },\n );\n }\n if (origin.profileHash && marker.profileHash !== origin.profileHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker profile hash (${marker.profileHash}) does not match plan origin profile hash (${origin.profileHash}).`,\n {\n meta: {\n markerProfileHash: marker.profileHash,\n expectedOriginProfileHash: origin.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private ensurePlanMatchesDestinationContract(\n destination: SqlMigrationPlanContractInfo,\n contract: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['destinationContract'],\n ): Result<void, SqlMigrationRunnerFailure> {\n if (destination.storageHash !== contract.storage.storageHash) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination storage hash (${destination.storageHash}) does not match provided contract storage hash (${contract.storage.storageHash}).`,\n {\n meta: {\n planStorageHash: destination.storageHash,\n contractStorageHash: contract.storage.storageHash,\n },\n },\n );\n }\n if (\n destination.profileHash &&\n contract.profileHash &&\n destination.profileHash !== contract.profileHash\n ) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination profile hash (${destination.profileHash}) does not match provided contract profile hash (${contract.profileHash}).`,\n {\n meta: {\n planProfileHash: destination.profileHash,\n contractProfileHash: contract.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private async upsertMarker(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n ): Promise<void> {\n // SQLite has no native array type, so we can't merge invariants in SQL\n // the way Postgres does. Merge client-side under the runner's\n // BEGIN EXCLUSIVE — sort + dedupe so the JSON-encoded value is stable.\n const merged = new Set<string>(existingMarker?.invariants ?? []);\n for (const inv of options.plan.providedInvariants) merged.add(inv);\n const invariants = Array.from(merged).sort();\n const writeStatements = buildWriteMarkerStatements({\n space: options.plan.spaceId,\n storageHash: options.plan.destination.storageHash,\n profileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.storageHash,\n contractJson: options.destinationContract,\n canonicalVersion: null,\n meta: {},\n invariants,\n });\n const statement = existingMarker ? writeStatements.update : writeStatements.insert;\n await this.executeStatement(driver, statement);\n }\n\n private async recordLedgerEntry(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[],\n ): Promise<void> {\n const ledgerStatement = buildLedgerInsertStatement({\n originStorageHash: existingMarker?.storageHash ?? null,\n originProfileHash: existingMarker?.profileHash ?? null,\n destinationStorageHash: options.plan.destination.storageHash,\n destinationProfileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.storageHash,\n contractJsonBefore: existingMarker?.contractJson ?? null,\n contractJsonAfter: options.destinationContract,\n operations: executedOperations,\n });\n await this.executeStatement(driver, ledgerStatement);\n }\n\n private async beginExclusiveTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('BEGIN EXCLUSIVE');\n }\n\n private async commitTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('COMMIT');\n }\n\n private async rollbackTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('ROLLBACK');\n }\n\n private async executeStatement(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n statement: SqlStatement,\n ): Promise<void> {\n if (statement.params.length > 0) {\n await driver.query(statement.sql, statement.params);\n return;\n }\n await driver.query(statement.sql);\n }\n}\n","import type { ColumnDefault, Contract } from '@prisma-next/contract/types';\nimport type {\n SqlControlFamilyInstance,\n SqlControlTargetDescriptor,\n} from '@prisma-next/family-sql/control';\nimport { contractToSchemaIR } from '@prisma-next/family-sql/control';\nimport type {\n ControlTargetInstance,\n MigrationPlanner,\n MigrationRunner,\n} from '@prisma-next/framework-components/control';\nimport type { SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';\nimport { sqliteTargetDescriptorMeta } from './descriptor-meta';\nimport { createSqliteMigrationPlanner } from './migrations/planner';\nimport { renderDefaultLiteral } from './migrations/planner-ddl-builders';\nimport type { SqlitePlanTargetDetails } from './migrations/planner-target-details';\nimport { createSqliteMigrationRunner } from './migrations/runner';\n\nfunction sqliteRenderDefault(def: ColumnDefault, _column: StorageColumn): string {\n if (def.kind === 'function') {\n if (def.expression === 'now()') {\n return \"datetime('now')\";\n }\n return def.expression;\n }\n return renderDefaultLiteral(def.value);\n}\n\nconst sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', SqlitePlanTargetDetails> =\n {\n ...sqliteTargetDescriptorMeta,\n migrations: {\n createPlanner(_family: SqlControlFamilyInstance): MigrationPlanner<'sql', 'sqlite'> {\n return createSqliteMigrationPlanner();\n },\n createRunner(family) {\n return createSqliteMigrationRunner(family) as MigrationRunner<'sql', 'sqlite'>;\n },\n contractToSchema(contract, frameworkComponents) {\n return contractToSchemaIR(contract as Contract<SqlStorage> | null, {\n annotationNamespace: 'sqlite',\n renderDefault: sqliteRenderDefault,\n frameworkComponents: frameworkComponents ?? [],\n });\n },\n },\n create(): ControlTargetInstance<'sql', 'sqlite'> {\n return {\n familyId: 'sql',\n targetId: 'sqlite',\n };\n },\n createPlanner(_family: SqlControlFamilyInstance) {\n return createSqliteMigrationPlanner();\n },\n createRunner(family) {\n return createSqliteMigrationRunner(family);\n },\n };\n\nexport default sqliteControlTargetDescriptor;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"control.mjs","names":[],"sources":["../src/core/migrations/runner.ts","../src/core/control-target.ts"],"sourcesContent":["import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n MultiSpaceRunnerResult,\n SqlControlFamilyInstance,\n SqlMigrationPlanContractInfo,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationRunner,\n SqlMigrationRunnerExecuteOptions,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerResult,\n SqlMigrationRunnerSuccessValue,\n} from '@prisma-next/family-sql/control';\nimport { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport { type ContractMarkerRow, parseContractMarkerRow } from '@prisma-next/family-sql/verify';\nimport type { ControlDriverInstance } from '@prisma-next/framework-components/control';\nimport { APP_SPACE_ID } from '@prisma-next/framework-components/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok, okVoid } from '@prisma-next/utils/result';\nimport { parseSqliteDefault } from '../default-normalizer';\nimport { normalizeSqliteNativeType } from '../native-type-normalizer';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\nimport {\n buildLedgerInsertStatement,\n buildWriteMarkerStatements,\n ensureLedgerTableStatement,\n ensureMarkerTableStatement,\n MARKER_TABLE_NAME,\n readMarkerStatement,\n type SqlStatement,\n} from './statement-builders';\n\nexport function createSqliteMigrationRunner(\n family: SqlControlFamilyInstance,\n): SqlMigrationRunner<SqlitePlanTargetDetails> {\n return new SqliteMigrationRunner(family);\n}\n\nclass SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetails> {\n constructor(private readonly family: SqlControlFamilyInstance) {}\n\n async execute(\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<SqlMigrationRunnerResult> {\n const driver = options.driver;\n\n const destinationCheck = this.ensurePlanMatchesDestinationContract(\n options.plan.destination,\n options.destinationContract,\n );\n if (!destinationCheck.ok) return destinationCheck;\n\n const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);\n if (!policyCheck.ok) return policyCheck;\n\n // SQLite recreate-table drops and rebuilds the table. If foreign_keys is ON,\n // dropping a referenced parent cascade-deletes child rows; we must disable FK\n // enforcement for the duration of the migration and validate integrity before\n // committing. PRAGMA foreign_keys is a no-op inside a transaction, so toggle\n // around BEGIN/COMMIT.\n const fkWasEnabled = await this.readForeignKeysEnabled(driver);\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = OFF');\n }\n\n try {\n await this.beginExclusiveTransaction(driver);\n let committed = false;\n try {\n const result = await this.executeOnConnection(options);\n if (!result.ok) return result;\n\n if (fkWasEnabled) {\n const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);\n if (!fkIntegrityCheck.ok) return fkIntegrityCheck;\n }\n\n await this.commitTransaction(driver);\n committed = true;\n return result;\n } finally {\n if (!committed) {\n await this.rollbackTransaction(driver);\n }\n }\n } finally {\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = ON');\n }\n }\n }\n\n /**\n * Apply the plan against an already-open connection without managing\n * the transaction lifecycle. The caller owns BEGIN/COMMIT/ROLLBACK\n * and any connection-level setup (FK pragma toggle, FK integrity\n * check). Used by the per-space runner orchestration to fan out\n * across contract spaces inside one outer transaction.\n */\n async executeOnConnection(\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<SqlMigrationRunnerResult> {\n const driver = options.driver;\n if (options.space !== undefined && options.space !== options.plan.spaceId) {\n throw new Error(\n `SqlMigrationRunner: options.space (${options.space}) does not match plan.spaceId (${options.plan.spaceId})`,\n );\n }\n const space = options.plan.spaceId;\n\n const destinationCheck = this.ensurePlanMatchesDestinationContract(\n options.plan.destination,\n options.destinationContract,\n );\n if (!destinationCheck.ok) return destinationCheck;\n\n const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);\n if (!policyCheck.ok) return policyCheck;\n\n const ensureResult = await this.ensureControlTables(driver);\n if (!ensureResult.ok) return ensureResult;\n const existingMarker = await this.readMarker(driver, space);\n\n const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);\n if (!markerCheck.ok) return markerCheck;\n\n const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);\n const isSelfEdge = options.plan.origin?.storageHash === options.plan.destination.storageHash;\n const skipOperations = markerAtDestination && options.plan.origin != null && !isSelfEdge;\n\n let operationsExecuted: number;\n let executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[];\n\n if (skipOperations) {\n operationsExecuted = 0;\n executedOperations = [];\n } else {\n const applyResult = await this.applyPlan(driver, options);\n if (!applyResult.ok) return applyResult;\n operationsExecuted = applyResult.value.operationsExecuted;\n executedOperations = applyResult.value.executedOperations;\n }\n\n if (space === APP_SPACE_ID) {\n const schemaIR = await this.family.introspect({\n driver,\n contract: options.destinationContract,\n });\n\n const schemaVerifyResult = verifySqlSchema({\n contract: options.destinationContract,\n schema: schemaIR,\n strict: options.strictVerification ?? true,\n context: options.context ?? {},\n typeMetadataRegistry: this.family.typeMetadataRegistry,\n frameworkComponents: options.frameworkComponents,\n normalizeDefault: parseSqliteDefault,\n normalizeNativeType: normalizeSqliteNativeType,\n });\n if (!schemaVerifyResult.ok) {\n return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {\n why: 'The resulting database schema does not satisfy the destination contract.',\n meta: { issues: schemaVerifyResult.schema.issues },\n });\n }\n }\n\n // Self-edge no-op detection: see Postgres runner for the rationale\n // (kept symmetric across both targets).\n const incomingInvariants = options.plan.providedInvariants;\n const existingInvariants = new Set(existingMarker?.invariants ?? []);\n const incomingIsSubsetOfExisting = incomingInvariants.every((id) => existingInvariants.has(id));\n const isSelfEdgeNoOp = isSelfEdge && operationsExecuted === 0 && incomingIsSubsetOfExisting;\n\n if (!isSelfEdgeNoOp) {\n await this.upsertMarker(driver, options, existingMarker, space);\n await this.recordLedgerEntry(driver, options, existingMarker, executedOperations);\n }\n\n return runnerSuccess({\n operationsPlanned: options.plan.operations.length,\n operationsExecuted,\n });\n }\n\n async executeAcrossSpaces(options: {\n readonly driver: ControlDriverInstance<'sql', string>;\n readonly perSpaceOptions: ReadonlyArray<\n SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>\n >;\n }): Promise<MultiSpaceRunnerResult> {\n const driver = options.driver;\n const perSpaceOptions = options.perSpaceOptions;\n\n if (perSpaceOptions.length === 0) {\n return ok({ perSpaceResults: [] });\n }\n\n // FK pragma toggle and the FK integrity check both span the outer\n // transaction — see `execute(...)` for the full rationale.\n const fkWasEnabled = await this.readForeignKeysEnabled(driver);\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = OFF');\n }\n\n try {\n await this.beginExclusiveTransaction(driver);\n let committed = false;\n try {\n const perSpaceResults: Array<{\n space: string;\n value: SqlMigrationRunnerSuccessValue;\n }> = [];\n let lastProcessedSpace: string | undefined;\n for (const spaceOptions of perSpaceOptions) {\n const space = spaceOptions.space ?? spaceOptions.plan.spaceId;\n const result = await this.executeOnConnection({ ...spaceOptions, driver, space });\n if (!result.ok) {\n return notOk({ ...result.failure, failingSpace: space });\n }\n perSpaceResults.push({ space, value: result.value });\n lastProcessedSpace = space;\n }\n\n if (fkWasEnabled) {\n const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);\n if (!fkIntegrityCheck.ok) {\n // Post-loop integrity violations cannot be attributed to a\n // single per-space step (the cumulative effect of all\n // applied plans was needed to reveal the broken\n // reference). Surface the last successfully-applied space\n // so operators can investigate from the most recent\n // migration first.\n return notOk({\n ...fkIntegrityCheck.failure,\n failingSpace: lastProcessedSpace ?? APP_SPACE_ID,\n });\n }\n }\n\n await this.commitTransaction(driver);\n committed = true;\n return ok({ perSpaceResults });\n } finally {\n if (!committed) {\n await this.rollbackTransaction(driver);\n }\n }\n } finally {\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = ON');\n }\n }\n }\n\n private async readForeignKeysEnabled(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<boolean> {\n const result = await driver.query<{ foreign_keys: number }>('PRAGMA foreign_keys');\n const row = result.rows[0];\n return row?.foreign_keys === 1;\n }\n\n private async verifyForeignKeyIntegrity(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n const result = await driver.query<Record<string, unknown>>('PRAGMA foreign_key_check');\n if (result.rows.length === 0) {\n return okVoid();\n }\n return runnerFailure(\n 'FOREIGN_KEY_VIOLATION',\n `Foreign key integrity check failed after migration: ${result.rows.length} violation(s).`,\n {\n why: 'PRAGMA foreign_key_check reported violations after applying recreate-table operations.',\n meta: { violations: result.rows },\n },\n );\n }\n\n private async applyPlan(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<\n Result<\n {\n readonly operationsExecuted: number;\n readonly executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[];\n },\n SqlMigrationRunnerFailure\n >\n > {\n const checks = options.executionChecks;\n const runPrechecks = checks?.prechecks !== false;\n const runPostchecks = checks?.postchecks !== false;\n const runIdempotency = checks?.idempotencyChecks !== false;\n\n let operationsExecuted = 0;\n const executedOperations: Array<SqlMigrationPlanOperation<SqlitePlanTargetDetails>> = [];\n\n for (const operation of options.plan.operations) {\n options.callbacks?.onOperationStart?.(operation);\n try {\n if (runPostchecks && runIdempotency) {\n const postcheckAlreadySatisfied = await this.expectationsAreSatisfied(\n driver,\n operation.postcheck,\n );\n if (postcheckAlreadySatisfied) {\n executedOperations.push(this.createSkipRecord(operation));\n continue;\n }\n }\n\n if (runPrechecks) {\n const precheckResult = await this.runExpectationSteps(\n driver,\n operation.precheck,\n operation,\n 'precheck',\n );\n if (!precheckResult.ok) {\n return precheckResult;\n }\n }\n\n const executeResult = await this.runExecuteSteps(driver, operation.execute, operation);\n if (!executeResult.ok) {\n return executeResult;\n }\n\n if (runPostchecks) {\n const postcheckResult = await this.runExpectationSteps(\n driver,\n operation.postcheck,\n operation,\n 'postcheck',\n );\n if (!postcheckResult.ok) {\n return postcheckResult;\n }\n }\n\n executedOperations.push(operation);\n operationsExecuted += 1;\n } finally {\n options.callbacks?.onOperationComplete?.(operation);\n }\n }\n return ok({ operationsExecuted, executedOperations });\n }\n\n private async ensureControlTables(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n // Pre-1.0 zero-range guardrail: detect a pre-cleanup single-row\n // marker table (no `space` column) and surface a structured failure\n // rather than silently rebuilding the table into the per-space\n // shape. See `specs/framework-mechanism.spec.md § 2`.\n const legacyDetection = await this.detectLegacyMarkerShape(driver);\n if (!legacyDetection.ok) {\n return legacyDetection;\n }\n await this.executeStatement(driver, ensureMarkerTableStatement);\n await this.executeStatement(driver, ensureLedgerTableStatement);\n return okVoid();\n }\n\n private async detectLegacyMarkerShape(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n const tableInfo = await driver.query<{ name: string }>(\n `PRAGMA table_info(\"${MARKER_TABLE_NAME}\")`,\n );\n if (tableInfo.rows.length === 0) {\n return okVoid();\n }\n const columns = new Set(tableInfo.rows.map((row) => row.name));\n if (columns.has('space')) {\n return okVoid();\n }\n return runnerFailure(\n 'LEGACY_MARKER_SHAPE',\n `Legacy marker-table shape detected on ${MARKER_TABLE_NAME} (no \\`space\\` column). ` +\n 'Prisma Next is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. ' +\n `Drop \\`${MARKER_TABLE_NAME}\\` and re-run \\`dbInit\\` to reinitialise from a clean baseline.`,\n {\n meta: {\n table: MARKER_TABLE_NAME,\n columns: [...columns].sort(),\n },\n },\n );\n }\n\n private async readMarker(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n space: string,\n ): Promise<ContractMarkerRecord | null> {\n const stmt = readMarkerStatement(space);\n try {\n const result = await driver.query<ContractMarkerRow>(stmt.sql, stmt.params);\n const row = result.rows[0];\n if (!row) return null;\n // SQLite stores arrays as JSON-encoded TEXT (no native array type), so\n // the driver returns `invariants` as a string. Decode before delegating\n // to the shared row schema, which expects `string[]`.\n const invariants =\n typeof row.invariants === 'string'\n ? (JSON.parse(row.invariants) as unknown)\n : row.invariants;\n return parseContractMarkerRow({ ...row, invariants });\n } catch (error) {\n // Table might not exist yet\n if (error instanceof Error && error.message.includes('no such table')) {\n return null;\n }\n throw error;\n }\n }\n\n private async runExpectationSteps(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n phase: 'precheck' | 'postcheck',\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n const result = await driver.query(step.sql, step.params ?? []);\n if (!this.stepResultIsTrue(result.rows)) {\n const code = phase === 'precheck' ? 'PRECHECK_FAILED' : 'POSTCHECK_FAILED';\n return runnerFailure(\n code,\n `Operation ${operation.id} failed during ${phase}: ${step.description}`,\n {\n meta: {\n operationId: operation.id,\n phase,\n stepDescription: step.description,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private async runExecuteSteps(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n try {\n await driver.query(step.sql, step.params ?? []);\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return runnerFailure(\n 'EXECUTION_FAILED',\n `Operation ${operation.id} failed during execution: ${step.description}`,\n {\n why: message,\n meta: {\n operationId: operation.id,\n stepDescription: step.description,\n sql: step.sql,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private stepResultIsTrue(rows: readonly Record<string, unknown>[]): boolean {\n if (!rows || rows.length === 0) {\n return false;\n }\n const firstRow = rows[0];\n const firstValue = firstRow ? Object.values(firstRow)[0] : undefined;\n if (typeof firstValue === 'number') {\n return firstValue !== 0;\n }\n if (typeof firstValue === 'boolean') {\n return firstValue;\n }\n if (typeof firstValue === 'string') {\n const lower = firstValue.toLowerCase();\n if (lower === 'true' || lower === '1') return true;\n if (lower === 'false' || lower === '0') return false;\n return firstValue.length > 0;\n }\n return Boolean(firstValue);\n }\n\n private async expectationsAreSatisfied(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n ): Promise<boolean> {\n if (steps.length === 0) {\n return false;\n }\n for (const step of steps) {\n const result = await driver.query(step.sql, step.params ?? []);\n if (!this.stepResultIsTrue(result.rows)) {\n return false;\n }\n }\n return true;\n }\n\n private createSkipRecord(\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n ): SqlMigrationPlanOperation<SqlitePlanTargetDetails> {\n return Object.freeze({\n id: operation.id,\n label: operation.label,\n ...ifDefined('summary', operation.summary),\n operationClass: operation.operationClass,\n target: operation.target,\n precheck: Object.freeze([]),\n execute: Object.freeze([]),\n postcheck: Object.freeze([...operation.postcheck]),\n meta: Object.freeze({\n ...(operation.meta ?? {}),\n runner: Object.freeze({ skipped: true, reason: 'postcheck_pre_satisfied' }),\n }),\n });\n }\n\n private markerMatchesDestination(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['plan'],\n ): boolean {\n if (!marker) return false;\n if (marker.storageHash !== plan.destination.storageHash) return false;\n if (plan.destination.profileHash && marker.profileHash !== plan.destination.profileHash) {\n return false;\n }\n return true;\n }\n\n private enforcePolicyCompatibility(\n policy: MigrationOperationPolicy,\n operations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[],\n ): Result<void, SqlMigrationRunnerFailure> {\n const allowedClasses = new Set(policy.allowedOperationClasses);\n for (const operation of operations) {\n if (!allowedClasses.has(operation.operationClass)) {\n return runnerFailure(\n 'POLICY_VIOLATION',\n `Operation ${operation.id} has class \"${operation.operationClass}\" which is not allowed by policy.`,\n {\n why: `Policy only allows: ${policy.allowedOperationClasses.join(', ')}.`,\n meta: {\n operationId: operation.id,\n operationClass: operation.operationClass,\n allowedClasses: policy.allowedOperationClasses,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private ensureMarkerCompatibility(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['plan'],\n ): Result<void, SqlMigrationRunnerFailure> {\n const origin = plan.origin ?? null;\n if (!origin) {\n return okVoid();\n }\n if (!marker) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Missing contract marker: expected origin storage hash ${origin.storageHash}.`,\n { meta: { expectedOriginStorageHash: origin.storageHash } },\n );\n }\n if (marker.storageHash !== origin.storageHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker (${marker.storageHash}) does not match plan origin (${origin.storageHash}).`,\n {\n meta: {\n markerStorageHash: marker.storageHash,\n expectedOriginStorageHash: origin.storageHash,\n },\n },\n );\n }\n if (origin.profileHash && marker.profileHash !== origin.profileHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker profile hash (${marker.profileHash}) does not match plan origin profile hash (${origin.profileHash}).`,\n {\n meta: {\n markerProfileHash: marker.profileHash,\n expectedOriginProfileHash: origin.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private ensurePlanMatchesDestinationContract(\n destination: SqlMigrationPlanContractInfo,\n contract: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['destinationContract'],\n ): Result<void, SqlMigrationRunnerFailure> {\n if (destination.storageHash !== contract.storage.storageHash) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination storage hash (${destination.storageHash}) does not match provided contract storage hash (${contract.storage.storageHash}).`,\n {\n meta: {\n planStorageHash: destination.storageHash,\n contractStorageHash: contract.storage.storageHash,\n },\n },\n );\n }\n if (\n destination.profileHash &&\n contract.profileHash &&\n destination.profileHash !== contract.profileHash\n ) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination profile hash (${destination.profileHash}) does not match provided contract profile hash (${contract.profileHash}).`,\n {\n meta: {\n planProfileHash: destination.profileHash,\n contractProfileHash: contract.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private async upsertMarker(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n space: string,\n ): Promise<void> {\n // SQLite has no native array type, so we can't merge invariants in SQL\n // the way Postgres does. Merge client-side under the runner's\n // BEGIN EXCLUSIVE — sort + dedupe so the JSON-encoded value is stable.\n const merged = new Set<string>(existingMarker?.invariants ?? []);\n for (const inv of options.plan.providedInvariants) merged.add(inv);\n const invariants = Array.from(merged).sort();\n const writeStatements = buildWriteMarkerStatements({\n space,\n storageHash: options.plan.destination.storageHash,\n profileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.storageHash,\n contractJson: options.destinationContract,\n canonicalVersion: null,\n meta: {},\n invariants,\n });\n const statement = existingMarker ? writeStatements.update : writeStatements.insert;\n await this.executeStatement(driver, statement);\n }\n\n private async recordLedgerEntry(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[],\n ): Promise<void> {\n const ledgerStatement = buildLedgerInsertStatement({\n originStorageHash: existingMarker?.storageHash ?? null,\n originProfileHash: existingMarker?.profileHash ?? null,\n destinationStorageHash: options.plan.destination.storageHash,\n destinationProfileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.storageHash,\n contractJsonBefore: existingMarker?.contractJson ?? null,\n contractJsonAfter: options.destinationContract,\n operations: executedOperations,\n });\n await this.executeStatement(driver, ledgerStatement);\n }\n\n private async beginExclusiveTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('BEGIN EXCLUSIVE');\n }\n\n private async commitTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('COMMIT');\n }\n\n private async rollbackTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('ROLLBACK');\n }\n\n private async executeStatement(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n statement: SqlStatement,\n ): Promise<void> {\n if (statement.params.length > 0) {\n await driver.query(statement.sql, statement.params);\n return;\n }\n await driver.query(statement.sql);\n }\n}\n","import type { ColumnDefault, Contract } from '@prisma-next/contract/types';\nimport type {\n SqlControlFamilyInstance,\n SqlControlTargetDescriptor,\n} from '@prisma-next/family-sql/control';\nimport { contractToSchemaIR } from '@prisma-next/family-sql/control';\nimport type {\n ControlTargetInstance,\n MigrationPlanner,\n MigrationRunner,\n} from '@prisma-next/framework-components/control';\nimport type { SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';\nimport { sqliteTargetDescriptorMeta } from './descriptor-meta';\nimport { createSqliteMigrationPlanner } from './migrations/planner';\nimport { renderDefaultLiteral } from './migrations/planner-ddl-builders';\nimport type { SqlitePlanTargetDetails } from './migrations/planner-target-details';\nimport { createSqliteMigrationRunner } from './migrations/runner';\n\nfunction sqliteRenderDefault(def: ColumnDefault, _column: StorageColumn): string {\n if (def.kind === 'function') {\n if (def.expression === 'now()') {\n return \"datetime('now')\";\n }\n return def.expression;\n }\n return renderDefaultLiteral(def.value);\n}\n\nconst sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', SqlitePlanTargetDetails> =\n {\n ...sqliteTargetDescriptorMeta,\n migrations: {\n createPlanner(_family: SqlControlFamilyInstance): MigrationPlanner<'sql', 'sqlite'> {\n return createSqliteMigrationPlanner();\n },\n createRunner(family) {\n return createSqliteMigrationRunner(family) as MigrationRunner<'sql', 'sqlite'>;\n },\n contractToSchema(contract, frameworkComponents) {\n return contractToSchemaIR(contract as Contract<SqlStorage> | null, {\n annotationNamespace: 'sqlite',\n renderDefault: sqliteRenderDefault,\n frameworkComponents: frameworkComponents ?? [],\n });\n },\n },\n create(): ControlTargetInstance<'sql', 'sqlite'> {\n return {\n familyId: 'sql',\n targetId: 'sqlite',\n };\n },\n createPlanner(_family: SqlControlFamilyInstance) {\n return createSqliteMigrationPlanner();\n },\n createRunner(family) {\n return createSqliteMigrationRunner(family);\n },\n };\n\nexport default sqliteControlTargetDescriptor;\n"],"mappings":"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"}
|
package/dist/migration.d.mts
CHANGED
|
@@ -37,6 +37,16 @@ declare function dataTransform(opts: DataTransformOptions): Op;
|
|
|
37
37
|
declare function createIndex(tableName: string, indexName: string, columns: readonly string[]): Op;
|
|
38
38
|
declare function dropIndex(tableName: string, indexName: string): Op;
|
|
39
39
|
//#endregion
|
|
40
|
+
//#region src/core/migrations/operations/raw.d.ts
|
|
41
|
+
/**
|
|
42
|
+
* Identity factory for an already-materialized
|
|
43
|
+
* `SqlMigrationPlanOperation<SqlitePlanTargetDetails>`. Mirrors the Postgres
|
|
44
|
+
* `rawSql` factory: the planner uses this to carry ops produced by SQL-family
|
|
45
|
+
* paths (codec lifecycle hooks, raw-SQL escape hatches) alongside structured
|
|
46
|
+
* call IR without reverse-engineering their shape.
|
|
47
|
+
*/
|
|
48
|
+
declare function rawSql(op: Op): Op;
|
|
49
|
+
//#endregion
|
|
40
50
|
//#region src/core/migrations/operations/tables.d.ts
|
|
41
51
|
declare function createTable(tableName: string, spec: SqliteTableSpec): Op;
|
|
42
52
|
declare function dropTable(tableName: string): Op;
|
|
@@ -71,5 +81,5 @@ interface RecreateTableArgs {
|
|
|
71
81
|
}
|
|
72
82
|
declare function recreateTable(args: RecreateTableArgs): Op;
|
|
73
83
|
//#endregion
|
|
74
|
-
export { type DataTransformOptions, SqliteMigration as Migration, MigrationCLI, addColumn, createIndex, createTable, dataTransform, dropColumn, dropIndex, dropTable, placeholder, recreateTable };
|
|
84
|
+
export { type DataTransformOptions, SqliteMigration as Migration, MigrationCLI, addColumn, createIndex, createTable, dataTransform, dropColumn, dropIndex, dropTable, placeholder, rawSql, recreateTable };
|
|
75
85
|
//# sourceMappingURL=migration.d.mts.map
|
package/dist/migration.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration.d.mts","names":[],"sources":["../src/core/migrations/operations/columns.ts","../src/core/migrations/operations/data-transform.ts","../src/core/migrations/operations/indexes.ts","../src/core/migrations/operations/tables.ts"],"mappings":";;;;;;;iBAIgB,SAAA,CAAU,SAAA,UAAmB,MAAA,EAAQ,gBAAA,GAAmB,EAAA;AAAA,iBA+BxD,UAAA,CAAW,SAAA,UAAmB,UAAA,WAAqB,EAAA;;;UCnBlD,oBAAA;EDZ4B;EAAA,SCclC,EAAA;EDd+D;EAAA,SCgB/D,KAAA;EDeK;EAAA,SCbL,KAAA;;;;;WAKA,WAAA;EDQ0D;;;;;ACnBrE;;;EDmBqE,SCC1D,GAAA;AAAA;AAAA,iBAGK,aAAA,CAAc,IAAA,EAAM,oBAAA,GAAuB,EAAA;;;iBClC3C,WAAA,CAAY,SAAA,UAAmB,SAAA,UAAmB,OAAA,sBAA6B,EAAA;AAAA,iBAyB/E,SAAA,CAAU,SAAA,UAAmB,SAAA,WAAoB,EAAA;;;
|
|
1
|
+
{"version":3,"file":"migration.d.mts","names":[],"sources":["../src/core/migrations/operations/columns.ts","../src/core/migrations/operations/data-transform.ts","../src/core/migrations/operations/indexes.ts","../src/core/migrations/operations/raw.ts","../src/core/migrations/operations/tables.ts"],"mappings":";;;;;;;iBAIgB,SAAA,CAAU,SAAA,UAAmB,MAAA,EAAQ,gBAAA,GAAmB,EAAA;AAAA,iBA+BxD,UAAA,CAAW,SAAA,UAAmB,UAAA,WAAqB,EAAA;;;UCnBlD,oBAAA;EDZ4B;EAAA,SCclC,EAAA;EDd+D;EAAA,SCgB/D,KAAA;EDeK;EAAA,SCbL,KAAA;;;;;WAKA,WAAA;EDQ0D;;;;;ACnBrE;;;EDmBqE,SCC1D,GAAA;AAAA;AAAA,iBAGK,aAAA,CAAc,IAAA,EAAM,oBAAA,GAAuB,EAAA;;;iBClC3C,WAAA,CAAY,SAAA,UAAmB,SAAA,UAAmB,OAAA,sBAA6B,EAAA;AAAA,iBAyB/E,SAAA,CAAU,SAAA,UAAmB,SAAA,WAAoB,EAAA;;;;;;;;;;iBCrBjD,MAAA,CAAO,EAAA,EAAI,EAAA,GAAK,EAAA;;;iBCmChB,WAAA,CAAY,SAAA,UAAmB,IAAA,EAAM,eAAA,GAAkB,EAAA;AAAA,iBAuBvD,SAAA,CAAU,SAAA,WAAoB,EAAA;AAAA,UAuB7B,iBAAA;EAAA,SACN,SAAA;;WAEA,aAAA,EAAe,eAAA;EJzFD;;;;;;EAAA,SIgGd,iBAAA;EJhG+D;;AA+B1E;;EA/B0E,SIqG/D,OAAA,WAAkB,eAAA;EJtEwC;EAAA,SIwE1D,OAAA;EJxEmC;;;;;EAAA,SI8EnC,UAAA;IAAA,SAAgC,WAAA;IAAA,SAA8B,GAAA;EAAA;EAAA,SAC9D,cAAA,EAAgB,uBAAA;AAAA;AAAA,iBAGX,aAAA,CAAc,IAAA,EAAM,iBAAA,GAAoB,EAAA"}
|
package/dist/migration.mjs
CHANGED
|
@@ -32,6 +32,18 @@ function dataTransform(opts) {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
//#endregion
|
|
35
|
-
|
|
35
|
+
//#region src/core/migrations/operations/raw.ts
|
|
36
|
+
/**
|
|
37
|
+
* Identity factory for an already-materialized
|
|
38
|
+
* `SqlMigrationPlanOperation<SqlitePlanTargetDetails>`. Mirrors the Postgres
|
|
39
|
+
* `rawSql` factory: the planner uses this to carry ops produced by SQL-family
|
|
40
|
+
* paths (codec lifecycle hooks, raw-SQL escape hatches) alongside structured
|
|
41
|
+
* call IR without reverse-engineering their shape.
|
|
42
|
+
*/
|
|
43
|
+
function rawSql(op) {
|
|
44
|
+
return op;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { SqliteMigration as Migration, MigrationCLI, addColumn, createIndex, createTable, dataTransform, dropColumn, dropIndex, dropTable, placeholder, rawSql, recreateTable };
|
|
36
48
|
|
|
37
49
|
//# sourceMappingURL=migration.mjs.map
|
package/dist/migration.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration.mjs","names":[],"sources":["../src/core/migrations/operations/data-transform.ts"],"sourcesContent":["/**\n * User-facing `dataTransform` factory for the SQLite migration authoring\n * surface. Invoked directly inside a `migration.ts` file to supply a\n * user-authored SQL statement that runs with operation class `'data'`.\n *\n * Typical use: the planner emits a `DataTransformCall` stub when a NOT NULL\n * tightening requires a backfill. The rendered `migration.ts` exposes the\n * backfill as a `placeholder(\"…\")` slot the user fills in with an\n * `UPDATE … WHERE col IS NULL` statement. The filled-in `dataTransform(...)`\n * invocation returns a runnable operation the runner executes before the\n * subsequent recreate-table op copies data into the tightened schema.\n */\n\nimport { buildTargetDetails } from '../planner-target-details';\nimport { type Op, step } from './shared';\n\nexport interface DataTransformOptions {\n /** Stable id used in the ledger / for runner idempotency tracking. */\n readonly id: string;\n /** Human-readable label surfaced in CLI output. */\n readonly label: string;\n /** Table the backfill targets; informs `target.details`. */\n readonly table: string;\n /**\n * Short description of the step (shown by the runner on execute). The\n * planner leaves this as `placeholder(...)` for users to replace.\n */\n readonly description: string;\n /**\n * Producer of the SQL string to execute. Invoked eagerly by\n * `dataTransform(...)`, mirroring the Postgres factory — by the time the\n * user calls this factory in `migration.ts`, the SQL is expected to be\n * ready. Planner-emitted stubs that need to defer until the user fills\n * in the SQL go through `DataTransformCall.renderTypeScript()` instead;\n * this factory is only for the post-fill, runnable form.\n */\n readonly run: () => string;\n}\n\nexport function dataTransform(opts: DataTransformOptions): Op {\n return {\n id: opts.id,\n label: opts.label,\n summary: opts.description,\n operationClass: 'data',\n target: { id: 'sqlite', details: buildTargetDetails('table', opts.table) },\n precheck: [],\n execute: [step(opts.description, opts.run())],\n postcheck: [],\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuCA,SAAgB,cAAc,MAAgC;CAC5D,OAAO;EACL,IAAI,KAAK;EACT,OAAO,KAAK;EACZ,SAAS,KAAK;EACd,gBAAgB;EAChB,QAAQ;GAAE,IAAI;GAAU,SAAS,mBAAmB,SAAS,KAAK,MAAM;GAAE;EAC1E,UAAU,EAAE;EACZ,SAAS,CAAC,KAAK,KAAK,aAAa,KAAK,KAAK,CAAC,CAAC;EAC7C,WAAW,EAAE;EACd"}
|
|
1
|
+
{"version":3,"file":"migration.mjs","names":[],"sources":["../src/core/migrations/operations/data-transform.ts","../src/core/migrations/operations/raw.ts"],"sourcesContent":["/**\n * User-facing `dataTransform` factory for the SQLite migration authoring\n * surface. Invoked directly inside a `migration.ts` file to supply a\n * user-authored SQL statement that runs with operation class `'data'`.\n *\n * Typical use: the planner emits a `DataTransformCall` stub when a NOT NULL\n * tightening requires a backfill. The rendered `migration.ts` exposes the\n * backfill as a `placeholder(\"…\")` slot the user fills in with an\n * `UPDATE … WHERE col IS NULL` statement. The filled-in `dataTransform(...)`\n * invocation returns a runnable operation the runner executes before the\n * subsequent recreate-table op copies data into the tightened schema.\n */\n\nimport { buildTargetDetails } from '../planner-target-details';\nimport { type Op, step } from './shared';\n\nexport interface DataTransformOptions {\n /** Stable id used in the ledger / for runner idempotency tracking. */\n readonly id: string;\n /** Human-readable label surfaced in CLI output. */\n readonly label: string;\n /** Table the backfill targets; informs `target.details`. */\n readonly table: string;\n /**\n * Short description of the step (shown by the runner on execute). The\n * planner leaves this as `placeholder(...)` for users to replace.\n */\n readonly description: string;\n /**\n * Producer of the SQL string to execute. Invoked eagerly by\n * `dataTransform(...)`, mirroring the Postgres factory — by the time the\n * user calls this factory in `migration.ts`, the SQL is expected to be\n * ready. Planner-emitted stubs that need to defer until the user fills\n * in the SQL go through `DataTransformCall.renderTypeScript()` instead;\n * this factory is only for the post-fill, runnable form.\n */\n readonly run: () => string;\n}\n\nexport function dataTransform(opts: DataTransformOptions): Op {\n return {\n id: opts.id,\n label: opts.label,\n summary: opts.description,\n operationClass: 'data',\n target: { id: 'sqlite', details: buildTargetDetails('table', opts.table) },\n precheck: [],\n execute: [step(opts.description, opts.run())],\n postcheck: [],\n };\n}\n","import type { Op } from './shared';\n\n/**\n * Identity factory for an already-materialized\n * `SqlMigrationPlanOperation<SqlitePlanTargetDetails>`. Mirrors the Postgres\n * `rawSql` factory: the planner uses this to carry ops produced by SQL-family\n * paths (codec lifecycle hooks, raw-SQL escape hatches) alongside structured\n * call IR without reverse-engineering their shape.\n */\nexport function rawSql(op: Op): Op {\n return op;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuCA,SAAgB,cAAc,MAAgC;CAC5D,OAAO;EACL,IAAI,KAAK;EACT,OAAO,KAAK;EACZ,SAAS,KAAK;EACd,gBAAgB;EAChB,QAAQ;GAAE,IAAI;GAAU,SAAS,mBAAmB,SAAS,KAAK,MAAM;GAAE;EAC1E,UAAU,EAAE;EACZ,SAAS,CAAC,KAAK,KAAK,aAAa,KAAK,KAAK,CAAC,CAAC;EAC7C,WAAW,EAAE;EACd;;;;;;;;;;;ACxCH,SAAgB,OAAO,IAAY;CACjC,OAAO"}
|
|
@@ -245,7 +245,35 @@ var DataTransformCall = class extends SqliteOpFactoryCallNode {
|
|
|
245
245
|
}];
|
|
246
246
|
}
|
|
247
247
|
};
|
|
248
|
+
/**
|
|
249
|
+
* Laundered pre-built operation. Mirrors Postgres's `RawSqlCall`: wraps an
|
|
250
|
+
* already-materialized `SqlMigrationPlanOperation` (typically produced by a
|
|
251
|
+
* SQL-family helper or a codec lifecycle hook) so the planner can carry it
|
|
252
|
+
* alongside structured call IR. `toOp()` returns the stored op unchanged;
|
|
253
|
+
* `renderTypeScript()` emits `rawSql({...})` with the op serialized as a
|
|
254
|
+
* JSON literal — round-tripping requires every field on the op to be
|
|
255
|
+
* JSON-serializable (no closures).
|
|
256
|
+
*/
|
|
257
|
+
var RawSqlCall = class extends SqliteOpFactoryCallNode {
|
|
258
|
+
factoryName = "rawSql";
|
|
259
|
+
operationClass;
|
|
260
|
+
label;
|
|
261
|
+
op;
|
|
262
|
+
constructor(op) {
|
|
263
|
+
super();
|
|
264
|
+
this.op = op;
|
|
265
|
+
this.label = op.label;
|
|
266
|
+
this.operationClass = op.operationClass;
|
|
267
|
+
this.freeze();
|
|
268
|
+
}
|
|
269
|
+
toOp() {
|
|
270
|
+
return this.op;
|
|
271
|
+
}
|
|
272
|
+
renderTypeScript() {
|
|
273
|
+
return `rawSql(${jsonToTsSource(this.op)})`;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
248
276
|
//#endregion
|
|
249
|
-
export { DropColumnCall as a,
|
|
277
|
+
export { DropColumnCall as a, RawSqlCall as c, DataTransformCall as i, RecreateTableCall as l, CreateIndexCall as n, DropIndexCall as o, CreateTableCall as r, DropTableCall as s, AddColumnCall as t };
|
|
250
278
|
|
|
251
|
-
//# sourceMappingURL=op-factory-call-
|
|
279
|
+
//# sourceMappingURL=op-factory-call-DRKKURAO.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"op-factory-call-DvewDQ7a.mjs","names":[],"sources":["../src/core/migrations/op-factory-call.ts"],"sourcesContent":["/**\n * SQLite migration IR: one concrete `*Call` class per pure factory under\n * `operations/`, plus a shared `SqliteOpFactoryCallNode` abstract base.\n *\n * Each call class carries fully-resolved literal arguments (flat\n * `SqliteColumnSpec` / `SqliteTableSpec` etc.) — codec / `typeRef` / default\n * expansion happens upstream in the issue-planner / strategies, mirroring\n * the Postgres `ColumnSpec` pattern. As a result, `toOp()` and\n * `renderTypeScript()` both pass the same flat data through; the rendered\n * TypeScript scaffold is fully self-contained and does not need access to a\n * `storageTypes` map at runtime.\n */\n\nimport { errorUnfilledPlaceholder } from '@prisma-next/errors/migration';\nimport type {\n MigrationOperationClass,\n SqlMigrationPlanOperation,\n} from '@prisma-next/family-sql/control';\nimport type { OpFactoryCall as FrameworkOpFactoryCall } from '@prisma-next/framework-components/control';\nimport { type ImportRequirement, jsonToTsSource, TsExpression } from '@prisma-next/ts-render';\nimport { addColumn, dropColumn } from './operations/columns';\nimport { createIndex, dropIndex } from './operations/indexes';\nimport type { SqliteColumnSpec, SqliteIndexSpec, SqliteTableSpec } from './operations/shared';\nimport { createTable, dropTable, recreateTable } from './operations/tables';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\n\ntype Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;\n\nconst TARGET_MIGRATION_MODULE = '@prisma-next/target-sqlite/migration';\n\nabstract class SqliteOpFactoryCallNode extends TsExpression implements FrameworkOpFactoryCall {\n abstract readonly factoryName: string;\n abstract readonly operationClass: MigrationOperationClass;\n abstract readonly label: string;\n abstract toOp(): Op;\n\n importRequirements(): readonly ImportRequirement[] {\n return [{ moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: this.factoryName }];\n }\n\n protected freeze(): void {\n Object.freeze(this);\n }\n}\n\n// ============================================================================\n// Table\n// ============================================================================\n\nexport class CreateTableCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'createTable' as const;\n readonly operationClass = 'additive' as const;\n readonly tableName: string;\n readonly spec: SqliteTableSpec;\n readonly label: string;\n\n constructor(tableName: string, spec: SqliteTableSpec) {\n super();\n this.tableName = tableName;\n this.spec = spec;\n this.label = `Create table ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return createTable(this.tableName, this.spec);\n }\n\n renderTypeScript(): string {\n return `createTable(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.spec)})`;\n }\n}\n\nexport class DropTableCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dropTable' as const;\n readonly operationClass = 'destructive' as const;\n readonly tableName: string;\n readonly label: string;\n\n constructor(tableName: string) {\n super();\n this.tableName = tableName;\n this.label = `Drop table ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return dropTable(this.tableName);\n }\n\n renderTypeScript(): string {\n return `dropTable(${jsonToTsSource(this.tableName)})`;\n }\n}\n\nexport class RecreateTableCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'recreateTable' as const;\n readonly operationClass: MigrationOperationClass;\n readonly tableName: string;\n readonly contractTable: SqliteTableSpec;\n readonly schemaColumnNames: readonly string[];\n readonly indexes: readonly SqliteIndexSpec[];\n readonly summary: string;\n readonly postchecks: readonly { readonly description: string; readonly sql: string }[];\n readonly label: string;\n\n constructor(args: {\n tableName: string;\n contractTable: SqliteTableSpec;\n schemaColumnNames: readonly string[];\n indexes: readonly SqliteIndexSpec[];\n summary: string;\n postchecks: readonly { readonly description: string; readonly sql: string }[];\n operationClass: MigrationOperationClass;\n }) {\n super();\n this.tableName = args.tableName;\n this.contractTable = args.contractTable;\n this.schemaColumnNames = args.schemaColumnNames;\n this.indexes = args.indexes;\n this.summary = args.summary;\n this.postchecks = args.postchecks;\n this.operationClass = args.operationClass;\n this.label = `Recreate table ${args.tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return recreateTable({\n tableName: this.tableName,\n contractTable: this.contractTable,\n schemaColumnNames: this.schemaColumnNames,\n indexes: this.indexes,\n summary: this.summary,\n postchecks: this.postchecks,\n operationClass: this.operationClass,\n });\n }\n\n renderTypeScript(): string {\n const args = {\n tableName: this.tableName,\n contractTable: this.contractTable,\n schemaColumnNames: this.schemaColumnNames,\n indexes: this.indexes,\n summary: this.summary,\n postchecks: this.postchecks,\n operationClass: this.operationClass,\n };\n return `recreateTable(${jsonToTsSource(args)})`;\n }\n}\n\n// ============================================================================\n// Column\n// ============================================================================\n\nexport class AddColumnCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'addColumn' as const;\n readonly operationClass = 'additive' as const;\n readonly tableName: string;\n readonly columnName: string;\n readonly column: SqliteColumnSpec;\n readonly label: string;\n\n constructor(tableName: string, column: SqliteColumnSpec) {\n super();\n this.tableName = tableName;\n this.columnName = column.name;\n this.column = column;\n this.label = `Add column ${column.name} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return addColumn(this.tableName, this.column);\n }\n\n renderTypeScript(): string {\n return `addColumn(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.column)})`;\n }\n}\n\nexport class DropColumnCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dropColumn' as const;\n readonly operationClass = 'destructive' as const;\n readonly tableName: string;\n readonly columnName: string;\n readonly label: string;\n\n constructor(tableName: string, columnName: string) {\n super();\n this.tableName = tableName;\n this.columnName = columnName;\n this.label = `Drop column ${columnName} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return dropColumn(this.tableName, this.columnName);\n }\n\n renderTypeScript(): string {\n return `dropColumn(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.columnName)})`;\n }\n}\n\n// ============================================================================\n// Index\n// ============================================================================\n\nexport class CreateIndexCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'createIndex' as const;\n readonly operationClass = 'additive' as const;\n readonly tableName: string;\n readonly indexName: string;\n readonly columns: readonly string[];\n readonly label: string;\n\n constructor(tableName: string, indexName: string, columns: readonly string[]) {\n super();\n this.tableName = tableName;\n this.indexName = indexName;\n this.columns = columns;\n this.label = `Create index ${indexName} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return createIndex(this.tableName, this.indexName, this.columns);\n }\n\n renderTypeScript(): string {\n return `createIndex(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.indexName)}, ${jsonToTsSource(this.columns)})`;\n }\n}\n\nexport class DropIndexCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dropIndex' as const;\n readonly operationClass = 'destructive' as const;\n readonly tableName: string;\n readonly indexName: string;\n readonly label: string;\n\n constructor(tableName: string, indexName: string) {\n super();\n this.tableName = tableName;\n this.indexName = indexName;\n this.label = `Drop index ${indexName} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return dropIndex(this.tableName, this.indexName);\n }\n\n renderTypeScript(): string {\n return `dropIndex(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.indexName)})`;\n }\n}\n\n// ============================================================================\n// Data transform\n// ============================================================================\n\n/**\n * A planner-generated data-transform stub. The current default strategy\n * (`nullabilityTighteningBackfillStrategy`) emits one of these with a\n * backfill-flavored `id`/`label` when the policy allows `'data'` and the\n * contract tightens a column's nullability, but the op itself is generic —\n * any future strategy that needs a placeholder data step can construct one\n * with its own id/label.\n *\n * `toOp()` always throws `PN-MIG-2001`: the planner cannot lower a stubbed\n * transform to a runtime op — the user must edit the rendered\n * `migration.ts` and re-emit.\n */\nexport class DataTransformCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dataTransform' as const;\n readonly operationClass = 'data' as const;\n readonly id: string;\n readonly label: string;\n readonly tableName: string;\n readonly columnName: string;\n\n constructor(id: string, label: string, tableName: string, columnName: string) {\n super();\n this.id = id;\n this.label = label;\n this.tableName = tableName;\n this.columnName = columnName;\n this.freeze();\n }\n\n toOp(): Op {\n throw errorUnfilledPlaceholder(this.label);\n }\n\n renderTypeScript(): string {\n const slot = `${this.tableName}-${this.columnName}-backfill-sql`;\n return [\n 'dataTransform({',\n ` id: ${jsonToTsSource(this.id)},`,\n ` label: ${jsonToTsSource(this.label)},`,\n ` table: ${jsonToTsSource(this.tableName)},`,\n ` description: ${jsonToTsSource(`Backfill NULL ${this.columnName} values in ${this.tableName}`)},`,\n ` run: () => placeholder(${jsonToTsSource(slot)}),`,\n '})',\n ].join('\\n');\n }\n\n override importRequirements(): readonly ImportRequirement[] {\n return [\n { moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: this.factoryName },\n { moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: 'placeholder' },\n ];\n }\n}\n\n// ============================================================================\n// Union\n// ============================================================================\n\nexport type SqliteOpFactoryCall =\n | CreateTableCall\n | DropTableCall\n | RecreateTableCall\n | AddColumnCall\n | DropColumnCall\n | CreateIndexCall\n | DropIndexCall\n | DataTransformCall;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"op-factory-call-DRKKURAO.mjs","names":[],"sources":["../src/core/migrations/op-factory-call.ts"],"sourcesContent":["/**\n * SQLite migration IR: one concrete `*Call` class per pure factory under\n * `operations/`, plus a shared `SqliteOpFactoryCallNode` abstract base.\n *\n * Each call class carries fully-resolved literal arguments (flat\n * `SqliteColumnSpec` / `SqliteTableSpec` etc.) — codec / `typeRef` / default\n * expansion happens upstream in the issue-planner / strategies, mirroring\n * the Postgres `ColumnSpec` pattern. As a result, `toOp()` and\n * `renderTypeScript()` both pass the same flat data through; the rendered\n * TypeScript scaffold is fully self-contained and does not need access to a\n * `storageTypes` map at runtime.\n */\n\nimport { errorUnfilledPlaceholder } from '@prisma-next/errors/migration';\nimport type {\n MigrationOperationClass,\n SqlMigrationPlanOperation,\n} from '@prisma-next/family-sql/control';\nimport type { OpFactoryCall as FrameworkOpFactoryCall } from '@prisma-next/framework-components/control';\nimport { type ImportRequirement, jsonToTsSource, TsExpression } from '@prisma-next/ts-render';\nimport { addColumn, dropColumn } from './operations/columns';\nimport { createIndex, dropIndex } from './operations/indexes';\nimport type { SqliteColumnSpec, SqliteIndexSpec, SqliteTableSpec } from './operations/shared';\nimport { createTable, dropTable, recreateTable } from './operations/tables';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\n\ntype Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;\n\nconst TARGET_MIGRATION_MODULE = '@prisma-next/target-sqlite/migration';\n\nabstract class SqliteOpFactoryCallNode extends TsExpression implements FrameworkOpFactoryCall {\n abstract readonly factoryName: string;\n abstract readonly operationClass: MigrationOperationClass;\n abstract readonly label: string;\n abstract toOp(): Op;\n\n importRequirements(): readonly ImportRequirement[] {\n return [{ moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: this.factoryName }];\n }\n\n protected freeze(): void {\n Object.freeze(this);\n }\n}\n\n// ============================================================================\n// Table\n// ============================================================================\n\nexport class CreateTableCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'createTable' as const;\n readonly operationClass = 'additive' as const;\n readonly tableName: string;\n readonly spec: SqliteTableSpec;\n readonly label: string;\n\n constructor(tableName: string, spec: SqliteTableSpec) {\n super();\n this.tableName = tableName;\n this.spec = spec;\n this.label = `Create table ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return createTable(this.tableName, this.spec);\n }\n\n renderTypeScript(): string {\n return `createTable(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.spec)})`;\n }\n}\n\nexport class DropTableCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dropTable' as const;\n readonly operationClass = 'destructive' as const;\n readonly tableName: string;\n readonly label: string;\n\n constructor(tableName: string) {\n super();\n this.tableName = tableName;\n this.label = `Drop table ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return dropTable(this.tableName);\n }\n\n renderTypeScript(): string {\n return `dropTable(${jsonToTsSource(this.tableName)})`;\n }\n}\n\nexport class RecreateTableCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'recreateTable' as const;\n readonly operationClass: MigrationOperationClass;\n readonly tableName: string;\n readonly contractTable: SqliteTableSpec;\n readonly schemaColumnNames: readonly string[];\n readonly indexes: readonly SqliteIndexSpec[];\n readonly summary: string;\n readonly postchecks: readonly { readonly description: string; readonly sql: string }[];\n readonly label: string;\n\n constructor(args: {\n tableName: string;\n contractTable: SqliteTableSpec;\n schemaColumnNames: readonly string[];\n indexes: readonly SqliteIndexSpec[];\n summary: string;\n postchecks: readonly { readonly description: string; readonly sql: string }[];\n operationClass: MigrationOperationClass;\n }) {\n super();\n this.tableName = args.tableName;\n this.contractTable = args.contractTable;\n this.schemaColumnNames = args.schemaColumnNames;\n this.indexes = args.indexes;\n this.summary = args.summary;\n this.postchecks = args.postchecks;\n this.operationClass = args.operationClass;\n this.label = `Recreate table ${args.tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return recreateTable({\n tableName: this.tableName,\n contractTable: this.contractTable,\n schemaColumnNames: this.schemaColumnNames,\n indexes: this.indexes,\n summary: this.summary,\n postchecks: this.postchecks,\n operationClass: this.operationClass,\n });\n }\n\n renderTypeScript(): string {\n const args = {\n tableName: this.tableName,\n contractTable: this.contractTable,\n schemaColumnNames: this.schemaColumnNames,\n indexes: this.indexes,\n summary: this.summary,\n postchecks: this.postchecks,\n operationClass: this.operationClass,\n };\n return `recreateTable(${jsonToTsSource(args)})`;\n }\n}\n\n// ============================================================================\n// Column\n// ============================================================================\n\nexport class AddColumnCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'addColumn' as const;\n readonly operationClass = 'additive' as const;\n readonly tableName: string;\n readonly columnName: string;\n readonly column: SqliteColumnSpec;\n readonly label: string;\n\n constructor(tableName: string, column: SqliteColumnSpec) {\n super();\n this.tableName = tableName;\n this.columnName = column.name;\n this.column = column;\n this.label = `Add column ${column.name} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return addColumn(this.tableName, this.column);\n }\n\n renderTypeScript(): string {\n return `addColumn(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.column)})`;\n }\n}\n\nexport class DropColumnCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dropColumn' as const;\n readonly operationClass = 'destructive' as const;\n readonly tableName: string;\n readonly columnName: string;\n readonly label: string;\n\n constructor(tableName: string, columnName: string) {\n super();\n this.tableName = tableName;\n this.columnName = columnName;\n this.label = `Drop column ${columnName} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return dropColumn(this.tableName, this.columnName);\n }\n\n renderTypeScript(): string {\n return `dropColumn(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.columnName)})`;\n }\n}\n\n// ============================================================================\n// Index\n// ============================================================================\n\nexport class CreateIndexCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'createIndex' as const;\n readonly operationClass = 'additive' as const;\n readonly tableName: string;\n readonly indexName: string;\n readonly columns: readonly string[];\n readonly label: string;\n\n constructor(tableName: string, indexName: string, columns: readonly string[]) {\n super();\n this.tableName = tableName;\n this.indexName = indexName;\n this.columns = columns;\n this.label = `Create index ${indexName} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return createIndex(this.tableName, this.indexName, this.columns);\n }\n\n renderTypeScript(): string {\n return `createIndex(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.indexName)}, ${jsonToTsSource(this.columns)})`;\n }\n}\n\nexport class DropIndexCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dropIndex' as const;\n readonly operationClass = 'destructive' as const;\n readonly tableName: string;\n readonly indexName: string;\n readonly label: string;\n\n constructor(tableName: string, indexName: string) {\n super();\n this.tableName = tableName;\n this.indexName = indexName;\n this.label = `Drop index ${indexName} on ${tableName}`;\n this.freeze();\n }\n\n toOp(): Op {\n return dropIndex(this.tableName, this.indexName);\n }\n\n renderTypeScript(): string {\n return `dropIndex(${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.indexName)})`;\n }\n}\n\n// ============================================================================\n// Data transform\n// ============================================================================\n\n/**\n * A planner-generated data-transform stub. The current default strategy\n * (`nullabilityTighteningBackfillStrategy`) emits one of these with a\n * backfill-flavored `id`/`label` when the policy allows `'data'` and the\n * contract tightens a column's nullability, but the op itself is generic —\n * any future strategy that needs a placeholder data step can construct one\n * with its own id/label.\n *\n * `toOp()` always throws `PN-MIG-2001`: the planner cannot lower a stubbed\n * transform to a runtime op — the user must edit the rendered\n * `migration.ts` and re-emit.\n */\nexport class DataTransformCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'dataTransform' as const;\n readonly operationClass = 'data' as const;\n readonly id: string;\n readonly label: string;\n readonly tableName: string;\n readonly columnName: string;\n\n constructor(id: string, label: string, tableName: string, columnName: string) {\n super();\n this.id = id;\n this.label = label;\n this.tableName = tableName;\n this.columnName = columnName;\n this.freeze();\n }\n\n toOp(): Op {\n throw errorUnfilledPlaceholder(this.label);\n }\n\n renderTypeScript(): string {\n const slot = `${this.tableName}-${this.columnName}-backfill-sql`;\n return [\n 'dataTransform({',\n ` id: ${jsonToTsSource(this.id)},`,\n ` label: ${jsonToTsSource(this.label)},`,\n ` table: ${jsonToTsSource(this.tableName)},`,\n ` description: ${jsonToTsSource(`Backfill NULL ${this.columnName} values in ${this.tableName}`)},`,\n ` run: () => placeholder(${jsonToTsSource(slot)}),`,\n '})',\n ].join('\\n');\n }\n\n override importRequirements(): readonly ImportRequirement[] {\n return [\n { moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: this.factoryName },\n { moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: 'placeholder' },\n ];\n }\n}\n\n// ============================================================================\n// Raw SQL\n// ============================================================================\n\n/**\n * Laundered pre-built operation. Mirrors Postgres's `RawSqlCall`: wraps an\n * already-materialized `SqlMigrationPlanOperation` (typically produced by a\n * SQL-family helper or a codec lifecycle hook) so the planner can carry it\n * alongside structured call IR. `toOp()` returns the stored op unchanged;\n * `renderTypeScript()` emits `rawSql({...})` with the op serialized as a\n * JSON literal — round-tripping requires every field on the op to be\n * JSON-serializable (no closures).\n */\nexport class RawSqlCall extends SqliteOpFactoryCallNode {\n readonly factoryName = 'rawSql' as const;\n readonly operationClass: MigrationOperationClass;\n readonly label: string;\n readonly op: Op;\n\n constructor(op: Op) {\n super();\n this.op = op;\n this.label = op.label;\n this.operationClass = op.operationClass;\n this.freeze();\n }\n\n toOp(): Op {\n return this.op;\n }\n\n renderTypeScript(): string {\n return `rawSql(${jsonToTsSource(this.op)})`;\n }\n}\n\n// ============================================================================\n// Union\n// ============================================================================\n\nexport type SqliteOpFactoryCall =\n | CreateTableCall\n | DropTableCall\n | RecreateTableCall\n | AddColumnCall\n | DropColumnCall\n | CreateIndexCall\n | DropIndexCall\n | DataTransformCall\n | RawSqlCall;\n"],"mappings":"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"}
|
|
@@ -127,7 +127,25 @@ declare class DataTransformCall extends SqliteOpFactoryCallNode {
|
|
|
127
127
|
renderTypeScript(): string;
|
|
128
128
|
importRequirements(): readonly ImportRequirement[];
|
|
129
129
|
}
|
|
130
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Laundered pre-built operation. Mirrors Postgres's `RawSqlCall`: wraps an
|
|
132
|
+
* already-materialized `SqlMigrationPlanOperation` (typically produced by a
|
|
133
|
+
* SQL-family helper or a codec lifecycle hook) so the planner can carry it
|
|
134
|
+
* alongside structured call IR. `toOp()` returns the stored op unchanged;
|
|
135
|
+
* `renderTypeScript()` emits `rawSql({...})` with the op serialized as a
|
|
136
|
+
* JSON literal — round-tripping requires every field on the op to be
|
|
137
|
+
* JSON-serializable (no closures).
|
|
138
|
+
*/
|
|
139
|
+
declare class RawSqlCall extends SqliteOpFactoryCallNode {
|
|
140
|
+
readonly factoryName: "rawSql";
|
|
141
|
+
readonly operationClass: MigrationOperationClass;
|
|
142
|
+
readonly label: string;
|
|
143
|
+
readonly op: Op;
|
|
144
|
+
constructor(op: Op);
|
|
145
|
+
toOp(): Op;
|
|
146
|
+
renderTypeScript(): string;
|
|
147
|
+
}
|
|
148
|
+
type SqliteOpFactoryCall = CreateTableCall | DropTableCall | RecreateTableCall | AddColumnCall | DropColumnCall | CreateIndexCall | DropIndexCall | DataTransformCall | RawSqlCall;
|
|
131
149
|
//#endregion
|
|
132
|
-
export { DropColumnCall as a,
|
|
133
|
-
//# sourceMappingURL=op-factory-call-
|
|
150
|
+
export { DropColumnCall as a, RawSqlCall as c, DataTransformCall as i, RecreateTableCall as l, CreateIndexCall as n, DropIndexCall as o, CreateTableCall as r, DropTableCall as s, AddColumnCall as t, SqliteOpFactoryCall as u };
|
|
151
|
+
//# sourceMappingURL=op-factory-call-FrU2vXqw.d.mts.map
|