@prisma-next/target-sqlite 0.13.0-dev.4 → 0.13.0-dev.40
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.d.mts +35 -2
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/contract-free.mjs +3 -22
- package/dist/contract-free.mjs.map +1 -1
- package/dist/control.d.mts +5 -8
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +18 -20
- package/dist/control.mjs.map +1 -1
- package/dist/ddl-DrtjQMFK.mjs +68 -0
- package/dist/ddl-DrtjQMFK.mjs.map +1 -0
- package/dist/{descriptor-meta-Dxx2A6PT.mjs → descriptor-meta-DxmEeTJ-.mjs} +10 -3
- package/dist/descriptor-meta-DxmEeTJ-.mjs.map +1 -0
- package/dist/migration.d.mts +4 -46
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +4 -3
- package/dist/migration.mjs.map +1 -1
- package/dist/op-factory-call-DmdfD1yd.mjs +794 -0
- package/dist/op-factory-call-DmdfD1yd.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +22 -12
- package/dist/op-factory-call.d.mts.map +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-DSNDwQy9.mjs → planner-Ciq8p_dL.mjs} +80 -12
- package/dist/planner-Ciq8p_dL.mjs.map +1 -0
- package/dist/{planner-produced-sqlite-migration-DowV_vHw.mjs → planner-produced-sqlite-migration-0xPEm3R1.mjs} +9 -5
- package/dist/planner-produced-sqlite-migration-0xPEm3R1.mjs.map +1 -0
- package/dist/{planner-produced-sqlite-migration-C1yqJAiM.d.mts → planner-produced-sqlite-migration-CpgsY-M9.d.mts} +5 -4
- package/dist/planner-produced-sqlite-migration-CpgsY-M9.d.mts.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-BDW2tUeR.mjs +22 -0
- package/dist/render-ops-BDW2tUeR.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.d.mts +1 -0
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/shared-Dhc8mLK1.d.mts.map +1 -1
- package/dist/{sqlite-contract-serializer-jcRu8aHh.mjs → sqlite-contract-serializer--iaDgC8e.mjs} +17 -6
- package/dist/sqlite-contract-serializer--iaDgC8e.mjs.map +1 -0
- package/dist/sqlite-migration-A0rwqPOG.mjs +92 -0
- package/dist/sqlite-migration-A0rwqPOG.mjs.map +1 -0
- package/dist/sqlite-migration-DVfhQwN_.d.mts +75 -0
- package/dist/sqlite-migration-DVfhQwN_.d.mts.map +1 -0
- package/package.json +18 -18
- package/src/contract-free/checks.ts +75 -0
- package/src/core/control-target.ts +4 -4
- package/src/core/errors.ts +28 -0
- package/src/core/migrations/issue-planner.ts +151 -8
- package/src/core/migrations/op-factory-call.ts +332 -45
- package/src/core/migrations/operations/columns.ts +32 -26
- package/src/core/migrations/operations/indexes.ts +31 -27
- package/src/core/migrations/operations/shared.ts +11 -3
- package/src/core/migrations/operations/tables.ts +39 -37
- package/src/core/migrations/planner-ddl-builders.ts +7 -16
- package/src/core/migrations/planner-produced-sqlite-migration.ts +8 -2
- package/src/core/migrations/planner-strategies.ts +3 -3
- package/src/core/migrations/planner.ts +14 -2
- package/src/core/migrations/render-ops.ts +37 -9
- package/src/core/migrations/runner.ts +16 -12
- package/src/core/migrations/sqlite-migration.ts +119 -1
- package/src/core/sqlite-contract-serializer.ts +5 -0
- package/src/core/sqlite-unbound-database.ts +30 -54
- package/src/exports/contract-free.ts +8 -0
- package/src/exports/migration.ts +8 -3
- package/dist/descriptor-meta-Dxx2A6PT.mjs.map +0 -1
- package/dist/descriptor-meta-runtime-BkXK3OjD.mjs +0 -12
- package/dist/descriptor-meta-runtime-BkXK3OjD.mjs.map +0 -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-contract-serializer-jcRu8aHh.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 +0 -412
- package/dist/tables-CjB7vXCr.mjs.map +0 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { t as SqlitePlanTargetDetails } from "./planner-target-details-xR6UfIcz.mjs";
|
|
2
|
+
import { i as SqliteTableSpec, n as SqliteColumnSpec, r as SqliteIndexSpec } from "./shared-Dhc8mLK1.mjs";
|
|
3
|
+
import { DdlColumn, DdlTableConstraint } from "@prisma-next/sql-relational-core/ast";
|
|
4
|
+
import { MigrationOperationClass, SqlMigrationPlanOperation } from "@prisma-next/family-sql/control";
|
|
5
|
+
import { Migration } from "@prisma-next/family-sql/migration";
|
|
6
|
+
import { ControlStack } from "@prisma-next/framework-components/control";
|
|
7
|
+
import { SqlControlAdapter } from "@prisma-next/family-sql/control-adapter";
|
|
8
|
+
|
|
9
|
+
//#region src/core/migrations/sqlite-migration.d.ts
|
|
10
|
+
type Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;
|
|
11
|
+
/**
|
|
12
|
+
* Target-owned base class for SQLite migrations. Fixes the `SqlMigration`
|
|
13
|
+
* generic to `SqlitePlanTargetDetails` and the abstract `targetId` to the
|
|
14
|
+
* SQLite literal, so both user-authored migrations and renderer-generated
|
|
15
|
+
* scaffolds can extend `SqliteMigration` directly without redeclaring
|
|
16
|
+
* target-local identity.
|
|
17
|
+
*
|
|
18
|
+
* The constructor materializes a single SQLite `SqlControlAdapter` from
|
|
19
|
+
* `stack.adapter.create(stack)` and stores it; the protected instance methods
|
|
20
|
+
* forward to the corresponding `*Call` with that stored adapter, so user
|
|
21
|
+
* migrations can write `this.createTable({...})` without threading the adapter
|
|
22
|
+
* through every call.
|
|
23
|
+
*/
|
|
24
|
+
declare abstract class SqliteMigration extends Migration<SqlitePlanTargetDetails, 'sqlite'> {
|
|
25
|
+
readonly targetId: "sqlite";
|
|
26
|
+
/**
|
|
27
|
+
* Materialized SQLite control adapter, created once per migration
|
|
28
|
+
* instance from the injected stack. `undefined` only when the migration
|
|
29
|
+
* was instantiated without a stack (test fixtures); the operation methods
|
|
30
|
+
* throw in that case to surface the misuse.
|
|
31
|
+
*/
|
|
32
|
+
protected readonly controlAdapter: SqlControlAdapter<'sqlite'> | undefined;
|
|
33
|
+
constructor(stack?: ControlStack<'sql', 'sqlite'>);
|
|
34
|
+
protected createTable(options: {
|
|
35
|
+
readonly table: string;
|
|
36
|
+
readonly ifNotExists?: boolean;
|
|
37
|
+
readonly columns: readonly DdlColumn[];
|
|
38
|
+
readonly constraints?: readonly DdlTableConstraint[];
|
|
39
|
+
}): Promise<Op>;
|
|
40
|
+
protected dropTable(options: {
|
|
41
|
+
readonly table: string;
|
|
42
|
+
}): Promise<Op>;
|
|
43
|
+
protected addColumn(options: {
|
|
44
|
+
readonly table: string;
|
|
45
|
+
readonly column: SqliteColumnSpec;
|
|
46
|
+
}): Promise<Op>;
|
|
47
|
+
protected dropColumn(options: {
|
|
48
|
+
readonly table: string;
|
|
49
|
+
readonly column: string;
|
|
50
|
+
}): Promise<Op>;
|
|
51
|
+
protected createIndex(options: {
|
|
52
|
+
readonly table: string;
|
|
53
|
+
readonly index: string;
|
|
54
|
+
readonly columns: readonly string[];
|
|
55
|
+
}): Promise<Op>;
|
|
56
|
+
protected dropIndex(options: {
|
|
57
|
+
readonly table: string;
|
|
58
|
+
readonly index: string;
|
|
59
|
+
}): Promise<Op>;
|
|
60
|
+
protected recreateTable(options: {
|
|
61
|
+
readonly tableName: string;
|
|
62
|
+
readonly contractTable: SqliteTableSpec;
|
|
63
|
+
readonly schemaColumnNames: readonly string[];
|
|
64
|
+
readonly indexes: readonly SqliteIndexSpec[];
|
|
65
|
+
readonly summary: string;
|
|
66
|
+
readonly postchecks: readonly {
|
|
67
|
+
readonly description: string;
|
|
68
|
+
readonly sql: string;
|
|
69
|
+
}[];
|
|
70
|
+
readonly operationClass: MigrationOperationClass;
|
|
71
|
+
}): Promise<Op>;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { SqliteMigration as t };
|
|
75
|
+
//# sourceMappingURL=sqlite-migration-DVfhQwN_.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-migration-DVfhQwN_.d.mts","names":[],"sources":["../src/core/migrations/sqlite-migration.ts"],"mappings":";;;;;;;;;KAsBK,EAAA,GAAK,yBAAyB,CAAC,uBAAA;;AAFoC;;;;AAEb;AAe3D;;;;;;;uBAAsB,eAAA,SAAwB,SAAA,CAAa,uBAAA;EAAA,SAChD,QAAA;EAyBL;;;;;;EAAA,mBAjBe,cAAA,EAAgB,iBAAA;cAEvB,KAAA,GAAQ,YAAA;EAAA,UAUV,WAAA,CAAY,OAAA;IAAA,SACX,KAAA;IAAA,SACA,WAAA;IAAA,SACA,OAAA,WAAkB,SAAA;IAAA,SAClB,WAAA,YAAuB,kBAAA;EAAA,IAC9B,OAAA,CAAQ,EAAA;EAAA,UASF,SAAA,CAAU,OAAA;IAAA,SAAoB,KAAA;EAAA,IAAkB,OAAA,CAAQ,EAAA;EAAA,UAOxD,SAAA,CAAU,OAAA;IAAA,SACT,KAAA;IAAA,SACA,MAAA,EAAQ,gBAAA;EAAA,IACf,OAAA,CAAQ,EAAA;EAAA,UAOF,UAAA,CAAW,OAAA;IAAA,SAAoB,KAAA;IAAA,SAAwB,MAAA;EAAA,IAAmB,OAAA,CAAQ,EAAA;EAAA,UAOlF,WAAA,CAAY,OAAA;IAAA,SACX,KAAA;IAAA,SACA,KAAA;IAAA,SACA,OAAA;EAAA,IACP,OAAA,CAAQ,EAAA;EAAA,UASF,SAAA,CAAU,OAAA;IAAA,SAAoB,KAAA;IAAA,SAAwB,KAAA;EAAA,IAAkB,OAAA,CAAQ,EAAA;EAAA,UAOhF,aAAA,CAAc,OAAA;IAAA,SACb,SAAA;IAAA,SACA,aAAA,EAAe,eAAA;IAAA,SACf,iBAAA;IAAA,SACA,OAAA,WAAkB,eAAA;IAAA,SAClB,OAAA;IAAA,SACA,UAAA;MAAA,SAAgC,WAAA;MAAA,SAA8B,GAAA;IAAA;IAAA,SAC9D,cAAA,EAAgB,uBAAA;EAAA,IACvB,OAAA,CAAQ,EAAA;AAAA"}
|
package/package.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/target-sqlite",
|
|
3
|
-
"version": "0.13.0-dev.
|
|
3
|
+
"version": "0.13.0-dev.40",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@prisma-next/cli": "0.13.0-dev.
|
|
9
|
-
"@prisma-next/contract": "0.13.0-dev.
|
|
10
|
-
"@prisma-next/errors": "0.13.0-dev.
|
|
11
|
-
"@prisma-next/family-sql": "0.13.0-dev.
|
|
12
|
-
"@prisma-next/framework-components": "0.13.0-dev.
|
|
13
|
-
"@prisma-next/migration-tools": "0.13.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract": "0.13.0-dev.
|
|
15
|
-
"@prisma-next/sql-errors": "0.13.0-dev.
|
|
16
|
-
"@prisma-next/sql-relational-core": "0.13.0-dev.
|
|
17
|
-
"@prisma-next/sql-runtime": "0.13.0-dev.
|
|
18
|
-
"@prisma-next/sql-schema-ir": "0.13.0-dev.
|
|
19
|
-
"@prisma-next/ts-render": "0.13.0-dev.
|
|
20
|
-
"@prisma-next/utils": "0.13.0-dev.
|
|
8
|
+
"@prisma-next/cli": "0.13.0-dev.40",
|
|
9
|
+
"@prisma-next/contract": "0.13.0-dev.40",
|
|
10
|
+
"@prisma-next/errors": "0.13.0-dev.40",
|
|
11
|
+
"@prisma-next/family-sql": "0.13.0-dev.40",
|
|
12
|
+
"@prisma-next/framework-components": "0.13.0-dev.40",
|
|
13
|
+
"@prisma-next/migration-tools": "0.13.0-dev.40",
|
|
14
|
+
"@prisma-next/sql-contract": "0.13.0-dev.40",
|
|
15
|
+
"@prisma-next/sql-errors": "0.13.0-dev.40",
|
|
16
|
+
"@prisma-next/sql-relational-core": "0.13.0-dev.40",
|
|
17
|
+
"@prisma-next/sql-runtime": "0.13.0-dev.40",
|
|
18
|
+
"@prisma-next/sql-schema-ir": "0.13.0-dev.40",
|
|
19
|
+
"@prisma-next/ts-render": "0.13.0-dev.40",
|
|
20
|
+
"@prisma-next/utils": "0.13.0-dev.40",
|
|
21
21
|
"@standard-schema/spec": "1.1.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@prisma-next/driver-sqlite": "0.13.0-dev.
|
|
25
|
-
"@prisma-next/test-utils": "0.13.0-dev.
|
|
26
|
-
"@prisma-next/tsconfig": "0.13.0-dev.
|
|
27
|
-
"@prisma-next/tsdown": "0.13.0-dev.
|
|
24
|
+
"@prisma-next/driver-sqlite": "0.13.0-dev.40",
|
|
25
|
+
"@prisma-next/test-utils": "0.13.0-dev.40",
|
|
26
|
+
"@prisma-next/tsconfig": "0.13.0-dev.40",
|
|
27
|
+
"@prisma-next/tsdown": "0.13.0-dev.40",
|
|
28
28
|
"tsdown": "0.22.1",
|
|
29
29
|
"typescript": "5.9.3",
|
|
30
30
|
"vitest": "4.1.8"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { FunctionSource, type SelectAst } from '@prisma-next/sql-relational-core/ast';
|
|
2
|
+
import { cfExpr, cfTable, exprSelect } from '@prisma-next/sql-relational-core/contract-free';
|
|
3
|
+
import { SQLITE_TEXT_CODEC_ID } from '../core/codec-ids';
|
|
4
|
+
|
|
5
|
+
export interface ColumnExistsCheckBuilder {
|
|
6
|
+
columnAbsent(): SelectAst;
|
|
7
|
+
columnPresent(): SelectAst;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Typed builder for the migration planner's column-existence checks. Produces
|
|
12
|
+
* `SELECT COUNT(*) {=|>} 0 AS "result" FROM pragma_table_info(?) WHERE "name" = ?`
|
|
13
|
+
* ASTs with the table and column names bound as text parameters — never
|
|
14
|
+
* inlined into the SQL.
|
|
15
|
+
*/
|
|
16
|
+
export function columnExistsAst(table: string, column: string): ColumnExistsCheckBuilder {
|
|
17
|
+
const source = FunctionSource.of('pragma_table_info', [
|
|
18
|
+
cfExpr.param(table, SQLITE_TEXT_CODEC_ID).ast,
|
|
19
|
+
]);
|
|
20
|
+
const where = cfExpr.identifierRef('name').eqParam(column, SQLITE_TEXT_CODEC_ID);
|
|
21
|
+
return {
|
|
22
|
+
columnAbsent: () =>
|
|
23
|
+
exprSelect().from(source).project('result', cfExpr.countStar().eqLit(0)).where(where).build(),
|
|
24
|
+
columnPresent: () =>
|
|
25
|
+
exprSelect().from(source).project('result', cfExpr.countStar().gtLit(0)).where(where).build(),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface TableExistsCheckBuilder {
|
|
30
|
+
tableAbsent(): SelectAst;
|
|
31
|
+
tablePresent(): SelectAst;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Typed builder for table-existence checks over `sqlite_master`.
|
|
36
|
+
* Produces `SELECT COUNT(*) {=|>} 0 AS "result" FROM "sqlite_master" WHERE "type" = ? AND "name" = ?`
|
|
37
|
+
* with the table name and the literal `'table'` bound as text parameters.
|
|
38
|
+
*/
|
|
39
|
+
export function tableExistsAst(tableName: string): TableExistsCheckBuilder {
|
|
40
|
+
const source = cfTable('sqlite_master');
|
|
41
|
+
const where = cfExpr.allOf([
|
|
42
|
+
cfExpr.identifierRef('type').eqParam('table', SQLITE_TEXT_CODEC_ID),
|
|
43
|
+
cfExpr.identifierRef('name').eqParam(tableName, SQLITE_TEXT_CODEC_ID),
|
|
44
|
+
]);
|
|
45
|
+
return {
|
|
46
|
+
tableAbsent: () =>
|
|
47
|
+
exprSelect().from(source).project('result', cfExpr.countStar().eqLit(0)).where(where).build(),
|
|
48
|
+
tablePresent: () =>
|
|
49
|
+
exprSelect().from(source).project('result', cfExpr.countStar().gtLit(0)).where(where).build(),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IndexExistsCheckBuilder {
|
|
54
|
+
indexAbsent(): SelectAst;
|
|
55
|
+
indexPresent(): SelectAst;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Typed builder for index-existence checks over `sqlite_master`.
|
|
60
|
+
* Produces `SELECT COUNT(*) {=|>} 0 AS "result" FROM "sqlite_master" WHERE "type" = ? AND "name" = ?`
|
|
61
|
+
* with the index name and the literal `'index'` bound as text parameters.
|
|
62
|
+
*/
|
|
63
|
+
export function indexExistsAst(indexName: string): IndexExistsCheckBuilder {
|
|
64
|
+
const source = cfTable('sqlite_master');
|
|
65
|
+
const where = cfExpr.allOf([
|
|
66
|
+
cfExpr.identifierRef('type').eqParam('index', SQLITE_TEXT_CODEC_ID),
|
|
67
|
+
cfExpr.identifierRef('name').eqParam(indexName, SQLITE_TEXT_CODEC_ID),
|
|
68
|
+
]);
|
|
69
|
+
return {
|
|
70
|
+
indexAbsent: () =>
|
|
71
|
+
exprSelect().from(source).project('result', cfExpr.countStar().eqLit(0)).where(where).build(),
|
|
72
|
+
indexPresent: () =>
|
|
73
|
+
exprSelect().from(source).project('result', cfExpr.countStar().gtLit(0)).where(where).build(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -36,8 +36,8 @@ const sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', Sqlite
|
|
|
36
36
|
contractSerializer: new SqliteContractSerializer(),
|
|
37
37
|
schemaVerifier: new SqliteSchemaVerifier(),
|
|
38
38
|
migrations: {
|
|
39
|
-
createPlanner(
|
|
40
|
-
return createSqliteMigrationPlanner();
|
|
39
|
+
createPlanner(adapter: SqlControlAdapter<'sqlite'>): MigrationPlanner<'sql', 'sqlite'> {
|
|
40
|
+
return createSqliteMigrationPlanner(adapter);
|
|
41
41
|
},
|
|
42
42
|
createRunner(family) {
|
|
43
43
|
return createSqliteMigrationRunner(family) as MigrationRunner<'sql', 'sqlite'>;
|
|
@@ -67,8 +67,8 @@ const sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', Sqlite
|
|
|
67
67
|
targetId: 'sqlite',
|
|
68
68
|
};
|
|
69
69
|
},
|
|
70
|
-
createPlanner(
|
|
71
|
-
return createSqliteMigrationPlanner();
|
|
70
|
+
createPlanner(adapter: SqlControlAdapter<'sqlite'>) {
|
|
71
|
+
return createSqliteMigrationPlanner(adapter);
|
|
72
72
|
},
|
|
73
73
|
createRunner(family) {
|
|
74
74
|
return createSqliteMigrationRunner(family);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CliStructuredError } from '@prisma-next/errors/control';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A `SqliteMigration` instance method that needs the materialized control
|
|
5
|
+
* adapter (currently only `this.createTable(...)`) was invoked, but the
|
|
6
|
+
* migration was constructed without a `ControlStack`. Concrete authoring
|
|
7
|
+
* usage always goes through the migration CLI entrypoint, which assembles
|
|
8
|
+
* a stack from the loaded `prisma-next.config.ts`; reaching this error
|
|
9
|
+
* means a test fixture or ad-hoc consumer instantiated `SqliteMigration`
|
|
10
|
+
* with the no-arg form (legal for `operations` / `describe` introspection
|
|
11
|
+
* only).
|
|
12
|
+
*
|
|
13
|
+
* Distinct from `PN-MIG-2001` (placeholder not filled) because the missing
|
|
14
|
+
* input is the stack itself, not the per-operation contract.
|
|
15
|
+
*
|
|
16
|
+
* Lives in `@prisma-next/target-sqlite/errors` rather than the shared
|
|
17
|
+
* framework migration errors module because the failure is target-specific:
|
|
18
|
+
* the contract it talks about (`SqliteMigration`, the SQLite control
|
|
19
|
+
* adapter, the SQLite-target stack) only exists in this package.
|
|
20
|
+
*/
|
|
21
|
+
export function errorSqliteMigrationStackMissing(): CliStructuredError {
|
|
22
|
+
return new CliStructuredError('2008', 'SqliteMigration.createTable requires a control adapter', {
|
|
23
|
+
domain: 'MIG',
|
|
24
|
+
why: 'SqliteMigration.createTable was invoked on an instance constructed without a ControlStack. The stored controlAdapter is undefined, so createTable cannot lower its DDL node.',
|
|
25
|
+
fix: 'Construct the migration via the migration CLI entrypoint (which assembles a ControlStack from the loaded prisma-next.config.ts), or pass a ControlStack containing a SQLite adapter to the migration constructor in test fixtures.',
|
|
26
|
+
meta: {},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* remaining issues flow through `mapIssueToCall` for the default case.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { Contract } from '@prisma-next/contract/types';
|
|
11
|
+
import type { Contract, JsonValue } from '@prisma-next/contract/types';
|
|
12
12
|
import type {
|
|
13
13
|
CodecControlHooks,
|
|
14
14
|
MigrationOperationPolicy,
|
|
@@ -18,14 +18,24 @@ import type {
|
|
|
18
18
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
19
19
|
import type { SchemaIssue } from '@prisma-next/framework-components/control';
|
|
20
20
|
import type {
|
|
21
|
-
PostgresEnumStorageEntry,
|
|
22
21
|
SqlStorage,
|
|
23
22
|
StorageColumn,
|
|
24
23
|
StorageTable,
|
|
25
24
|
StorageTypeInstance,
|
|
26
25
|
} from '@prisma-next/sql-contract/types';
|
|
26
|
+
import type { CodecRef, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
|
|
27
|
+
import {
|
|
28
|
+
DdlColumn,
|
|
29
|
+
ForeignKeyConstraint,
|
|
30
|
+
FunctionColumnDefault,
|
|
31
|
+
LiteralColumnDefault,
|
|
32
|
+
PrimaryKeyConstraint,
|
|
33
|
+
UniqueConstraint,
|
|
34
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
27
35
|
import { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';
|
|
28
36
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
37
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
38
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
29
39
|
import type { Result } from '@prisma-next/utils/result';
|
|
30
40
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
31
41
|
import { CONTROL_TABLE_NAMES } from '../control-tables';
|
|
@@ -48,6 +58,7 @@ import {
|
|
|
48
58
|
buildColumnDefaultSql,
|
|
49
59
|
buildColumnTypeSql,
|
|
50
60
|
isInlineAutoincrementPrimaryKey,
|
|
61
|
+
resolveColumnTypeMetadata,
|
|
51
62
|
} from './planner-ddl-builders';
|
|
52
63
|
import {
|
|
53
64
|
type CallMigrationStrategy,
|
|
@@ -206,12 +217,15 @@ function isMissing(issue: SchemaIssue): boolean {
|
|
|
206
217
|
export function toColumnSpec(
|
|
207
218
|
name: string,
|
|
208
219
|
column: StorageColumn,
|
|
209
|
-
storageTypes: Readonly<Record<string, StorageTypeInstance
|
|
220
|
+
storageTypes: Readonly<Record<string, StorageTypeInstance>>,
|
|
210
221
|
inlineAutoincrementPrimaryKey = false,
|
|
211
222
|
): SqliteColumnSpec {
|
|
212
223
|
const typeSql = buildColumnTypeSql(
|
|
213
224
|
column,
|
|
214
|
-
|
|
225
|
+
blindCast<
|
|
226
|
+
Record<string, StorageTypeInstance>,
|
|
227
|
+
'buildColumnTypeSql declares its storageTypes parameter as mutable Record while the planner stores it readonly; the helper does not mutate, so the readonly→mutable narrowing is sound'
|
|
228
|
+
>(storageTypes),
|
|
215
229
|
);
|
|
216
230
|
const defaultSql = buildColumnDefaultSql(column.default);
|
|
217
231
|
return {
|
|
@@ -231,7 +245,7 @@ export function toColumnSpec(
|
|
|
231
245
|
*/
|
|
232
246
|
export function toTableSpec(
|
|
233
247
|
table: StorageTable,
|
|
234
|
-
storageTypes: Readonly<Record<string, StorageTypeInstance
|
|
248
|
+
storageTypes: Readonly<Record<string, StorageTypeInstance>>,
|
|
235
249
|
): SqliteTableSpec {
|
|
236
250
|
const columns: SqliteColumnSpec[] = Object.entries(table.columns).map(([name, column]) =>
|
|
237
251
|
toColumnSpec(name, column, storageTypes, isInlineAutoincrementPrimaryKey(table, name)),
|
|
@@ -256,6 +270,126 @@ export function toTableSpec(
|
|
|
256
270
|
};
|
|
257
271
|
}
|
|
258
272
|
|
|
273
|
+
// ============================================================================
|
|
274
|
+
// StorageTable / StorageColumn → DdlColumn[] + DdlTableConstraint[] (for CreateTableCall)
|
|
275
|
+
// ============================================================================
|
|
276
|
+
|
|
277
|
+
function sqliteDefaultToDdlColumnDefault(
|
|
278
|
+
columnDefault: StorageColumn['default'],
|
|
279
|
+
): DdlColumn['default'] {
|
|
280
|
+
if (!columnDefault) return undefined;
|
|
281
|
+
switch (columnDefault.kind) {
|
|
282
|
+
case 'literal':
|
|
283
|
+
return new LiteralColumnDefault(columnDefault.value);
|
|
284
|
+
case 'function':
|
|
285
|
+
// `autoincrement()` is not a DEFAULT clause — SQLite encodes it as
|
|
286
|
+
// `INTEGER PRIMARY KEY AUTOINCREMENT` inline on the column. Skip it
|
|
287
|
+
// here; the renderer also has a defensive guard for the same case.
|
|
288
|
+
if (columnDefault.expression === 'autoincrement()') return undefined;
|
|
289
|
+
return new FunctionColumnDefault(columnDefault.expression);
|
|
290
|
+
default: {
|
|
291
|
+
const exhaustive: never = columnDefault;
|
|
292
|
+
throw new Error(
|
|
293
|
+
`sqliteDefaultToDdlColumnDefault: unhandled kind "${blindCast<{ kind: string }, 'exhaustiveness: surface the unhandled default kind'>(exhaustive).kind}"`,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Converts a `StorageTable` to the `DdlColumn[]` + `DdlTableConstraint[]`
|
|
301
|
+
* pair used by `CreateTableCall`. This is the structured form consumed by
|
|
302
|
+
* the DDL lowering path; `toTableSpec` / `toColumnSpec` remain in use for
|
|
303
|
+
* `RecreateTableCall` and `AddColumnCall` (Phase 2).
|
|
304
|
+
*/
|
|
305
|
+
export function tableToDdlParts(
|
|
306
|
+
table: StorageTable,
|
|
307
|
+
storageTypes: Record<string, StorageTypeInstance>,
|
|
308
|
+
): { columns: DdlColumn[]; constraints: DdlTableConstraint[] } {
|
|
309
|
+
const columns: DdlColumn[] = Object.entries(table.columns).map(([name, column]) => {
|
|
310
|
+
const inlineAutoincrement = isInlineAutoincrementPrimaryKey(table, name);
|
|
311
|
+
const typeSql = buildColumnTypeSql(
|
|
312
|
+
column,
|
|
313
|
+
blindCast<
|
|
314
|
+
Record<string, StorageTypeInstance>,
|
|
315
|
+
'buildColumnTypeSql declares its storageTypes parameter as mutable Record while the planner stores it readonly; the helper does not mutate, so the readonly→mutable narrowing is sound'
|
|
316
|
+
>(storageTypes),
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
if (inlineAutoincrement) {
|
|
320
|
+
// `DdlColumn` has no SQLite-specific autoincrement flag, so the full
|
|
321
|
+
// `PRIMARY KEY AUTOINCREMENT` clause is embedded in the `type` string.
|
|
322
|
+
// The DDL renderer (`ddl-renderer.ts`) substring-detects `AUTOINCREMENT`
|
|
323
|
+
// to suppress the normal NOT NULL / PRIMARY KEY / DEFAULT clause rendering
|
|
324
|
+
// and emit the entire type string verbatim. Both sites must stay in sync.
|
|
325
|
+
// The structural fix (a SQLite-specific column option) is tracked in TML-2866.
|
|
326
|
+
return new DdlColumn({ name, type: `${typeSql} PRIMARY KEY AUTOINCREMENT` });
|
|
327
|
+
}
|
|
328
|
+
const colDefault = sqliteDefaultToDdlColumnDefault(column.default);
|
|
329
|
+
const resolved = resolveColumnTypeMetadata(
|
|
330
|
+
column,
|
|
331
|
+
blindCast<
|
|
332
|
+
Record<string, StorageTypeInstance>,
|
|
333
|
+
'resolveColumnTypeMetadata declares its storageTypes parameter as mutable Record while the planner stores it readonly; the helper does not mutate, so the readonly→mutable narrowing is sound'
|
|
334
|
+
>(storageTypes),
|
|
335
|
+
);
|
|
336
|
+
const codecRef: CodecRef | undefined = resolved.codecId
|
|
337
|
+
? {
|
|
338
|
+
codecId: resolved.codecId,
|
|
339
|
+
...(resolved.typeParams !== undefined
|
|
340
|
+
? {
|
|
341
|
+
typeParams: blindCast<
|
|
342
|
+
JsonValue,
|
|
343
|
+
'resolved.typeParams is JsonValue-shaped storage metadata; the narrowed (non-undefined) value lands in CodecRef.typeParams which is JsonValue'
|
|
344
|
+
>(resolved.typeParams),
|
|
345
|
+
}
|
|
346
|
+
: {}),
|
|
347
|
+
}
|
|
348
|
+
: undefined;
|
|
349
|
+
return new DdlColumn({
|
|
350
|
+
name,
|
|
351
|
+
type: typeSql,
|
|
352
|
+
...(!column.nullable ? { notNull: true } : {}),
|
|
353
|
+
...(colDefault !== undefined ? { default: colDefault } : {}),
|
|
354
|
+
...(codecRef !== undefined ? { codecRef } : {}),
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const constraints: DdlTableConstraint[] = [];
|
|
359
|
+
|
|
360
|
+
const hasInlinePk = Object.entries(table.columns).some(([name]) =>
|
|
361
|
+
isInlineAutoincrementPrimaryKey(table, name),
|
|
362
|
+
);
|
|
363
|
+
if (table.primaryKey && !hasInlinePk) {
|
|
364
|
+
constraints.push(new PrimaryKeyConstraint({ columns: table.primaryKey.columns }));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
for (const u of table.uniques) {
|
|
368
|
+
constraints.push(
|
|
369
|
+
new UniqueConstraint({
|
|
370
|
+
columns: u.columns,
|
|
371
|
+
...(u.name !== undefined ? { name: u.name } : {}),
|
|
372
|
+
}),
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
for (const fk of table.foreignKeys) {
|
|
377
|
+
if (fk.constraint === false) continue;
|
|
378
|
+
constraints.push(
|
|
379
|
+
new ForeignKeyConstraint({
|
|
380
|
+
columns: fk.source.columns,
|
|
381
|
+
refTable: fk.target.tableName,
|
|
382
|
+
refColumns: fk.target.columns,
|
|
383
|
+
...ifDefined('name', fk.name),
|
|
384
|
+
...ifDefined('onDelete', fk.onDelete),
|
|
385
|
+
...ifDefined('onUpdate', fk.onUpdate),
|
|
386
|
+
}),
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return { columns, constraints };
|
|
391
|
+
}
|
|
392
|
+
|
|
259
393
|
// ============================================================================
|
|
260
394
|
// Issue planner
|
|
261
395
|
// ============================================================================
|
|
@@ -265,7 +399,7 @@ export interface IssuePlannerOptions {
|
|
|
265
399
|
readonly toContract: Contract<SqlStorage>;
|
|
266
400
|
readonly fromContract: Contract<SqlStorage> | null;
|
|
267
401
|
readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;
|
|
268
|
-
readonly storageTypes: Readonly<Record<string, StorageTypeInstance
|
|
402
|
+
readonly storageTypes: Readonly<Record<string, StorageTypeInstance>>;
|
|
269
403
|
readonly schema?: SqlSchemaIR;
|
|
270
404
|
readonly policy?: MigrationOperationPolicy;
|
|
271
405
|
readonly frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
|
|
@@ -309,8 +443,17 @@ function mapIssueToCall(
|
|
|
309
443
|
),
|
|
310
444
|
);
|
|
311
445
|
}
|
|
312
|
-
const
|
|
313
|
-
|
|
446
|
+
const { columns: ddlColumns, constraints: ddlConstraints } = tableToDdlParts(
|
|
447
|
+
contractTable,
|
|
448
|
+
ctx.storageTypes,
|
|
449
|
+
);
|
|
450
|
+
const calls: SqliteOpFactoryCall[] = [
|
|
451
|
+
new CreateTableCall(
|
|
452
|
+
issue.table,
|
|
453
|
+
ddlColumns,
|
|
454
|
+
ddlConstraints.length > 0 ? ddlConstraints : undefined,
|
|
455
|
+
),
|
|
456
|
+
];
|
|
314
457
|
const declaredIndexColumnKeys = new Set<string>();
|
|
315
458
|
for (const index of contractTable.indexes) {
|
|
316
459
|
const indexName = index.name ?? defaultIndexName(issue.table, index.columns);
|