@prisma-next/target-sqlite 0.13.0-dev.3 → 0.13.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 (67) hide show
  1. package/dist/contract-free.mjs +1 -20
  2. package/dist/contract-free.mjs.map +1 -1
  3. package/dist/control.d.mts +5 -8
  4. package/dist/control.d.mts.map +1 -1
  5. package/dist/control.mjs +17 -19
  6. package/dist/control.mjs.map +1 -1
  7. package/dist/ddl-CH8V_qcd.mjs +23 -0
  8. package/dist/ddl-CH8V_qcd.mjs.map +1 -0
  9. package/dist/migration.d.mts +3 -3
  10. package/dist/migration.d.mts.map +1 -1
  11. package/dist/migration.mjs +4 -3
  12. package/dist/migration.mjs.map +1 -1
  13. package/dist/{tables-CjB7vXCr.mjs → op-factory-call-z4TT72k3.mjs} +375 -32
  14. package/dist/op-factory-call-z4TT72k3.mjs.map +1 -0
  15. package/dist/op-factory-call.d.mts +16 -12
  16. package/dist/op-factory-call.d.mts.map +1 -1
  17. package/dist/op-factory-call.mjs +1 -1
  18. package/dist/{planner-DSNDwQy9.mjs → planner-jMHqfl1A.mjs} +80 -12
  19. package/dist/planner-jMHqfl1A.mjs.map +1 -0
  20. package/dist/{planner-produced-sqlite-migration-C1yqJAiM.d.mts → planner-produced-sqlite-migration-BWpnDmhM.d.mts} +5 -4
  21. package/dist/planner-produced-sqlite-migration-BWpnDmhM.d.mts.map +1 -0
  22. package/dist/{planner-produced-sqlite-migration-DowV_vHw.mjs → planner-produced-sqlite-migration-CyyvoPmm.mjs} +9 -5
  23. package/dist/planner-produced-sqlite-migration-CyyvoPmm.mjs.map +1 -0
  24. package/dist/planner-produced-sqlite-migration.d.mts +1 -1
  25. package/dist/planner-produced-sqlite-migration.mjs +1 -1
  26. package/dist/planner.d.mts +5 -2
  27. package/dist/planner.d.mts.map +1 -1
  28. package/dist/planner.mjs +1 -1
  29. package/dist/render-ops-BDW2tUeR.mjs +22 -0
  30. package/dist/render-ops-BDW2tUeR.mjs.map +1 -0
  31. package/dist/render-ops.d.mts +2 -1
  32. package/dist/render-ops.d.mts.map +1 -1
  33. package/dist/render-ops.mjs +1 -1
  34. package/dist/runtime.mjs +1 -1
  35. package/dist/{sqlite-contract-serializer-jcRu8aHh.mjs → sqlite-contract-serializer-B_Cu0o3G.mjs} +20 -4
  36. package/dist/sqlite-contract-serializer-B_Cu0o3G.mjs.map +1 -0
  37. package/dist/sqlite-migration-CJrASAxf.d.mts +46 -0
  38. package/dist/sqlite-migration-CJrASAxf.d.mts.map +1 -0
  39. package/dist/sqlite-migration-DhW4ycZV.mjs +73 -0
  40. package/dist/sqlite-migration-DhW4ycZV.mjs.map +1 -0
  41. package/package.json +18 -18
  42. package/src/core/control-target.ts +4 -4
  43. package/src/core/errors.ts +28 -0
  44. package/src/core/migrations/issue-planner.ts +151 -8
  45. package/src/core/migrations/op-factory-call.ts +162 -23
  46. package/src/core/migrations/planner-ddl-builders.ts +7 -16
  47. package/src/core/migrations/planner-produced-sqlite-migration.ts +8 -2
  48. package/src/core/migrations/planner-strategies.ts +3 -3
  49. package/src/core/migrations/planner.ts +14 -2
  50. package/src/core/migrations/render-ops.ts +37 -9
  51. package/src/core/migrations/runner.ts +16 -12
  52. package/src/core/migrations/sqlite-migration.ts +51 -1
  53. package/src/core/sqlite-unbound-database.ts +34 -51
  54. package/src/exports/migration.ts +9 -1
  55. package/dist/op-factory-call-DymqdXQW.mjs +0 -279
  56. package/dist/op-factory-call-DymqdXQW.mjs.map +0 -1
  57. package/dist/planner-DSNDwQy9.mjs.map +0 -1
  58. package/dist/planner-produced-sqlite-migration-C1yqJAiM.d.mts.map +0 -1
  59. package/dist/planner-produced-sqlite-migration-DowV_vHw.mjs.map +0 -1
  60. package/dist/render-ops-CFRbJ3Yb.mjs +0 -8
  61. package/dist/render-ops-CFRbJ3Yb.mjs.map +0 -1
  62. package/dist/sqlite-contract-serializer-jcRu8aHh.mjs.map +0 -1
  63. package/dist/sqlite-migration-CUqgmzQH.mjs +0 -16
  64. package/dist/sqlite-migration-CUqgmzQH.mjs.map +0 -1
  65. package/dist/sqlite-migration-D4XGYzgQ.d.mts +0 -17
  66. package/dist/sqlite-migration-D4XGYzgQ.d.mts.map +0 -1
  67. package/dist/tables-CjB7vXCr.mjs.map +0 -1
@@ -1,2 +1,2 @@
1
- import { t as renderOps } from "./render-ops-CFRbJ3Yb.mjs";
1
+ import { t as renderOps } from "./render-ops-BDW2tUeR.mjs";
2
2
  export { renderOps };
package/dist/runtime.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as sqliteTargetDescriptorMetaRuntime } from "./descriptor-meta-runtime-BkXK3OjD.mjs";
2
- import { t as SqliteContractSerializer } from "./sqlite-contract-serializer-jcRu8aHh.mjs";
2
+ import { t as SqliteContractSerializer } from "./sqlite-contract-serializer-B_Cu0o3G.mjs";
3
3
  //#region src/core/runtime-target.ts
4
4
  const sqliteRuntimeTargetDescriptor = {
5
5
  ...sqliteTargetDescriptorMetaRuntime,
@@ -1,7 +1,7 @@
1
1
  import { StorageTable } from "@prisma-next/sql-contract/types";
2
2
  import { NamespaceBase, UNBOUND_NAMESPACE_ID, freezeNode } from "@prisma-next/framework-components/ir";
3
+ import { blindCast } from "@prisma-next/utils/casts";
3
4
  import { SqlContractSerializerBase } from "@prisma-next/family-sql/ir";
4
- import { blindCast, castAs } from "@prisma-next/utils/casts";
5
5
  //#region src/core/sqlite-unbound-database.ts
6
6
  const SQLITE_NAMESPACE_KIND = "sqlite-namespace";
7
7
  /**
@@ -15,7 +15,17 @@ var SqliteDatabase = class extends NamespaceBase {
15
15
  constructor(input) {
16
16
  super();
17
17
  this.id = input.id;
18
- this.entries = Object.freeze({ table: Object.freeze(Object.fromEntries(Object.entries(input.entries.table).map(([k, v]) => [k, v instanceof StorageTable ? v : new StorageTable(v)]))) });
18
+ const carried = {};
19
+ let table = Object.freeze({});
20
+ for (const [kind, rawMap] of Object.entries(input.entries)) if (kind === "table") {
21
+ const tableMap = {};
22
+ for (const [name, v] of Object.entries(blindCast(rawMap))) tableMap[name] = new StorageTable(v);
23
+ table = Object.freeze(tableMap);
24
+ } else carried[kind] = Object.freeze(rawMap);
25
+ this.entries = Object.freeze({
26
+ ...carried,
27
+ table
28
+ });
19
29
  Object.defineProperty(this, "kind", {
20
30
  value: SQLITE_NAMESPACE_KIND,
21
31
  writable: false,
@@ -24,6 +34,9 @@ var SqliteDatabase = class extends NamespaceBase {
24
34
  });
25
35
  freezeNode(this);
26
36
  }
37
+ get table() {
38
+ return this.entries.table ?? Object.freeze({});
39
+ }
27
40
  qualifier() {
28
41
  return "";
29
42
  }
@@ -59,7 +72,10 @@ var SqliteUnboundDatabase = class SqliteUnboundDatabase extends SqliteDatabase {
59
72
  };
60
73
  function buildSqliteNamespace(input) {
61
74
  if (input.id !== UNBOUND_NAMESPACE_ID) throw new Error(`buildSqliteNamespace: SQLite has no schema concept; the only valid namespace id is "${UNBOUND_NAMESPACE_ID}" (received "${input.id}").`);
62
- if (Object.keys(input.entries.table).length === 0) return castAs(SqliteUnboundDatabase.instance);
75
+ const tableKind = input.entries["table"];
76
+ const tableCount = tableKind !== void 0 ? Object.keys(tableKind).length : 0;
77
+ const hasUnknownKinds = Object.keys(input.entries).some((kind) => kind !== "table");
78
+ if (tableCount === 0 && !hasUnknownKinds) return SqliteUnboundDatabase.instance;
63
79
  return new SqliteDatabase({
64
80
  id: input.id,
65
81
  entries: input.entries
@@ -98,4 +114,4 @@ var SqliteContractSerializer = class extends SqlContractSerializerBase {
98
114
  //#endregion
99
115
  export { SqliteUnboundDatabase as n, sqliteCreateNamespace as r, SqliteContractSerializer as t };
100
116
 
101
- //# sourceMappingURL=sqlite-contract-serializer-jcRu8aHh.mjs.map
117
+ //# sourceMappingURL=sqlite-contract-serializer-B_Cu0o3G.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-contract-serializer-B_Cu0o3G.mjs","names":[],"sources":["../src/core/sqlite-unbound-database.ts","../src/core/sqlite-contract-serializer.ts"],"sourcesContent":["import {\n freezeNode,\n NamespaceBase,\n UNBOUND_NAMESPACE_ID,\n} from '@prisma-next/framework-components/ir';\nimport {\n type SqlNamespaceEntries,\n type SqlNamespaceTablesInput,\n StorageTable,\n type StorageTableInput,\n} from '@prisma-next/sql-contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\n\nexport type SqliteDatabaseInput = {\n readonly id: string;\n readonly entries: SqlNamespaceEntries;\n};\n\nconst SQLITE_NAMESPACE_KIND = 'sqlite-namespace' as const;\n\n/**\n * SQLite namespace concretion carrying table metadata under\n * `entries.table` and unqualified `qualifyTable()` emission for runtime\n * SQL rendering.\n */\nexport class SqliteDatabase extends NamespaceBase {\n declare readonly kind: string;\n\n readonly id: string;\n readonly entries: SqlNamespaceEntries;\n\n constructor(input: SqliteDatabaseInput) {\n super();\n this.id = input.id;\n\n const carried: Record<string, Readonly<Record<string, unknown>>> = {};\n let table: Readonly<Record<string, StorageTable>> = Object.freeze({});\n for (const [kind, rawMap] of Object.entries(input.entries)) {\n if (kind === 'table') {\n const tableMap: Record<string, StorageTable> = {};\n for (const [name, v] of Object.entries(\n blindCast<\n Record<string, StorageTableInput>,\n 'entries[table] holds StorageTableInput by construction'\n >(rawMap),\n )) {\n tableMap[name] = new StorageTable(v);\n }\n table = Object.freeze(tableMap);\n } else {\n carried[kind] = Object.freeze(rawMap);\n }\n }\n\n this.entries = Object.freeze({ ...carried, table });\n Object.defineProperty(this, 'kind', {\n value: SQLITE_NAMESPACE_KIND,\n writable: false,\n enumerable: false,\n configurable: true,\n });\n freezeNode(this);\n }\n\n get table(): Readonly<Record<string, StorageTable>> {\n return this.entries.table ?? Object.freeze({});\n }\n\n qualifier(): string {\n return '';\n }\n\n qualifyTable(tableName: string): string {\n return `\"${tableName}\"`;\n }\n}\n\n/**\n * SQLite target `Namespace` concretion. SQLite has no schema or\n * database-namespacing concept at the SQL level — there is exactly one\n * effective namespace per connection, so the target ships a single\n * singleton bound to the framework's `UNBOUND_NAMESPACE_ID` slot.\n *\n * Qualifier emission elides the prefix entirely: rendered DDL and\n * queries look unqualified (`CREATE TABLE \"users\" (...)`), matching\n * SQLite's native dialect. Call sites stay polymorphic — they ask the\n * namespace for its qualifier and consume the empty/unqualified result\n * the same way Postgres consumes a `\"schema\"` prefix.\n *\n * The SQLite PSL interpreter rejects every explicit `namespace { … }`\n * block with a diagnostic naming SQLite; only the implicit\n * `__unspecified__` AST bucket reaches the SQLite interpreter, which\n * lowers it to this singleton.\n */\nexport class SqliteUnboundDatabase extends SqliteDatabase {\n static readonly instance: SqliteUnboundDatabase = new SqliteUnboundDatabase();\n\n private constructor() {\n super({ id: UNBOUND_NAMESPACE_ID, entries: { table: {} } });\n }\n}\n\nexport function buildSqliteNamespace(\n input: SqlNamespaceTablesInput,\n): SqliteDatabase | SqliteUnboundDatabase {\n if (input.id !== UNBOUND_NAMESPACE_ID) {\n throw new Error(\n `buildSqliteNamespace: SQLite has no schema concept; the only valid namespace id is \"${UNBOUND_NAMESPACE_ID}\" (received \"${input.id}\").`,\n );\n }\n const tableKind = input.entries['table'];\n const tableCount = tableKind !== undefined ? Object.keys(tableKind).length : 0;\n const hasUnknownKinds = Object.keys(input.entries).some((kind) => kind !== 'table');\n if (tableCount === 0 && !hasUnknownKinds) {\n return SqliteUnboundDatabase.instance;\n }\n return new SqliteDatabase({ id: input.id, entries: input.entries });\n}\n\n/**\n * Target-supplied `Namespace` factory the SQLite target plumbs through\n * `defineContract({ createNamespace })`. SQLite has only one\n * effective namespace slot — the framework `UNBOUND_NAMESPACE_ID`\n * sentinel — so the factory always returns the singleton or a fresh\n * `SqliteDatabase` for the unbound slot with tables. The SQL family's\n * defensive validation in `defineContract` already rejects\n * user-declared SQLite namespaces, so this throw is a structural\n * safety net rather than a user-facing surface.\n */\nexport function sqliteCreateNamespace(\n input: SqlNamespaceTablesInput,\n): SqliteDatabase | SqliteUnboundDatabase {\n return buildSqliteNamespace(input);\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport { SqlContractSerializerBase } from '@prisma-next/family-sql/ir';\nimport { type Namespace, NamespaceBase } from '@prisma-next/framework-components/ir';\nimport type { SqlNamespaceTablesInput, SqlStorage } from '@prisma-next/sql-contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { buildSqliteNamespace } from './sqlite-unbound-database';\n\n/**\n * SQLite target `ContractSerializer` concretion. Mirrors the Postgres\n * shape: inherits the full SQL-family deserialization pipeline and\n * materialises namespace entries as SQLite database concretions that\n * expose `qualifyTable()` for runtime SQL rendering.\n */\nexport class SqliteContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {\n constructor() {\n super(new Map());\n }\n\n protected override hydrateSqlNamespaceEntry(\n nsId: string,\n raw: Namespace | Record<string, unknown>,\n ): Namespace | SqlNamespaceTablesInput {\n if (raw instanceof NamespaceBase) {\n return raw;\n }\n const hydrated = blindCast<\n SqlNamespaceTablesInput,\n 'super.hydrateSqlNamespaceEntry returns the tables form when raw is not a NamespaceBase'\n >(super.hydrateSqlNamespaceEntry(nsId, raw));\n return buildSqliteNamespace(hydrated);\n }\n}\n"],"mappings":";;;;;AAkBA,MAAM,wBAAwB;;;;;;AAO9B,IAAa,iBAAb,cAAoC,cAAc;CAGhD;CACA;CAEA,YAAY,OAA4B;EACtC,MAAM;EACN,KAAK,KAAK,MAAM;EAEhB,MAAM,UAA6D,CAAC;EACpE,IAAI,QAAgD,OAAO,OAAO,CAAC,CAAC;EACpE,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,MAAM,OAAO,GACvD,IAAI,SAAS,SAAS;GACpB,MAAM,WAAyC,CAAC;GAChD,KAAK,MAAM,CAAC,MAAM,MAAM,OAAO,QAC7B,UAGE,MAAM,CACV,GACE,SAAS,QAAQ,IAAI,aAAa,CAAC;GAErC,QAAQ,OAAO,OAAO,QAAQ;EAChC,OACE,QAAQ,QAAQ,OAAO,OAAO,MAAM;EAIxC,KAAK,UAAU,OAAO,OAAO;GAAE,GAAG;GAAS;EAAM,CAAC;EAClD,OAAO,eAAe,MAAM,QAAQ;GAClC,OAAO;GACP,UAAU;GACV,YAAY;GACZ,cAAc;EAChB,CAAC;EACD,WAAW,IAAI;CACjB;CAEA,IAAI,QAAgD;EAClD,OAAO,KAAK,QAAQ,SAAS,OAAO,OAAO,CAAC,CAAC;CAC/C;CAEA,YAAoB;EAClB,OAAO;CACT;CAEA,aAAa,WAA2B;EACtC,OAAO,IAAI,UAAU;CACvB;AACF;;;;;;;;;;;;;;;;;;AAmBA,IAAa,wBAAb,MAAa,8BAA8B,eAAe;CACxD,OAAgB,WAAkC,IAAI,sBAAsB;CAE5E,cAAsB;EACpB,MAAM;GAAE,IAAI;GAAsB,SAAS,EAAE,OAAO,CAAC,EAAE;EAAE,CAAC;CAC5D;AACF;AAEA,SAAgB,qBACd,OACwC;CACxC,IAAI,MAAM,OAAO,sBACf,MAAM,IAAI,MACR,uFAAuF,qBAAqB,eAAe,MAAM,GAAG,IACtI;CAEF,MAAM,YAAY,MAAM,QAAQ;CAChC,MAAM,aAAa,cAAc,KAAA,IAAY,OAAO,KAAK,SAAS,CAAC,CAAC,SAAS;CAC7E,MAAM,kBAAkB,OAAO,KAAK,MAAM,OAAO,CAAC,CAAC,MAAM,SAAS,SAAS,OAAO;CAClF,IAAI,eAAe,KAAK,CAAC,iBACvB,OAAO,sBAAsB;CAE/B,OAAO,IAAI,eAAe;EAAE,IAAI,MAAM;EAAI,SAAS,MAAM;CAAQ,CAAC;AACpE;;;;;;;;;;;AAYA,SAAgB,sBACd,OACwC;CACxC,OAAO,qBAAqB,KAAK;AACnC;;;;;;;;;ACxHA,IAAa,2BAAb,cAA8C,0BAAgD;CAC5F,cAAc;EACZ,sBAAM,IAAI,IAAI,CAAC;CACjB;CAEA,yBACE,MACA,KACqC;EACrC,IAAI,eAAe,eACjB,OAAO;EAMT,OAAO,qBAJU,UAGf,MAAM,yBAAyB,MAAM,GAAG,CACP,CAAC;CACtC;AACF"}
@@ -0,0 +1,46 @@
1
+ import { t as SqlitePlanTargetDetails } from "./planner-target-details-xR6UfIcz.mjs";
2
+ import { DdlColumn, DdlTableConstraint } from "@prisma-next/sql-relational-core/ast";
3
+ import { SqlMigrationPlanOperation } from "@prisma-next/family-sql/control";
4
+ import { Migration } from "@prisma-next/family-sql/migration";
5
+ import { ControlStack } from "@prisma-next/framework-components/control";
6
+ import { SqlControlAdapter } from "@prisma-next/family-sql/control-adapter";
7
+
8
+ //#region src/core/migrations/sqlite-migration.d.ts
9
+ /**
10
+ * Target-owned base class for SQLite migrations. Fixes the `SqlMigration`
11
+ * generic to `SqlitePlanTargetDetails` and the abstract `targetId` to the
12
+ * SQLite literal, so both user-authored migrations and renderer-generated
13
+ * scaffolds can extend `SqliteMigration` directly without redeclaring
14
+ * target-local identity.
15
+ *
16
+ * The constructor materializes a single SQLite `SqlControlAdapter` from
17
+ * `stack.adapter.create(stack)` and stores it; the protected `createTable`
18
+ * instance method forwards to `CreateTableCall` with that stored adapter,
19
+ * so user migrations can write `this.createTable({...})` without threading
20
+ * the adapter through every call.
21
+ */
22
+ declare abstract class SqliteMigration extends Migration<SqlitePlanTargetDetails, 'sqlite'> {
23
+ readonly targetId: "sqlite";
24
+ /**
25
+ * Materialized SQLite control adapter, created once per migration
26
+ * instance from the injected stack. `undefined` only when the migration
27
+ * was instantiated without a stack (test fixtures); `createTable`
28
+ * throws in that case to surface the misuse.
29
+ */
30
+ protected readonly controlAdapter: SqlControlAdapter<'sqlite'> | undefined;
31
+ constructor(stack?: ControlStack<'sql', 'sqlite'>);
32
+ /**
33
+ * Emit a `CREATE TABLE` migration operation. Builds a typed DDL node from
34
+ * the supplied options and lowers it through the stored control adapter.
35
+ * Throws if no adapter is present (i.e. migration instantiated without a stack).
36
+ */
37
+ protected createTable(options: {
38
+ readonly table: string;
39
+ readonly ifNotExists?: boolean;
40
+ readonly columns: readonly DdlColumn[];
41
+ readonly constraints?: readonly DdlTableConstraint[];
42
+ }): Promise<SqlMigrationPlanOperation<SqlitePlanTargetDetails>>;
43
+ }
44
+ //#endregion
45
+ export { SqliteMigration as t };
46
+ //# sourceMappingURL=sqlite-migration-CJrASAxf.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-migration-CJrASAxf.d.mts","names":[],"sources":["../src/core/migrations/sqlite-migration.ts"],"mappings":";;;;;;;;;;AAuBA;;;;;;;;;;;uBAAsB,eAAA,SAAwB,SAAA,CAAa,uBAAA;EAAA,SAChD,QAAA;EAD+C;;;;;;EAAA,mBASrC,cAAA,EAAgB,iBAAA;cAEvB,KAAA,GAAQ,YAAA;EAAR;;;;;EAAA,UAeF,WAAA,CAAY,OAAA;IAAA,SACX,KAAA;IAAA,SACA,WAAA;IAAA,SACA,OAAA,WAAkB,SAAA;IAAA,SAClB,WAAA,YAAuB,kBAAA;EAAA,IAC9B,OAAA,CAAQ,yBAAA,CAA0B,uBAAA;AAAA"}
@@ -0,0 +1,73 @@
1
+ import { r as CreateTableCall } from "./op-factory-call-z4TT72k3.mjs";
2
+ import { blindCast } from "@prisma-next/utils/casts";
3
+ import { Migration } from "@prisma-next/family-sql/migration";
4
+ import { CliStructuredError } from "@prisma-next/errors/control";
5
+ //#region src/core/errors.ts
6
+ /**
7
+ * A `SqliteMigration` instance method that needs the materialized control
8
+ * adapter (currently only `this.createTable(...)`) was invoked, but the
9
+ * migration was constructed without a `ControlStack`. Concrete authoring
10
+ * usage always goes through the migration CLI entrypoint, which assembles
11
+ * a stack from the loaded `prisma-next.config.ts`; reaching this error
12
+ * means a test fixture or ad-hoc consumer instantiated `SqliteMigration`
13
+ * with the no-arg form (legal for `operations` / `describe` introspection
14
+ * only).
15
+ *
16
+ * Distinct from `PN-MIG-2001` (placeholder not filled) because the missing
17
+ * input is the stack itself, not the per-operation contract.
18
+ *
19
+ * Lives in `@prisma-next/target-sqlite/errors` rather than the shared
20
+ * framework migration errors module because the failure is target-specific:
21
+ * the contract it talks about (`SqliteMigration`, the SQLite control
22
+ * adapter, the SQLite-target stack) only exists in this package.
23
+ */
24
+ function errorSqliteMigrationStackMissing() {
25
+ return new CliStructuredError("2008", "SqliteMigration.createTable requires a control adapter", {
26
+ domain: "MIG",
27
+ why: "SqliteMigration.createTable was invoked on an instance constructed without a ControlStack. The stored controlAdapter is undefined, so createTable cannot lower its DDL node.",
28
+ 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.",
29
+ meta: {}
30
+ });
31
+ }
32
+ //#endregion
33
+ //#region src/core/migrations/sqlite-migration.ts
34
+ /**
35
+ * Target-owned base class for SQLite migrations. Fixes the `SqlMigration`
36
+ * generic to `SqlitePlanTargetDetails` and the abstract `targetId` to the
37
+ * SQLite literal, so both user-authored migrations and renderer-generated
38
+ * scaffolds can extend `SqliteMigration` directly without redeclaring
39
+ * target-local identity.
40
+ *
41
+ * The constructor materializes a single SQLite `SqlControlAdapter` from
42
+ * `stack.adapter.create(stack)` and stores it; the protected `createTable`
43
+ * instance method forwards to `CreateTableCall` with that stored adapter,
44
+ * so user migrations can write `this.createTable({...})` without threading
45
+ * the adapter through every call.
46
+ */
47
+ var SqliteMigration = class extends Migration {
48
+ targetId = "sqlite";
49
+ /**
50
+ * Materialized SQLite control adapter, created once per migration
51
+ * instance from the injected stack. `undefined` only when the migration
52
+ * was instantiated without a stack (test fixtures); `createTable`
53
+ * throws in that case to surface the misuse.
54
+ */
55
+ controlAdapter;
56
+ constructor(stack) {
57
+ super(stack);
58
+ this.controlAdapter = stack?.adapter ? blindCast(stack.adapter.create(stack)) : void 0;
59
+ }
60
+ /**
61
+ * Emit a `CREATE TABLE` migration operation. Builds a typed DDL node from
62
+ * the supplied options and lowers it through the stored control adapter.
63
+ * Throws if no adapter is present (i.e. migration instantiated without a stack).
64
+ */
65
+ createTable(options) {
66
+ if (!this.controlAdapter) throw errorSqliteMigrationStackMissing();
67
+ return new CreateTableCall(options.table, options.columns, options.constraints).toOp(this.controlAdapter);
68
+ }
69
+ };
70
+ //#endregion
71
+ export { SqliteMigration as t };
72
+
73
+ //# sourceMappingURL=sqlite-migration-DhW4ycZV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-migration-DhW4ycZV.mjs","names":["SqlMigration"],"sources":["../src/core/errors.ts","../src/core/migrations/sqlite-migration.ts"],"sourcesContent":["import { CliStructuredError } from '@prisma-next/errors/control';\n\n/**\n * A `SqliteMigration` instance method that needs the materialized control\n * adapter (currently only `this.createTable(...)`) was invoked, but the\n * migration was constructed without a `ControlStack`. Concrete authoring\n * usage always goes through the migration CLI entrypoint, which assembles\n * a stack from the loaded `prisma-next.config.ts`; reaching this error\n * means a test fixture or ad-hoc consumer instantiated `SqliteMigration`\n * with the no-arg form (legal for `operations` / `describe` introspection\n * only).\n *\n * Distinct from `PN-MIG-2001` (placeholder not filled) because the missing\n * input is the stack itself, not the per-operation 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(): CliStructuredError {\n return new CliStructuredError('2008', 'SqliteMigration.createTable requires a control adapter', {\n domain: 'MIG',\n why: 'SqliteMigration.createTable was invoked on an instance constructed without a ControlStack. The stored controlAdapter is undefined, so createTable 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: {},\n });\n}\n","import type { SqlMigrationPlanOperation } 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 type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { errorSqliteMigrationStackMissing } from '../errors';\nimport { CreateTableCall } from './op-factory-call';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\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 `createTable`\n * instance method forwards to `CreateTableCall` with that stored adapter,\n * so user migrations can write `this.createTable({...})` without threading\n * the adapter through every call.\n */\nexport abstract class SqliteMigration extends SqlMigration<SqlitePlanTargetDetails, 'sqlite'> {\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); `createTable`\n * throws in that case to surface the misuse.\n */\n protected readonly controlAdapter: SqlControlAdapter<'sqlite'> | undefined;\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 * Emit a `CREATE TABLE` migration operation. Builds a typed DDL node from\n * the supplied options and lowers it through the stored control adapter.\n * Throws if no adapter is present (i.e. migration instantiated without a stack).\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<SqlMigrationPlanOperation<SqlitePlanTargetDetails>> {\n if (!this.controlAdapter) {\n throw errorSqliteMigrationStackMissing();\n }\n return new CreateTableCall(options.table, options.columns, options.constraints).toOp(\n this.controlAdapter,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,mCAAuD;CACrE,OAAO,IAAI,mBAAmB,QAAQ,0DAA0D;EAC9F,QAAQ;EACR,KAAK;EACL,KAAK;EACL,MAAM,CAAC;CACT,CAAC;AACH;;;;;;;;;;;;;;;;ACJA,IAAsB,kBAAtB,cAA8CA,UAAgD;CAC5F,WAAoB;;;;;;;CAQpB;CAEA,YAAY,OAAuC;EACjD,MAAM,KAAK;EACX,KAAK,iBAAiB,OAAO,UACzB,UAGE,MAAM,QAAQ,OAAO,KAAK,CAAC,IAC7B,KAAA;CACN;;;;;;CAOA,YAAsB,SAK0C;EAC9D,IAAI,CAAC,KAAK,gBACR,MAAM,iCAAiC;EAEzC,OAAO,IAAI,gBAAgB,QAAQ,OAAO,QAAQ,SAAS,QAAQ,WAAW,CAAC,CAAC,KAC9E,KAAK,cACP;CACF;AACF"}
package/package.json CHANGED
@@ -1,30 +1,30 @@
1
1
  {
2
2
  "name": "@prisma-next/target-sqlite",
3
- "version": "0.13.0-dev.3",
3
+ "version": "0.13.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.13.0-dev.3",
9
- "@prisma-next/contract": "0.13.0-dev.3",
10
- "@prisma-next/errors": "0.13.0-dev.3",
11
- "@prisma-next/family-sql": "0.13.0-dev.3",
12
- "@prisma-next/framework-components": "0.13.0-dev.3",
13
- "@prisma-next/migration-tools": "0.13.0-dev.3",
14
- "@prisma-next/sql-contract": "0.13.0-dev.3",
15
- "@prisma-next/sql-errors": "0.13.0-dev.3",
16
- "@prisma-next/sql-relational-core": "0.13.0-dev.3",
17
- "@prisma-next/sql-runtime": "0.13.0-dev.3",
18
- "@prisma-next/sql-schema-ir": "0.13.0-dev.3",
19
- "@prisma-next/ts-render": "0.13.0-dev.3",
20
- "@prisma-next/utils": "0.13.0-dev.3",
8
+ "@prisma-next/cli": "0.13.0-dev.31",
9
+ "@prisma-next/contract": "0.13.0-dev.31",
10
+ "@prisma-next/errors": "0.13.0-dev.31",
11
+ "@prisma-next/family-sql": "0.13.0-dev.31",
12
+ "@prisma-next/framework-components": "0.13.0-dev.31",
13
+ "@prisma-next/migration-tools": "0.13.0-dev.31",
14
+ "@prisma-next/sql-contract": "0.13.0-dev.31",
15
+ "@prisma-next/sql-errors": "0.13.0-dev.31",
16
+ "@prisma-next/sql-relational-core": "0.13.0-dev.31",
17
+ "@prisma-next/sql-runtime": "0.13.0-dev.31",
18
+ "@prisma-next/sql-schema-ir": "0.13.0-dev.31",
19
+ "@prisma-next/ts-render": "0.13.0-dev.31",
20
+ "@prisma-next/utils": "0.13.0-dev.31",
21
21
  "@standard-schema/spec": "1.1.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@prisma-next/driver-sqlite": "0.13.0-dev.3",
25
- "@prisma-next/test-utils": "0.13.0-dev.3",
26
- "@prisma-next/tsconfig": "0.13.0-dev.3",
27
- "@prisma-next/tsdown": "0.13.0-dev.3",
24
+ "@prisma-next/driver-sqlite": "0.13.0-dev.31",
25
+ "@prisma-next/test-utils": "0.13.0-dev.31",
26
+ "@prisma-next/tsconfig": "0.13.0-dev.31",
27
+ "@prisma-next/tsdown": "0.13.0-dev.31",
28
28
  "tsdown": "0.22.1",
29
29
  "typescript": "5.9.3",
30
30
  "vitest": "4.1.8"
@@ -36,8 +36,8 @@ const sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', Sqlite
36
36
  contractSerializer: new SqliteContractSerializer(),
37
37
  schemaVerifier: new SqliteSchemaVerifier(),
38
38
  migrations: {
39
- createPlanner(_adapter: SqlControlAdapter<'sqlite'>): MigrationPlanner<'sql', 'sqlite'> {
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(_adapter: SqlControlAdapter<'sqlite'>) {
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 | PostgresEnumStorageEntry>>,
220
+ storageTypes: Readonly<Record<string, StorageTypeInstance>>,
210
221
  inlineAutoincrementPrimaryKey = false,
211
222
  ): SqliteColumnSpec {
212
223
  const typeSql = buildColumnTypeSql(
213
224
  column,
214
- storageTypes as Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
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 | PostgresEnumStorageEntry>>,
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 | PostgresEnumStorageEntry>>;
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 tableSpec = toTableSpec(contractTable, ctx.storageTypes);
313
- const calls: SqliteOpFactoryCall[] = [new CreateTableCall(issue.table, tableSpec)];
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);