@voltro/database 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sql.d.ts CHANGED
@@ -702,6 +702,18 @@ export declare const defaultJsonClause: (value: object, dialect: DialectId) => s
702
702
 
703
703
  export declare const describeOutcome: (outcome: BootMigrationOutcome, dialectId: string) => string;
704
704
 
705
+ /**
706
+ * Compare declared reactivity against the triggers actually installed.
707
+ *
708
+ * Postgres only — it is the one dialect where reactivity is carried by DDL. The
709
+ * binlog and Change Tracking readers are configured at runtime from the same
710
+ * in-memory table list the schema produced, so they cannot drift from it.
711
+ */
712
+ export declare const detectReactiveTriggerDrift: (sql: SqlClient.SqlClient, tables: ReadonlyArray<{
713
+ readonly tableName: string;
714
+ readonly isReactive?: boolean;
715
+ }>) => Effect.Effect<ReactiveTriggerDrift, SqlError_2>;
716
+
705
717
  /** Dialect IDs the framework supports. */
706
718
  declare type DialectId = 'postgres' | 'mysql' | 'mariadb' | 'mssql' | 'sqlite' | 'turso';
707
719
 
@@ -879,6 +891,9 @@ export declare interface FileMigrationRunResult {
879
891
  */
880
892
  export declare const fingerprintSchema: (snapshot: SchemaSnapshot) => string;
881
893
 
894
+ /** Human report, or `undefined` when the database and the schema agree. */
895
+ export declare const formatReactiveTriggerDrift: (drift: ReactiveTriggerDrift) => string | undefined;
896
+
882
897
  /**
883
898
  * Fully-resolved scheme stored on the `id` column definition AFTER
884
899
  * `table()` walks the fields. For `typeid`, the prefix is always
@@ -1369,6 +1384,17 @@ export declare const parseEnumCheck: (clause: string) => {
1369
1384
  readonly values: ReadonlyArray<string>;
1370
1385
  } | null;
1371
1386
 
1387
+ /**
1388
+ * The ids of migration files present on disk but NOT yet recorded against THIS
1389
+ * database — i.e. exactly what `runFileBasedMigrations` would execute next.
1390
+ *
1391
+ * Exists so a caller can decide WHETHER to apply before applying. `voltro dev`
1392
+ * uses it to refuse unattended file migrations against a remote database: that
1393
+ * decision needs the list (to name it in the refusal) and must not have run
1394
+ * anything to get it.
1395
+ */
1396
+ export declare const pendingFileMigrationIds: (sql: SqlClient.SqlClient, projectRoot: string) => Effect.Effect<ReadonlyArray<string>, unknown>;
1397
+
1372
1398
  export declare interface PlanInput {
1373
1399
  readonly declared: ReadonlyArray<TableLike>;
1374
1400
  readonly live: SchemaSnapshot;
@@ -1483,6 +1509,17 @@ export declare interface RawSqlFragment {
1483
1509
  readonly dependsOn?: ReadonlyArray<string>;
1484
1510
  }
1485
1511
 
1512
+ /** Prefix `reactiveTableTriggerSql` names its triggers with. */
1513
+ export declare const REACTIVE_TRIGGER_PREFIX = "framework_changes_";
1514
+
1515
+ export declare interface ReactiveTriggerDrift {
1516
+ /** Tables the schema says are reactive that carry no trigger in the DB. */
1517
+ readonly missing: ReadonlyArray<string>;
1518
+ /** Tables that carry a trigger but are declared `.nonReactive()` — their
1519
+ * writes still hit the NOTIFY channel and cost WAL for nothing. */
1520
+ readonly stale: ReadonlyArray<string>;
1521
+ }
1522
+
1486
1523
  export declare const releaseMigrationLock: (sql: SqlClient.SqlClient) => Effect.Effect<void, SqlError_2>;
1487
1524
 
1488
1525
  export declare const renderColumnMysql: (col: ColumnSnapshot) => string;
@@ -1507,16 +1544,6 @@ export declare const rollbackFileBasedMigration: (sql: SqlClient.SqlClient, ctx:
1507
1544
  durationMs: number;
1508
1545
  }, unknown>;
1509
1546
 
1510
- /**
1511
- * Discover + apply every pending file-based migration under
1512
- * `projectRoot/migrations/`. Runs under the same advisory lock as
1513
- * the planner-based applier, so concurrent invocations serialise.
1514
- *
1515
- * - Returns `applied` (newly-run ids + durations) + `skipped`
1516
- * (ids that were already applied) for the caller's log line.
1517
- * - Failures abort the run + propagate as the Effect's error
1518
- * channel; the caller (dev.ts boot) is expected to refuse-to-boot.
1519
- */
1520
1547
  export declare const runFileBasedMigrations: (sql: SqlClient.SqlClient, ctx: RunFileBasedMigrationsCtx) => Effect.Effect<FileMigrationRunResult, unknown>;
1521
1548
 
1522
1549
  export declare interface RunFileBasedMigrationsCtx {
@@ -1655,7 +1682,7 @@ export declare interface SquashResult {
1655
1682
  readonly snapshotId: string;
1656
1683
  }
1657
1684
 
1658
- declare interface Table<Name extends string, Fields extends Record<string, ColumnDefinition<unknown>>, Reactive extends boolean = false, IxNames extends string = never> extends TableLike {
1685
+ declare interface Table<Name extends string, Fields extends Record<string, ColumnDefinition<unknown>>, Reactive extends boolean = true, IxNames extends string = never> extends TableLike {
1659
1686
  readonly tableName: Name;
1660
1687
  readonly fields: Fields;
1661
1688
  readonly isReactive: Reactive;
@@ -1967,11 +1994,39 @@ declare interface Table<Name extends string, Fields extends Record<string, Colum
1967
1994
  */
1968
1995
  primaryKey: <const F extends readonly [keyof Fields & string, keyof Fields & string, ...Array<keyof Fields & string>]>(fields: F) => Table<Name, Fields, Reactive, IxNames>;
1969
1996
  /**
1970
- * Opt the table into the reactive engine. Applies
1971
- * `alter table <name> replica identity full` at migration time so the WAL
1972
- * stream carries full pre-images on UPDATE/DELETE. See the schema-DSL plan.
1997
+ * Turn reactivity OFF for this table.
1998
+ *
1999
+ * Not "off across instances" off. The table emits no change events at all:
2000
+ * no local subscriber fires, no cross-instance transport carries it. That is
2001
+ * what the name says, and a version of this that only silenced the
2002
+ * cross-instance half would leave every in-process subscription live on a
2003
+ * table declared non-reactive.
2004
+ *
2005
+ * Reactivity is the default because that is what this framework is for. The
2006
+ * inverse (`.reactive()`) was the API for a long time and failed in both
2007
+ * directions silently: written on mariadb it did nothing at all, omitted on
2008
+ * postgres+cdc it meant a write on one instance never reached another
2009
+ * instance's subscribers.
2010
+ *
2011
+ * Implemented in EVERY dialect, at the store's emit:
2012
+ *
2013
+ * memory the store's single emit point drops the event
2014
+ * sqlite / same, and turso reuses that store
2015
+ * turso
2016
+ * postgres also: no `REPLICA IDENTITY FULL`, no `pg_notify` trigger
2017
+ * mysql / also: excluded from the binlog reader's table filter
2018
+ * mariadb
2019
+ * mssql also: excluded from the Change Tracking table set
2020
+ *
2021
+ * The WRITE is unaffected — this is about notification, never persistence.
2022
+ *
2023
+ * Worth using for a genuinely hot table nobody subscribes to: an append-only
2024
+ * event log, a metrics sink. On postgres it also drops `REPLICA IDENTITY
2025
+ * FULL`, which widens every UPDATE/DELETE in the WAL. Do NOT use it on a
2026
+ * table a query reads — that subscription simply never fires. `voltro dev`
2027
+ * says so at boot.
1973
2028
  */
1974
- reactive: () => Table<Name, Fields, true, IxNames>;
2029
+ nonReactive: () => Table<Name, Fields, false, IxNames>;
1975
2030
  }
1976
2031
 
1977
2032
  /**