@voltro/database 0.54.0 → 0.55.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 +142 -2
- package/dist/{frameworkLiveTables-ChVR-C5F.js → frameworkLiveTables-CwDemhjW.js} +139 -139
- package/dist/index.d.ts +154 -0
- package/dist/index.js +763 -737
- package/dist/sql.js +819 -819
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2478,6 +2478,38 @@ export declare interface DataStore {
|
|
|
2478
2478
|
* callers guard with `if (store.refreshChangeCaptureExclusions)`.
|
|
2479
2479
|
*/
|
|
2480
2480
|
refreshChangeCaptureExclusions?(): Promise<ChangeCaptureExclusionRefresh>;
|
|
2481
|
+
/**
|
|
2482
|
+
* Run an Effect that needs this store's own `SqlClient` — the raw-SQL seam.
|
|
2483
|
+
*
|
|
2484
|
+
* The capability the STAGED SWAP is built on. `--mode replace` loads into
|
|
2485
|
+
* `_voltro_staging_<t>` tables and then swaps the CONTENT in one short
|
|
2486
|
+
* transaction (`DELETE FROM t; INSERT INTO t (…) SELECT … FROM
|
|
2487
|
+
* _voltro_staging_t`), which moves the long, network-bound load OUT of the
|
|
2488
|
+
* destructive transaction. None of that is expressible through the typed row
|
|
2489
|
+
* API: it is DDL plus a server-side `INSERT … SELECT`, and the whole point is
|
|
2490
|
+
* that no row crosses the wire.
|
|
2491
|
+
*
|
|
2492
|
+
* OPTIONAL on the interface, and declared here rather than duck-typed at the
|
|
2493
|
+
* call site for the reason the house rule gives: the four dialect stores are
|
|
2494
|
+
* four hand-written copies of one interface, and a capability nothing declares
|
|
2495
|
+
* is a capability nothing can be red about. A store that loses it now fails to
|
|
2496
|
+
* satisfy this member instead of silently falling out of `canStage()` and
|
|
2497
|
+
* taking the weaker path forever, on one dialect, in silence.
|
|
2498
|
+
*
|
|
2499
|
+
* The DECISION does not live per store — that would be the four-copies trap
|
|
2500
|
+
* wearing a different hat. `@voltro/data-transfer`'s `stagedSwap.ts` writes
|
|
2501
|
+
* the per-dialect SQL ONCE and sends it down this seam; the store contributes
|
|
2502
|
+
* a connection, not a policy.
|
|
2503
|
+
*
|
|
2504
|
+
* Callers guard with `if (store.run)` (or `canStage(store)`), and a store
|
|
2505
|
+
* without it keeps the path it already has: the in-memory store has no SQL
|
|
2506
|
+
* and no catalog, and neither does a bare `DataStore` view.
|
|
2507
|
+
*
|
|
2508
|
+
* `R` is deliberately `SqlClient.SqlClient`: the effect asks for the client
|
|
2509
|
+
* and the store provides its own, which is what makes this a SEAM rather than
|
|
2510
|
+
* a way to hand a store somebody else's connection.
|
|
2511
|
+
*/
|
|
2512
|
+
run?<A, E>(effect: Effect.Effect<A, E, SqlClient.SqlClient>): Promise<A>;
|
|
2481
2513
|
}
|
|
2482
2514
|
|
|
2483
2515
|
/** One transfer, as the inspector reads it back. */
|
|
@@ -3828,6 +3860,13 @@ export declare interface InterruptedReplace {
|
|
|
3828
3860
|
readonly tables: number | null;
|
|
3829
3861
|
readonly capture: string | null;
|
|
3830
3862
|
readonly via: string;
|
|
3863
|
+
/** The staging tables the run created. Empty for every kind but `staging`. */
|
|
3864
|
+
readonly staging: ReadonlyArray<string>;
|
|
3865
|
+
/** Last sign of life from the run, or `null` when it never wrote one. */
|
|
3866
|
+
readonly heartbeatAt: Date | null;
|
|
3867
|
+
/** `true` when the run was started `--no-atomic` — its staging is a resume
|
|
3868
|
+
* point, not a leftover. */
|
|
3869
|
+
readonly resumable: boolean;
|
|
3831
3870
|
}
|
|
3832
3871
|
|
|
3833
3872
|
/**
|
|
@@ -3972,6 +4011,41 @@ export declare const isSeedDefinition: (value: unknown) => value is SeedDefiniti
|
|
|
3972
4011
|
*/
|
|
3973
4012
|
export declare const isSqliteFamily: (dialect: DialectId) => boolean;
|
|
3974
4013
|
|
|
4014
|
+
/**
|
|
4015
|
+
* True when `name` is a `--mode replace` staging table.
|
|
4016
|
+
*
|
|
4017
|
+
* ── This is a THIRD rule, and it must not be folded into the other two ─────
|
|
4018
|
+
*
|
|
4019
|
+
* The framework-table filter above is deliberately ASYMMETRIC: a framework
|
|
4020
|
+
* table nobody declares is never planned for a drop, and one we DO declare
|
|
4021
|
+
* diffs like any other table. Collapsing those two into one filter is what
|
|
4022
|
+
* produced a postgres-only evolution path for the framework's own tables, and
|
|
4023
|
+
* the comment in `boot.ts` exists to stop it being collapsed again.
|
|
4024
|
+
*
|
|
4025
|
+
* A staging table satisfies NEITHER half. It is not a schema fact at all — it is
|
|
4026
|
+
* a scratch copy of a target table that exists for the length of one import and
|
|
4027
|
+
* is dropped after the swap. So:
|
|
4028
|
+
*
|
|
4029
|
+
* - the DROP direction is already covered, because `_voltro_staging_` starts
|
|
4030
|
+
* with `_voltro_` and `isFrameworkOwnedLiveTable` therefore says "never
|
|
4031
|
+
* drop it". Correct: a `replace` in flight on another replica is loading
|
|
4032
|
+
* into it right now.
|
|
4033
|
+
* - the CREATE direction is NOT, and that is the gap this closes. `--mode
|
|
4034
|
+
* replace` REGISTERS each staging table as a clone of its target for the
|
|
4035
|
+
* duration of the load — it has to, or a typed write cannot resolve the
|
|
4036
|
+
* column types and a `json()` column is written unencoded. A registered
|
|
4037
|
+
* table is a DECLARED table, and by the asymmetry above a declared
|
|
4038
|
+
* framework table diffs like any other: a plan computed while an import is
|
|
4039
|
+
* in flight proposes `create-table _voltro_staging_notes` and, once
|
|
4040
|
+
* applied, a table nothing will ever declare again is kept forever.
|
|
4041
|
+
*
|
|
4042
|
+
* So staging is excluded from the DECLARED side (in `declaredSnapshot`, which is
|
|
4043
|
+
* the one input both the plan and its fingerprint are built from) and left to
|
|
4044
|
+
* the existing prefix rule on the live side. Two different rules, two different
|
|
4045
|
+
* places, on purpose.
|
|
4046
|
+
*/
|
|
4047
|
+
export declare const isStagingTableName: (name: string) => boolean;
|
|
4048
|
+
|
|
3975
4049
|
/**
|
|
3976
4050
|
* Does this table emit change events at all?
|
|
3977
4051
|
*
|
|
@@ -6593,6 +6667,86 @@ export declare interface SqlDialect {
|
|
|
6593
6667
|
readonly retryFilter: (error: unknown) => RetryDecision;
|
|
6594
6668
|
}
|
|
6595
6669
|
|
|
6670
|
+
/**
|
|
6671
|
+
* How long a staged run's silence has to last before its scratch tables are
|
|
6672
|
+
* treated as abandoned.
|
|
6673
|
+
*
|
|
6674
|
+
* Generous on purpose. The beat is written every couple of seconds while rows
|
|
6675
|
+
* land, so this is not "how long a load may take" — it is how long a load may
|
|
6676
|
+
* be stalled, or its bookkeeping write failing, before a boot on another
|
|
6677
|
+
* replica decides nobody is coming back. The cost of being wrong here is that
|
|
6678
|
+
* an in-flight import's swap fails with a missing table and the operator
|
|
6679
|
+
* re-runs it; the target is untouched either way, which is what makes an
|
|
6680
|
+
* automatic sweep affordable at all.
|
|
6681
|
+
*
|
|
6682
|
+
* Declared as `dataTransfer.stagingStaleMinutes` in `app.config.ts`;
|
|
6683
|
+
* `VOLTRO_STAGING_STALE_MINUTES` overrides that in turn, on the same rule every
|
|
6684
|
+
* other tunable here follows — an operator acting on a running deployment
|
|
6685
|
+
* outranks what the project declared.
|
|
6686
|
+
*/
|
|
6687
|
+
export declare const STAGING_STALE_MINUTES = 30;
|
|
6688
|
+
|
|
6689
|
+
/**
|
|
6690
|
+
* The prefix a STAGING table carries: `_voltro_staging_<target>`.
|
|
6691
|
+
*
|
|
6692
|
+
* Defined in this leaf module, not in `@voltro/data-transfer` where the swap
|
|
6693
|
+
* lives, because the differ has to know it and `@voltro/database` cannot depend
|
|
6694
|
+
* on the package that imports it. One definition; `stagedSwap.ts` re-exports
|
|
6695
|
+
* this one rather than spelling the prefix a second time.
|
|
6696
|
+
*/
|
|
6697
|
+
export declare const STAGING_TABLE_PREFIX = "_voltro_staging_";
|
|
6698
|
+
|
|
6699
|
+
/**
|
|
6700
|
+
* What a boot says about them.
|
|
6701
|
+
*
|
|
6702
|
+
* A NOTE, never a refusal — the target of a staged run is untouched by
|
|
6703
|
+
* definition. But it is said out loud, because the alternative is what shipped:
|
|
6704
|
+
* a set of tables holding a whole bundle that only an introspection could find,
|
|
6705
|
+
* so nobody knew they existed until a disk filled up.
|
|
6706
|
+
*/
|
|
6707
|
+
export declare const stagingLeftoverReport: (leftovers: StagingLeftovers, now: number) => string | undefined;
|
|
6708
|
+
|
|
6709
|
+
/** One staged run's leftovers, and what a boot may do about them. */
|
|
6710
|
+
export declare interface StagingLeftovers {
|
|
6711
|
+
/** Every `kind: 'staging'` row, for the report. */
|
|
6712
|
+
readonly all: ReadonlyArray<InterruptedReplace>;
|
|
6713
|
+
/**
|
|
6714
|
+
* The rows whose tables a boot may DROP: the beat is stale AND the run was
|
|
6715
|
+
* not resumable.
|
|
6716
|
+
*
|
|
6717
|
+
* Both halves are load-bearing and neither is enough alone. A fresh beat is
|
|
6718
|
+
* an import in flight — on this pod or another replica — and dropping its
|
|
6719
|
+
* staging would destroy a load in progress. A resumable run's staging is a
|
|
6720
|
+
* RESUME POINT that is meant to outlive the process, so no amount of silence
|
|
6721
|
+
* makes it collectable.
|
|
6722
|
+
*/
|
|
6723
|
+
readonly droppable: ReadonlyArray<InterruptedReplace>;
|
|
6724
|
+
}
|
|
6725
|
+
|
|
6726
|
+
/**
|
|
6727
|
+
* Decide, from the marker rows alone, which staging sets a boot may collect.
|
|
6728
|
+
*
|
|
6729
|
+
* Pure, and separated from the boot so the DECISION can be tested without a
|
|
6730
|
+
* database — the rule is three lines and every one of them has a way to be
|
|
6731
|
+
* quietly wrong in the direction that destroys someone's work.
|
|
6732
|
+
*/
|
|
6733
|
+
export declare const stagingLeftovers: (rows: ReadonlyArray<InterruptedReplace>, now: number, staleAfterMs: number) => StagingLeftovers;
|
|
6734
|
+
|
|
6735
|
+
/** Split a `kind: 'staging'` row's comma-separated name list. */
|
|
6736
|
+
export declare const stagingNamesOf: (raw: unknown) => ReadonlyArray<string>;
|
|
6737
|
+
|
|
6738
|
+
/**
|
|
6739
|
+
* The threshold in ms: the env override, else what the app declared, else the
|
|
6740
|
+
* default above.
|
|
6741
|
+
*
|
|
6742
|
+
* A non-positive or unparseable value at EITHER level falls through to the next
|
|
6743
|
+
* one rather than failing. This runs on a boot path whose whole contract is that
|
|
6744
|
+
* scratch-table housekeeping cannot stop a boot, so a typo in a tunable must not
|
|
6745
|
+
* be the thing that does — and the fall-through lands on a threshold that is
|
|
6746
|
+
* generous in the safe direction.
|
|
6747
|
+
*/
|
|
6748
|
+
export declare const stagingStaleAfterMs: (env: Record<string, string | undefined>, declaredMinutes?: number) => number;
|
|
6749
|
+
|
|
6596
6750
|
/**
|
|
6597
6751
|
* Fill `row.id` from the table's declared scheme when it is absent.
|
|
6598
6752
|
*
|