@prisma-next/target-sqlite 0.15.0 → 0.16.0-dev.10
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/{codec-ids-BfPkjMmk.d.mts → codec-ids-Dof8fZfe.d.mts} +1 -2
- package/dist/codec-ids-Dof8fZfe.d.mts.map +1 -0
- package/dist/codec-ids.d.mts +1 -1
- package/dist/{codec-types-izdPhp_9.d.mts → codec-types-CcFkbJ3o.d.mts} +3 -4
- package/dist/codec-types-CcFkbJ3o.d.mts.map +1 -0
- package/dist/codec-types.d.mts +2 -2
- package/dist/{codecs-BGeJavlQ.d.mts → codecs-DGgo--O0.d.mts} +2 -3
- package/dist/codecs-DGgo--O0.d.mts.map +1 -0
- package/dist/codecs.d.mts +1 -1
- package/dist/contract-free.d.mts +1 -2
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/control-tables.d.mts.map +1 -1
- package/dist/control.d.mts +0 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +14 -14
- package/dist/control.mjs.map +1 -1
- package/dist/ddl.d.mts +1 -1
- package/dist/default-normalizer.d.mts +0 -1
- package/dist/default-normalizer.d.mts.map +1 -1
- package/dist/{descriptor-meta-D1fap-5t.mjs → descriptor-meta-BPrgV878.mjs} +12 -6
- package/dist/descriptor-meta-BPrgV878.mjs.map +1 -0
- package/dist/migration.d.mts +2 -3
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +2 -2
- package/dist/native-type-normalizer.d.mts.map +1 -1
- package/dist/{nodes-VzaaeUTb.d.mts → nodes-COZjF41I.d.mts} +1 -2
- package/dist/nodes-COZjF41I.d.mts.map +1 -0
- package/dist/{op-factory-call-Do03QgD9.mjs → op-factory-call-8pTnIHhR.mjs} +8 -8
- package/dist/op-factory-call-8pTnIHhR.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +2 -3
- package/dist/op-factory-call.d.mts.map +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.d.mts +41 -2
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-produced-sqlite-migration-CeGjNfd2.mjs → planner-produced-sqlite-migration-CWmvnJi4.mjs} +21 -11
- package/dist/planner-produced-sqlite-migration-CWmvnJi4.mjs.map +1 -0
- package/dist/{planner-produced-sqlite-migration-o1qUzwLk.d.mts → planner-produced-sqlite-migration-fd_Jw-mL.d.mts} +3 -4
- package/dist/planner-produced-sqlite-migration-fd_Jw-mL.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-D2hMk3oC.mjs → planner-sc4nqpzL.mjs} +19 -59
- package/dist/planner-sc4nqpzL.mjs.map +1 -0
- package/dist/planner-target-details-xR6UfIcz.d.mts.map +1 -1
- package/dist/planner.d.mts +7 -2
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/render-ops.d.mts +0 -1
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/runtime.d.mts +1 -2
- package/dist/runtime.d.mts.map +1 -1
- package/dist/{shared-C6sM-wel.d.mts → shared-DLUM4Ae2.d.mts} +1 -3
- package/dist/shared-DLUM4Ae2.d.mts.map +1 -0
- package/dist/sql-utils.d.mts.map +1 -1
- package/dist/{sqlite-contract-view-J32K82Gi.d.mts → sqlite-contract-view-CMgE0L4W.d.mts} +4 -3
- package/dist/sqlite-contract-view-CMgE0L4W.d.mts.map +1 -0
- package/dist/{sqlite-migration-BYbzskpE.d.mts → sqlite-migration-CBXynqeE.d.mts} +8 -8
- package/dist/sqlite-migration-CBXynqeE.d.mts.map +1 -0
- package/dist/{sqlite-migration-C9bD6XDl.mjs → sqlite-migration-CLXPhPxF.mjs} +11 -10
- package/dist/sqlite-migration-CLXPhPxF.mjs.map +1 -0
- package/package.json +19 -19
- package/src/core/authoring.ts +11 -5
- package/src/core/errors.ts +12 -8
- package/src/core/migrations/issue-planner.ts +18 -62
- package/src/core/migrations/op-factory-call.ts +1 -1
- package/src/core/migrations/operations/shared.ts +3 -5
- package/src/core/migrations/operations/tables.ts +3 -2
- package/src/core/migrations/planner-produced-sqlite-migration.ts +4 -0
- package/src/core/migrations/planner-strategies.ts +4 -3
- package/src/core/migrations/planner.ts +11 -2
- package/src/core/migrations/render-typescript.ts +20 -8
- package/src/core/migrations/runner.ts +13 -12
- package/src/core/migrations/sqlite-migration.ts +5 -4
- package/dist/codec-ids-BfPkjMmk.d.mts.map +0 -1
- package/dist/codec-types-izdPhp_9.d.mts.map +0 -1
- package/dist/codecs-BGeJavlQ.d.mts.map +0 -1
- package/dist/descriptor-meta-D1fap-5t.mjs.map +0 -1
- package/dist/nodes-VzaaeUTb.d.mts.map +0 -1
- package/dist/op-factory-call-Do03QgD9.mjs.map +0 -1
- package/dist/planner-D2hMk3oC.mjs.map +0 -1
- package/dist/planner-produced-sqlite-migration-CeGjNfd2.mjs.map +0 -1
- package/dist/planner-produced-sqlite-migration-o1qUzwLk.d.mts.map +0 -1
- package/dist/shared-C6sM-wel.d.mts.map +0 -1
- package/dist/sqlite-contract-view-J32K82Gi.d.mts.map +0 -1
- package/dist/sqlite-migration-BYbzskpE.d.mts.map +0 -1
- package/dist/sqlite-migration-C9bD6XDl.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DropColumnCall, l as RecreateTableCall, n as CreateIndexCall, o as DropIndexCall, r as CreateTableCall, s as DropTableCall, t as AddColumnCall } from "./op-factory-call-
|
|
1
|
+
import { a as DropColumnCall, l as RecreateTableCall, n as CreateIndexCall, o as DropIndexCall, r as CreateTableCall, s as DropTableCall, t as AddColumnCall } from "./op-factory-call-8pTnIHhR.mjs";
|
|
2
2
|
import { t as SqliteContractView } from "./sqlite-contract-view-B8qeCczc.mjs";
|
|
3
3
|
import { blindCast } from "@prisma-next/utils/casts";
|
|
4
4
|
import { Migration } from "@prisma-next/family-sql/migration";
|
|
@@ -17,8 +17,9 @@ import { CliStructuredError } from "@prisma-next/errors/control";
|
|
|
17
17
|
* The `operation` argument is required so every throw site names the operation
|
|
18
18
|
* that actually failed; a new operation cannot inherit a misattributed message.
|
|
19
19
|
*
|
|
20
|
-
* Distinct from `
|
|
21
|
-
* input is the stack itself, not the per-operation
|
|
20
|
+
* Distinct from `MIGRATION.UNFILLED_PLACEHOLDER` (placeholder not filled)
|
|
21
|
+
* because the missing input is the stack itself, not the per-operation
|
|
22
|
+
* contract.
|
|
22
23
|
*
|
|
23
24
|
* Lives in `@prisma-next/target-sqlite/errors` rather than the shared
|
|
24
25
|
* framework migration errors module because the failure is target-specific:
|
|
@@ -26,8 +27,7 @@ import { CliStructuredError } from "@prisma-next/errors/control";
|
|
|
26
27
|
* adapter, the SQLite-target stack) only exists in this package.
|
|
27
28
|
*/
|
|
28
29
|
function errorSqliteMigrationStackMissing(operation) {
|
|
29
|
-
return new CliStructuredError("
|
|
30
|
-
domain: "MIG",
|
|
30
|
+
return new CliStructuredError("MIGRATION.SQLITE_CONTROL_STACK_MISSING", `SqliteMigration.${operation} requires a control adapter`, {
|
|
31
31
|
why: `SqliteMigration.${operation} was invoked on an instance constructed without a ControlStack, so the stored controlAdapter is undefined and the operation cannot lower its DDL node.`,
|
|
32
32
|
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.",
|
|
33
33
|
meta: { operation }
|
|
@@ -49,8 +49,9 @@ function errorSqliteMigrationStackMissing(operation) {
|
|
|
49
49
|
* through every call.
|
|
50
50
|
*
|
|
51
51
|
* Binds the framework base's `Start` / `End` contract generics so a subclass
|
|
52
|
-
* that assigns its
|
|
53
|
-
* fully-typed view accessors:
|
|
52
|
+
* that assigns its snapshot-store `contract.json` imports to
|
|
53
|
+
* `startContractJson` / `endContractJson` gets fully-typed view accessors:
|
|
54
|
+
* `this.endContract` is a `SqliteContractView<End>`
|
|
54
55
|
* (sole namespace unwrapped to the root — `this.endContract.table.<name>`),
|
|
55
56
|
* built lazily from the JSON fields via the shared `MigrationContractViews`
|
|
56
57
|
* helper. Mirrors `MongoMigration`'s view getters; the framework base derives
|
|
@@ -62,7 +63,7 @@ var SqliteMigration = class extends Migration {
|
|
|
62
63
|
* Materialized SQLite control adapter, created once per migration
|
|
63
64
|
* instance from the injected stack. `undefined` only when the migration
|
|
64
65
|
* was instantiated without a stack (test fixtures); `controlAdapterFor`
|
|
65
|
-
* throws a
|
|
66
|
+
* throws a MIGRATION.SQLITE_CONTROL_STACK_MISSING in that case to surface the misuse.
|
|
66
67
|
*/
|
|
67
68
|
controlAdapter;
|
|
68
69
|
#endView = new MigrationContractViews(this, "SqliteMigration", (json) => SqliteContractView.fromJson(json));
|
|
@@ -72,7 +73,7 @@ var SqliteMigration = class extends Migration {
|
|
|
72
73
|
this.controlAdapter = stack?.adapter ? blindCast(stack.adapter.create(stack)) : void 0;
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
|
-
* Returns the materialized control adapter, or throws a
|
|
76
|
+
* Returns the materialized control adapter, or throws a MIGRATION.SQLITE_CONTROL_STACK_MISSING naming
|
|
76
77
|
* `operation` when the migration was constructed without a `ControlStack`.
|
|
77
78
|
* Single home for the null-check that every DDL/DML method shares.
|
|
78
79
|
*/
|
|
@@ -120,4 +121,4 @@ var SqliteMigration = class extends Migration {
|
|
|
120
121
|
//#endregion
|
|
121
122
|
export { SqliteMigration as t };
|
|
122
123
|
|
|
123
|
-
//# sourceMappingURL=sqlite-migration-
|
|
124
|
+
//# sourceMappingURL=sqlite-migration-CLXPhPxF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-migration-CLXPhPxF.mjs","names":["SqlMigration","#endView","#startView"],"sources":["../src/core/errors.ts","../src/core/migrations/sqlite-migration.ts"],"sourcesContent":["import { CliStructuredError } from '@prisma-next/errors/control';\n\n/**\n * A `SqliteMigration` operation that needs the materialized control adapter\n * — named by `operation` (e.g. `createTable`, `dropColumn`, `recreateTable`) —\n * was invoked, but the migration was constructed without a `ControlStack`.\n * Concrete authoring usage always goes through the migration CLI entrypoint,\n * which assembles a stack from the loaded `prisma-next.config.ts`; reaching this\n * error means a test fixture or ad-hoc consumer instantiated `SqliteMigration`\n * with the no-arg form (legal for `operations` / `describe` introspection only).\n *\n * The `operation` argument is required so every throw site names the operation\n * that actually failed; a new operation cannot inherit a misattributed message.\n *\n * Distinct from `MIGRATION.UNFILLED_PLACEHOLDER` (placeholder not filled)\n * because the missing input is the stack itself, not the per-operation\n * contract.\n *\n * Lives in `@prisma-next/target-sqlite/errors` rather than the shared\n * framework migration errors module because the failure is target-specific:\n * the contract it talks about (`SqliteMigration`, the SQLite control\n * adapter, the SQLite-target stack) only exists in this package.\n */\nexport function errorSqliteMigrationStackMissing(operation: string): CliStructuredError {\n return new CliStructuredError(\n 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',\n `SqliteMigration.${operation} requires a control adapter`,\n {\n why: `SqliteMigration.${operation} was invoked on an instance constructed without a ControlStack, so the stored controlAdapter is undefined and the operation cannot lower its DDL node.`,\n 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.',\n meta: { operation },\n },\n );\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationClass,\n SqlMigrationPlanOperation,\n} from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport { Migration as SqlMigration } from '@prisma-next/family-sql/migration';\nimport type { ControlStack } from '@prisma-next/framework-components/control';\nimport { MigrationContractViews } from '@prisma-next/migration-tools/migration';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { errorSqliteMigrationStackMissing } from '../errors';\nimport { SqliteContractView } from '../sqlite-contract-view';\nimport {\n AddColumnCall,\n CreateIndexCall,\n CreateTableCall,\n DropColumnCall,\n DropIndexCall,\n DropTableCall,\n RecreateTableCall,\n} from './op-factory-call';\nimport type { SqliteColumnSpec, SqliteIndexSpec, SqliteTableSpec } from './operations/shared';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\n\ntype Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;\n\n/**\n * Target-owned base class for SQLite migrations. Fixes the `SqlMigration`\n * generic to `SqlitePlanTargetDetails` and the abstract `targetId` to the\n * SQLite literal, so both user-authored migrations and renderer-generated\n * scaffolds can extend `SqliteMigration` directly without redeclaring\n * target-local identity.\n *\n * The constructor materializes a single SQLite `SqlControlAdapter` from\n * `stack.adapter.create(stack)` and stores it; the protected instance methods\n * forward to the corresponding `*Call` with that stored adapter, so user\n * migrations can write `this.createTable({...})` without threading the adapter\n * through every call.\n *\n * Binds the framework base's `Start` / `End` contract generics so a subclass\n * that assigns its snapshot-store `contract.json` imports to\n * `startContractJson` / `endContractJson` gets fully-typed view accessors:\n * `this.endContract` is a `SqliteContractView<End>`\n * (sole namespace unwrapped to the root — `this.endContract.table.<name>`),\n * built lazily from the JSON fields via the shared `MigrationContractViews`\n * helper. Mirrors `MongoMigration`'s view getters; the framework base derives\n * `describe()` from the same JSON.\n */\nexport abstract class SqliteMigration<\n Start extends Contract<SqlStorage> = Contract<SqlStorage>,\n End extends Contract<SqlStorage> = Contract<SqlStorage>,\n> extends SqlMigration<SqlitePlanTargetDetails, 'sqlite', Start, End> {\n readonly targetId = 'sqlite' as const;\n\n /**\n * Materialized SQLite control adapter, created once per migration\n * instance from the injected stack. `undefined` only when the migration\n * was instantiated without a stack (test fixtures); `controlAdapterFor`\n * throws a MIGRATION.SQLITE_CONTROL_STACK_MISSING in that case to surface the misuse.\n */\n protected readonly controlAdapter: SqlControlAdapter<'sqlite'> | undefined;\n\n #endView = new MigrationContractViews<SqliteContractView<End>>(this, 'SqliteMigration', (json) =>\n SqliteContractView.fromJson<End>(json),\n );\n #startView = new MigrationContractViews<SqliteContractView<Start>>(\n this,\n 'SqliteMigration',\n (json) => SqliteContractView.fromJson<Start>(json),\n );\n\n constructor(stack?: ControlStack<'sql', 'sqlite'>) {\n super(stack);\n this.controlAdapter = stack?.adapter\n ? blindCast<\n SqlControlAdapter<'sqlite'>,\n 'The SQLite descriptor create() returns SqlControlAdapter<sqlite>; typed as wider ControlAdapterInstance at the framework boundary'\n >(stack.adapter.create(stack))\n : undefined;\n }\n\n /**\n * Returns the materialized control adapter, or throws a MIGRATION.SQLITE_CONTROL_STACK_MISSING naming\n * `operation` when the migration was constructed without a `ControlStack`.\n * Single home for the null-check that every DDL/DML method shares.\n */\n private controlAdapterFor(operation: string): SqlControlAdapter<'sqlite'> {\n if (!this.controlAdapter) {\n throw errorSqliteMigrationStackMissing(operation);\n }\n return this.controlAdapter;\n }\n\n /**\n * The typed SQLite view over this migration's end-state contract — sole\n * namespace unwrapped to the root, so `this.endContract.table.<name>` etc.\n * Throws if no `endContractJson` was provided.\n */\n get endContract(): SqliteContractView<End> {\n return this.#endView.endContract;\n }\n\n /**\n * The typed SQLite view over this migration's start-state contract, or\n * `null` for a baseline migration (no `startContractJson`).\n */\n get startContract(): SqliteContractView<Start> | null {\n return this.#startView.startContract;\n }\n\n protected createTable(options: {\n readonly table: string;\n readonly ifNotExists?: boolean;\n readonly columns: readonly DdlColumn[];\n readonly constraints?: readonly DdlTableConstraint[];\n }): Promise<Op> {\n return new CreateTableCall(options.table, options.columns, options.constraints).toOp(\n this.controlAdapterFor('createTable'),\n );\n }\n\n protected dropTable(options: { readonly table: string }): Promise<Op> {\n return new DropTableCall(options.table).toOp(this.controlAdapterFor('dropTable'));\n }\n\n protected addColumn(options: {\n readonly table: string;\n readonly column: SqliteColumnSpec;\n }): Promise<Op> {\n return new AddColumnCall(options.table, options.column).toOp(\n this.controlAdapterFor('addColumn'),\n );\n }\n\n protected dropColumn(options: { readonly table: string; readonly column: string }): Promise<Op> {\n return new DropColumnCall(options.table, options.column).toOp(\n this.controlAdapterFor('dropColumn'),\n );\n }\n\n protected createIndex(options: {\n readonly table: string;\n readonly index: string;\n readonly columns: readonly string[];\n }): Promise<Op> {\n return new CreateIndexCall(options.table, options.index, options.columns).toOp(\n this.controlAdapterFor('createIndex'),\n );\n }\n\n protected dropIndex(options: { readonly table: string; readonly index: string }): Promise<Op> {\n return new DropIndexCall(options.table, options.index).toOp(\n this.controlAdapterFor('dropIndex'),\n );\n }\n\n protected recreateTable(options: {\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 operationClass: MigrationOperationClass;\n }): Promise<Op> {\n return new RecreateTableCall(options).toOp(this.controlAdapterFor('recreateTable'));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,iCAAiC,WAAuC;CACtF,OAAO,IAAI,mBACT,0CACA,mBAAmB,UAAU,8BAC7B;EACE,KAAK,mBAAmB,UAAU;EAClC,KAAK;EACL,MAAM,EAAE,UAAU;CACpB,CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;ACiBA,IAAsB,kBAAtB,cAGUA,UAA4D;CACpE,WAAoB;;;;;;;CAQpB;CAEA,WAAW,IAAI,uBAAgD,MAAM,oBAAoB,SACvF,mBAAmB,SAAc,IAAI,CACvC;CACA,aAAa,IAAI,uBACf,MACA,oBACC,SAAS,mBAAmB,SAAgB,IAAI,CACnD;CAEA,YAAY,OAAuC;EACjD,MAAM,KAAK;EACX,KAAK,iBAAiB,OAAO,UACzB,UAGE,MAAM,QAAQ,OAAO,KAAK,CAAC,IAC7B,KAAA;CACN;;;;;;CAOA,kBAA0B,WAAgD;EACxE,IAAI,CAAC,KAAK,gBACR,MAAM,iCAAiC,SAAS;EAElD,OAAO,KAAK;CACd;;;;;;CAOA,IAAI,cAAuC;EACzC,OAAO,KAAKC,SAAS;CACvB;;;;;CAMA,IAAI,gBAAkD;EACpD,OAAO,KAAKC,WAAW;CACzB;CAEA,YAAsB,SAKN;EACd,OAAO,IAAI,gBAAgB,QAAQ,OAAO,QAAQ,SAAS,QAAQ,WAAW,CAAC,CAAC,KAC9E,KAAK,kBAAkB,aAAa,CACtC;CACF;CAEA,UAAoB,SAAkD;EACpE,OAAO,IAAI,cAAc,QAAQ,KAAK,CAAC,CAAC,KAAK,KAAK,kBAAkB,WAAW,CAAC;CAClF;CAEA,UAAoB,SAGJ;EACd,OAAO,IAAI,cAAc,QAAQ,OAAO,QAAQ,MAAM,CAAC,CAAC,KACtD,KAAK,kBAAkB,WAAW,CACpC;CACF;CAEA,WAAqB,SAA2E;EAC9F,OAAO,IAAI,eAAe,QAAQ,OAAO,QAAQ,MAAM,CAAC,CAAC,KACvD,KAAK,kBAAkB,YAAY,CACrC;CACF;CAEA,YAAsB,SAIN;EACd,OAAO,IAAI,gBAAgB,QAAQ,OAAO,QAAQ,OAAO,QAAQ,OAAO,CAAC,CAAC,KACxE,KAAK,kBAAkB,aAAa,CACtC;CACF;CAEA,UAAoB,SAA0E;EAC5F,OAAO,IAAI,cAAc,QAAQ,OAAO,QAAQ,KAAK,CAAC,CAAC,KACrD,KAAK,kBAAkB,WAAW,CACpC;CACF;CAEA,cAAwB,SAQR;EACd,OAAO,IAAI,kBAAkB,OAAO,CAAC,CAAC,KAAK,KAAK,kBAAkB,eAAe,CAAC;CACpF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/target-sqlite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0-dev.10",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@prisma-next/cli": "0.
|
|
9
|
-
"@prisma-next/contract": "0.
|
|
10
|
-
"@prisma-next/errors": "0.
|
|
11
|
-
"@prisma-next/family-sql": "0.
|
|
12
|
-
"@prisma-next/framework-components": "0.
|
|
13
|
-
"@prisma-next/migration-tools": "0.
|
|
14
|
-
"@prisma-next/sql-contract": "0.
|
|
15
|
-
"@prisma-next/sql-errors": "0.
|
|
16
|
-
"@prisma-next/sql-relational-core": "0.
|
|
17
|
-
"@prisma-next/sql-runtime": "0.
|
|
18
|
-
"@prisma-next/sql-schema-ir": "0.
|
|
19
|
-
"@prisma-next/ts-render": "0.
|
|
20
|
-
"@prisma-next/utils": "0.
|
|
8
|
+
"@prisma-next/cli": "0.16.0-dev.10",
|
|
9
|
+
"@prisma-next/contract": "0.16.0-dev.10",
|
|
10
|
+
"@prisma-next/errors": "0.16.0-dev.10",
|
|
11
|
+
"@prisma-next/family-sql": "0.16.0-dev.10",
|
|
12
|
+
"@prisma-next/framework-components": "0.16.0-dev.10",
|
|
13
|
+
"@prisma-next/migration-tools": "0.16.0-dev.10",
|
|
14
|
+
"@prisma-next/sql-contract": "0.16.0-dev.10",
|
|
15
|
+
"@prisma-next/sql-errors": "0.16.0-dev.10",
|
|
16
|
+
"@prisma-next/sql-relational-core": "0.16.0-dev.10",
|
|
17
|
+
"@prisma-next/sql-runtime": "0.16.0-dev.10",
|
|
18
|
+
"@prisma-next/sql-schema-ir": "0.16.0-dev.10",
|
|
19
|
+
"@prisma-next/ts-render": "0.16.0-dev.10",
|
|
20
|
+
"@prisma-next/utils": "0.16.0-dev.10",
|
|
21
21
|
"@standard-schema/spec": "1.1.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@prisma-next/driver-sqlite": "0.
|
|
25
|
-
"@prisma-next/test-utils": "0.
|
|
26
|
-
"@prisma-next/tsconfig": "0.
|
|
27
|
-
"@prisma-next/tsdown": "0.
|
|
28
|
-
"tsdown": "0.22.
|
|
24
|
+
"@prisma-next/driver-sqlite": "0.16.0-dev.10",
|
|
25
|
+
"@prisma-next/test-utils": "0.16.0-dev.10",
|
|
26
|
+
"@prisma-next/tsconfig": "0.16.0-dev.10",
|
|
27
|
+
"@prisma-next/tsdown": "0.16.0-dev.10",
|
|
28
|
+
"tsdown": "0.22.8",
|
|
29
29
|
"typescript": "5.9.3",
|
|
30
30
|
"vitest": "4.1.10"
|
|
31
31
|
},
|
package/src/core/authoring.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';
|
|
1
|
+
import { temporalAuthoringPresets, temporalCodecPreset } from '@prisma-next/family-sql/control';
|
|
2
2
|
import type { AuthoringFieldNamespace } from '@prisma-next/framework-components/authoring';
|
|
3
3
|
|
|
4
4
|
export const sqliteAuthoringFieldPresets = {
|
|
5
|
-
temporal:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
temporal: {
|
|
6
|
+
.../* @__PURE__ */ temporalAuthoringPresets({
|
|
7
|
+
codecId: 'sqlite/datetime@1',
|
|
8
|
+
nativeType: 'text',
|
|
9
|
+
}),
|
|
10
|
+
datetime: /* @__PURE__ */ temporalCodecPreset({
|
|
11
|
+
codecId: 'sqlite/datetime@1',
|
|
12
|
+
nativeType: 'text',
|
|
13
|
+
}),
|
|
14
|
+
},
|
|
9
15
|
} as const satisfies AuthoringFieldNamespace;
|
package/src/core/errors.ts
CHANGED
|
@@ -12,8 +12,9 @@ import { CliStructuredError } from '@prisma-next/errors/control';
|
|
|
12
12
|
* The `operation` argument is required so every throw site names the operation
|
|
13
13
|
* that actually failed; a new operation cannot inherit a misattributed message.
|
|
14
14
|
*
|
|
15
|
-
* Distinct from `
|
|
16
|
-
* input is the stack itself, not the per-operation
|
|
15
|
+
* Distinct from `MIGRATION.UNFILLED_PLACEHOLDER` (placeholder not filled)
|
|
16
|
+
* because the missing input is the stack itself, not the per-operation
|
|
17
|
+
* contract.
|
|
17
18
|
*
|
|
18
19
|
* Lives in `@prisma-next/target-sqlite/errors` rather than the shared
|
|
19
20
|
* framework migration errors module because the failure is target-specific:
|
|
@@ -21,10 +22,13 @@ import { CliStructuredError } from '@prisma-next/errors/control';
|
|
|
21
22
|
* adapter, the SQLite-target stack) only exists in this package.
|
|
22
23
|
*/
|
|
23
24
|
export function errorSqliteMigrationStackMissing(operation: string): CliStructuredError {
|
|
24
|
-
return new CliStructuredError(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
return new CliStructuredError(
|
|
26
|
+
'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
|
|
27
|
+
`SqliteMigration.${operation} requires a control adapter`,
|
|
28
|
+
{
|
|
29
|
+
why: `SqliteMigration.${operation} was invoked on an instance constructed without a ControlStack, so the stored controlAdapter is undefined and the operation cannot lower its DDL node.`,
|
|
30
|
+
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.',
|
|
31
|
+
meta: { operation },
|
|
32
|
+
},
|
|
33
|
+
);
|
|
30
34
|
}
|
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
} from '@prisma-next/family-sql/control';
|
|
22
22
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
23
23
|
import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
24
|
+
import { issueOutcome, orderIssuesByDependencies } from '@prisma-next/framework-components/control';
|
|
24
25
|
import { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';
|
|
25
26
|
import {
|
|
26
27
|
RelationalSchemaNodeKind,
|
|
@@ -63,51 +64,6 @@ import {
|
|
|
63
64
|
|
|
64
65
|
export type { CallMigrationStrategy, StrategyContext };
|
|
65
66
|
|
|
66
|
-
// ============================================================================
|
|
67
|
-
// Node-keyed issue ordering (dependency order)
|
|
68
|
-
// ============================================================================
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Re-keys the legacy `ISSUE_KIND_ORDER` (kind string → priority number) on
|
|
72
|
-
* `(nodeKind, reason)`. Numbers are preserved from the legacy table so the
|
|
73
|
-
* dependency intent stays legible; the final emission order is actually
|
|
74
|
-
* fixed downstream by category bucketing (create-table → add-column →
|
|
75
|
-
* create-index → recreate → drop-column → drop-index → drop-table), so this
|
|
76
|
-
* only breaks ties within a single bucket.
|
|
77
|
-
*/
|
|
78
|
-
export function nodeIssueOrder(issue: SchemaDiffIssue): number {
|
|
79
|
-
const node = issueNode(issue);
|
|
80
|
-
if (node === undefined) return 99;
|
|
81
|
-
switch (node.nodeKind) {
|
|
82
|
-
case RelationalSchemaNodeKind.foreignKey:
|
|
83
|
-
return issue.reason === 'not-expected' ? 10 : 60;
|
|
84
|
-
case RelationalSchemaNodeKind.unique:
|
|
85
|
-
return issue.reason === 'not-expected' ? 11 : 51;
|
|
86
|
-
case RelationalSchemaNodeKind.primaryKey:
|
|
87
|
-
return issue.reason === 'not-expected' ? 12 : 50;
|
|
88
|
-
case RelationalSchemaNodeKind.index:
|
|
89
|
-
return issue.reason === 'not-expected' ? 13 : 52;
|
|
90
|
-
case RelationalSchemaNodeKind.columnDefault:
|
|
91
|
-
if (issue.reason === 'not-expected') return 14;
|
|
92
|
-
return issue.reason === 'not-found' ? 42 : 43;
|
|
93
|
-
case RelationalSchemaNodeKind.column:
|
|
94
|
-
if (issue.reason === 'not-expected') return 15;
|
|
95
|
-
return issue.reason === 'not-found' ? 30 : 40;
|
|
96
|
-
case RelationalSchemaNodeKind.table:
|
|
97
|
-
return issue.reason === 'not-expected' ? 16 : 20;
|
|
98
|
-
case RelationalSchemaNodeKind.check:
|
|
99
|
-
if (issue.reason === 'not-found') return 53;
|
|
100
|
-
return issue.reason === 'not-expected' ? 54 : 55;
|
|
101
|
-
default:
|
|
102
|
-
return 99;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Deterministic tiebreak within an order bucket: the diff path itself already encodes table → child → grandchild. */
|
|
107
|
-
export function nodeIssueKey(issue: SchemaDiffIssue): string {
|
|
108
|
-
return issue.path.join(' ');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
67
|
// ============================================================================
|
|
112
68
|
// Subtree coalescing — the planner's responsibility per the differ's contract
|
|
113
69
|
// ============================================================================
|
|
@@ -126,7 +82,9 @@ export function coalesceSubtreeIssues(
|
|
|
126
82
|
issues: readonly SchemaDiffIssue[],
|
|
127
83
|
): readonly SchemaDiffIssue[] {
|
|
128
84
|
const collapsingPaths = issues
|
|
129
|
-
.filter(
|
|
85
|
+
.filter(
|
|
86
|
+
(issue) => issueOutcome(issue) === 'not-found' || issueOutcome(issue) === 'not-expected',
|
|
87
|
+
)
|
|
130
88
|
.map((issue) => issue.path);
|
|
131
89
|
if (collapsingPaths.length === 0) return issues;
|
|
132
90
|
return issues.filter(
|
|
@@ -180,12 +138,11 @@ export function tableSpecFromNode(table: SqlTableIR): SqliteTableSpec {
|
|
|
180
138
|
...(u.name !== undefined ? { name: u.name } : {}),
|
|
181
139
|
}));
|
|
182
140
|
// Every FK node on the expected tree is constraint-bearing by construction
|
|
183
|
-
// (
|
|
184
|
-
//
|
|
141
|
+
// (a persisted `foreignKeys[]` entry is a constraint; a non-constraint FK
|
|
142
|
+
// contributes only a backing index, never an FK node).
|
|
185
143
|
const foreignKeys: SqliteForeignKeySpec[] = table.foreignKeys.map((fk) => ({
|
|
186
144
|
columns: fk.columns,
|
|
187
145
|
references: { table: fk.referencedTable, columns: fk.referencedColumns },
|
|
188
|
-
constraint: true,
|
|
189
146
|
...(fk.name !== undefined ? { name: fk.name } : {}),
|
|
190
147
|
...(fk.onDelete !== undefined ? { onDelete: fk.onDelete } : {}),
|
|
191
148
|
...(fk.onUpdate !== undefined ? { onUpdate: fk.onUpdate } : {}),
|
|
@@ -274,14 +231,14 @@ function buildCreateTableCalls(table: SqlTableIR): SqliteOpFactoryCall[] {
|
|
|
274
231
|
function mapTableIssue(
|
|
275
232
|
issue: SchemaDiffIssue,
|
|
276
233
|
): Result<readonly SqliteOpFactoryCall[], SqlPlannerConflict> {
|
|
277
|
-
if (issue
|
|
234
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
278
235
|
const table = blindCast<
|
|
279
236
|
SqlTableIR,
|
|
280
237
|
'a not-found table issue always carries the expected table node'
|
|
281
238
|
>(issue.expected);
|
|
282
239
|
return ok(buildCreateTableCalls(table));
|
|
283
240
|
}
|
|
284
|
-
if (issue
|
|
241
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
285
242
|
const table = blindCast<
|
|
286
243
|
SqlTableIR,
|
|
287
244
|
'a not-expected table issue always carries the actual table node'
|
|
@@ -310,7 +267,7 @@ function mapColumnIssue(
|
|
|
310
267
|
),
|
|
311
268
|
);
|
|
312
269
|
}
|
|
313
|
-
if (issue
|
|
270
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
314
271
|
const column = blindCast<
|
|
315
272
|
SqlColumnIR,
|
|
316
273
|
'a not-found column issue always carries the expected column node'
|
|
@@ -323,7 +280,7 @@ function mapColumnIssue(
|
|
|
323
280
|
const inline = table !== undefined && isInlineAutoincrementPrimaryKeyNode(table, column);
|
|
324
281
|
return ok([new AddColumnCall(tableName, columnSpecFromNode(column, inline))]);
|
|
325
282
|
}
|
|
326
|
-
if (issue
|
|
283
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
327
284
|
const column = blindCast<
|
|
328
285
|
SqlColumnIR,
|
|
329
286
|
'a not-expected column issue always carries the actual column node'
|
|
@@ -357,7 +314,7 @@ function mapIndexIssue(
|
|
|
357
314
|
),
|
|
358
315
|
);
|
|
359
316
|
}
|
|
360
|
-
if (issue
|
|
317
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
361
318
|
const index = blindCast<
|
|
362
319
|
SqlIndexIR,
|
|
363
320
|
'a not-found index issue always carries the expected index node'
|
|
@@ -365,7 +322,7 @@ function mapIndexIssue(
|
|
|
365
322
|
const indexName = index.name ?? defaultIndexName(tableName, index.columns);
|
|
366
323
|
return ok([new CreateIndexCall(tableName, indexName, index.columns)]);
|
|
367
324
|
}
|
|
368
|
-
if (issue
|
|
325
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
369
326
|
const index = blindCast<
|
|
370
327
|
SqlIndexIR,
|
|
371
328
|
'a not-expected index issue always carries the actual index node'
|
|
@@ -505,13 +462,12 @@ export function planIssues(
|
|
|
505
462
|
}
|
|
506
463
|
}
|
|
507
464
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
});
|
|
465
|
+
// Dependency-graph order: a topological sort over the issues' `dependsOn`
|
|
466
|
+
// cross-links and containment edges (edge direction from the ordering law's
|
|
467
|
+
// presence rule), path-tiebroken for determinism. `classifyCall` bucketing
|
|
468
|
+
// downstream fixes the coarse create/recreate/drop sequence; this settles
|
|
469
|
+
// the order within each bucket.
|
|
470
|
+
const sorted = orderIssuesByDependencies(remaining);
|
|
515
471
|
|
|
516
472
|
const defaultCalls: SqliteOpFactoryCall[] = [];
|
|
517
473
|
const conflicts: SqlPlannerConflict[] = [];
|
|
@@ -563,7 +563,7 @@ export class DropIndexCall extends SqliteOpFactoryCallNode {
|
|
|
563
563
|
* any future strategy that needs a placeholder data step can construct one
|
|
564
564
|
* with its own id/label.
|
|
565
565
|
*
|
|
566
|
-
* `toOp()` always throws `
|
|
566
|
+
* `toOp()` always throws `MIGRATION.UNFILLED_PLACEHOLDER`: the planner cannot lower a stubbed
|
|
567
567
|
* transform to a runtime op — the user must edit the rendered
|
|
568
568
|
* `migration.ts` and re-emit.
|
|
569
569
|
*/
|
|
@@ -60,7 +60,6 @@ export interface SqliteForeignKeySpec {
|
|
|
60
60
|
readonly name?: string;
|
|
61
61
|
readonly onDelete?: ReferentialAction;
|
|
62
62
|
readonly onUpdate?: ReferentialAction;
|
|
63
|
-
readonly constraint: boolean;
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
/**
|
|
@@ -103,12 +102,11 @@ export function renderColumnDefinition(column: SqliteColumnSpec): string {
|
|
|
103
102
|
|
|
104
103
|
/**
|
|
105
104
|
* Renders an inline FOREIGN KEY constraint clause for a `CREATE TABLE`
|
|
106
|
-
* body.
|
|
107
|
-
*
|
|
108
|
-
*
|
|
105
|
+
* body. Every `SqliteForeignKeySpec` is constraint-bearing by construction
|
|
106
|
+
* (`tableSpecFromNode` only ever builds specs from schema-IR FK nodes, which
|
|
107
|
+
* are themselves constraint-only — a non-constraint FK contributes no node).
|
|
109
108
|
*/
|
|
110
109
|
export function renderForeignKeyClause(fk: SqliteForeignKeySpec): string {
|
|
111
|
-
if (!fk.constraint) return '';
|
|
112
110
|
const name = fk.name ? `CONSTRAINT ${quoteIdentifier(fk.name)} ` : '';
|
|
113
111
|
let sql = `${name}FOREIGN KEY (${fk.columns.map(quoteIdentifier).join(', ')}) REFERENCES ${quoteIdentifier(fk.references.table)} (${fk.references.columns.map(quoteIdentifier).join(', ')})`;
|
|
114
112
|
if (fk.onDelete !== undefined) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { MigrationOperationClass } from '@prisma-next/family-sql/control';
|
|
2
2
|
import type { ExecuteRequestLowerer } from '@prisma-next/family-sql/control-adapter';
|
|
3
3
|
import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
4
|
+
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
4
5
|
import { RelationalSchemaNodeKind, type SqlColumnIR } from '@prisma-next/sql-schema-ir/types';
|
|
5
6
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
6
7
|
import { tableExistsAst } from '../../../contract-free/checks';
|
|
@@ -294,7 +295,7 @@ export function buildRecreatePostchecks(
|
|
|
294
295
|
|
|
295
296
|
for (const issue of issues) {
|
|
296
297
|
const nodeKind = nodeKindOf(issue);
|
|
297
|
-
if (nodeKind === RelationalSchemaNodeKind.column && issue
|
|
298
|
+
if (nodeKind === RelationalSchemaNodeKind.column && issueOutcome(issue) === 'not-equal') {
|
|
298
299
|
const columnName = columnNameFromNode(issue);
|
|
299
300
|
if (columnName === undefined) continue;
|
|
300
301
|
const c = escapeLiteral(columnName);
|
|
@@ -325,7 +326,7 @@ export function buildRecreatePostchecks(
|
|
|
325
326
|
const columnName = columnNameFromDefaultIssuePath(issue);
|
|
326
327
|
if (columnName === undefined) continue;
|
|
327
328
|
const c = escapeLiteral(columnName);
|
|
328
|
-
if (issue
|
|
329
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
329
330
|
checks.push({
|
|
330
331
|
description: `verify "${columnName}" has no default on "${tableName}"`,
|
|
331
332
|
sql: `SELECT COUNT(*) > 0 FROM pragma_table_info('${t}') WHERE name = '${c}' AND dflt_value IS NULL`,
|
|
@@ -25,6 +25,7 @@ export class TypeScriptRenderableSqliteMigration
|
|
|
25
25
|
readonly #meta: MigrationMeta;
|
|
26
26
|
readonly #destination: SqliteMigrationDestinationInfo;
|
|
27
27
|
readonly #spaceId: string;
|
|
28
|
+
readonly #snapshotsImportPath: string;
|
|
28
29
|
readonly #lowerer: ExecuteRequestLowerer | undefined;
|
|
29
30
|
#operationsCache: readonly (Op | Promise<Op>)[] | undefined;
|
|
30
31
|
|
|
@@ -32,6 +33,7 @@ export class TypeScriptRenderableSqliteMigration
|
|
|
32
33
|
calls: readonly OpFactoryCall[],
|
|
33
34
|
meta: MigrationMeta,
|
|
34
35
|
spaceId: string,
|
|
36
|
+
snapshotsImportPath: string,
|
|
35
37
|
destination?: SqliteMigrationDestinationInfo,
|
|
36
38
|
lowerer?: ExecuteRequestLowerer,
|
|
37
39
|
) {
|
|
@@ -39,6 +41,7 @@ export class TypeScriptRenderableSqliteMigration
|
|
|
39
41
|
this.#calls = calls;
|
|
40
42
|
this.#meta = meta;
|
|
41
43
|
this.#spaceId = spaceId;
|
|
44
|
+
this.#snapshotsImportPath = snapshotsImportPath;
|
|
42
45
|
this.#destination = destination ?? { storageHash: meta.to };
|
|
43
46
|
this.#lowerer = lowerer;
|
|
44
47
|
}
|
|
@@ -69,6 +72,7 @@ export class TypeScriptRenderableSqliteMigration
|
|
|
69
72
|
return renderCallsToTypeScript(this.#calls, {
|
|
70
73
|
from: this.#meta.from,
|
|
71
74
|
to: this.#meta.to,
|
|
75
|
+
snapshotsImportPath: this.#snapshotsImportPath,
|
|
72
76
|
});
|
|
73
77
|
}
|
|
74
78
|
}
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
} from '@prisma-next/family-sql/control';
|
|
20
20
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
21
21
|
import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
22
|
+
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
22
23
|
import { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';
|
|
23
24
|
import {
|
|
24
25
|
RelationalSchemaNodeKind,
|
|
@@ -78,7 +79,7 @@ function classifyNodeIssue(issue: SchemaDiffIssue): 'widening' | 'destructive' |
|
|
|
78
79
|
>(node).nodeKind;
|
|
79
80
|
switch (nodeKind) {
|
|
80
81
|
case RelationalSchemaNodeKind.column: {
|
|
81
|
-
if (issue
|
|
82
|
+
if (issueOutcome(issue) !== 'not-equal') return null;
|
|
82
83
|
const expected = blindCast<SqlColumnIR, 'a not-equal column issue carries the expected node'>(
|
|
83
84
|
issue.expected,
|
|
84
85
|
);
|
|
@@ -91,7 +92,7 @@ function classifyNodeIssue(issue: SchemaDiffIssue): 'widening' | 'destructive' |
|
|
|
91
92
|
return expected.nullable ? 'widening' : 'destructive';
|
|
92
93
|
}
|
|
93
94
|
case RelationalSchemaNodeKind.columnDefault:
|
|
94
|
-
return issue
|
|
95
|
+
return issueOutcome(issue) === 'not-expected' ? 'destructive' : 'widening';
|
|
95
96
|
case RelationalSchemaNodeKind.primaryKey:
|
|
96
97
|
case RelationalSchemaNodeKind.foreignKey:
|
|
97
98
|
case RelationalSchemaNodeKind.unique:
|
|
@@ -206,7 +207,7 @@ export const nullabilityTighteningBackfillStrategy: CallMigrationStrategy = (iss
|
|
|
206
207
|
const calls: SqliteOpFactoryCall[] = [];
|
|
207
208
|
for (const issue of issues) {
|
|
208
209
|
if (
|
|
209
|
-
issue
|
|
210
|
+
issueOutcome(issue) !== 'not-equal' ||
|
|
210
211
|
issue.expected === undefined ||
|
|
211
212
|
issue.actual === undefined
|
|
212
213
|
) {
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
SchemaDiffIssue,
|
|
19
19
|
SchemaOwnership,
|
|
20
20
|
} from '@prisma-next/framework-components/control';
|
|
21
|
+
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
21
22
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
22
23
|
import { RelationalSchemaNodeKind, type SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
23
24
|
import { buildSqlitePlanDiff } from './diff-database-schema';
|
|
@@ -91,6 +92,12 @@ export class SqliteMigrationPlanner
|
|
|
91
92
|
* {@link SqlMigrationPlannerPlanOptions.ownership}.
|
|
92
93
|
*/
|
|
93
94
|
readonly ownership?: SchemaOwnership;
|
|
95
|
+
/**
|
|
96
|
+
* POSIX-relative path from the migration package dir to
|
|
97
|
+
* `migrations/snapshots` — see
|
|
98
|
+
* {@link SqlMigrationPlannerPlanOptions.snapshotsImportPath}.
|
|
99
|
+
*/
|
|
100
|
+
readonly snapshotsImportPath: string;
|
|
94
101
|
}): SqlitePlanResult {
|
|
95
102
|
return this.planSql(options as SqlMigrationPlannerPlanOptions);
|
|
96
103
|
}
|
|
@@ -106,6 +113,7 @@ export class SqliteMigrationPlanner
|
|
|
106
113
|
to: context.toHash,
|
|
107
114
|
},
|
|
108
115
|
spaceId,
|
|
116
|
+
context.snapshotsImportPath,
|
|
109
117
|
undefined,
|
|
110
118
|
this.#lowerer,
|
|
111
119
|
);
|
|
@@ -163,6 +171,7 @@ export class SqliteMigrationPlanner
|
|
|
163
171
|
to: options.contract.storage.storageHash,
|
|
164
172
|
},
|
|
165
173
|
options.spaceId,
|
|
174
|
+
options.snapshotsImportPath,
|
|
166
175
|
destination,
|
|
167
176
|
this.#lowerer,
|
|
168
177
|
),
|
|
@@ -229,7 +238,7 @@ export class SqliteMigrationPlanner
|
|
|
229
238
|
});
|
|
230
239
|
const coalesced = coalesceSubtreeIssues(rawIssues);
|
|
231
240
|
const owned = retainUnownedExtras(coalesced, options.ownership);
|
|
232
|
-
const issues = strict ? owned : owned.filter((issue) => issue
|
|
241
|
+
const issues = strict ? owned : owned.filter((issue) => issueOutcome(issue) !== 'not-expected');
|
|
233
242
|
return { expected, actual, issues };
|
|
234
243
|
}
|
|
235
244
|
}
|
|
@@ -266,7 +275,7 @@ function retainUnownedExtras(
|
|
|
266
275
|
): readonly SchemaDiffIssue[] {
|
|
267
276
|
if (ownership === undefined) return issues;
|
|
268
277
|
return issues.filter((issue) => {
|
|
269
|
-
if (issue
|
|
278
|
+
if (issueOutcome(issue) !== 'not-expected') return true;
|
|
270
279
|
const node = issueNode(issue);
|
|
271
280
|
if (node === undefined || node.nodeKind !== RelationalSchemaNodeKind.table) return true;
|
|
272
281
|
const tableName = issue.path[1];
|
|
@@ -4,13 +4,19 @@
|
|
|
4
4
|
* specifier, same overall shape.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import {
|
|
8
|
+
contractSnapshotJsonSpecifier,
|
|
9
|
+
contractSnapshotTypesSpecifier,
|
|
10
|
+
type OpFactoryCall,
|
|
11
|
+
} from '@prisma-next/framework-components/control';
|
|
8
12
|
import { detectScaffoldRuntime, shebangLineFor } from '@prisma-next/migration-tools/migration-ts';
|
|
9
13
|
import { type ImportRequirement, renderImports } from '@prisma-next/ts-render';
|
|
10
14
|
|
|
11
15
|
export interface RenderMigrationMeta {
|
|
12
16
|
readonly from: string | null;
|
|
13
17
|
readonly to: string;
|
|
18
|
+
/** POSIX-relative path from the migration package dir to `migrations/snapshots`, e.g. '../../snapshots'. */
|
|
19
|
+
readonly snapshotsImportPath: string;
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
/**
|
|
@@ -72,31 +78,37 @@ function buildImports(calls: ReadonlyArray<OpFactoryCall>, meta: RenderMigration
|
|
|
72
78
|
|
|
73
79
|
/**
|
|
74
80
|
* The committed contract-JSON imports the scaffold reads its from/to identity
|
|
75
|
-
* from
|
|
76
|
-
*
|
|
77
|
-
*
|
|
81
|
+
* from, resolved to the deduplicated snapshot store under
|
|
82
|
+
* `meta.snapshotsImportPath`. The end snapshot is always present; the start
|
|
83
|
+
* snapshot is added only for a non-baseline migration (`meta.from !== null`).
|
|
84
|
+
* The matching `Contract` type imports (aliased `Start`/`End`) feed the
|
|
78
85
|
* `Migration<Start, End>` generics. Baseline emits `Migration<never, End>` with
|
|
79
86
|
* no start imports — `never` is the honest "no prior contract" Start.
|
|
80
87
|
*/
|
|
81
88
|
function contractImports(meta: RenderMigrationMeta): readonly ImportRequirement[] {
|
|
82
89
|
const reqs: ImportRequirement[] = [
|
|
83
90
|
{
|
|
84
|
-
moduleSpecifier:
|
|
91
|
+
moduleSpecifier: contractSnapshotJsonSpecifier(meta.snapshotsImportPath, meta.to),
|
|
85
92
|
symbol: 'endContract',
|
|
86
93
|
kind: 'default',
|
|
87
94
|
attributes: { type: 'json' },
|
|
88
95
|
},
|
|
89
|
-
{
|
|
96
|
+
{
|
|
97
|
+
moduleSpecifier: contractSnapshotTypesSpecifier(meta.snapshotsImportPath, meta.to),
|
|
98
|
+
symbol: 'Contract',
|
|
99
|
+
alias: 'End',
|
|
100
|
+
typeOnly: true,
|
|
101
|
+
},
|
|
90
102
|
];
|
|
91
103
|
if (meta.from !== null) {
|
|
92
104
|
reqs.push({
|
|
93
|
-
moduleSpecifier:
|
|
105
|
+
moduleSpecifier: contractSnapshotJsonSpecifier(meta.snapshotsImportPath, meta.from),
|
|
94
106
|
symbol: 'startContract',
|
|
95
107
|
kind: 'default',
|
|
96
108
|
attributes: { type: 'json' },
|
|
97
109
|
});
|
|
98
110
|
reqs.push({
|
|
99
|
-
moduleSpecifier:
|
|
111
|
+
moduleSpecifier: contractSnapshotTypesSpecifier(meta.snapshotsImportPath, meta.from),
|
|
100
112
|
symbol: 'Contract',
|
|
101
113
|
alias: 'Start',
|
|
102
114
|
typeOnly: true,
|