@prisma-next/target-sqlite 0.13.0-dev.13 → 0.13.0-dev.14
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/contract-free.mjs +1 -20
- package/dist/contract-free.mjs.map +1 -1
- package/dist/control.mjs +8 -8
- package/dist/control.mjs.map +1 -1
- package/dist/ddl-CH8V_qcd.mjs +23 -0
- package/dist/ddl-CH8V_qcd.mjs.map +1 -0
- package/dist/migration.d.mts +3 -3
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +4 -3
- package/dist/migration.mjs.map +1 -1
- package/dist/{tables-CjB7vXCr.mjs → op-factory-call-Cc-rDnXB.mjs} +370 -17
- package/dist/op-factory-call-Cc-rDnXB.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +16 -12
- package/dist/op-factory-call.d.mts.map +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/{planner-DSNDwQy9.mjs → planner-D-scZdGe.mjs} +71 -10
- package/dist/planner-D-scZdGe.mjs.map +1 -0
- package/dist/{planner-produced-sqlite-migration-C1yqJAiM.d.mts → planner-produced-sqlite-migration-DcrsKVHA.d.mts} +4 -3
- package/dist/planner-produced-sqlite-migration-DcrsKVHA.d.mts.map +1 -0
- package/dist/{planner-produced-sqlite-migration-DowV_vHw.mjs → planner-produced-sqlite-migration-WsWCQb58.mjs} +7 -5
- package/dist/planner-produced-sqlite-migration-WsWCQb58.mjs.map +1 -0
- package/dist/planner-produced-sqlite-migration.d.mts +1 -1
- package/dist/planner-produced-sqlite-migration.mjs +1 -1
- package/dist/planner.d.mts +5 -2
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/render-ops-D2IuTDVc.mjs +9 -0
- package/dist/render-ops-D2IuTDVc.mjs.map +1 -0
- package/dist/render-ops.d.mts +2 -1
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/{sqlite-contract-serializer-jcRu8aHh.mjs → sqlite-contract-serializer-C41PO7DT.mjs} +2 -2
- package/dist/{sqlite-contract-serializer-jcRu8aHh.mjs.map → sqlite-contract-serializer-C41PO7DT.mjs.map} +1 -1
- package/dist/sqlite-migration-CteI6Mrg.mjs +73 -0
- package/dist/sqlite-migration-CteI6Mrg.mjs.map +1 -0
- package/dist/sqlite-migration-znjM-dc_.d.mts +46 -0
- package/dist/sqlite-migration-znjM-dc_.d.mts.map +1 -0
- package/package.json +18 -18
- package/src/core/control-target.ts +4 -4
- package/src/core/errors.ts +28 -0
- package/src/core/migrations/issue-planner.ts +114 -2
- package/src/core/migrations/op-factory-call.ts +155 -23
- package/src/core/migrations/planner-produced-sqlite-migration.ts +5 -1
- package/src/core/migrations/planner.ts +12 -2
- package/src/core/migrations/render-ops.ts +10 -2
- package/src/core/migrations/sqlite-migration.ts +51 -1
- package/src/exports/migration.ts +9 -1
- package/dist/op-factory-call-DymqdXQW.mjs +0 -279
- package/dist/op-factory-call-DymqdXQW.mjs.map +0 -1
- package/dist/planner-DSNDwQy9.mjs.map +0 -1
- package/dist/planner-produced-sqlite-migration-C1yqJAiM.d.mts.map +0 -1
- package/dist/planner-produced-sqlite-migration-DowV_vHw.mjs.map +0 -1
- package/dist/render-ops-CFRbJ3Yb.mjs +0 -8
- package/dist/render-ops-CFRbJ3Yb.mjs.map +0 -1
- package/dist/sqlite-migration-CUqgmzQH.mjs +0 -16
- package/dist/sqlite-migration-CUqgmzQH.mjs.map +0 -1
- package/dist/sqlite-migration-D4XGYzgQ.d.mts +0 -17
- package/dist/sqlite-migration-D4XGYzgQ.d.mts.map +0 -1
- package/dist/tables-CjB7vXCr.mjs.map +0 -1
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
* SQLite migration IR: one concrete `*Call` class per pure factory under
|
|
3
3
|
* `operations/`, plus a shared `SqliteOpFactoryCallNode` abstract base.
|
|
4
4
|
*
|
|
5
|
-
* Each call class carries fully-resolved literal arguments
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* TypeScript scaffold is fully self-contained and does not need access to a
|
|
11
|
-
* `storageTypes` map at runtime.
|
|
5
|
+
* Each call class carries fully-resolved literal arguments. `CreateTableCall`
|
|
6
|
+
* holds structured `DdlColumn[]` + `DdlTableConstraint[]` and lowers via the
|
|
7
|
+
* adapter's DDL path; other call classes carry flat SQL fragments. Codec /
|
|
8
|
+
* `typeRef` / default expansion happens upstream in the issue-planner /
|
|
9
|
+
* strategies, mirroring the Postgres `ColumnSpec` pattern.
|
|
12
10
|
*/
|
|
13
11
|
|
|
14
12
|
import { errorUnfilledPlaceholder } from '@prisma-next/errors/migration';
|
|
@@ -16,13 +14,23 @@ import type {
|
|
|
16
14
|
MigrationOperationClass,
|
|
17
15
|
SqlMigrationPlanOperation,
|
|
18
16
|
} from '@prisma-next/family-sql/control';
|
|
17
|
+
import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
|
|
19
18
|
import type { OpFactoryCall as FrameworkOpFactoryCall } from '@prisma-next/framework-components/control';
|
|
19
|
+
import type {
|
|
20
|
+
AnyDdlColumnDefault,
|
|
21
|
+
DdlColumn,
|
|
22
|
+
DdlTableConstraint,
|
|
23
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
20
24
|
import { type ImportRequirement, jsonToTsSource, TsExpression } from '@prisma-next/ts-render';
|
|
25
|
+
import * as contractFreeDdl from '../../contract-free/ddl';
|
|
26
|
+
import { escapeLiteral } from '../sql-utils';
|
|
21
27
|
import { addColumn, dropColumn } from './operations/columns';
|
|
22
28
|
import { createIndex, dropIndex } from './operations/indexes';
|
|
23
29
|
import type { SqliteColumnSpec, SqliteIndexSpec, SqliteTableSpec } from './operations/shared';
|
|
24
|
-
import {
|
|
30
|
+
import { step } from './operations/shared';
|
|
31
|
+
import { dropTable, recreateTable } from './operations/tables';
|
|
25
32
|
import type { SqlitePlanTargetDetails } from './planner-target-details';
|
|
33
|
+
import { buildTargetDetails } from './planner-target-details';
|
|
26
34
|
|
|
27
35
|
type Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;
|
|
28
36
|
|
|
@@ -32,7 +40,7 @@ abstract class SqliteOpFactoryCallNode extends TsExpression implements Framework
|
|
|
32
40
|
abstract readonly factoryName: string;
|
|
33
41
|
abstract readonly operationClass: MigrationOperationClass;
|
|
34
42
|
abstract readonly label: string;
|
|
35
|
-
abstract toOp(): Op;
|
|
43
|
+
abstract toOp(lowerer?: Lowerer): Op;
|
|
36
44
|
|
|
37
45
|
importRequirements(): readonly ImportRequirement[] {
|
|
38
46
|
return [{ moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: this.factoryName }];
|
|
@@ -47,27 +55,151 @@ abstract class SqliteOpFactoryCallNode extends TsExpression implements Framework
|
|
|
47
55
|
// Table
|
|
48
56
|
// ============================================================================
|
|
49
57
|
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// TypeScript rendering helpers for DdlColumn / DdlTableConstraint
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
function renderDdlColumnDefault(def: AnyDdlColumnDefault | undefined): string {
|
|
63
|
+
if (!def) return '';
|
|
64
|
+
if (def.kind === 'literal') {
|
|
65
|
+
return `lit(${jsonToTsSource(def.value)})`;
|
|
66
|
+
}
|
|
67
|
+
return `fn(${jsonToTsSource(def.expression)})`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function renderDdlColumnAsTsCall(column: DdlColumn): string {
|
|
71
|
+
const opts: string[] = [];
|
|
72
|
+
if (column.notNull) opts.push('notNull: true');
|
|
73
|
+
if (column.primaryKey) opts.push('primaryKey: true');
|
|
74
|
+
if (column.default) opts.push(`default: ${renderDdlColumnDefault(column.default)}`);
|
|
75
|
+
const optsStr = opts.length > 0 ? `, { ${opts.join(', ')} }` : '';
|
|
76
|
+
return `col(${jsonToTsSource(column.name)}, ${jsonToTsSource(column.type)}${optsStr})`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function renderDdlConstraintAsTsCall(constraint: DdlTableConstraint): string {
|
|
80
|
+
switch (constraint.kind) {
|
|
81
|
+
case 'primary-key': {
|
|
82
|
+
const nameOpt = constraint.name ? `, { name: ${jsonToTsSource(constraint.name)} }` : '';
|
|
83
|
+
return `primaryKey(${jsonToTsSource(constraint.columns)}${nameOpt})`;
|
|
84
|
+
}
|
|
85
|
+
case 'foreign-key': {
|
|
86
|
+
const opts: string[] = [];
|
|
87
|
+
if (constraint.name) opts.push(`name: ${jsonToTsSource(constraint.name)}`);
|
|
88
|
+
if (constraint.onDelete) opts.push(`onDelete: ${jsonToTsSource(constraint.onDelete)}`);
|
|
89
|
+
if (constraint.onUpdate) opts.push(`onUpdate: ${jsonToTsSource(constraint.onUpdate)}`);
|
|
90
|
+
const optsStr = opts.length > 0 ? `, { ${opts.join(', ')} }` : '';
|
|
91
|
+
return `foreignKey(${jsonToTsSource(constraint.columns)}, ${jsonToTsSource(constraint.refTable)}, ${jsonToTsSource(constraint.refColumns)}${optsStr})`;
|
|
92
|
+
}
|
|
93
|
+
case 'unique': {
|
|
94
|
+
const nameOpt = constraint.name ? `, { name: ${jsonToTsSource(constraint.name)} }` : '';
|
|
95
|
+
return `unique(${jsonToTsSource(constraint.columns)}${nameOpt})`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function constraintImportSymbols(constraints: readonly DdlTableConstraint[] | undefined): string[] {
|
|
101
|
+
if (!constraints || constraints.length === 0) return [];
|
|
102
|
+
const symbols = new Set<string>();
|
|
103
|
+
for (const c of constraints) {
|
|
104
|
+
if (c.kind === 'primary-key') symbols.add('primaryKey');
|
|
105
|
+
else if (c.kind === 'foreign-key') symbols.add('foreignKey');
|
|
106
|
+
else if (c.kind === 'unique') symbols.add('unique');
|
|
107
|
+
}
|
|
108
|
+
return [...symbols];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function defaultImportSymbols(columns: readonly DdlColumn[]): string[] {
|
|
112
|
+
const symbols = new Set<string>();
|
|
113
|
+
for (const col of columns) {
|
|
114
|
+
if (col.default?.kind === 'literal') symbols.add('lit');
|
|
115
|
+
else if (col.default?.kind === 'function') symbols.add('fn');
|
|
116
|
+
}
|
|
117
|
+
return [...symbols];
|
|
118
|
+
}
|
|
119
|
+
|
|
50
120
|
export class CreateTableCall extends SqliteOpFactoryCallNode {
|
|
51
121
|
readonly factoryName = 'createTable' as const;
|
|
52
122
|
readonly operationClass = 'additive' as const;
|
|
53
123
|
readonly tableName: string;
|
|
54
|
-
readonly
|
|
124
|
+
readonly columns: readonly DdlColumn[];
|
|
125
|
+
readonly constraints: readonly DdlTableConstraint[] | undefined;
|
|
55
126
|
readonly label: string;
|
|
56
127
|
|
|
57
|
-
constructor(
|
|
128
|
+
constructor(
|
|
129
|
+
tableName: string,
|
|
130
|
+
columns: readonly DdlColumn[],
|
|
131
|
+
constraints?: readonly DdlTableConstraint[],
|
|
132
|
+
) {
|
|
58
133
|
super();
|
|
59
134
|
this.tableName = tableName;
|
|
60
|
-
this.
|
|
135
|
+
this.columns = Object.freeze([...columns]);
|
|
136
|
+
this.constraints = constraints ? Object.freeze([...constraints]) : undefined;
|
|
61
137
|
this.label = `Create table ${tableName}`;
|
|
62
138
|
this.freeze();
|
|
63
139
|
}
|
|
64
140
|
|
|
65
|
-
toOp(): Op {
|
|
66
|
-
|
|
141
|
+
toOp(lowerer?: Lowerer): Op {
|
|
142
|
+
if (lowerer === undefined) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`CreateTableCall.toOp: a DDL lowerer is required on the SQLite planner path (table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
const ddlNode = contractFreeDdl.createTable({
|
|
148
|
+
table: this.tableName,
|
|
149
|
+
columns: this.columns,
|
|
150
|
+
...(this.constraints ? { constraints: this.constraints } : {}),
|
|
151
|
+
});
|
|
152
|
+
const { sql } = lowerer.lower(ddlNode, { contract: {} });
|
|
153
|
+
const tableName = this.tableName;
|
|
154
|
+
const escapedName = escapeLiteral(tableName);
|
|
155
|
+
return {
|
|
156
|
+
id: `table.${tableName}`,
|
|
157
|
+
label: `Create table ${tableName}`,
|
|
158
|
+
summary: `Creates table ${tableName} with required columns`,
|
|
159
|
+
operationClass: 'additive',
|
|
160
|
+
target: { id: 'sqlite', details: buildTargetDetails('table', tableName) },
|
|
161
|
+
precheck: [
|
|
162
|
+
step(
|
|
163
|
+
`ensure table "${tableName}" does not exist`,
|
|
164
|
+
`SELECT COUNT(*) = 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapedName}'`,
|
|
165
|
+
),
|
|
166
|
+
],
|
|
167
|
+
execute: [step(`create table "${tableName}"`, sql)],
|
|
168
|
+
postcheck: [
|
|
169
|
+
step(
|
|
170
|
+
`verify table "${tableName}" exists`,
|
|
171
|
+
`SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapedName}'`,
|
|
172
|
+
),
|
|
173
|
+
],
|
|
174
|
+
};
|
|
67
175
|
}
|
|
68
176
|
|
|
69
177
|
renderTypeScript(): string {
|
|
70
|
-
|
|
178
|
+
const columnsList = this.columns.map(renderDdlColumnAsTsCall).join(', ');
|
|
179
|
+
const constraintsList = this.constraints
|
|
180
|
+
? this.constraints.map(renderDdlConstraintAsTsCall).join(', ')
|
|
181
|
+
: undefined;
|
|
182
|
+
|
|
183
|
+
const opts: string[] = [];
|
|
184
|
+
opts.push(`table: ${jsonToTsSource(this.tableName)}`);
|
|
185
|
+
opts.push(`columns: [${columnsList}]`);
|
|
186
|
+
if (constraintsList) opts.push(`constraints: [${constraintsList}]`);
|
|
187
|
+
|
|
188
|
+
return `this.createTable({ ${opts.join(', ')} })`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
192
|
+
const req: ImportRequirement[] = [];
|
|
193
|
+
if (this.columns.length > 0) {
|
|
194
|
+
req.push({ moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: 'col' });
|
|
195
|
+
for (const sym of defaultImportSymbols(this.columns)) {
|
|
196
|
+
req.push({ moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: sym });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const sym of constraintImportSymbols(this.constraints)) {
|
|
200
|
+
req.push({ moduleSpecifier: TARGET_MIGRATION_MODULE, symbol: sym });
|
|
201
|
+
}
|
|
202
|
+
return req;
|
|
71
203
|
}
|
|
72
204
|
}
|
|
73
205
|
|
|
@@ -84,7 +216,7 @@ export class DropTableCall extends SqliteOpFactoryCallNode {
|
|
|
84
216
|
this.freeze();
|
|
85
217
|
}
|
|
86
218
|
|
|
87
|
-
toOp(): Op {
|
|
219
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
88
220
|
return dropTable(this.tableName);
|
|
89
221
|
}
|
|
90
222
|
|
|
@@ -125,7 +257,7 @@ export class RecreateTableCall extends SqliteOpFactoryCallNode {
|
|
|
125
257
|
this.freeze();
|
|
126
258
|
}
|
|
127
259
|
|
|
128
|
-
toOp(): Op {
|
|
260
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
129
261
|
return recreateTable({
|
|
130
262
|
tableName: this.tableName,
|
|
131
263
|
contractTable: this.contractTable,
|
|
@@ -172,7 +304,7 @@ export class AddColumnCall extends SqliteOpFactoryCallNode {
|
|
|
172
304
|
this.freeze();
|
|
173
305
|
}
|
|
174
306
|
|
|
175
|
-
toOp(): Op {
|
|
307
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
176
308
|
return addColumn(this.tableName, this.column);
|
|
177
309
|
}
|
|
178
310
|
|
|
@@ -196,7 +328,7 @@ export class DropColumnCall extends SqliteOpFactoryCallNode {
|
|
|
196
328
|
this.freeze();
|
|
197
329
|
}
|
|
198
330
|
|
|
199
|
-
toOp(): Op {
|
|
331
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
200
332
|
return dropColumn(this.tableName, this.columnName);
|
|
201
333
|
}
|
|
202
334
|
|
|
@@ -226,7 +358,7 @@ export class CreateIndexCall extends SqliteOpFactoryCallNode {
|
|
|
226
358
|
this.freeze();
|
|
227
359
|
}
|
|
228
360
|
|
|
229
|
-
toOp(): Op {
|
|
361
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
230
362
|
return createIndex(this.tableName, this.indexName, this.columns);
|
|
231
363
|
}
|
|
232
364
|
|
|
@@ -250,7 +382,7 @@ export class DropIndexCall extends SqliteOpFactoryCallNode {
|
|
|
250
382
|
this.freeze();
|
|
251
383
|
}
|
|
252
384
|
|
|
253
|
-
toOp(): Op {
|
|
385
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
254
386
|
return dropIndex(this.tableName, this.indexName);
|
|
255
387
|
}
|
|
256
388
|
|
|
@@ -292,7 +424,7 @@ export class DataTransformCall extends SqliteOpFactoryCallNode {
|
|
|
292
424
|
this.freeze();
|
|
293
425
|
}
|
|
294
426
|
|
|
295
|
-
toOp(): Op {
|
|
427
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
296
428
|
throw errorUnfilledPlaceholder(this.label);
|
|
297
429
|
}
|
|
298
430
|
|
|
@@ -344,7 +476,7 @@ export class RawSqlCall extends SqliteOpFactoryCallNode {
|
|
|
344
476
|
this.freeze();
|
|
345
477
|
}
|
|
346
478
|
|
|
347
|
-
toOp(): Op {
|
|
479
|
+
toOp(_lowerer?: Lowerer): Op {
|
|
348
480
|
return this.op;
|
|
349
481
|
}
|
|
350
482
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
2
|
+
import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
|
|
2
3
|
import type {
|
|
3
4
|
MigrationPlanWithAuthoringSurface,
|
|
4
5
|
OpFactoryCall,
|
|
@@ -24,22 +25,25 @@ export class TypeScriptRenderableSqliteMigration
|
|
|
24
25
|
readonly #meta: MigrationMeta;
|
|
25
26
|
readonly #destination: SqliteMigrationDestinationInfo;
|
|
26
27
|
readonly #spaceId: string;
|
|
28
|
+
readonly #lowerer: Lowerer | undefined;
|
|
27
29
|
|
|
28
30
|
constructor(
|
|
29
31
|
calls: readonly OpFactoryCall[],
|
|
30
32
|
meta: MigrationMeta,
|
|
31
33
|
spaceId: string,
|
|
32
34
|
destination?: SqliteMigrationDestinationInfo,
|
|
35
|
+
lowerer?: Lowerer,
|
|
33
36
|
) {
|
|
34
37
|
super();
|
|
35
38
|
this.#calls = calls;
|
|
36
39
|
this.#meta = meta;
|
|
37
40
|
this.#spaceId = spaceId;
|
|
38
41
|
this.#destination = destination ?? { storageHash: meta.to };
|
|
42
|
+
this.#lowerer = lowerer;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
override get operations(): readonly Op[] {
|
|
42
|
-
return renderOps(this.#calls);
|
|
46
|
+
return renderOps(this.#calls, this.#lowerer);
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
override describe(): MigrationMeta {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
planFieldEventOperations,
|
|
11
11
|
plannerFailure,
|
|
12
12
|
} from '@prisma-next/family-sql/control';
|
|
13
|
+
import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
|
|
13
14
|
import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
|
|
14
15
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
15
16
|
import type {
|
|
@@ -27,8 +28,8 @@ import {
|
|
|
27
28
|
import { sqlitePlannerStrategies } from './planner-strategies';
|
|
28
29
|
import type { SqlitePlanTargetDetails } from './planner-target-details';
|
|
29
30
|
|
|
30
|
-
export function createSqliteMigrationPlanner(): SqliteMigrationPlanner {
|
|
31
|
-
return new SqliteMigrationPlanner();
|
|
31
|
+
export function createSqliteMigrationPlanner(lowerer: Lowerer): SqliteMigrationPlanner {
|
|
32
|
+
return new SqliteMigrationPlanner(lowerer);
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export type SqlitePlanResult =
|
|
@@ -52,6 +53,12 @@ export type SqlitePlanResult =
|
|
|
52
53
|
export class SqliteMigrationPlanner
|
|
53
54
|
implements SqlMigrationPlanner<SqlitePlanTargetDetails>, MigrationPlanner<'sql', 'sqlite'>
|
|
54
55
|
{
|
|
56
|
+
readonly #lowerer: Lowerer;
|
|
57
|
+
|
|
58
|
+
constructor(lowerer: Lowerer) {
|
|
59
|
+
this.#lowerer = lowerer;
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
plan(options: {
|
|
56
63
|
readonly contract: unknown;
|
|
57
64
|
readonly schema: unknown;
|
|
@@ -89,6 +96,8 @@ export class SqliteMigrationPlanner
|
|
|
89
96
|
to: context.toHash,
|
|
90
97
|
},
|
|
91
98
|
spaceId,
|
|
99
|
+
undefined,
|
|
100
|
+
this.#lowerer,
|
|
92
101
|
);
|
|
93
102
|
}
|
|
94
103
|
|
|
@@ -149,6 +158,7 @@ export class SqliteMigrationPlanner
|
|
|
149
158
|
},
|
|
150
159
|
options.spaceId,
|
|
151
160
|
destination,
|
|
161
|
+
this.#lowerer,
|
|
152
162
|
),
|
|
153
163
|
};
|
|
154
164
|
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
2
|
+
import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
|
|
2
3
|
import type { OpFactoryCall } from '@prisma-next/framework-components/control';
|
|
4
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
3
5
|
import type { SqlitePlanTargetDetails } from './planner-target-details';
|
|
4
6
|
|
|
5
7
|
type Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;
|
|
6
8
|
|
|
7
|
-
export function renderOps(calls: readonly OpFactoryCall[]): Op[] {
|
|
9
|
+
export function renderOps(calls: readonly OpFactoryCall[], lowerer?: Lowerer): Op[] {
|
|
8
10
|
// Each call's `toOp()` is typed as the framework `MigrationPlanOperation`;
|
|
9
11
|
// every concrete Call class on the sqlite planner path produces an op
|
|
10
12
|
// whose `target.details` is `SqlitePlanTargetDetails`-shaped (or whose
|
|
11
13
|
// `target.details` is absent, which is structurally compatible). The
|
|
12
14
|
// narrowing cast happens at this single integration boundary instead of
|
|
13
15
|
// poisoning every caller's type.
|
|
14
|
-
return calls.map(
|
|
16
|
+
return calls.map(
|
|
17
|
+
(c) =>
|
|
18
|
+
blindCast<
|
|
19
|
+
{ toOp(lowerer?: Lowerer): ReturnType<OpFactoryCall['toOp']> },
|
|
20
|
+
'SQLite OpFactoryCall.toOp accepts an optional Lowerer; the framework interface omits it because not all targets need a lowerer — the SQLite target overrides with this extended signature'
|
|
21
|
+
>(c).toOp(lowerer) as Op,
|
|
22
|
+
);
|
|
15
23
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
2
|
+
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
1
3
|
import { Migration as SqlMigration } from '@prisma-next/family-sql/migration';
|
|
4
|
+
import type { ControlStack } from '@prisma-next/framework-components/control';
|
|
5
|
+
import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
|
|
6
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
7
|
+
import { errorSqliteMigrationStackMissing } from '../errors';
|
|
8
|
+
import { CreateTableCall } from './op-factory-call';
|
|
2
9
|
import type { SqlitePlanTargetDetails } from './planner-target-details';
|
|
3
10
|
|
|
4
11
|
/**
|
|
@@ -7,7 +14,50 @@ import type { SqlitePlanTargetDetails } from './planner-target-details';
|
|
|
7
14
|
* SQLite literal, so both user-authored migrations and renderer-generated
|
|
8
15
|
* scaffolds can extend `SqliteMigration` directly without redeclaring
|
|
9
16
|
* target-local identity.
|
|
17
|
+
*
|
|
18
|
+
* The constructor materializes a single SQLite `SqlControlAdapter` from
|
|
19
|
+
* `stack.adapter.create(stack)` and stores it; the protected `createTable`
|
|
20
|
+
* instance method forwards to `CreateTableCall` with that stored adapter,
|
|
21
|
+
* so user migrations can write `this.createTable({...})` without threading
|
|
22
|
+
* the adapter through every call.
|
|
10
23
|
*/
|
|
11
|
-
export abstract class SqliteMigration extends SqlMigration<SqlitePlanTargetDetails> {
|
|
24
|
+
export abstract class SqliteMigration extends SqlMigration<SqlitePlanTargetDetails, 'sqlite'> {
|
|
12
25
|
readonly targetId = 'sqlite' as const;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Materialized SQLite control adapter, created once per migration
|
|
29
|
+
* instance from the injected stack. `undefined` only when the migration
|
|
30
|
+
* was instantiated without a stack (test fixtures); `createTable`
|
|
31
|
+
* throws in that case to surface the misuse.
|
|
32
|
+
*/
|
|
33
|
+
protected readonly controlAdapter: SqlControlAdapter<'sqlite'> | undefined;
|
|
34
|
+
|
|
35
|
+
constructor(stack?: ControlStack<'sql', 'sqlite'>) {
|
|
36
|
+
super(stack);
|
|
37
|
+
this.controlAdapter = stack?.adapter
|
|
38
|
+
? blindCast<
|
|
39
|
+
SqlControlAdapter<'sqlite'>,
|
|
40
|
+
'The SQLite descriptor create() returns SqlControlAdapter<sqlite>; typed as wider ControlAdapterInstance at the framework boundary'
|
|
41
|
+
>(stack.adapter.create(stack))
|
|
42
|
+
: undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Emit a `CREATE TABLE` migration operation. Builds a typed DDL node from
|
|
47
|
+
* the supplied options and lowers it through the stored control adapter.
|
|
48
|
+
* Throws if no adapter is present (i.e. migration instantiated without a stack).
|
|
49
|
+
*/
|
|
50
|
+
protected createTable(options: {
|
|
51
|
+
readonly table: string;
|
|
52
|
+
readonly ifNotExists?: boolean;
|
|
53
|
+
readonly columns: readonly DdlColumn[];
|
|
54
|
+
readonly constraints?: readonly DdlTableConstraint[];
|
|
55
|
+
}): SqlMigrationPlanOperation<SqlitePlanTargetDetails> {
|
|
56
|
+
if (!this.controlAdapter) {
|
|
57
|
+
throw errorSqliteMigrationStackMissing();
|
|
58
|
+
}
|
|
59
|
+
return new CreateTableCall(options.table, options.columns, options.constraints).toOp(
|
|
60
|
+
this.controlAdapter,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
13
63
|
}
|
package/src/exports/migration.ts
CHANGED
|
@@ -9,6 +9,14 @@ export { MigrationCLI } from '@prisma-next/cli/migration-cli';
|
|
|
9
9
|
// `placeholder("…")` slots, instead of pulling in `@prisma-next/errors`
|
|
10
10
|
// directly. The planner emits an import from this same module.
|
|
11
11
|
export { placeholder } from '@prisma-next/errors/migration';
|
|
12
|
+
export {
|
|
13
|
+
col,
|
|
14
|
+
fn,
|
|
15
|
+
foreignKey,
|
|
16
|
+
lit,
|
|
17
|
+
primaryKey,
|
|
18
|
+
unique,
|
|
19
|
+
} from '@prisma-next/sql-relational-core/contract-free';
|
|
12
20
|
export { addColumn, dropColumn } from '../core/migrations/operations/columns';
|
|
13
21
|
export {
|
|
14
22
|
type DataTransformOptions,
|
|
@@ -16,7 +24,7 @@ export {
|
|
|
16
24
|
} from '../core/migrations/operations/data-transform';
|
|
17
25
|
export { createIndex, dropIndex } from '../core/migrations/operations/indexes';
|
|
18
26
|
export { rawSql } from '../core/migrations/operations/raw';
|
|
19
|
-
export {
|
|
27
|
+
export { dropTable, recreateTable } from '../core/migrations/operations/tables';
|
|
20
28
|
// Target-owned base class for migrations. Aliased to `Migration` so
|
|
21
29
|
// user-edited migration.ts files (and the renderer's scaffold) read as
|
|
22
30
|
// `class M extends Migration { … }` without having to thread the
|