@prisma-next/target-sqlite 0.12.0-dev.4 → 0.12.0-dev.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/{codec-ids-C4UfWqAE.d.mts → codec-ids-yG2RRHnw.d.mts} +1 -1
  2. package/dist/{codec-ids-C4UfWqAE.d.mts.map → codec-ids-yG2RRHnw.d.mts.map} +1 -1
  3. package/dist/codec-ids.d.mts +1 -1
  4. package/dist/{codec-types-B2ci-b_W.d.mts → codec-types-CM7OkQLM.d.mts} +2 -2
  5. package/dist/{codec-types-B2ci-b_W.d.mts.map → codec-types-CM7OkQLM.d.mts.map} +1 -1
  6. package/dist/codec-types.d.mts +2 -2
  7. package/dist/{codecs-DqDWNIKq.d.mts → codecs-t6YnHZkK.d.mts} +2 -2
  8. package/dist/{codecs-DqDWNIKq.d.mts.map → codecs-t6YnHZkK.d.mts.map} +1 -1
  9. package/dist/codecs.d.mts +1 -1
  10. package/dist/contract-free.d.mts +50 -0
  11. package/dist/contract-free.d.mts.map +1 -0
  12. package/dist/contract-free.mjs +107 -0
  13. package/dist/contract-free.mjs.map +1 -0
  14. package/dist/control-tables-C0Nkzhv9.mjs +12 -0
  15. package/dist/control-tables-C0Nkzhv9.mjs.map +1 -0
  16. package/dist/control-tables.d.mts +11 -0
  17. package/dist/control-tables.d.mts.map +1 -0
  18. package/dist/control-tables.mjs +2 -0
  19. package/dist/control.d.mts +1 -1
  20. package/dist/control.d.mts.map +1 -1
  21. package/dist/control.mjs +62 -120
  22. package/dist/control.mjs.map +1 -1
  23. package/dist/ddl.d.mts +2 -0
  24. package/dist/ddl.mjs +2 -0
  25. package/dist/{descriptor-meta-DIbCXU65.mjs → descriptor-meta-rKforwQA.mjs} +3 -1
  26. package/dist/descriptor-meta-rKforwQA.mjs.map +1 -0
  27. package/dist/migration.d.mts +2 -2
  28. package/dist/migration.mjs +2 -2
  29. package/dist/nodes-09ul6DNV.mjs +28 -0
  30. package/dist/nodes-09ul6DNV.mjs.map +1 -0
  31. package/dist/nodes-D8LGV4Yk.d.mts +27 -0
  32. package/dist/nodes-D8LGV4Yk.d.mts.map +1 -0
  33. package/dist/{op-factory-call-VBm-wu5R.mjs → op-factory-call-DulOHPZX.mjs} +2 -2
  34. package/dist/{op-factory-call-VBm-wu5R.mjs.map → op-factory-call-DulOHPZX.mjs.map} +1 -1
  35. package/dist/op-factory-call.d.mts +2 -2
  36. package/dist/op-factory-call.mjs +1 -1
  37. package/dist/pack.d.mts +2 -1
  38. package/dist/pack.d.mts.map +1 -1
  39. package/dist/pack.mjs +1 -1
  40. package/dist/{planner-produced-sqlite-migration-D4FSvPE4.d.mts → planner-produced-sqlite-migration-BwFkd0br.d.mts} +3 -3
  41. package/dist/{planner-produced-sqlite-migration-D4FSvPE4.d.mts.map → planner-produced-sqlite-migration-BwFkd0br.d.mts.map} +1 -1
  42. package/dist/planner-produced-sqlite-migration.d.mts +1 -1
  43. package/dist/{planner-target-details-BRS591Zt.mjs → planner-target-details-B-H_bvo0.mjs} +1 -1
  44. package/dist/{planner-target-details-BRS591Zt.mjs.map → planner-target-details-B-H_bvo0.mjs.map} +1 -1
  45. package/dist/{planner-target-details-B-VJkUsu.d.mts → planner-target-details-RVPqF2ug.d.mts} +1 -1
  46. package/dist/{planner-target-details-B-VJkUsu.d.mts.map → planner-target-details-RVPqF2ug.d.mts.map} +1 -1
  47. package/dist/planner-target-details.d.mts +1 -1
  48. package/dist/planner-target-details.mjs +1 -1
  49. package/dist/{planner-BBvwGy0f.mjs → planner-yHMaXnOO.mjs} +5 -5
  50. package/dist/planner-yHMaXnOO.mjs.map +1 -0
  51. package/dist/planner.d.mts +2 -2
  52. package/dist/planner.mjs +1 -1
  53. package/dist/render-ops.d.mts +1 -1
  54. package/dist/runtime.d.mts +17 -1
  55. package/dist/runtime.d.mts.map +1 -1
  56. package/dist/runtime.mjs +2 -1
  57. package/dist/runtime.mjs.map +1 -1
  58. package/dist/{shared-DDOJntxk.d.mts → shared-Bw5G0I-c.d.mts} +2 -2
  59. package/dist/{shared-DDOJntxk.d.mts.map → shared-Bw5G0I-c.d.mts.map} +1 -1
  60. package/dist/{sql-utils-D0gQAMLB.mjs → sql-utils-DcrE1Hm4.mjs} +1 -1
  61. package/dist/{sql-utils-D0gQAMLB.mjs.map → sql-utils-DcrE1Hm4.mjs.map} +1 -1
  62. package/dist/sql-utils.mjs +1 -1
  63. package/dist/sqlite-contract-serializer-Hy7WQPea.mjs +100 -0
  64. package/dist/sqlite-contract-serializer-Hy7WQPea.mjs.map +1 -0
  65. package/dist/{sqlite-migration-Feio34n3.d.mts → sqlite-migration-D-O3Glz1.d.mts} +2 -2
  66. package/dist/{sqlite-migration-Feio34n3.d.mts.map → sqlite-migration-D-O3Glz1.d.mts.map} +1 -1
  67. package/dist/{tables-gB0XiFu8.mjs → tables-zrEJsCi9.mjs} +3 -3
  68. package/dist/{tables-gB0XiFu8.mjs.map → tables-zrEJsCi9.mjs.map} +1 -1
  69. package/package.json +21 -19
  70. package/src/contract-free/columns.ts +44 -0
  71. package/src/contract-free/control-bootstrap.ts +54 -0
  72. package/src/contract-free/ddl.ts +21 -0
  73. package/src/core/control-tables.ts +11 -0
  74. package/src/core/ddl/nodes.ts +41 -0
  75. package/src/core/descriptor-meta.ts +2 -0
  76. package/src/core/migrations/issue-planner.ts +1 -1
  77. package/src/core/migrations/runner.ts +76 -78
  78. package/src/core/sqlite-contract-serializer.ts +38 -9
  79. package/src/core/sqlite-unbound-database.ts +30 -0
  80. package/src/exports/contract-free.ts +6 -0
  81. package/src/exports/control-tables.ts +5 -0
  82. package/src/exports/ddl.ts +6 -0
  83. package/src/exports/runtime.ts +1 -0
  84. package/dist/descriptor-meta-DIbCXU65.mjs.map +0 -1
  85. package/dist/planner-BBvwGy0f.mjs.map +0 -1
  86. package/dist/statement-builders-BiRmeyJM.mjs +0 -158
  87. package/dist/statement-builders-BiRmeyJM.mjs.map +0 -1
  88. package/dist/statement-builders.d.mts +0 -68
  89. package/dist/statement-builders.d.mts.map +0 -1
  90. package/dist/statement-builders.mjs +0 -2
  91. package/src/core/migrations/statement-builders.ts +0 -212
  92. package/src/exports/statement-builders.ts +0 -12
@@ -1,4 +1,4 @@
1
- import type { ContractMarkerRecord } from '@prisma-next/contract/types';
1
+ import type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';
2
2
  import type {
3
3
  MigrationOperationPolicy,
4
4
  SqlControlFamilyInstance,
@@ -13,27 +13,20 @@ import type {
13
13
  } from '@prisma-next/family-sql/control';
14
14
  import { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';
15
15
  import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
16
- import { type ContractMarkerRow, parseContractMarkerRow } from '@prisma-next/family-sql/verify';
17
16
  import type {
18
17
  ControlDriverInstance,
19
18
  MigrationRunnerResult,
20
19
  } from '@prisma-next/framework-components/control';
21
20
  import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
21
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
22
+ import type { LoweredStatement } from '@prisma-next/sql-relational-core/ast';
22
23
  import { ifDefined } from '@prisma-next/utils/defined';
23
24
  import type { Result } from '@prisma-next/utils/result';
24
25
  import { notOk, ok, okVoid } from '@prisma-next/utils/result';
26
+ import { MARKER_TABLE_NAME } from '../control-tables';
25
27
  import { parseSqliteDefault } from '../default-normalizer';
26
28
  import { normalizeSqliteNativeType } from '../native-type-normalizer';
27
29
  import type { SqlitePlanTargetDetails } from './planner-target-details';
28
- import {
29
- buildLedgerInsertStatement,
30
- buildWriteMarkerStatements,
31
- ensureLedgerTableStatement,
32
- ensureMarkerTableStatement,
33
- MARKER_TABLE_NAME,
34
- readMarkerStatement,
35
- type SqlStatement,
36
- } from './statement-builders';
37
30
 
38
31
  export function createSqliteMigrationRunner(
39
32
  family: SqlControlFamilyInstance,
@@ -70,9 +63,9 @@ class SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetail
70
63
  const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);
71
64
  if (!policyCheck.ok) return policyCheck;
72
65
 
73
- const ensureResult = await this.ensureControlTables(driver);
66
+ const ensureResult = await this.ensureControlTables(driver, options.destinationContract);
74
67
  if (!ensureResult.ok) return ensureResult;
75
- const existingMarker = await this.readMarker(driver, space);
68
+ const existingMarker = await this.family.readMarker({ driver, space });
76
69
 
77
70
  const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);
78
71
  if (!markerCheck.ok) return markerCheck;
@@ -126,8 +119,9 @@ class SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetail
126
119
  const isSelfEdgeNoOp = isSelfEdge && operationsExecuted === 0 && incomingIsSubsetOfExisting;
127
120
 
128
121
  if (!isSelfEdgeNoOp) {
129
- await this.upsertMarker(driver, options, existingMarker, space);
130
- await this.recordLedgerEntry(driver, options, existingMarker, executedOperations);
122
+ const markerResult = await this.upsertMarker(driver, options, existingMarker, space);
123
+ if (!markerResult.ok) return markerResult;
124
+ await this.recordLedgerEntries(driver, options, executedOperations);
131
125
  }
132
126
 
133
127
  return runnerSuccess({
@@ -306,17 +300,16 @@ class SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetail
306
300
 
307
301
  private async ensureControlTables(
308
302
  driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],
303
+ contract: Contract<SqlStorage>,
309
304
  ): Promise<Result<void, SqlMigrationRunnerFailure>> {
310
- // Pre-1.0 zero-range guardrail: detect a pre-cleanup single-row
311
- // marker table (no `space` column) and surface a structured failure
312
- // rather than silently rebuilding the table into the per-space
313
- // shape. See `specs/framework-mechanism.spec.md § 2`.
314
305
  const legacyDetection = await this.detectLegacyMarkerShape(driver);
315
306
  if (!legacyDetection.ok) {
316
307
  return legacyDetection;
317
308
  }
318
- await this.executeStatement(driver, ensureMarkerTableStatement);
319
- await this.executeStatement(driver, ensureLedgerTableStatement);
309
+ const lowererContext = { contract };
310
+ for (const query of this.family.bootstrapControlTableQueries()) {
311
+ await this.executeStatement(driver, this.family.lowerAst(query, lowererContext));
312
+ }
320
313
  return okVoid();
321
314
  }
322
315
 
@@ -347,32 +340,6 @@ class SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetail
347
340
  );
348
341
  }
349
342
 
350
- private async readMarker(
351
- driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],
352
- space: string,
353
- ): Promise<ContractMarkerRecord | null> {
354
- const stmt = readMarkerStatement(space);
355
- try {
356
- const result = await driver.query<ContractMarkerRow>(stmt.sql, stmt.params);
357
- const row = result.rows[0];
358
- if (!row) return null;
359
- // SQLite stores arrays as JSON-encoded TEXT (no native array type), so
360
- // the driver returns `invariants` as a string. Decode before delegating
361
- // to the shared row schema, which expects `string[]`.
362
- const invariants =
363
- typeof row.invariants === 'string'
364
- ? (JSON.parse(row.invariants) as unknown)
365
- : row.invariants;
366
- return parseContractMarkerRow({ ...row, invariants });
367
- } catch (error) {
368
- // Table might not exist yet
369
- if (error instanceof Error && error.message.includes('no such table')) {
370
- return null;
371
- }
372
- throw error;
373
- }
374
- }
375
-
376
343
  private async runExpectationSteps(
377
344
  driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],
378
345
  steps: readonly SqlMigrationPlanOperationStep[],
@@ -600,48 +567,79 @@ class SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetail
600
567
  options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,
601
568
  existingMarker: ContractMarkerRecord | null,
602
569
  space: string,
603
- ): Promise<void> {
604
- // SQLite has no native array type, so we can't merge invariants in SQL
605
- // the way Postgres does. Merge client-side under the runner's
606
- // BEGIN EXCLUSIVE — sort + dedupe so the JSON-encoded value is stable.
607
- const merged = new Set<string>(existingMarker?.invariants ?? []);
608
- for (const inv of options.plan.providedInvariants) merged.add(inv);
609
- const invariants = Array.from(merged).sort();
610
- const writeStatements = buildWriteMarkerStatements({
611
- space,
570
+ ): Promise<Result<void, SqlMigrationRunnerFailure>> {
571
+ // Pass the plan's incoming invariants verbatim; `updateMarker` unions them
572
+ // with the stored set (TS-side, dialect-uniform) under the runner's
573
+ // BEGIN EXCLUSIVE — no client-side pre-merge here, so there is no
574
+ // double-merge with the SPI's internal accumulate-dedupe.
575
+ const destination = {
612
576
  storageHash: options.plan.destination.storageHash,
613
577
  profileHash:
614
578
  options.plan.destination.profileHash ??
615
579
  options.destinationContract.profileHash ??
616
580
  options.plan.destination.storageHash,
617
- contractJson: options.destinationContract,
618
- canonicalVersion: null,
619
- meta: {},
620
- invariants,
581
+ invariants: options.plan.providedInvariants ?? [],
582
+ };
583
+ if (!existingMarker) {
584
+ await this.family.initMarker({ driver, space, destination });
585
+ return okVoid();
586
+ }
587
+ const updated = await this.family.updateMarker({
588
+ driver,
589
+ space,
590
+ expectedFrom: existingMarker.storageHash,
591
+ destination,
621
592
  });
622
- const statement = existingMarker ? writeStatements.update : writeStatements.insert;
623
- await this.executeStatement(driver, statement);
593
+ if (!updated) {
594
+ return runnerFailure(
595
+ 'MARKER_CAS_FAILURE',
596
+ 'Marker was modified by another process during migration execution.',
597
+ {
598
+ meta: {
599
+ space,
600
+ expectedStorageHash: existingMarker.storageHash,
601
+ destinationStorageHash: options.plan.destination.storageHash,
602
+ },
603
+ },
604
+ );
605
+ }
606
+ return okVoid();
624
607
  }
625
608
 
626
- private async recordLedgerEntry(
609
+ private async recordLedgerEntries(
627
610
  driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],
628
611
  options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,
629
- existingMarker: ContractMarkerRecord | null,
630
612
  executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[],
631
613
  ): Promise<void> {
632
- const ledgerStatement = buildLedgerInsertStatement({
633
- originStorageHash: existingMarker?.storageHash ?? null,
634
- originProfileHash: existingMarker?.profileHash ?? null,
635
- destinationStorageHash: options.plan.destination.storageHash,
636
- destinationProfileHash:
637
- options.plan.destination.profileHash ??
638
- options.destinationContract.profileHash ??
639
- options.plan.destination.storageHash,
640
- contractJsonBefore: existingMarker?.contractJson ?? null,
641
- contractJsonAfter: options.destinationContract,
642
- operations: executedOperations,
643
- });
644
- await this.executeStatement(driver, ledgerStatement);
614
+ const plan = options.plan;
615
+ const space = plan.spaceId;
616
+ const edges = options.migrationEdges;
617
+ const totalEdgeOps = edges.reduce((sum, edge) => sum + edge.operationCount, 0);
618
+ if (totalEdgeOps !== plan.operations.length) {
619
+ throw new Error(
620
+ `Ledger write: plan.operations length (${plan.operations.length}) does not match sum of migrationEdges operationCount (${totalEdgeOps})`,
621
+ );
622
+ }
623
+ // The ledger records the operations as executed — idempotency-skipped ops
624
+ // are substituted with skip records (empty `execute`) by `applyPlan`, so the
625
+ // journal reflects what actually ran rather than the raw plan.
626
+ let offset = 0;
627
+ for (const edge of edges) {
628
+ const edgeOps = executedOperations.slice(offset, offset + edge.operationCount);
629
+ offset += edge.operationCount;
630
+ await this.family.writeLedgerEntry({
631
+ driver,
632
+ space,
633
+ entry: {
634
+ edgeId: `${edge.from}->${edge.to}`,
635
+ from: edge.from,
636
+ to: edge.to,
637
+ migrationName: edge.dirName,
638
+ migrationHash: edge.migrationHash,
639
+ operations: edgeOps,
640
+ },
641
+ });
642
+ }
645
643
  }
646
644
 
647
645
  private async beginExclusiveTransaction(
@@ -664,7 +662,7 @@ class SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetail
664
662
 
665
663
  private async executeStatement(
666
664
  driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],
667
- statement: SqlStatement,
665
+ statement: LoweredStatement,
668
666
  ): Promise<void> {
669
667
  if (statement.params.length > 0) {
670
668
  await driver.query(statement.sql, statement.params);
@@ -1,20 +1,49 @@
1
1
  import type { Contract } from '@prisma-next/contract/types';
2
2
  import { SqlContractSerializerBase } from '@prisma-next/family-sql/ir';
3
- import type { SqlStorage } from '@prisma-next/sql-contract/types';
3
+ import {
4
+ type Namespace,
5
+ NamespaceBase,
6
+ UNBOUND_NAMESPACE_ID,
7
+ } from '@prisma-next/framework-components/ir';
8
+ import type {
9
+ SqlNamespaceTablesInput,
10
+ SqlStorage,
11
+ StorageTable,
12
+ } from '@prisma-next/sql-contract/types';
13
+ import { SqliteDatabase, SqliteUnboundDatabase } from './sqlite-unbound-database';
4
14
 
5
15
  /**
6
16
  * SQLite target `ContractSerializer` concretion. Mirrors the Postgres
7
- * shape: inherits the full SQL-family deserialization pipeline. Today's
8
- * SQLite contract shape is the family-shared shape; no target-specific
9
- * polymorphic `storage.types` factories are registered yet.
10
- *
11
- * `serializeContract` falls through to the family-base default —
12
- * SQLite's contract is JSON-clean today. Once target-only fields land
13
- * (e.g. per-target derived storage fields) this is the home for
14
- * stripping them from the persisted envelope.
17
+ * shape: inherits the full SQL-family deserialization pipeline and
18
+ * materialises namespace entries as SQLite database concretions that
19
+ * expose `qualifyTable()` for runtime SQL rendering.
15
20
  */
16
21
  export class SqliteContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {
17
22
  constructor() {
18
23
  super(new Map());
19
24
  }
25
+
26
+ protected override hydrateSqlNamespaceEntry(
27
+ nsId: string,
28
+ raw: Namespace | Record<string, unknown>,
29
+ ): Namespace | SqlNamespaceTablesInput {
30
+ if (raw instanceof NamespaceBase) {
31
+ return raw;
32
+ }
33
+ const hydrated = super.hydrateSqlNamespaceEntry(nsId, raw) as {
34
+ id: string;
35
+ tables: Readonly<Record<string, StorageTable>>;
36
+ };
37
+ const { id, tables } = hydrated;
38
+ const emptyTables = Object.keys(tables).length === 0;
39
+ if (id === UNBOUND_NAMESPACE_ID && emptyTables) {
40
+ return SqliteUnboundDatabase.instance;
41
+ }
42
+ if (id !== UNBOUND_NAMESPACE_ID) {
43
+ throw new Error(
44
+ `SqliteContractSerializer: SQLite has no schema concept; the only valid namespace id is "${UNBOUND_NAMESPACE_ID}" (received "${id}").`,
45
+ );
46
+ }
47
+ return new SqliteDatabase({ id, tables });
48
+ }
20
49
  }
@@ -5,6 +5,36 @@ import {
5
5
  } from '@prisma-next/framework-components/ir';
6
6
  import type { StorageTable } from '@prisma-next/sql-contract/types';
7
7
 
8
+ export type SqliteDatabaseInput = {
9
+ readonly id: string;
10
+ readonly tables: Readonly<Record<string, StorageTable>>;
11
+ };
12
+
13
+ /**
14
+ * SQLite namespace concretion carrying table metadata and unqualified
15
+ * `qualifyTable()` emission for runtime SQL rendering.
16
+ */
17
+ export class SqliteDatabase extends NamespaceBase {
18
+ readonly kind = 'database' as const;
19
+ readonly id: string;
20
+ readonly tables: Readonly<Record<string, StorageTable>>;
21
+
22
+ constructor(input: SqliteDatabaseInput) {
23
+ super();
24
+ this.id = input.id;
25
+ this.tables = Object.freeze({ ...input.tables });
26
+ freezeNode(this);
27
+ }
28
+
29
+ qualifier(): string {
30
+ return '';
31
+ }
32
+
33
+ qualifyTable(tableName: string): string {
34
+ return `"${tableName}"`;
35
+ }
36
+ }
37
+
8
38
  /**
9
39
  * SQLite target `Namespace` concretion. SQLite has no schema or
10
40
  * database-namespacing concept at the SQL level — there is exactly one
@@ -0,0 +1,6 @@
1
+ export { datetime, integer, jsonText, sqliteTable, text } from '../contract-free/columns';
2
+ export {
3
+ buildControlTableBootstrapQueries,
4
+ buildSignMarkerBootstrapQueries,
5
+ } from '../contract-free/control-bootstrap';
6
+ export { createTable } from '../contract-free/ddl';
@@ -0,0 +1,5 @@
1
+ export {
2
+ CONTROL_TABLE_NAMES,
3
+ LEDGER_TABLE_NAME,
4
+ MARKER_TABLE_NAME,
5
+ } from '../core/control-tables';
@@ -0,0 +1,6 @@
1
+ export {
2
+ type AnySqliteDdlNode,
3
+ SqliteCreateTable,
4
+ SqliteDdlNode,
5
+ type SqliteDdlVisitor,
6
+ } from '../core/ddl/nodes';
@@ -1,2 +1,3 @@
1
1
  export type { SqliteRuntimeTargetInstance } from '../core/runtime-target';
2
2
  export { default } from '../core/runtime-target';
3
+ export { SqliteContractSerializer } from '../core/sqlite-contract-serializer';
@@ -1 +0,0 @@
1
- {"version":3,"file":"descriptor-meta-DIbCXU65.mjs","names":[],"sources":["../src/core/authoring.ts","../src/core/descriptor-meta.ts"],"sourcesContent":["import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';\nimport type { AuthoringFieldNamespace } from '@prisma-next/framework-components/authoring';\n\nexport const sqliteAuthoringFieldPresets = {\n temporal: /* @__PURE__ */ temporalAuthoringPresets({\n codecId: 'sqlite/datetime@1',\n nativeType: 'text',\n }),\n} as const satisfies AuthoringFieldNamespace;\n","import type { CodecTypes } from '../exports/codec-types';\nimport { sqliteAuthoringFieldPresets } from './authoring';\nimport { sqliteTargetDescriptorMetaRuntime } from './descriptor-meta-runtime';\n\nconst sqliteTargetDescriptorMetaBase = {\n ...sqliteTargetDescriptorMetaRuntime,\n authoring: {\n field: sqliteAuthoringFieldPresets,\n },\n} as const;\n\nexport const sqliteTargetDescriptorMeta: typeof sqliteTargetDescriptorMetaBase & {\n readonly __codecTypes?: CodecTypes;\n} = sqliteTargetDescriptorMetaBase;\n"],"mappings":";;;AAGA,MAAa,8BAA8B,EACzC,UAA0B,yCAAyB;CACjD,SAAS;CACT,YAAY;AACd,CAAC,EACH;ACGA,MAAa,6BAET;CARF,GAAG;CACH,WAAW,EACT,OAAO,4BACT;AAKE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"planner-BBvwGy0f.mjs","names":[],"sources":["../src/core/migrations/planner-strategies.ts","../src/core/migrations/issue-planner.ts","../src/core/migrations/planner.ts"],"sourcesContent":["/**\n * SQLite migration strategies.\n *\n * Each strategy examines the issue list, consumes issues it handles, and\n * returns the `SqliteOpFactoryCall[]` to address them. The issue planner\n * runs each strategy in order and routes whatever's left through\n * `mapIssueToCall`.\n *\n * SQLite has no enums, no data-safe backfill, and no component-declared\n * database dependencies. The only recipe that needs strategy-level\n * multi-issue consumption is `recreateTable` (added in a later phase), which\n * absorbs type/nullability/default/constraint mismatches for a given table\n * into a single recreate operation.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n CodecControlHooks,\n MigrationOperationClass,\n MigrationOperationPolicy,\n} from '@prisma-next/family-sql/control';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type { SchemaIssue } from '@prisma-next/framework-components/control';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type {\n PostgresEnumStorageEntry,\n SqlStorage,\n StorageTable,\n StorageTypeInstance,\n} from '@prisma-next/sql-contract/types';\nimport { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\nimport { toTableSpec } from './issue-planner';\nimport { DataTransformCall, RecreateTableCall, type SqliteOpFactoryCall } from './op-factory-call';\nimport type { SqliteIndexSpec } from './operations/shared';\nimport { buildRecreatePostchecks, buildRecreateSummary } from './operations/tables';\n\nexport interface StrategyContext {\n readonly toContract: Contract<SqlStorage>;\n readonly fromContract: Contract<SqlStorage> | null;\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n readonly storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>;\n readonly schema: SqlSchemaIR;\n readonly policy: MigrationOperationPolicy;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n}\n\n/**\n * Look up a storage table by its explicit namespace coordinate. Returns\n * `undefined` when the namespace has no table by that name (or no such\n * namespace exists). Callers that get `undefined` MUST treat it as an\n * explicit conflict rather than silently falling back to a name-only\n * walk across namespaces — the SQLite target currently has a single\n * namespace, but this helper enforces the explicit-coordinate\n * discipline so a future multi-namespace SQLite shape inherits the\n * conflict-on-stale-coordinate behaviour the Postgres planner already\n * has.\n */\nexport function tableAt(\n storage: SqlStorage,\n namespaceId: string,\n tableName: string,\n): StorageTable | undefined {\n return storage.namespaces[namespaceId]?.tables[tableName] as StorageTable | undefined;\n}\n\n/**\n * Default namespace coordinate for an issue that does not carry one\n * explicitly. Hand-crafted unit-test issues fall back to `__unbound__`,\n * the only namespace any single-namespace contract carries —\n * verifier-emitted issues for legacy single-namespace contracts already\n * stamp this id explicitly. Typed structurally so issue variants\n * without a `namespaceId` slot flow through to the same fallback.\n */\nexport function resolveNamespaceIdForIssue(issue: { readonly namespaceId?: string }): string {\n return issue.namespaceId ?? UNBOUND_NAMESPACE_ID;\n}\n\nexport type CallMigrationStrategy = (\n issues: readonly SchemaIssue[],\n context: StrategyContext,\n) =>\n | {\n kind: 'match';\n issues: readonly SchemaIssue[];\n calls: readonly SqliteOpFactoryCall[];\n recipe?: boolean;\n }\n | { kind: 'no_match' };\n\n// ============================================================================\n// Recreate-table strategy\n// ============================================================================\n\nconst WIDENING_ISSUE_KINDS = new Set<SchemaIssue['kind']>(['default_mismatch', 'default_missing']);\n\nconst DESTRUCTIVE_ISSUE_KINDS = new Set<SchemaIssue['kind']>([\n 'extra_default',\n 'type_mismatch',\n 'primary_key_mismatch',\n 'foreign_key_mismatch',\n 'unique_constraint_mismatch',\n 'extra_foreign_key',\n 'extra_unique_constraint',\n 'extra_primary_key',\n]);\n\nfunction classifyIssue(issue: SchemaIssue): 'widening' | 'destructive' | null {\n if (issue.kind === 'enum_values_changed') return null;\n if (!issue.table) return null;\n if (issue.kind === 'nullability_mismatch') {\n // Relaxing (NOT NULL → nullable) is widening; tightening is destructive.\n return issue.expected === 'true' ? 'widening' : 'destructive';\n }\n if (WIDENING_ISSUE_KINDS.has(issue.kind)) return 'widening';\n if (DESTRUCTIVE_ISSUE_KINDS.has(issue.kind)) return 'destructive';\n return null;\n}\n\n/**\n * Groups recreate-eligible issues by table, decides per-table operation class\n * (destructive wins over widening), and emits one `RecreateTableCall` per\n * table. Returns unchanged-or-smaller issue list — issues the strategy\n * consumed are removed so `mapIssueToCall` doesn't double-handle them.\n */\nexport const recreateTableStrategy: CallMigrationStrategy = (issues, ctx) => {\n const byTable = new Map<\n string,\n { issues: SchemaIssue[]; hasDestructive: boolean; namespaceId: string }\n >();\n const consumed = new Set<SchemaIssue>();\n\n for (const issue of issues) {\n const cls = classifyIssue(issue);\n if (!cls) continue;\n if (issue.kind === 'enum_values_changed') continue;\n if (!issue.table) continue;\n const table = issue.table;\n const entry = byTable.get(table);\n if (entry) {\n entry.issues.push(issue);\n if (cls === 'destructive') entry.hasDestructive = true;\n } else {\n byTable.set(table, {\n issues: [issue],\n hasDestructive: cls === 'destructive',\n namespaceId: resolveNamespaceIdForIssue(issue),\n });\n }\n consumed.add(issue);\n }\n\n if (byTable.size === 0) return { kind: 'no_match' };\n\n const calls: SqliteOpFactoryCall[] = [];\n for (const [tableName, entry] of byTable) {\n const contractTable = tableAt(ctx.toContract.storage, entry.namespaceId, tableName);\n const schemaTable = ctx.schema.tables[tableName];\n if (!contractTable || !schemaTable) continue;\n const operationClass: MigrationOperationClass = entry.hasDestructive\n ? 'destructive'\n : 'widening';\n\n // Flatten the contract table to a self-contained spec — the Call holds\n // pre-rendered SQL fragments only, no `StorageColumn` or `storageTypes`.\n const tableSpec = toTableSpec(contractTable, ctx.storageTypes);\n\n const seenIndexColumnKeys = new Set<string>();\n const indexes: SqliteIndexSpec[] = [];\n for (const idx of contractTable.indexes) {\n const key = idx.columns.join(',');\n if (seenIndexColumnKeys.has(key)) continue;\n seenIndexColumnKeys.add(key);\n indexes.push({\n name: idx.name ?? defaultIndexName(tableName, idx.columns),\n columns: idx.columns,\n });\n }\n for (const fk of contractTable.foreignKeys) {\n if (fk.index === false) continue;\n const key = fk.source.columns.join(',');\n if (seenIndexColumnKeys.has(key)) continue;\n seenIndexColumnKeys.add(key);\n indexes.push({\n name: defaultIndexName(tableName, fk.source.columns),\n columns: fk.source.columns,\n });\n }\n\n calls.push(\n new RecreateTableCall({\n tableName,\n contractTable: tableSpec,\n schemaColumnNames: Object.keys(schemaTable.columns),\n indexes,\n summary: buildRecreateSummary(tableName, entry.issues),\n postchecks: buildRecreatePostchecks(tableName, entry.issues, tableSpec),\n operationClass,\n }),\n );\n }\n\n return {\n kind: 'match',\n issues: issues.filter((i) => !consumed.has(i)),\n calls,\n recipe: true,\n };\n};\n\n// ============================================================================\n// Nullability-tightening backfill strategy\n// ============================================================================\n\n/**\n * When the policy allows `'data'` and the contract tightens one or more\n * columns from nullable to NOT NULL, emit a `DataTransformCall` stub per\n * tightened column. The user fills the backfill `UPDATE` in the rendered\n * `migration.ts` before the subsequent `RecreateTableCall` copies data into\n * the tightened schema (whose `INSERT INTO temp SELECT … FROM old` would\n * otherwise fail at runtime if any `NULL`s remain).\n *\n * Does NOT consume the tightening issue — `recreateTableStrategy` still\n * needs it to produce the actual recreate that enforces the NOT NULL at\n * the schema level. The backfill op and the recreate op end up in the\n * recipe slot in strategy order (backfill first, recreate second), which\n * matches the required execution order.\n *\n * Mirrors Postgres's `nullableTighteningCallStrategy` / `'data'`-class\n * gating. When `'data'` is not in the policy (the default `db update` /\n * `db init` path), the strategy short-circuits and the recreate alone\n * runs with its current destructive-class gating — preserving today's\n * behavior where a tightening blows up at runtime if NULLs are present.\n */\nexport const nullabilityTighteningBackfillStrategy: CallMigrationStrategy = (issues, ctx) => {\n if (!ctx.policy.allowedOperationClasses.includes('data')) {\n return { kind: 'no_match' };\n }\n\n const calls: SqliteOpFactoryCall[] = [];\n for (const issue of issues) {\n if (issue.kind !== 'nullability_mismatch') continue;\n if (!issue.table || !issue.column) continue;\n // Tightening only: `expected === 'true'` means the contract wants the\n // column nullable (relaxing from NOT NULL → nullable), which is safe and\n // needs no backfill.\n if (issue.expected === 'true') continue;\n\n const namespaceId = resolveNamespaceIdForIssue(issue);\n const column = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.columns[issue.column];\n if (!column || column.nullable === true) continue;\n\n calls.push(\n new DataTransformCall(\n `data_migration.backfill-${issue.table}-${issue.column}`,\n `Backfill NULLs in \"${issue.table}\".\"${issue.column}\" before NOT NULL tightening`,\n issue.table,\n issue.column,\n ),\n );\n }\n\n if (calls.length === 0) return { kind: 'no_match' };\n\n return {\n kind: 'match',\n issues,\n calls,\n recipe: true,\n };\n};\n\nexport const sqlitePlannerStrategies: readonly CallMigrationStrategy[] = [\n nullabilityTighteningBackfillStrategy,\n recreateTableStrategy,\n];\n","/**\n * SQLite migration issue planner.\n *\n * Takes schema issues (from `verifySqlSchema`) and emits migration IR\n * (`SqliteOpFactoryCall[]`). Strategies consume issues they recognize and\n * produce specialized call sequences (e.g. recreateTableStrategy absorbs\n * type/nullability/default/constraint mismatches into a single recreate op);\n * remaining issues flow through `mapIssueToCall` for the default case.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n CodecControlHooks,\n MigrationOperationPolicy,\n SqlPlannerConflict,\n SqlPlannerConflictLocation,\n} from '@prisma-next/family-sql/control';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type { SchemaIssue } from '@prisma-next/framework-components/control';\nimport type {\n PostgresEnumStorageEntry,\n SqlStorage,\n StorageColumn,\n StorageTable,\n StorageTypeInstance,\n} from '@prisma-next/sql-contract/types';\nimport { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\nimport type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport {\n AddColumnCall,\n CreateIndexCall,\n CreateTableCall,\n DropColumnCall,\n DropIndexCall,\n DropTableCall,\n type SqliteOpFactoryCall,\n} from './op-factory-call';\nimport type {\n SqliteColumnSpec,\n SqliteForeignKeySpec,\n SqliteTableSpec,\n SqliteUniqueSpec,\n} from './operations/shared';\nimport {\n buildColumnDefaultSql,\n buildColumnTypeSql,\n isInlineAutoincrementPrimaryKey,\n} from './planner-ddl-builders';\nimport {\n type CallMigrationStrategy,\n resolveNamespaceIdForIssue,\n type StrategyContext,\n sqlitePlannerStrategies,\n tableAt,\n} from './planner-strategies';\nimport { CONTROL_TABLE_NAMES } from './statement-builders';\n\nexport type { CallMigrationStrategy, StrategyContext };\n\n// ============================================================================\n// Issue kind ordering (dependency order)\n// ============================================================================\n\nconst ISSUE_KIND_ORDER: Record<string, number> = {\n // Drops (reconciliation — clear the way for creates)\n extra_foreign_key: 10,\n extra_unique_constraint: 11,\n extra_primary_key: 12,\n extra_index: 13,\n extra_default: 14,\n extra_column: 15,\n extra_table: 16,\n\n // Tables before columns\n missing_table: 20,\n\n // Columns before constraints\n missing_column: 30,\n\n // Reconciliation alters (on existing objects)\n type_mismatch: 40,\n nullability_mismatch: 41,\n default_missing: 42,\n default_mismatch: 43,\n\n // Constraints after columns exist\n primary_key_mismatch: 50,\n unique_constraint_mismatch: 51,\n index_mismatch: 52,\n foreign_key_mismatch: 60,\n};\n\nfunction issueOrder(issue: SchemaIssue): number {\n return ISSUE_KIND_ORDER[issue.kind] ?? 99;\n}\n\nfunction issueKey(issue: SchemaIssue): string {\n const table = 'table' in issue && typeof issue.table === 'string' ? issue.table : '';\n const column = 'column' in issue && typeof issue.column === 'string' ? issue.column : '';\n const name =\n 'indexOrConstraint' in issue && typeof issue.indexOrConstraint === 'string'\n ? issue.indexOrConstraint\n : '';\n return `${table}\\u0000${column}\\u0000${name}`;\n}\n\n// ============================================================================\n// Conflict helpers\n// ============================================================================\n\nfunction issueConflict(\n kind: SqlPlannerConflict['kind'],\n summary: string,\n location?: SqlPlannerConflict['location'],\n): SqlPlannerConflict {\n return {\n kind,\n summary,\n why: 'Use `migration new` to author a custom migration for this change.',\n ...(location ? { location } : {}),\n };\n}\n\nfunction conflictKindForIssue(issue: SchemaIssue): SqlPlannerConflict['kind'] {\n switch (issue.kind) {\n case 'type_mismatch':\n return 'typeMismatch';\n case 'nullability_mismatch':\n return 'nullabilityConflict';\n case 'primary_key_mismatch':\n case 'unique_constraint_mismatch':\n case 'index_mismatch':\n case 'extra_primary_key':\n case 'extra_unique_constraint':\n return 'indexIncompatible';\n case 'foreign_key_mismatch':\n case 'extra_foreign_key':\n return 'foreignKeyConflict';\n default:\n return 'missingButNonAdditive';\n }\n}\n\nfunction issueLocation(issue: SchemaIssue): SqlPlannerConflictLocation | undefined {\n if (issue.kind === 'enum_values_changed') return undefined;\n const location: {\n table?: string;\n column?: string;\n constraint?: string;\n } = {};\n if (issue.table) location.table = issue.table;\n if (issue.column) location.column = issue.column;\n if (issue.indexOrConstraint) location.constraint = issue.indexOrConstraint;\n return Object.keys(location).length > 0 ? (location as SqlPlannerConflictLocation) : undefined;\n}\n\nfunction conflictForDisallowedCall(\n call: SqliteOpFactoryCall,\n allowed: readonly string[],\n): SqlPlannerConflict {\n const summary = `Operation \"${call.label}\" requires class \"${call.operationClass}\", but policy allows only: ${allowed.join(', ')}`;\n const location = locationForCall(call);\n return {\n kind: conflictKindForCall(call),\n summary,\n why: 'Use `migration new` to author a custom migration for this change.',\n ...(location ? { location } : {}),\n };\n}\n\nfunction conflictKindForCall(call: SqliteOpFactoryCall): SqlPlannerConflict['kind'] {\n switch (call.factoryName) {\n case 'createIndex':\n case 'dropIndex':\n return 'indexIncompatible';\n default:\n return 'missingButNonAdditive';\n }\n}\n\nfunction locationForCall(call: SqliteOpFactoryCall): SqlPlannerConflictLocation | undefined {\n const location: { table?: string; column?: string; index?: string } = {};\n if ('tableName' in call) location.table = call.tableName;\n if ('columnName' in call) location.column = call.columnName;\n if ('indexName' in call) location.index = call.indexName;\n return Object.keys(location).length > 0 ? (location as SqlPlannerConflictLocation) : undefined;\n}\n\nfunction isMissing(issue: SchemaIssue): boolean {\n if (issue.kind === 'enum_values_changed') return false;\n return issue.actual === undefined;\n}\n\n// ============================================================================\n// StorageTable / StorageColumn → flat SqliteTableSpec\n// ============================================================================\n\n/**\n * Resolves codec / `typeRef` / default rendering into a flat\n * `SqliteColumnSpec`. Mirrors Postgres's `toColumnSpec`. Once a column is\n * flattened, downstream Calls and operation factories never see\n * `StorageColumn` again — they deal in pre-rendered SQL fragments.\n */\nexport function toColumnSpec(\n name: string,\n column: StorageColumn,\n storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>,\n inlineAutoincrementPrimaryKey = false,\n): SqliteColumnSpec {\n const typeSql = buildColumnTypeSql(\n column,\n storageTypes as Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,\n );\n const defaultSql = buildColumnDefaultSql(column.default);\n return {\n name,\n typeSql,\n defaultSql,\n nullable: column.nullable,\n ...(inlineAutoincrementPrimaryKey ? { inlineAutoincrementPrimaryKey: true } : {}),\n };\n}\n\n/**\n * Flattens a `StorageTable` into a `SqliteTableSpec` ready for\n * `CreateTableCall` / `RecreateTableCall`. Sole-column AUTOINCREMENT\n * primary keys are detected here and marked on the column spec so the\n * renderer emits `INTEGER PRIMARY KEY AUTOINCREMENT` inline.\n */\nexport function toTableSpec(\n table: StorageTable,\n storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>,\n): SqliteTableSpec {\n const columns: SqliteColumnSpec[] = Object.entries(table.columns).map(([name, column]) =>\n toColumnSpec(name, column, storageTypes, isInlineAutoincrementPrimaryKey(table, name)),\n );\n const uniques: SqliteUniqueSpec[] = table.uniques.map((u) => ({\n columns: u.columns,\n ...(u.name !== undefined ? { name: u.name } : {}),\n }));\n const foreignKeys: SqliteForeignKeySpec[] = table.foreignKeys.map((fk) => ({\n columns: fk.source.columns,\n references: { table: fk.target.tableName, columns: fk.target.columns },\n constraint: fk.constraint !== false,\n ...(fk.name !== undefined ? { name: fk.name } : {}),\n ...(fk.onDelete !== undefined ? { onDelete: fk.onDelete } : {}),\n ...(fk.onUpdate !== undefined ? { onUpdate: fk.onUpdate } : {}),\n }));\n return {\n columns,\n ...(table.primaryKey ? { primaryKey: { columns: table.primaryKey.columns } } : {}),\n uniques,\n foreignKeys,\n };\n}\n\n// ============================================================================\n// Issue planner\n// ============================================================================\n\nexport interface IssuePlannerOptions {\n readonly issues: readonly SchemaIssue[];\n readonly toContract: Contract<SqlStorage>;\n readonly fromContract: Contract<SqlStorage> | null;\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n readonly storageTypes: Readonly<Record<string, StorageTypeInstance | PostgresEnumStorageEntry>>;\n readonly schema?: SqlSchemaIR;\n readonly policy?: MigrationOperationPolicy;\n readonly frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n readonly strategies?: readonly CallMigrationStrategy[];\n}\n\nexport interface IssuePlannerValue {\n readonly calls: readonly SqliteOpFactoryCall[];\n}\n\nconst DEFAULT_POLICY: MigrationOperationPolicy = {\n allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'],\n};\n\nfunction emptySchemaIR(): SqlSchemaIR {\n return { tables: {} };\n}\n\n// ============================================================================\n// Issue → Call mapping (per-issue default path)\n// ============================================================================\n\nfunction mapIssueToCall(\n issue: SchemaIssue,\n ctx: StrategyContext,\n): Result<readonly SqliteOpFactoryCall[], SqlPlannerConflict> {\n switch (issue.kind) {\n case 'missing_table': {\n if (!issue.table) {\n return notOk(\n issueConflict('unsupportedOperation', 'Missing table issue has no table name'),\n );\n }\n const namespaceId = resolveNamespaceIdForIssue(issue);\n const contractTable = tableAt(ctx.toContract.storage, namespaceId, issue.table);\n if (!contractTable) {\n return notOk(\n issueConflict(\n 'unsupportedOperation',\n `Table \"${issue.table}\" in namespace \"${namespaceId}\" reported missing but not found in destination contract`,\n ),\n );\n }\n const tableSpec = toTableSpec(contractTable, ctx.storageTypes);\n const calls: SqliteOpFactoryCall[] = [new CreateTableCall(issue.table, tableSpec)];\n const declaredIndexColumnKeys = new Set<string>();\n for (const index of contractTable.indexes) {\n const indexName = index.name ?? defaultIndexName(issue.table, index.columns);\n declaredIndexColumnKeys.add(index.columns.join(','));\n calls.push(new CreateIndexCall(issue.table, indexName, index.columns));\n }\n for (const fk of contractTable.foreignKeys) {\n if (fk.index === false) continue;\n if (declaredIndexColumnKeys.has(fk.source.columns.join(','))) continue;\n const indexName = defaultIndexName(issue.table, fk.source.columns);\n calls.push(new CreateIndexCall(issue.table, indexName, fk.source.columns));\n }\n return ok(calls);\n }\n\n case 'missing_column': {\n if (!issue.table || !issue.column) {\n return notOk(\n issueConflict('unsupportedOperation', 'Missing column issue has no table/column name'),\n );\n }\n const namespaceId = resolveNamespaceIdForIssue(issue);\n const contractTable2 = tableAt(ctx.toContract.storage, namespaceId, issue.table);\n const column = contractTable2?.columns[issue.column];\n if (!column) {\n return notOk(\n issueConflict(\n 'unsupportedOperation',\n `Column \"${issue.table}\".\"${issue.column}\" not in destination contract`,\n ),\n );\n }\n const contractTable = contractTable2;\n const columnSpec = toColumnSpec(\n issue.column,\n column,\n ctx.storageTypes,\n contractTable ? isInlineAutoincrementPrimaryKey(contractTable, issue.column) : false,\n );\n return ok([new AddColumnCall(issue.table, columnSpec)]);\n }\n\n case 'index_mismatch': {\n if (!issue.table) {\n return notOk(issueConflict('indexIncompatible', 'Index issue has no table name'));\n }\n if (!isMissing(issue) || !issue.expected) {\n return notOk(\n issueConflict(\n 'indexIncompatible',\n `Index on \"${issue.table}\" differs (expected: ${issue.expected}, actual: ${issue.actual})`,\n { table: issue.table },\n ),\n );\n }\n const namespaceId = resolveNamespaceIdForIssue(issue);\n const columns = issue.expected.split(', ');\n const contractTable = tableAt(ctx.toContract.storage, namespaceId, issue.table);\n if (!contractTable) {\n return notOk(\n issueConflict(\n 'unsupportedOperation',\n `Table \"${issue.table}\" not found in destination contract`,\n ),\n );\n }\n const explicitIndex = contractTable.indexes.find(\n (idx) => idx.columns.join(',') === columns.join(','),\n );\n const indexName = explicitIndex?.name ?? defaultIndexName(issue.table, columns);\n return ok([new CreateIndexCall(issue.table, indexName, columns)]);\n }\n\n case 'extra_table': {\n if (!issue.table) {\n return notOk(issueConflict('unsupportedOperation', 'Extra table issue has no table name'));\n }\n // Runner-owned control tables must never be dropped.\n if (CONTROL_TABLE_NAMES.has(issue.table)) return ok([]);\n return ok([new DropTableCall(issue.table)]);\n }\n\n case 'extra_column': {\n if (!issue.table || !issue.column) {\n return notOk(\n issueConflict('unsupportedOperation', 'Extra column issue has no table/column name'),\n );\n }\n return ok([new DropColumnCall(issue.table, issue.column)]);\n }\n\n case 'extra_index': {\n if (!issue.table || !issue.indexOrConstraint) {\n return notOk(\n issueConflict('unsupportedOperation', 'Extra index issue has no table/index name'),\n );\n }\n return ok([new DropIndexCall(issue.table, issue.indexOrConstraint)]);\n }\n\n // SQLite has no enum types (capability `sql.enums: false`). The verifier\n // should never emit `enum_values_changed` against a SQLite schema, so if\n // we receive one it is a verifier bug — surface it as an explicit\n // conflict rather than silently dropping it.\n case 'enum_values_changed':\n return notOk(\n issueConflict(\n 'unsupportedOperation',\n 'Received enum_values_changed against a SQLite schema (sql.enums: false) — verifier bug',\n ),\n );\n\n // Everything below is absorbed by recreateTableStrategy. If it falls\n // through here, policy or context didn't allow the recreate — surface as\n // a conflict.\n case 'type_mismatch':\n case 'nullability_mismatch':\n case 'default_mismatch':\n case 'default_missing':\n case 'extra_default':\n case 'primary_key_mismatch':\n case 'unique_constraint_mismatch':\n case 'foreign_key_mismatch':\n case 'extra_foreign_key':\n case 'extra_unique_constraint':\n case 'extra_primary_key':\n return notOk(issueConflict(conflictKindForIssue(issue), issue.message, issueLocation(issue)));\n\n default:\n return notOk(\n issueConflict(\n 'unsupportedOperation',\n `Unhandled issue kind: ${(issue as SchemaIssue).kind}`,\n ),\n );\n }\n}\n\n// ============================================================================\n// Call categorization for final emission order\n// ============================================================================\n\ntype CallCategory =\n | 'drop-column'\n | 'drop-index'\n | 'drop-table'\n | 'create-table'\n | 'add-column'\n | 'create-index';\n\nfunction classifyCall(call: SqliteOpFactoryCall): CallCategory | null {\n switch (call.factoryName) {\n case 'createTable':\n return 'create-table';\n case 'addColumn':\n return 'add-column';\n case 'createIndex':\n return 'create-index';\n case 'dropColumn':\n return 'drop-column';\n case 'dropIndex':\n return 'drop-index';\n case 'dropTable':\n return 'drop-table';\n // recreateTable goes into the recipe slot; return null for bucketable.\n case 'recreateTable':\n return null;\n default:\n return null;\n }\n}\n\n// ============================================================================\n// Top-level planIssues\n// ============================================================================\n\nexport function planIssues(\n options: IssuePlannerOptions,\n): Result<IssuePlannerValue, readonly SqlPlannerConflict[]> {\n const policyProvided = options.policy !== undefined;\n const policy = options.policy ?? DEFAULT_POLICY;\n const schema = options.schema ?? emptySchemaIR();\n const frameworkComponents = options.frameworkComponents ?? [];\n\n const context: StrategyContext = {\n toContract: options.toContract,\n fromContract: options.fromContract,\n codecHooks: options.codecHooks,\n storageTypes: options.storageTypes,\n schema,\n policy,\n frameworkComponents,\n };\n\n const strategies = options.strategies ?? sqlitePlannerStrategies;\n\n let remaining = options.issues;\n const recipeCalls: SqliteOpFactoryCall[] = [];\n const bucketableCalls: SqliteOpFactoryCall[] = [];\n\n for (const strategy of strategies) {\n const result = strategy(remaining, context);\n if (result.kind === 'match') {\n remaining = result.issues;\n if (result.recipe) {\n recipeCalls.push(...result.calls);\n } else {\n bucketableCalls.push(...result.calls);\n }\n }\n }\n\n const sorted = [...remaining].sort((a, b) => {\n const kindDelta = issueOrder(a) - issueOrder(b);\n if (kindDelta !== 0) return kindDelta;\n const keyA = issueKey(a);\n const keyB = issueKey(b);\n return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;\n });\n\n const defaultCalls: SqliteOpFactoryCall[] = [];\n const conflicts: SqlPlannerConflict[] = [];\n\n for (const issue of sorted) {\n const result = mapIssueToCall(issue, context);\n if (result.ok) {\n defaultCalls.push(...result.value);\n } else {\n conflicts.push(result.failure);\n }\n }\n\n // Policy gating for recipe + bucketable. Default-mapped calls for disallowed\n // classes never get here (they're surfaced as per-issue conflicts above).\n const allowed = policy.allowedOperationClasses;\n let gatedRecipe = recipeCalls;\n let gatedBucketable = bucketableCalls;\n let gatedDefault = defaultCalls;\n if (policyProvided) {\n const sink = (acc: SqliteOpFactoryCall[]) => (call: SqliteOpFactoryCall) => {\n if (allowed.includes(call.operationClass)) {\n acc.push(call);\n return;\n }\n conflicts.push(conflictForDisallowedCall(call, allowed));\n };\n const gatedRecipeBucket: SqliteOpFactoryCall[] = [];\n const gatedBucketableBucket: SqliteOpFactoryCall[] = [];\n const gatedDefaultBucket: SqliteOpFactoryCall[] = [];\n recipeCalls.forEach(sink(gatedRecipeBucket));\n bucketableCalls.forEach(sink(gatedBucketableBucket));\n defaultCalls.forEach(sink(gatedDefaultBucket));\n gatedRecipe = gatedRecipeBucket;\n gatedBucketable = gatedBucketableBucket;\n gatedDefault = gatedDefaultBucket;\n }\n\n if (conflicts.length > 0) {\n return notOk(conflicts);\n }\n\n // Final emission order matches the current monolithic planner:\n // create-table → add-column → create-index → recreate → drop-column → drop-index → drop-table\n const combined = [...gatedDefault, ...gatedBucketable];\n const byCategory = (cat: CallCategory) => combined.filter((c) => classifyCall(c) === cat);\n\n const calls: SqliteOpFactoryCall[] = [\n ...byCategory('create-table'),\n ...byCategory('add-column'),\n ...byCategory('create-index'),\n ...gatedRecipe,\n ...byCategory('drop-column'),\n ...byCategory('drop-index'),\n ...byCategory('drop-table'),\n ];\n\n return ok({ calls });\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlMigrationPlanner,\n SqlMigrationPlannerPlanOptions,\n SqlPlannerFailureResult,\n} from '@prisma-next/family-sql/control';\nimport {\n extractCodecControlHooks,\n planFieldEventOperations,\n plannerFailure,\n} from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n MigrationPlanner,\n MigrationScaffoldContext,\n SchemaIssue,\n} from '@prisma-next/framework-components/control';\nimport { parseSqliteDefault } from '../default-normalizer';\nimport { normalizeSqliteNativeType } from '../native-type-normalizer';\nimport { planIssues } from './issue-planner';\nimport {\n type SqliteMigrationDestinationInfo,\n TypeScriptRenderableSqliteMigration,\n} from './planner-produced-sqlite-migration';\nimport { sqlitePlannerStrategies } from './planner-strategies';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\n\nexport function createSqliteMigrationPlanner(): SqliteMigrationPlanner {\n return new SqliteMigrationPlanner();\n}\n\nexport type SqlitePlanResult =\n | { readonly kind: 'success'; readonly plan: TypeScriptRenderableSqliteMigration }\n | SqlPlannerFailureResult;\n\n/**\n * SQLite migration planner — a thin wrapper over `planIssues`.\n *\n * `plan()` verifies the live schema against the target contract (producing\n * `SchemaIssue[]`) and delegates to `planIssues` with the registered\n * strategies. Strategies absorb groups of related issues into composite\n * recipes (e.g. recreating a table to apply type/nullability/default/\n * constraint changes at once); anything not absorbed by a strategy flows\n * through `mapIssueToCall` in the issue planner as a one-off call.\n *\n * FK-backing indexes are surfaced by `verifySqlSchema`'s index expansion\n * (see `verify-sql-schema.ts:459-469`), so `mapIssueToCall` handles them\n * uniformly alongside user-declared indexes.\n */\nexport class SqliteMigrationPlanner\n implements SqlMigrationPlanner<SqlitePlanTargetDetails>, MigrationPlanner<'sql', 'sqlite'>\n{\n plan(options: {\n readonly contract: unknown;\n readonly schema: unknown;\n readonly policy: MigrationOperationPolicy;\n /**\n * The \"from\" contract (state the planner assumes the database starts at),\n * or `null` for reconciliation flows.\n *\n * Typed as the framework `Contract | null` to satisfy the\n * `MigrationPlanner` interface contract; `planSql` narrows to the SQL\n * shape via `SqlMigrationPlannerPlanOptions`. Used to populate\n * `describe().from` on the produced plan as\n * `fromContract?.storage.storageHash ?? null`.\n */\n readonly fromContract: Contract | null;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n /**\n * Contract space this plan applies to. Stamped onto the produced\n * {@link TypeScriptRenderableSqliteMigration.spaceId} so the runner keys\n * the marker row by the right space.\n */\n readonly spaceId: string;\n }): SqlitePlanResult {\n return this.planSql(options as SqlMigrationPlannerPlanOptions);\n }\n\n emptyMigration(\n context: MigrationScaffoldContext,\n spaceId: string,\n ): TypeScriptRenderableSqliteMigration {\n return new TypeScriptRenderableSqliteMigration(\n [],\n {\n from: context.fromHash,\n to: context.toHash,\n },\n spaceId,\n );\n }\n\n private planSql(options: SqlMigrationPlannerPlanOptions): SqlitePlanResult {\n const policyResult = this.ensureAdditivePolicy(options.policy);\n if (policyResult) return policyResult;\n\n const schemaIssues = this.collectSchemaIssues(options);\n const codecHooks = extractCodecControlHooks(options.frameworkComponents);\n const storageTypes = options.contract.storage.types ?? {};\n\n const result = planIssues({\n issues: schemaIssues,\n toContract: options.contract,\n fromContract: options.fromContract,\n codecHooks,\n storageTypes,\n schema: options.schema,\n policy: options.policy,\n frameworkComponents: options.frameworkComponents,\n strategies: sqlitePlannerStrategies,\n });\n\n if (!result.ok) {\n return plannerFailure(result.failure);\n }\n\n // Codec lifecycle hook (T2.2): inline `onFieldEvent`-emitted ops after\n // structural DDL. Sub-spec § 5 fixes the ordering as\n // `structural → added → dropped → altered`, with within-group sorting by\n // `(tableName, fieldName)` deterministic for byte-stable re-emits.\n // Hook fires only at the application emitter — extension-space planning\n // (M2 R2) never reaches this helper.\n const fieldEventOps = planFieldEventOperations({\n priorContract: options.fromContract,\n newContract: options.contract,\n codecHooks,\n });\n // Codec-emitted calls already conform to `OpFactoryCall` — render +\n // toOp + importRequirements ride directly through the same emit path\n // as structural ops, no `RawSqlCall` wrap.\n const calls = [...result.value.calls, ...fieldEventOps];\n\n const destination: SqliteMigrationDestinationInfo = {\n storageHash: options.contract.storage.storageHash,\n ...(options.contract.profileHash !== undefined\n ? { profileHash: options.contract.profileHash }\n : {}),\n };\n\n return {\n kind: 'success' as const,\n plan: new TypeScriptRenderableSqliteMigration(\n calls,\n {\n from: options.fromContract?.storage.storageHash ?? null,\n to: options.contract.storage.storageHash,\n },\n options.spaceId,\n destination,\n ),\n };\n }\n\n private ensureAdditivePolicy(policy: MigrationOperationPolicy): SqlPlannerFailureResult | null {\n if (!policy.allowedOperationClasses.includes('additive')) {\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: 'Migration planner requires additive operations be allowed',\n why: 'The planner requires the \"additive\" operation class to be allowed in the policy.',\n },\n ]);\n }\n return null;\n }\n\n private collectSchemaIssues(options: SqlMigrationPlannerPlanOptions): readonly SchemaIssue[] {\n const allowed = options.policy.allowedOperationClasses;\n const strict = allowed.includes('widening') || allowed.includes('destructive');\n const verifyResult = verifySqlSchema({\n contract: options.contract,\n schema: options.schema,\n strict,\n typeMetadataRegistry: new Map(),\n frameworkComponents: options.frameworkComponents,\n normalizeDefault: parseSqliteDefault,\n normalizeNativeType: normalizeSqliteNativeType,\n });\n return verifyResult.schema.issues;\n }\n}\n"],"mappings":"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"}
@@ -1,158 +0,0 @@
1
- import { APP_SPACE_ID as APP_SPACE_ID$1 } from "@prisma-next/framework-components/control";
2
- //#region src/core/migrations/statement-builders.ts
3
- const MARKER_TABLE_NAME = "_prisma_marker";
4
- const LEDGER_TABLE_NAME = "_prisma_ledger";
5
- /**
6
- * Control tables the runner creates/manages. The planner must not drop these
7
- * when reconciling "extra" tables against the contract.
8
- */
9
- const CONTROL_TABLE_NAMES = new Set([MARKER_TABLE_NAME, LEDGER_TABLE_NAME]);
10
- /**
11
- * Schema for `_prisma_marker`. The `space TEXT PRIMARY KEY` shape
12
- * supports one row per loaded contract space (`'app'`,
13
- * `'<extension-id>'`, …); brand-new databases create this shape
14
- * directly. The migration runner detects pre-1.0 single-row markers
15
- * (no `space` column) at boot and fails with a structured
16
- * `LEGACY_MARKER_SHAPE` error rather than auto-rebuilding the table —
17
- * see `specs/framework-mechanism.spec.md § 2`.
18
- */
19
- const ensureMarkerTableStatement = {
20
- sql: `CREATE TABLE IF NOT EXISTS _prisma_marker (
21
- space TEXT NOT NULL PRIMARY KEY DEFAULT '${APP_SPACE_ID$1}',
22
- core_hash TEXT NOT NULL,
23
- profile_hash TEXT NOT NULL,
24
- contract_json TEXT,
25
- canonical_version INTEGER,
26
- updated_at TEXT NOT NULL DEFAULT (datetime('now')),
27
- app_tag TEXT,
28
- meta TEXT NOT NULL DEFAULT '{}',
29
- invariants TEXT NOT NULL DEFAULT '[]'
30
- )`,
31
- params: []
32
- };
33
- const ensureLedgerTableStatement = {
34
- sql: `CREATE TABLE IF NOT EXISTS _prisma_ledger (
35
- id INTEGER PRIMARY KEY AUTOINCREMENT,
36
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
37
- origin_core_hash TEXT,
38
- origin_profile_hash TEXT,
39
- destination_core_hash TEXT NOT NULL,
40
- destination_profile_hash TEXT,
41
- contract_json_before TEXT,
42
- contract_json_after TEXT,
43
- operations TEXT NOT NULL
44
- )`,
45
- params: []
46
- };
47
- function readMarkerStatement(space) {
48
- return {
49
- sql: `SELECT
50
- core_hash,
51
- profile_hash,
52
- contract_json,
53
- canonical_version,
54
- updated_at,
55
- app_tag,
56
- meta,
57
- invariants
58
- FROM _prisma_marker
59
- WHERE space = ?`,
60
- params: [space]
61
- };
62
- }
63
- function buildWriteMarkerStatements(input) {
64
- return {
65
- insert: {
66
- sql: `INSERT INTO _prisma_marker (
67
- space,
68
- core_hash,
69
- profile_hash,
70
- contract_json,
71
- canonical_version,
72
- updated_at,
73
- app_tag,
74
- meta,
75
- invariants
76
- ) VALUES (
77
- ?,
78
- ?,
79
- ?,
80
- ?,
81
- ?,
82
- datetime('now'),
83
- ?,
84
- ?,
85
- ?
86
- )`,
87
- params: [
88
- input.space,
89
- input.storageHash,
90
- input.profileHash,
91
- jsonParam(input.contractJson),
92
- input.canonicalVersion ?? null,
93
- input.appTag ?? null,
94
- jsonParam(input.meta ?? {}),
95
- jsonParam(input.invariants)
96
- ]
97
- },
98
- update: {
99
- sql: `UPDATE _prisma_marker SET
100
- core_hash = ?,
101
- profile_hash = ?,
102
- contract_json = ?,
103
- canonical_version = ?,
104
- updated_at = datetime('now'),
105
- app_tag = ?,
106
- meta = ?,
107
- invariants = ?
108
- WHERE space = ?`,
109
- params: [
110
- input.storageHash,
111
- input.profileHash,
112
- jsonParam(input.contractJson),
113
- input.canonicalVersion ?? null,
114
- input.appTag ?? null,
115
- jsonParam(input.meta ?? {}),
116
- jsonParam(input.invariants),
117
- input.space
118
- ]
119
- }
120
- };
121
- }
122
- function buildLedgerInsertStatement(input) {
123
- return {
124
- sql: `INSERT INTO _prisma_ledger (
125
- origin_core_hash,
126
- origin_profile_hash,
127
- destination_core_hash,
128
- destination_profile_hash,
129
- contract_json_before,
130
- contract_json_after,
131
- operations
132
- ) VALUES (
133
- ?,
134
- ?,
135
- ?,
136
- ?,
137
- ?,
138
- ?,
139
- ?
140
- )`,
141
- params: [
142
- input.originStorageHash ?? null,
143
- input.originProfileHash ?? null,
144
- input.destinationStorageHash,
145
- input.destinationProfileHash ?? null,
146
- jsonParam(input.contractJsonBefore),
147
- jsonParam(input.contractJsonAfter),
148
- jsonParam(input.operations)
149
- ]
150
- };
151
- }
152
- function jsonParam(value) {
153
- return JSON.stringify(value ?? null);
154
- }
155
- //#endregion
156
- export { buildLedgerInsertStatement as a, ensureMarkerTableStatement as c, MARKER_TABLE_NAME as i, readMarkerStatement as l, CONTROL_TABLE_NAMES as n, buildWriteMarkerStatements as o, LEDGER_TABLE_NAME as r, ensureLedgerTableStatement as s, APP_SPACE_ID$1 as t };
157
-
158
- //# sourceMappingURL=statement-builders-BiRmeyJM.mjs.map