@prisma-next/target-sqlite 0.16.0-dev.3 → 0.16.0-dev.31

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.
Files changed (68) hide show
  1. package/dist/codecs-DGgo--O0.d.mts.map +1 -1
  2. package/dist/codecs.mjs +25 -6
  3. package/dist/codecs.mjs.map +1 -1
  4. package/dist/control.d.mts.map +1 -1
  5. package/dist/control.mjs +10 -5
  6. package/dist/control.mjs.map +1 -1
  7. package/dist/errors-B1JPoWDh.mjs +38 -0
  8. package/dist/errors-B1JPoWDh.mjs.map +1 -0
  9. package/dist/migration.d.mts +1 -1
  10. package/dist/migration.mjs +2 -2
  11. package/dist/{op-factory-call-8pTnIHhR.mjs → op-factory-call-BkqsWGiy.mjs} +39 -13
  12. package/dist/op-factory-call-BkqsWGiy.mjs.map +1 -0
  13. package/dist/op-factory-call.d.mts.map +1 -1
  14. package/dist/op-factory-call.mjs +1 -1
  15. package/dist/{planner-D4B8Rugz.mjs → planner-Cdl1Lziz.mjs} +19 -15
  16. package/dist/planner-Cdl1Lziz.mjs.map +1 -0
  17. package/dist/{planner-produced-sqlite-migration-hyDa7QK-.mjs → planner-produced-sqlite-migration-BGcreGfL.mjs} +22 -12
  18. package/dist/planner-produced-sqlite-migration-BGcreGfL.mjs.map +1 -0
  19. package/dist/{planner-produced-sqlite-migration-C9k0q8Il.d.mts → planner-produced-sqlite-migration-fd_Jw-mL.d.mts} +3 -3
  20. package/dist/planner-produced-sqlite-migration-fd_Jw-mL.d.mts.map +1 -0
  21. package/dist/planner-produced-sqlite-migration.d.mts +1 -1
  22. package/dist/planner-produced-sqlite-migration.mjs +1 -1
  23. package/dist/planner.d.mts +7 -1
  24. package/dist/planner.d.mts.map +1 -1
  25. package/dist/planner.mjs +1 -1
  26. package/dist/{render-ops-BDW2tUeR.mjs → render-ops-BAw6MQWl.mjs} +7 -2
  27. package/dist/render-ops-BAw6MQWl.mjs.map +1 -0
  28. package/dist/render-ops.d.mts.map +1 -1
  29. package/dist/render-ops.mjs +1 -1
  30. package/dist/runtime.mjs +1 -1
  31. package/dist/{sql-utils-CV8Bdgtc.mjs → sql-utils-BMteAbKH.mjs} +15 -15
  32. package/dist/sql-utils-BMteAbKH.mjs.map +1 -0
  33. package/dist/sql-utils.d.mts +1 -6
  34. package/dist/sql-utils.d.mts.map +1 -1
  35. package/dist/sql-utils.mjs +2 -2
  36. package/dist/{sqlite-contract-view-B8qeCczc.mjs → sqlite-contract-view-DthhfCpb.mjs} +3 -2
  37. package/dist/sqlite-contract-view-DthhfCpb.mjs.map +1 -0
  38. package/dist/{sqlite-migration-BbSrmBAa.d.mts → sqlite-migration-CBXynqeE.d.mts} +4 -3
  39. package/dist/sqlite-migration-CBXynqeE.d.mts.map +1 -0
  40. package/dist/{sqlite-migration-BcFf2OFa.mjs → sqlite-migration-DrZIdg3i.mjs} +7 -36
  41. package/dist/sqlite-migration-DrZIdg3i.mjs.map +1 -0
  42. package/package.json +18 -18
  43. package/src/core/codecs.ts +33 -6
  44. package/src/core/control-target.ts +3 -1
  45. package/src/core/errors.ts +24 -0
  46. package/src/core/migrations/column-ddl-rendering.ts +4 -2
  47. package/src/core/migrations/issue-planner.ts +5 -6
  48. package/src/core/migrations/op-factory-call.ts +41 -8
  49. package/src/core/migrations/planner-ddl-builders.ts +10 -3
  50. package/src/core/migrations/planner-produced-sqlite-migration.ts +4 -0
  51. package/src/core/migrations/planner-strategies.ts +2 -3
  52. package/src/core/migrations/planner.ts +8 -0
  53. package/src/core/migrations/render-ops.ts +4 -1
  54. package/src/core/migrations/render-typescript.ts +20 -8
  55. package/src/core/migrations/runner.ts +6 -2
  56. package/src/core/migrations/sqlite-migration.ts +3 -2
  57. package/src/core/sql-utils.ts +10 -21
  58. package/src/core/sqlite-unbound-database.ts +4 -1
  59. package/src/exports/sql-utils.ts +1 -1
  60. package/dist/op-factory-call-8pTnIHhR.mjs.map +0 -1
  61. package/dist/planner-D4B8Rugz.mjs.map +0 -1
  62. package/dist/planner-produced-sqlite-migration-C9k0q8Il.d.mts.map +0 -1
  63. package/dist/planner-produced-sqlite-migration-hyDa7QK-.mjs.map +0 -1
  64. package/dist/render-ops-BDW2tUeR.mjs.map +0 -1
  65. package/dist/sql-utils-CV8Bdgtc.mjs.map +0 -1
  66. package/dist/sqlite-contract-view-B8qeCczc.mjs.map +0 -1
  67. package/dist/sqlite-migration-BbSrmBAa.d.mts.map +0 -1
  68. package/dist/sqlite-migration-BcFf2OFa.mjs.map +0 -1
@@ -1,39 +1,9 @@
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
- import { t as SqliteContractView } from "./sqlite-contract-view-B8qeCczc.mjs";
1
+ import { t as errorSqliteMigrationStackMissing } from "./errors-B1JPoWDh.mjs";
2
+ 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-BkqsWGiy.mjs";
3
+ import { t as SqliteContractView } from "./sqlite-contract-view-DthhfCpb.mjs";
3
4
  import { blindCast } from "@prisma-next/utils/casts";
4
5
  import { Migration } from "@prisma-next/family-sql/migration";
5
6
  import { MigrationContractViews } from "@prisma-next/migration-tools/migration";
6
- import { CliStructuredError } from "@prisma-next/errors/control";
7
- //#region src/core/errors.ts
8
- /**
9
- * A `SqliteMigration` operation that needs the materialized control adapter
10
- * — named by `operation` (e.g. `createTable`, `dropColumn`, `recreateTable`) —
11
- * was invoked, but the migration was constructed without a `ControlStack`.
12
- * Concrete authoring usage always goes through the migration CLI entrypoint,
13
- * which assembles a stack from the loaded `prisma-next.config.ts`; reaching this
14
- * error means a test fixture or ad-hoc consumer instantiated `SqliteMigration`
15
- * with the no-arg form (legal for `operations` / `describe` introspection only).
16
- *
17
- * The `operation` argument is required so every throw site names the operation
18
- * that actually failed; a new operation cannot inherit a misattributed message.
19
- *
20
- * Distinct from `MIGRATION.UNFILLED_PLACEHOLDER` (placeholder not filled)
21
- * because the missing input is the stack itself, not the per-operation
22
- * contract.
23
- *
24
- * Lives in `@prisma-next/target-sqlite/errors` rather than the shared
25
- * framework migration errors module because the failure is target-specific:
26
- * the contract it talks about (`SqliteMigration`, the SQLite control
27
- * adapter, the SQLite-target stack) only exists in this package.
28
- */
29
- function errorSqliteMigrationStackMissing(operation) {
30
- return new CliStructuredError("MIGRATION.SQLITE_CONTROL_STACK_MISSING", `SqliteMigration.${operation} requires a control adapter`, {
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
- 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
- meta: { operation }
34
- });
35
- }
36
- //#endregion
37
7
  //#region src/core/migrations/sqlite-migration.ts
38
8
  /**
39
9
  * Target-owned base class for SQLite migrations. Fixes the `SqlMigration`
@@ -49,8 +19,9 @@ function errorSqliteMigrationStackMissing(operation) {
49
19
  * through every call.
50
20
  *
51
21
  * Binds the framework base's `Start` / `End` contract generics so a subclass
52
- * that assigns its `start-contract.json` / `end-contract.json` imports gets
53
- * fully-typed view accessors: `this.endContract` is a `SqliteContractView<End>`
22
+ * that assigns its snapshot-store `contract.json` imports to
23
+ * `startContractJson` / `endContractJson` gets fully-typed view accessors:
24
+ * `this.endContract` is a `SqliteContractView<End>`
54
25
  * (sole namespace unwrapped to the root — `this.endContract.table.<name>`),
55
26
  * built lazily from the JSON fields via the shared `MigrationContractViews`
56
27
  * helper. Mirrors `MongoMigration`'s view getters; the framework base derives
@@ -120,4 +91,4 @@ var SqliteMigration = class extends Migration {
120
91
  //#endregion
121
92
  export { SqliteMigration as t };
122
93
 
123
- //# sourceMappingURL=sqlite-migration-BcFf2OFa.mjs.map
94
+ //# sourceMappingURL=sqlite-migration-DrZIdg3i.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-migration-DrZIdg3i.mjs","names":["SqlMigration","#endView","#startView"],"sources":["../src/core/migrations/sqlite-migration.ts"],"sourcesContent":["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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,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,30 +1,30 @@
1
1
  {
2
2
  "name": "@prisma-next/target-sqlite",
3
- "version": "0.16.0-dev.3",
3
+ "version": "0.16.0-dev.31",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "dependencies": {
8
- "@prisma-next/cli": "0.16.0-dev.3",
9
- "@prisma-next/contract": "0.16.0-dev.3",
10
- "@prisma-next/errors": "0.16.0-dev.3",
11
- "@prisma-next/family-sql": "0.16.0-dev.3",
12
- "@prisma-next/framework-components": "0.16.0-dev.3",
13
- "@prisma-next/migration-tools": "0.16.0-dev.3",
14
- "@prisma-next/sql-contract": "0.16.0-dev.3",
15
- "@prisma-next/sql-errors": "0.16.0-dev.3",
16
- "@prisma-next/sql-relational-core": "0.16.0-dev.3",
17
- "@prisma-next/sql-runtime": "0.16.0-dev.3",
18
- "@prisma-next/sql-schema-ir": "0.16.0-dev.3",
19
- "@prisma-next/ts-render": "0.16.0-dev.3",
20
- "@prisma-next/utils": "0.16.0-dev.3",
8
+ "@prisma-next/cli": "0.16.0-dev.31",
9
+ "@prisma-next/contract": "0.16.0-dev.31",
10
+ "@prisma-next/errors": "0.16.0-dev.31",
11
+ "@prisma-next/family-sql": "0.16.0-dev.31",
12
+ "@prisma-next/framework-components": "0.16.0-dev.31",
13
+ "@prisma-next/migration-tools": "0.16.0-dev.31",
14
+ "@prisma-next/sql-contract": "0.16.0-dev.31",
15
+ "@prisma-next/sql-errors": "0.16.0-dev.31",
16
+ "@prisma-next/sql-relational-core": "0.16.0-dev.31",
17
+ "@prisma-next/sql-runtime": "0.16.0-dev.31",
18
+ "@prisma-next/sql-schema-ir": "0.16.0-dev.31",
19
+ "@prisma-next/ts-render": "0.16.0-dev.31",
20
+ "@prisma-next/utils": "0.16.0-dev.31",
21
21
  "@standard-schema/spec": "1.1.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@prisma-next/driver-sqlite": "0.16.0-dev.3",
25
- "@prisma-next/test-utils": "0.16.0-dev.3",
26
- "@prisma-next/tsconfig": "0.16.0-dev.3",
27
- "@prisma-next/tsdown": "0.16.0-dev.3",
24
+ "@prisma-next/driver-sqlite": "0.16.0-dev.31",
25
+ "@prisma-next/test-utils": "0.16.0-dev.31",
26
+ "@prisma-next/tsconfig": "0.16.0-dev.31",
27
+ "@prisma-next/tsdown": "0.16.0-dev.31",
28
28
  "tsdown": "0.22.8",
29
29
  "typescript": "5.9.3",
30
30
  "vitest": "4.1.10"
@@ -38,6 +38,7 @@ import {
38
38
  SQLITE_REAL_CODEC_ID,
39
39
  SQLITE_TEXT_CODEC_ID,
40
40
  } from './codec-ids';
41
+ import { sqliteError } from './errors';
41
42
 
42
43
  export class SqliteTextCodec extends CodecImpl<
43
44
  typeof SQLITE_TEXT_CODEC_ID,
@@ -170,7 +171,13 @@ export class SqliteBlobCodec extends CodecImpl<
170
171
  }
171
172
  decodeJson(json: JsonValue): Uint8Array {
172
173
  if (typeof json !== 'string') {
173
- throw new TypeError('sqlite/blob@1 contract value must be a base64 string');
174
+ throw sqliteError(
175
+ 'RUNTIME.DECODE_FAILED',
176
+ 'sqlite/blob@1 contract value must be a base64 string',
177
+ {
178
+ meta: { codecId: SQLITE_BLOB_CODEC_ID, received: typeof json },
179
+ },
180
+ );
174
181
  }
175
182
  return new Uint8Array(Buffer.from(json, 'base64'));
176
183
  }
@@ -204,7 +211,11 @@ export class SqliteDatetimeCodec extends CodecImpl<
204
211
  private parseDate(value: string): Date {
205
212
  const date = new Date(value);
206
213
  if (Number.isNaN(date.getTime())) {
207
- throw new TypeError(`sqlite/datetime@1 value must be a valid ISO-8601 string: ${value}`);
214
+ throw sqliteError(
215
+ 'RUNTIME.DECODE_FAILED',
216
+ `sqlite/datetime@1 value must be a valid ISO-8601 string: ${value}`,
217
+ { meta: { codecId: SQLITE_DATETIME_CODEC_ID, received: value } },
218
+ );
208
219
  }
209
220
  return date;
210
221
  }
@@ -219,7 +230,11 @@ export class SqliteDatetimeCodec extends CodecImpl<
219
230
  }
220
231
  decodeJson(json: JsonValue): Date {
221
232
  if (typeof json !== 'string') {
222
- throw new TypeError('sqlite/datetime@1 contract value must be an ISO-8601 string');
233
+ throw sqliteError(
234
+ 'RUNTIME.DECODE_FAILED',
235
+ 'sqlite/datetime@1 contract value must be an ISO-8601 string',
236
+ { meta: { codecId: SQLITE_DATETIME_CODEC_ID, received: typeof json } },
237
+ );
223
238
  }
224
239
  return this.parseDate(json);
225
240
  }
@@ -296,16 +311,28 @@ export class SqliteBigintCodec extends CodecImpl<
296
311
  encodeJson(value: bigint): JsonValue {
297
312
  const number = Number(value);
298
313
  if (!Number.isSafeInteger(number)) {
299
- throw new TypeError('sqlite/bigint@1 database JSON value must be a safe integer');
314
+ throw sqliteError(
315
+ 'RUNTIME.ENCODE_FAILED',
316
+ 'sqlite/bigint@1 database JSON value must be a safe integer',
317
+ { meta: { codecId: SQLITE_BIGINT_CODEC_ID, received: String(value) } },
318
+ );
300
319
  }
301
320
  return number;
302
321
  }
303
322
  decodeJson(json: JsonValue): bigint {
304
323
  if (typeof json !== 'number') {
305
- throw new TypeError('sqlite/bigint@1 database JSON value must be a number');
324
+ throw sqliteError(
325
+ 'RUNTIME.DECODE_FAILED',
326
+ 'sqlite/bigint@1 database JSON value must be a number',
327
+ { meta: { codecId: SQLITE_BIGINT_CODEC_ID, received: typeof json } },
328
+ );
306
329
  }
307
330
  if (!Number.isSafeInteger(json)) {
308
- throw new TypeError('sqlite/bigint@1 database JSON value must be a safe integer');
331
+ throw sqliteError(
332
+ 'RUNTIME.DECODE_FAILED',
333
+ 'sqlite/bigint@1 database JSON value must be a safe integer',
334
+ { meta: { codecId: SQLITE_BIGINT_CODEC_ID, received: json } },
335
+ );
309
336
  }
310
337
  return BigInt(json);
311
338
  }
@@ -12,6 +12,7 @@ import {
12
12
  relationalNodeGranularity,
13
13
  } from '@prisma-next/sql-schema-ir/types';
14
14
  import { sqliteTargetDescriptorMeta } from './descriptor-meta';
15
+ import { sqliteError } from './errors';
15
16
  import { diffSqliteSchema, sqliteContractToSchema } from './migrations/diff-database-schema';
16
17
  import { createSqliteMigrationPlanner } from './migrations/planner';
17
18
  import type { SqlitePlanTargetDetails } from './migrations/planner-target-details';
@@ -49,7 +50,8 @@ const sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', Sqlite
49
50
  // encodes that invariant at runtime + narrows the generic
50
51
  // to `Contract<SqlStorage>` without a blind cast.
51
52
  if (!isSqlContract(contract)) {
52
- throw new Error(
53
+ throw sqliteError(
54
+ 'CONTRACT.TARGET_MISMATCH',
53
55
  'sqliteControlTargetDescriptor.contractToSchema received a non-SQL contract; expected Contract<SqlStorage>',
54
56
  );
55
57
  }
@@ -1,4 +1,28 @@
1
1
  import { CliStructuredError } from '@prisma-next/errors/control';
2
+ import type { StructuredError, StructuredErrorOptions } from '@prisma-next/utils/structured-error';
3
+ import { structuredError } from '@prisma-next/utils/structured-error';
4
+
5
+ export type SqliteTargetErrorCode =
6
+ | 'CONTRACT.CONSTRAINT_INVALID'
7
+ | 'CONTRACT.DEFAULT_INVALID'
8
+ | 'CONTRACT.IDENTIFIER_INVALID'
9
+ | 'CONTRACT.NAMESPACE_INVALID'
10
+ | 'CONTRACT.NATIVE_TYPE_INVALID'
11
+ | 'CONTRACT.TARGET_MISMATCH'
12
+ | 'CONTRACT.TYPE_UNKNOWN'
13
+ | 'MIGRATION.CONTRACT_SPACE_VIOLATION'
14
+ | 'MIGRATION.SQLITE_CONTROL_STACK_MISSING'
15
+ | 'MIGRATION.TARGET_MISMATCH'
16
+ | 'RUNTIME.DECODE_FAILED'
17
+ | 'RUNTIME.ENCODE_FAILED';
18
+
19
+ export function sqliteError(
20
+ code: SqliteTargetErrorCode,
21
+ message: string,
22
+ options?: StructuredErrorOptions,
23
+ ): StructuredError {
24
+ return structuredError(code, message, options);
25
+ }
2
26
 
3
27
  /**
4
28
  * A `SqliteMigration` operation that needs the materialized control adapter
@@ -10,6 +10,7 @@ import {
10
10
  } from '@prisma-next/sql-relational-core/ast';
11
11
  import type { SqlColumnIR, SqlTableIR } from '@prisma-next/sql-schema-ir/types';
12
12
  import { blindCast } from '@prisma-next/utils/casts';
13
+ import { assertNever, InternalError } from '@prisma-next/utils/internal-error';
13
14
  import type { SqliteColumnSpec } from './operations/shared';
14
15
  import { buildColumnDefaultSql, buildColumnTypeSql } from './planner-ddl-builders';
15
16
 
@@ -28,7 +29,7 @@ function columnLike(
28
29
  column: SqlColumnIR,
29
30
  ): Pick<StorageColumn, 'nativeType' | 'codecId' | 'nullable' | 'many' | 'typeParams' | 'default'> {
30
31
  if (column.codecRef === undefined || column.codecBaseNativeType === undefined) {
31
- throw new Error(
32
+ throw new InternalError(
32
33
  `columnLike: expected column "${column.name}" carries no codec identity — the expected tree must be derived via contractToSchemaIR for planning`,
33
34
  );
34
35
  }
@@ -69,7 +70,8 @@ function sqliteDefaultToDdlColumnDefault(
69
70
  return new FunctionColumnDefault(columnDefault.expression);
70
71
  default: {
71
72
  const exhaustive: never = columnDefault;
72
- throw new Error(
73
+ return assertNever(
74
+ exhaustive,
73
75
  `sqliteDefaultToDdlColumnDefault: unhandled kind "${blindCast<{ kind: string }, 'exhaustiveness: surface the unhandled default kind'>(exhaustive).kind}"`,
74
76
  );
75
77
  }
@@ -22,7 +22,6 @@ import type {
22
22
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
23
23
  import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
24
24
  import { issueOutcome, orderIssuesByDependencies } from '@prisma-next/framework-components/control';
25
- import { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';
26
25
  import {
27
26
  RelationalSchemaNodeKind,
28
27
  type SqlColumnIR,
@@ -218,8 +217,8 @@ function buildCreateTableCalls(table: SqlTableIR): SqliteOpFactoryCall[] {
218
217
  new CreateTableCall(table.name, columns, constraints.length > 0 ? constraints : undefined),
219
218
  ];
220
219
  for (const index of table.indexes) {
221
- const indexName = index.name ?? defaultIndexName(table.name, index.columns);
222
- calls.push(new CreateIndexCall(table.name, indexName, index.columns));
220
+ const indexName = index.name;
221
+ calls.push(new CreateIndexCall(table.name, indexName, index.columns ?? []));
223
222
  }
224
223
  return calls;
225
224
  }
@@ -319,15 +318,15 @@ function mapIndexIssue(
319
318
  SqlIndexIR,
320
319
  'a not-found index issue always carries the expected index node'
321
320
  >(issue.expected);
322
- const indexName = index.name ?? defaultIndexName(tableName, index.columns);
323
- return ok([new CreateIndexCall(tableName, indexName, index.columns)]);
321
+ const indexName = index.name;
322
+ return ok([new CreateIndexCall(tableName, indexName, index.columns ?? [])]);
324
323
  }
325
324
  if (issueOutcome(issue) === 'not-expected') {
326
325
  const index = blindCast<
327
326
  SqlIndexIR,
328
327
  'a not-expected index issue always carries the actual index node'
329
328
  >(issue.actual);
330
- const indexName = index.name ?? defaultIndexName(tableName, index.columns);
329
+ const indexName = index.name;
331
330
  return ok([new DropIndexCall(tableName, indexName)]);
332
331
  }
333
332
  // not-equal: index type/options/uniqueness drift. SQLite can't ALTER an
@@ -25,6 +25,7 @@ import { type ImportRequirement, jsonToTsSource, TsExpression } from '@prisma-ne
25
25
  import { ifDefined } from '@prisma-next/utils/defined';
26
26
  import { columnExistsAst, indexExistsAst, tableExistsAst } from '../../contract-free/checks';
27
27
  import * as contractFreeDdl from '../../contract-free/ddl';
28
+ import { sqliteError } from '../errors';
28
29
  import { quoteIdentifier } from '../sql-utils';
29
30
  import { addColumnExecuteSql, dropColumnExecuteSql } from './operations/columns';
30
31
  import type { SqliteColumnSpec, SqliteIndexSpec, SqliteTableSpec } from './operations/shared';
@@ -97,9 +98,11 @@ function renderDdlConstraintAsTsCall(constraint: DdlTableConstraint): string {
97
98
  return `unique(${jsonToTsSource(constraint.columns)}${nameOpt})`;
98
99
  }
99
100
  case 'check-expression':
100
- throw new Error(
101
+ throw sqliteError(
102
+ 'CONTRACT.CONSTRAINT_INVALID',
101
103
  `SQLite does not support expression CHECK constraints (constraint "${constraint.name}"). ` +
102
104
  'Scalar-array columns and their element-non-null checks are Postgres-only.',
105
+ { meta: { constraintName: constraint.name } },
103
106
  );
104
107
  }
105
108
  }
@@ -147,8 +150,10 @@ export class CreateTableCall extends SqliteOpFactoryCallNode {
147
150
 
148
151
  async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
149
152
  if (lowerer === undefined) {
150
- throw new Error(
153
+ throw sqliteError(
154
+ 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
151
155
  `CreateTableCall.toOp: a DDL lowerer is required on the SQLite planner path (table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
156
+ { meta: { factory: this.factoryName, tableName: this.tableName } },
152
157
  );
153
158
  }
154
159
  const ddlNode = contractFreeDdl.createTable({
@@ -223,8 +228,10 @@ export class DropTableCall extends SqliteOpFactoryCallNode {
223
228
 
224
229
  async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
225
230
  if (lowerer === undefined) {
226
- throw new Error(
231
+ throw sqliteError(
232
+ 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
227
233
  `DropTableCall.toOp: a lowerer is required on the SQLite planner path (table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
234
+ { meta: { factory: this.factoryName, tableName: this.tableName } },
228
235
  );
229
236
  }
230
237
  const checks = tableExistsAst(this.tableName);
@@ -287,8 +294,10 @@ export class RecreateTableCall extends SqliteOpFactoryCallNode {
287
294
 
288
295
  async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
289
296
  if (lowerer === undefined) {
290
- throw new Error(
297
+ throw sqliteError(
298
+ 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
291
299
  `RecreateTableCall.toOp: a lowerer is required on the SQLite planner path (table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
300
+ { meta: { factory: this.factoryName, tableName: this.tableName } },
292
301
  );
293
302
  }
294
303
  return recreateTable(
@@ -346,8 +355,16 @@ export class AddColumnCall extends SqliteOpFactoryCallNode {
346
355
 
347
356
  async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
348
357
  if (lowerer === undefined) {
349
- throw new Error(
358
+ throw sqliteError(
359
+ 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
350
360
  `AddColumnCall.toOp: a lowerer is required on the SQLite planner path (column "${this.column.name}" on table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
361
+ {
362
+ meta: {
363
+ factory: this.factoryName,
364
+ tableName: this.tableName,
365
+ columnName: this.column.name,
366
+ },
367
+ },
351
368
  );
352
369
  }
353
370
  const checks = columnExistsAst(this.tableName, this.column.name);
@@ -396,8 +413,16 @@ export class DropColumnCall extends SqliteOpFactoryCallNode {
396
413
 
397
414
  async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
398
415
  if (lowerer === undefined) {
399
- throw new Error(
416
+ throw sqliteError(
417
+ 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
400
418
  `DropColumnCall.toOp: a lowerer is required on the SQLite planner path (column "${this.columnName}" on table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
419
+ {
420
+ meta: {
421
+ factory: this.factoryName,
422
+ tableName: this.tableName,
423
+ columnName: this.columnName,
424
+ },
425
+ },
401
426
  );
402
427
  }
403
428
  const checks = columnExistsAst(this.tableName, this.columnName);
@@ -467,8 +492,12 @@ export class CreateIndexCall extends SqliteOpFactoryCallNode {
467
492
 
468
493
  async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
469
494
  if (lowerer === undefined) {
470
- throw new Error(
495
+ throw sqliteError(
496
+ 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
471
497
  `CreateIndexCall.toOp: a lowerer is required on the SQLite planner path (index "${this.indexName}" on table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
498
+ {
499
+ meta: { factory: this.factoryName, tableName: this.tableName, indexName: this.indexName },
500
+ },
472
501
  );
473
502
  }
474
503
  const checks = indexExistsAst(this.indexName);
@@ -520,8 +549,12 @@ export class DropIndexCall extends SqliteOpFactoryCallNode {
520
549
 
521
550
  async toOp(lowerer?: ExecuteRequestLowerer): Promise<Op> {
522
551
  if (lowerer === undefined) {
523
- throw new Error(
552
+ throw sqliteError(
553
+ 'MIGRATION.SQLITE_CONTROL_STACK_MISSING',
524
554
  `DropIndexCall.toOp: a lowerer is required on the SQLite planner path (index "${this.indexName}" on table "${this.tableName}"). Pass the control adapter to createSqliteMigrationPlanner.`,
555
+ {
556
+ meta: { factory: this.factoryName, tableName: this.tableName, indexName: this.indexName },
557
+ },
525
558
  );
526
559
  }
527
560
  const checks = indexExistsAst(this.indexName);
@@ -13,6 +13,7 @@ import type {
13
13
  StorageTable,
14
14
  StorageTypeInstance,
15
15
  } from '@prisma-next/sql-contract/types';
16
+ import { sqliteError } from '../errors';
16
17
  import { escapeLiteral, quoteIdentifier } from '../sql-utils';
17
18
 
18
19
  type SqliteColumnDefault = StorageColumn['default'];
@@ -21,18 +22,22 @@ const SAFE_NATIVE_TYPE_PATTERN = /^[a-zA-Z][a-zA-Z0-9_ ]*$/;
21
22
 
22
23
  function assertSafeNativeType(nativeType: string): void {
23
24
  if (!SAFE_NATIVE_TYPE_PATTERN.test(nativeType)) {
24
- throw new Error(
25
+ throw sqliteError(
26
+ 'CONTRACT.NATIVE_TYPE_INVALID',
25
27
  `Unsafe native type name in contract: "${nativeType}". ` +
26
28
  'Native type names must match /^[a-zA-Z][a-zA-Z0-9_ ]*$/',
29
+ { meta: { nativeType } },
27
30
  );
28
31
  }
29
32
  }
30
33
 
31
34
  function assertSafeDefaultExpression(expression: string): void {
32
35
  if (expression.includes(';') || /--|\/\*|\bSELECT\b/i.test(expression)) {
33
- throw new Error(
36
+ throw sqliteError(
37
+ 'CONTRACT.DEFAULT_INVALID',
34
38
  `Unsafe default expression in contract: "${expression}". ` +
35
39
  'Default expressions must not contain semicolons, SQL comment tokens, or subqueries.',
40
+ { meta: { expression } },
36
41
  );
37
42
  }
38
43
  }
@@ -130,8 +135,10 @@ export function resolveColumnTypeMetadata(
130
135
  }
131
136
  const referencedType = storageTypes[column.typeRef];
132
137
  if (!referencedType) {
133
- throw new Error(
138
+ throw sqliteError(
139
+ 'CONTRACT.TYPE_UNKNOWN',
134
140
  `Storage type "${column.typeRef}" referenced by column is not defined in storage.types.`,
141
+ { meta: { typeRef: column.typeRef } },
135
142
  );
136
143
  }
137
144
  return {
@@ -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
  }
@@ -20,7 +20,6 @@ import type {
20
20
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
21
21
  import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
22
22
  import { issueOutcome } from '@prisma-next/framework-components/control';
23
- import { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';
24
23
  import {
25
24
  RelationalSchemaNodeKind,
26
25
  type SqlColumnIR,
@@ -150,8 +149,8 @@ export const recreateTableStrategy: CallMigrationStrategy = (issues, ctx) => {
150
149
  // Indexes (declared + FK-backing) are already merged and deduped by
151
150
  // column-set at derivation (`contractToSchemaIR`'s `convertTable`).
152
151
  const indexes: SqliteIndexSpec[] = expectedTable.indexes.map((idx) => ({
153
- name: idx.name ?? defaultIndexName(tableName, idx.columns),
154
- columns: idx.columns,
152
+ name: idx.name,
153
+ columns: idx.columns ?? [],
155
154
  }));
156
155
 
157
156
  calls.push(
@@ -92,6 +92,12 @@ export class SqliteMigrationPlanner
92
92
  * {@link SqlMigrationPlannerPlanOptions.ownership}.
93
93
  */
94
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;
95
101
  }): SqlitePlanResult {
96
102
  return this.planSql(options as SqlMigrationPlannerPlanOptions);
97
103
  }
@@ -107,6 +113,7 @@ export class SqliteMigrationPlanner
107
113
  to: context.toHash,
108
114
  },
109
115
  spaceId,
116
+ context.snapshotsImportPath,
110
117
  undefined,
111
118
  this.#lowerer,
112
119
  );
@@ -164,6 +171,7 @@ export class SqliteMigrationPlanner
164
171
  to: options.contract.storage.storageHash,
165
172
  },
166
173
  options.spaceId,
174
+ options.snapshotsImportPath,
167
175
  destination,
168
176
  this.#lowerer,
169
177
  ),
@@ -6,6 +6,7 @@ import type {
6
6
  } from '@prisma-next/framework-components/control';
7
7
  import { blindCast } from '@prisma-next/utils/casts';
8
8
  import { isThenable } from '@prisma-next/utils/promise';
9
+ import { sqliteError } from '../errors';
9
10
  import type { SqlitePlanTargetDetails } from './planner-target-details';
10
11
 
11
12
  type Op = SqlMigrationPlanOperation<SqlitePlanTargetDetails>;
@@ -16,8 +17,10 @@ function assertSqliteOp(op: MigrationPlanOperation, callFactoryName: string): as
16
17
  'op.target is present on concrete SqlMigrationPlanOperation but absent on the framework MigrationPlanOperation base'
17
18
  >(op).target?.id;
18
19
  if (targetId !== 'sqlite') {
19
- throw new Error(
20
+ throw sqliteError(
21
+ 'MIGRATION.TARGET_MISMATCH',
20
22
  `renderOps: expected sqlite op but got target.id="${String(targetId)}" for op.id="${op.id}" (factoryName="${callFactoryName}"). An OpFactoryCall produced an op for a different target on the sqlite planner path; check the call's target binding.`,
23
+ { meta: { opId: op.id, targetId: String(targetId), factoryName: callFactoryName } },
21
24
  );
22
25
  }
23
26
  }