@voltro/database 0.76.0 → 0.77.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
@@ -611,6 +611,14 @@ export declare const chunkTables: <T>(xs: ReadonlyArray<T>, n: number) => T[][];
611
611
  /**
612
612
  * Classify a single DDL operation for rolling-deploy safety.
613
613
  *
614
+ * Every UNSAFE verdict rests on one premise, and its `reason` says so: an
615
+ * instance on the PREVIOUS release keeps serving against the new schema. A
616
+ * deployment with no such instance — first deploy, scale-to-zero, maintenance
617
+ * window — can read the premise and set the advisory aside.
618
+ *
619
+ * SAFE regardless of kind: any operation on a table the same plan creates
620
+ * (`context.createdTables`) — no previous release ever touched it.
621
+ *
614
622
  * UNSAFE (breaks old code during the overlap window):
615
623
  * - `drop-column` / `drop-table` — old code reads it → error.
616
624
  * - `rename-column` / `rename-table` — to old code the old name vanished.
@@ -628,7 +636,7 @@ export declare const chunkTables: <T>(xs: ReadonlyArray<T>, n: number) => T[][];
628
636
  * removing enforcement never makes an old query ERROR.
629
637
  * - `alter-column-nullability` → nullable, `alter-column-default` — relaxing.
630
638
  */
631
- export declare const classifyRollingDeploySafety: (op: MigrationOperation) => RollingDeploySafety;
639
+ export declare const classifyRollingDeploySafety: (op: MigrationOperation, context?: RollingDeployContext) => RollingDeploySafety;
632
640
 
633
641
  /**
634
642
  * Every resume-ledger row, gone — for a caller that has just UNDONE the run
@@ -1720,6 +1728,9 @@ declare type ColumnType = 'id' | 'text' | 'integer' | 'real' | 'decimal' | 'bigi
1720
1728
 
1721
1729
  declare type ColumnType_2 = 'id' | 'text' | 'integer' | 'real' | 'decimal' | 'bigint' | 'boolean' | 'timestamp' | 'date' | 'json' | 'bytes' | 'reference' | 'vector' | 'enum' | 'array' | 'interval' | 'raw';
1722
1730
 
1731
+ /** The tables a plan CREATEs — the set every same-plan operation is checked against. */
1732
+ export declare const createdTablesOf: (operations: ReadonlyArray<PlannedOperation>) => ReadonlySet<string>;
1733
+
1723
1734
  declare interface DataStore {
1724
1735
  /**
1725
1736
  * Execute a typed query descriptor and return matching rows.
@@ -2629,6 +2640,22 @@ export declare const ensureLedgerTable: (sql: SqlClient.SqlClient, dialect: Dial
2629
2640
  */
2630
2641
  export declare const ensurePlanLedgerTable: (sql: SqlClient.SqlClient, dialect: DialectId) => Effect.Effect<void, SqlError_2>;
2631
2642
 
2643
+ /**
2644
+ * The in-progress marker (`_voltro_replace_in_progress`) — same bootstrap,
2645
+ * for a caller `db apply` cannot precede: a native `voltro data restore` into
2646
+ * an EMPTY database writes the marker before its first destructive statement,
2647
+ * and applying the declared schema there first would install the very state
2648
+ * the artefact is about to replace.
2649
+ *
2650
+ * Trigger-free as well as index-free, and that half is load-bearing on
2651
+ * postgres: `applySchema` would add the reactive NOTIFY trigger, whose function
2652
+ * the dump then fails to `DROP` (a dependent object the dump does not know)
2653
+ * and fails to `CREATE` (it already exists) — two errors, and `pg_restore`
2654
+ * exits 1 over a database that is otherwise fine. The planner emits no trigger
2655
+ * for this table either, so the shape converges on the next apply.
2656
+ */
2657
+ export declare const ensureReplaceMarkerTable: (sql: SqlClient.SqlClient, dialect: DialectId) => Effect.Effect<void, SqlError_2>;
2658
+
2632
2659
  /** Exported for the same reason as {@link enumTypeBlocks}, and it MUST run
2633
2660
  * before it — see that function's note on ordering. */
2634
2661
  export declare const enumRenameBlocks: (tables: ReadonlyArray<AnyTable>, dialect: DialectId) => string;
@@ -2848,14 +2875,36 @@ export declare interface FileMigrationContext {
2848
2875
  }) => Promise<T> | Effect.Effect<T, unknown, SqlClient.SqlClient>) => Effect.Effect<T, unknown>;
2849
2876
  }
2850
2877
 
2851
- export declare interface FileMigrationContextInput {
2852
- readonly sql: SqlClient.SqlClient;
2853
- readonly store: DataStore;
2878
+ /**
2879
+ * A body driven over a store that has no SQL underneath — the in-memory
2880
+ * store a unit test uses. No client: `each`, `rewrite`, `expect`,
2881
+ * `skipUnless`, `store`, `log` and a Promise body under `transactional` run
2882
+ * against the store; `raw()`, every `schema` operation and an Effect body
2883
+ * under `transactional` fail with `MigrationNeedsSqlClient`. A store that
2884
+ * CAN run SQL (`run` present) is not accepted here: its migration context
2885
+ * needs the client, and the type says so before the runtime check does.
2886
+ */
2887
+ export declare interface FileMigrationContextInMemoryInput extends FileMigrationContextInputBase {
2888
+ readonly sql?: undefined;
2889
+ readonly store: DataStore & {
2890
+ readonly run?: undefined;
2891
+ };
2892
+ }
2893
+
2894
+ export declare type FileMigrationContextInput = FileMigrationContextLiveInput | FileMigrationContextInMemoryInput;
2895
+
2896
+ declare interface FileMigrationContextInputBase {
2854
2897
  readonly dialect: DialectId;
2855
2898
  readonly migrationId: string;
2856
2899
  readonly appliedAt: string;
2857
2900
  }
2858
2901
 
2902
+ /** The runner's shape: a SQL-backed store and the client it executes on. */
2903
+ export declare interface FileMigrationContextLiveInput extends FileMigrationContextInputBase {
2904
+ readonly sql: SqlClient.SqlClient;
2905
+ readonly store: DataStore;
2906
+ }
2907
+
2859
2908
  /**
2860
2909
  * A migration whose `up()` SUCCEEDED and whose ledger row could not be written.
2861
2910
  *
@@ -3351,6 +3400,25 @@ export declare interface MigrationLockScope {
3351
3400
  readonly schema?: string | undefined;
3352
3401
  }
3353
3402
 
3403
+ /**
3404
+ * A migration context was built without a SQL client — over the in-memory
3405
+ * store, the shape a unit test uses — and the body reached a surface that
3406
+ * needs a live connection: `raw()`, every `ctx.schema` operation, or an
3407
+ * Effect body under `ctx.transactional` (which runs ON the connection).
3408
+ * `each`, `rewrite`, `expect`, `skipUnless`, `store` and `log` work without
3409
+ * one. Also raised at construction when what was handed in as `sql` is not
3410
+ * an `@effect/sql` client, or when a SQL-backed store arrives without the
3411
+ * client it executes on — both are refused before a body can run rather
3412
+ * than surfacing as a TypeError from inside the first helper that touches
3413
+ * the client.
3414
+ */
3415
+ export declare class MigrationNeedsSqlClient extends Error {
3416
+ readonly migrationId: string;
3417
+ readonly operation: string;
3418
+ readonly _tag = "MigrationNeedsSqlClient";
3419
+ constructor(migrationId: string, operation: string, detail: string);
3420
+ }
3421
+
3354
3422
  /**
3355
3423
  * Discriminated union for the concrete DDL operations the planner
3356
3424
  * emits. Every variant carries the `table` (most ops act on one
@@ -4906,6 +4974,15 @@ export declare const rollbackFileBasedMigration: (sql: SqlClient.SqlClient, ctx:
4906
4974
  durationMs: number;
4907
4975
  }, unknown>;
4908
4976
 
4977
+ /**
4978
+ * What the plan already knows that a single operation does not: the tables it
4979
+ * creates. Optional — without it nothing is known to be new and every verdict
4980
+ * stays conservative.
4981
+ */
4982
+ export declare interface RollingDeployContext {
4983
+ readonly createdTables: ReadonlySet<string>;
4984
+ }
4985
+
4909
4986
  export declare interface RollingDeployGateVerdict {
4910
4987
  /** The apply MUST NOT proceed (opt-in gate tripped, not forced). */
4911
4988
  readonly refuse: boolean;