@voltro/database 0.73.0 → 0.75.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/CHANGELOG.md +449 -0
- package/dist/{frameworkLiveTables-C1WjQ_uI.js → frameworkTables-CfWuWeFG.js} +587 -292
- package/dist/index.d.ts +96 -2
- package/dist/index.js +628 -871
- package/dist/sql.d.ts +121 -7
- package/dist/sql.js +1356 -1308
- package/package.json +2 -2
package/dist/sql.d.ts
CHANGED
|
@@ -9,6 +9,48 @@ import { Statement } from '@effect/sql';
|
|
|
9
9
|
|
|
10
10
|
export declare const acquireMigrationLock: (sql: SqlClient.SqlClient, scope?: MigrationLockScope) => Effect.Effect<HeldMigrationLock, SqlError_2>;
|
|
11
11
|
|
|
12
|
+
export declare const addColumnDdl: (op: Extract<MigrationOperation, {
|
|
13
|
+
kind: "add-column";
|
|
14
|
+
}>, planned: PlannedOperation, backfillFromTable: (table: string, column: string) => {
|
|
15
|
+
sql?: Statement.Fragment;
|
|
16
|
+
js?: (row: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
17
|
+
batchSize?: number;
|
|
18
|
+
sleepMs?: number;
|
|
19
|
+
} | undefined, dialect: "mariadb" | "postgres" | "sqlite" | "mssql") => {
|
|
20
|
+
pre: ReadonlyArray<string>;
|
|
21
|
+
backfillKind?: "sql" | "js";
|
|
22
|
+
backfillSql?: Statement.Fragment;
|
|
23
|
+
backfillJs?: (row: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
24
|
+
batchSize?: number;
|
|
25
|
+
sleepMs?: number;
|
|
26
|
+
post: ReadonlyArray<string>;
|
|
27
|
+
/**
|
|
28
|
+
* The column declares `.unique()` and THIS emitter did not satisfy it.
|
|
29
|
+
*
|
|
30
|
+
* A column-level `.unique()` is a COLUMN FLAG, not a snapshot index — the
|
|
31
|
+
* planner says so itself, which is why `classifyColumnChange` has to catch a
|
|
32
|
+
* unique that appears on an EXISTING column. For a column the same plan
|
|
33
|
+
* CREATES there is no live side to compare against, so no `add-unique` op is
|
|
34
|
+
* ever emitted and this emitter is the only thing that can carry the flag.
|
|
35
|
+
*
|
|
36
|
+
* It carried it on exactly one of its three branches. `safe` (a nullable add)
|
|
37
|
+
* renders `UNIQUE` inline; `needs-default` and `needs-backfill` dropped it
|
|
38
|
+
* silently, so a new NOT NULL unique column arrived without its constraint,
|
|
39
|
+
* the re-plan then saw `declared.unique !== live.unique` and proposed
|
|
40
|
+
* `add-unique` — and `applyPlan` failed its own convergence proof on a plan
|
|
41
|
+
* that had executed without error. Reported from a MariaDB deploy where the
|
|
42
|
+
* first apply after an upgrade aborted and the second succeeded, because by
|
|
43
|
+
* then the column existed and the comparison branch could run.
|
|
44
|
+
*
|
|
45
|
+
* The flag rather than the DDL, because the statement is dialect-specific
|
|
46
|
+
* (mysql needs the key-prefix resolution, mssql bounds the text column first,
|
|
47
|
+
* sqlite rebuilds) and those emitters already exist at the call site, where
|
|
48
|
+
* `ctx.declared` is in scope. A second spelling here would be a second
|
|
49
|
+
* decision to keep in step.
|
|
50
|
+
*/
|
|
51
|
+
uniquePending?: true;
|
|
52
|
+
};
|
|
53
|
+
|
|
12
54
|
declare interface AggregateColumn<TResult = number | Date | null> {
|
|
13
55
|
readonly op: 'count' | 'sum' | 'avg' | 'min' | 'max' | 'count-distinct' | 'window-row-number' | 'window-rank' | 'window-dense-rank' | 'window-lag' | 'window-lead' | 'window-sum-over' | 'window-avg-over' | 'column';
|
|
14
56
|
readonly column?: string;
|
|
@@ -119,13 +161,21 @@ declare type AnyView = View<string, Record<string, ColumnDefinition<unknown>>>;
|
|
|
119
161
|
*/
|
|
120
162
|
export declare const appliedAtValue: (sql: SqlClient.SqlClient, iso: string) => Effect.Effect<string>;
|
|
121
163
|
|
|
164
|
+
export declare const appliedFileMigrationIds: (sql: SqlClient.SqlClient) => Effect.Effect<ReadonlyArray<string>, SqlError_2>;
|
|
165
|
+
|
|
122
166
|
/**
|
|
123
|
-
* The
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
167
|
+
* The applied file migrations WITH the body hash recorded at the time.
|
|
168
|
+
*
|
|
169
|
+
* An empty `hash` means the row predates hash recording — the answer there is
|
|
170
|
+
* "cannot compare", never "the body changed". Getting that backwards would
|
|
171
|
+
* report drift for every migration an existing database has ever applied, on
|
|
172
|
+
* the first run after upgrading, which is the loudest possible way to make a
|
|
173
|
+
* true warning ignorable.
|
|
127
174
|
*/
|
|
128
|
-
export declare const
|
|
175
|
+
export declare const appliedFileMigrations: (sql: SqlClient.SqlClient) => Effect.Effect<ReadonlyArray<{
|
|
176
|
+
readonly id: string;
|
|
177
|
+
readonly hash: string;
|
|
178
|
+
}>, SqlError_2>;
|
|
129
179
|
|
|
130
180
|
/**
|
|
131
181
|
* The operations the resume ledger says RAN — `started`, `added` or `applied` —
|
|
@@ -2564,6 +2614,21 @@ export declare const ensureDeployLedgerTable: (sql: SqlClient.SqlClient, dialect
|
|
|
2564
2614
|
*/
|
|
2565
2615
|
export declare const ensureLedgerTable: (sql: SqlClient.SqlClient, dialect: DialectId) => Effect.Effect<void, SqlError_2>;
|
|
2566
2616
|
|
|
2617
|
+
/**
|
|
2618
|
+
* The PLAN ledger (`_voltro_migration_plans`) — same bootstrap, one caller.
|
|
2619
|
+
*
|
|
2620
|
+
* A file migration records itself here, and the file pass runs BEFORE the
|
|
2621
|
+
* planner that would otherwise create this table. On a database that does not
|
|
2622
|
+
* have it yet, `up()` therefore succeeded and the recording INSERT failed —
|
|
2623
|
+
* `FileMigrationLedgerError`, the one outcome whose whole message is "do not
|
|
2624
|
+
* re-run this". Same reason the resume ledger above is created by the applier
|
|
2625
|
+
* rather than planned: a run needs it before any DDL of its own has happened.
|
|
2626
|
+
*
|
|
2627
|
+
* Index-free like the others, so the planner still owns the table's shape and a
|
|
2628
|
+
* re-plan converges by adding the indexes it declares.
|
|
2629
|
+
*/
|
|
2630
|
+
export declare const ensurePlanLedgerTable: (sql: SqlClient.SqlClient, dialect: DialectId) => Effect.Effect<void, SqlError_2>;
|
|
2631
|
+
|
|
2567
2632
|
/** Exported for the same reason as {@link enumTypeBlocks}, and it MUST run
|
|
2568
2633
|
* before it — see that function's note on ordering. */
|
|
2569
2634
|
export declare const enumRenameBlocks: (tables: ReadonlyArray<AnyTable>, dialect: DialectId) => string;
|
|
@@ -2797,6 +2862,9 @@ export declare interface FileMigrationContextInput {
|
|
|
2797
2862
|
* Its own error type because the recovery is the opposite of the ordinary one:
|
|
2798
2863
|
* do NOT re-run. The change has landed; what is missing is the record that says
|
|
2799
2864
|
* so, and every future invocation will apply it again until that row exists.
|
|
2865
|
+
* Unless the write failed because the row is ALREADY there — another process
|
|
2866
|
+
* recorded the same migration — and then the message says the opposite: the
|
|
2867
|
+
* record is correct and the body ran twice.
|
|
2800
2868
|
*/
|
|
2801
2869
|
export declare class FileMigrationLedgerError extends Error {
|
|
2802
2870
|
readonly migrationId: string;
|
|
@@ -2814,6 +2882,27 @@ export declare interface FileMigrationRunResult {
|
|
|
2814
2882
|
readonly skipped: ReadonlyArray<string>;
|
|
2815
2883
|
}
|
|
2816
2884
|
|
|
2885
|
+
/**
|
|
2886
|
+
* Applied and pending file migrations, for a caller that wants to REPORT rather
|
|
2887
|
+
* than apply.
|
|
2888
|
+
*
|
|
2889
|
+
* `voltro db status` had no way to ask: it walks `*.migration.ts` and reads the
|
|
2890
|
+
* other ledger, so against a project using `migrations/<timestamp>_<slug>.ts` it
|
|
2891
|
+
* answered "no migrations found" while `voltro db files` listed four. Two
|
|
2892
|
+
* commands that both say "migrations" and mean different files is a contradiction
|
|
2893
|
+
* a user is right to report as a bug, whichever one they read first.
|
|
2894
|
+
*/
|
|
2895
|
+
export declare const fileMigrationStatus: (sql: SqlClient.SqlClient, projectRoot: string) => Effect.Effect<ReadonlyArray<FileMigrationStatusRow>, unknown>;
|
|
2896
|
+
|
|
2897
|
+
/** One row of `voltro db status` for a `migrations/<timestamp>_<slug>.ts` file. */
|
|
2898
|
+
export declare interface FileMigrationStatusRow {
|
|
2899
|
+
readonly id: string;
|
|
2900
|
+
readonly applied: boolean;
|
|
2901
|
+
/** The file no longer hashes to what was recorded when it ran. Always false
|
|
2902
|
+
* for a row applied before hashes were recorded — see `appliedFileMigrations`. */
|
|
2903
|
+
readonly bodyChanged: boolean;
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2817
2906
|
/**
|
|
2818
2907
|
* Stable-hash a SchemaSnapshot. Returns the hex-encoded sha256 of the
|
|
2819
2908
|
* canonicalised JSON representation. Truncated identifiers are NOT
|
|
@@ -3204,6 +3293,22 @@ export declare type MigrationAtomicity = 'plan-transactional' | 'per-operation';
|
|
|
3204
3293
|
|
|
3205
3294
|
export declare const migrationAtomicityFor: (dialect: DialectId) => MigrationAtomicity;
|
|
3206
3295
|
|
|
3296
|
+
/**
|
|
3297
|
+
* The hash of a migration file's SOURCE, recorded beside its ledger row.
|
|
3298
|
+
*
|
|
3299
|
+
* A migration is looked up by id alone, so without this a body could be
|
|
3300
|
+
* rewritten after it was applied and nothing would say so — the file then reads
|
|
3301
|
+
* like something that ran, and is not. That is the check Liquibase and Flyway
|
|
3302
|
+
* make, for the same reason.
|
|
3303
|
+
*
|
|
3304
|
+
* Shared with the `.migration.ts` runner rather than spelled twice: it has
|
|
3305
|
+
* recorded a hash and warned on drift since it shipped, and two definitions of
|
|
3306
|
+
* "the hash of this file" would be two answers to one question the moment one
|
|
3307
|
+
* of them changed. Same algorithm, same truncation — a hash is only comparable
|
|
3308
|
+
* to one computed identically.
|
|
3309
|
+
*/
|
|
3310
|
+
export declare const migrationBodyHash: (source: string) => string;
|
|
3311
|
+
|
|
3207
3312
|
/** One or more `ctx.expect` post-conditions did not hold after `up`. */
|
|
3208
3313
|
export declare class MigrationExpectationFailed extends Error {
|
|
3209
3314
|
readonly migrationId: string;
|
|
@@ -3510,8 +3615,17 @@ export declare interface MigrationSchemaOps {
|
|
|
3510
3615
|
readonly onDelete?: 'cascade' | 'restrict' | 'setNull' | 'noAction';
|
|
3511
3616
|
readonly onUpdate?: 'cascade' | 'restrict' | 'setNull' | 'noAction';
|
|
3512
3617
|
}) => Effect.Effect<SchemaOpOutcome, unknown>;
|
|
3513
|
-
/**
|
|
3514
|
-
|
|
3618
|
+
/**
|
|
3619
|
+
* Remove every row. `DELETE FROM` rather than TRUNCATE: it is a data
|
|
3620
|
+
* statement on every dialect, so it stays inside a transactional migration
|
|
3621
|
+
* where TRUNCATE (DDL on the MySQL family and SQL Server) would commit it.
|
|
3622
|
+
*
|
|
3623
|
+
* Answers `already-absent` for a table that is not there, like every
|
|
3624
|
+
* operation above — and deliberately does NOT go through the store, whose
|
|
3625
|
+
* set-based delete returns the deleted rows in order to fan out one change
|
|
3626
|
+
* event per row.
|
|
3627
|
+
*/
|
|
3628
|
+
readonly truncate: (table: string) => Effect.Effect<SchemaOpOutcome, unknown>;
|
|
3515
3629
|
/**
|
|
3516
3630
|
* The Voltro way to change a table's shape in a migration: DECLARE the
|
|
3517
3631
|
* table as it should be from here on, and the same planner that drives
|