@voltro/database 0.67.0 → 0.69.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 +437 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +38 -31
- package/dist/sql.d.ts +25 -9
- package/dist/sql.js +801 -819
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2345,6 +2345,28 @@ export declare interface DataStore {
|
|
|
2345
2345
|
* - memory store: linear scan + match-by-conflict-columns
|
|
2346
2346
|
*/
|
|
2347
2347
|
upsert(table: string, row: Row, options: UpsertOptions): Promise<Row>;
|
|
2348
|
+
/**
|
|
2349
|
+
* `upsert`, plus the one thing it cannot report: whether the row was INSERTED
|
|
2350
|
+
* or UPDATED.
|
|
2351
|
+
*
|
|
2352
|
+
* An app that needs to know does the read itself today — look for the row,
|
|
2353
|
+
* then upsert — which costs a round trip AND opens a window in which the
|
|
2354
|
+
* answer stops being true. It does not have to: the framework's store wrapper
|
|
2355
|
+
* mints the id before the statement, and on the conflict path every dialect
|
|
2356
|
+
* hands back the EXISTING row's id. Two ids that differ ARE the answer, for
|
|
2357
|
+
* free.
|
|
2358
|
+
*
|
|
2359
|
+
* Optional, and provided by the framework's wrapper rather than by a dialect
|
|
2360
|
+
* store — the outcome is decided from what the wrapper already knows, so no
|
|
2361
|
+
* dialect implements anything. It is present on `ctx.store` in a handler; a
|
|
2362
|
+
* hand-written `DataStore` need not have it. The typed helper is
|
|
2363
|
+
* `upsertRowOutcome`.
|
|
2364
|
+
*
|
|
2365
|
+
* `'inserted'` is exact, never a default for "could not tell": where the free
|
|
2366
|
+
* comparison cannot answer (the caller supplied the id, or the table's id is
|
|
2367
|
+
* database-assigned) the destination is read first.
|
|
2368
|
+
*/
|
|
2369
|
+
upsertWithOutcome?(table: string, row: Row, options: UpsertOptions): Promise<UpsertResult>;
|
|
2348
2370
|
/**
|
|
2349
2371
|
* Insert-or-ignore: INSERT a row, but if it conflicts on
|
|
2350
2372
|
* `conflictColumns`, leave the existing row UNCHANGED and skip the
|
|
@@ -4049,6 +4071,29 @@ export declare type InferViewRow<V> = V extends View<string, infer F> ? InferRow
|
|
|
4049
4071
|
*/
|
|
4050
4072
|
export declare const INITIAL_VERSION = 1;
|
|
4051
4073
|
|
|
4074
|
+
/**
|
|
4075
|
+
* Insert MANY rows, typed against the table — `insertRow`'s batch, and nothing
|
|
4076
|
+
* else: it forwards to `store.insertMany` unchanged, so the chunking, the
|
|
4077
|
+
* dialect behaviour and the conflict semantics are exactly what the untyped
|
|
4078
|
+
* call already does. What it adds is the one thing the string-keyed form cannot
|
|
4079
|
+
* have: every element is checked against `InferInsertRow<T>`, so a row that
|
|
4080
|
+
* omits a required column, misspells one, or passes a `number` where the column
|
|
4081
|
+
* is a timestamp is a compile error at the call site instead of a dialect error
|
|
4082
|
+
* somewhere inside the batch.
|
|
4083
|
+
*
|
|
4084
|
+
* That last shape is why the batch form needs its own helper rather than a loop
|
|
4085
|
+
* over `insertRow`: a batch is usually MAPPED from something (a parsed import,
|
|
4086
|
+
* an API page), and a mapping is exactly where a `Date`-vs-`number` mismatch
|
|
4087
|
+
* survives review — the loop body's inferred element type is only as good as
|
|
4088
|
+
* whatever produced the array.
|
|
4089
|
+
*
|
|
4090
|
+
* await insertManyRows(ctx.store, roadmapEpicStats, rows)
|
|
4091
|
+
*
|
|
4092
|
+
* An empty array is a legal no-op, so a caller does not have to guard the call
|
|
4093
|
+
* — `store.insertMany` decides what that means, and it means "insert nothing".
|
|
4094
|
+
*/
|
|
4095
|
+
export declare const insertManyRows: <T extends AnyTable>(store: TypedInsertManyStore, table: T, rows: ReadonlyArray<InferInsertRow<T>>) => Promise<ReadonlyArray<InferRow<T>>>;
|
|
4096
|
+
|
|
4052
4097
|
/**
|
|
4053
4098
|
* Insert a row, typed against the table: the payload must carry every required
|
|
4054
4099
|
* column (NOT NULL, no default, not auto-filled) or it is a compile error.
|
|
@@ -8122,6 +8167,11 @@ export declare interface TxnRecorderPort {
|
|
|
8122
8167
|
readonly maxOf: TxnMaxOf;
|
|
8123
8168
|
}
|
|
8124
8169
|
|
|
8170
|
+
/** The minimal store surface `insertManyRows` needs. */
|
|
8171
|
+
export declare interface TypedInsertManyStore {
|
|
8172
|
+
readonly insertMany: (table: string, rows: ReadonlyArray<Row>) => Promise<ReadonlyArray<Row>>;
|
|
8173
|
+
}
|
|
8174
|
+
|
|
8125
8175
|
/** The minimal store surface `insertRow` needs — satisfied by `ctx.store`. */
|
|
8126
8176
|
export declare interface TypedInsertStore {
|
|
8127
8177
|
readonly insert: (table: string, row: Row) => Promise<Row>;
|
|
@@ -8134,6 +8184,14 @@ export declare interface TypedUpdateManyStore {
|
|
|
8134
8184
|
}) => Promise<number>;
|
|
8135
8185
|
}
|
|
8136
8186
|
|
|
8187
|
+
/** The minimal store surface `upsertRowOutcome` needs. */
|
|
8188
|
+
export declare interface TypedUpsertOutcomeStore {
|
|
8189
|
+
readonly upsertWithOutcome?: (table: string, row: Row, options: UpsertOptions) => Promise<{
|
|
8190
|
+
readonly row: Row;
|
|
8191
|
+
readonly outcome: 'inserted' | 'updated';
|
|
8192
|
+
}>;
|
|
8193
|
+
}
|
|
8194
|
+
|
|
8137
8195
|
/** The minimal store surface `upsertRow` needs. */
|
|
8138
8196
|
export declare interface TypedUpsertStore {
|
|
8139
8197
|
readonly upsert: (table: string, row: Row, options: UpsertOptions) => Promise<Row>;
|
|
@@ -8243,6 +8301,13 @@ export declare interface UpsertOptions {
|
|
|
8243
8301
|
readonly updateValues?: Readonly<Record<string, unknown>>;
|
|
8244
8302
|
}
|
|
8245
8303
|
|
|
8304
|
+
/** What an `upsertWithOutcome` did, beside the row it wrote. */
|
|
8305
|
+
export declare interface UpsertResult {
|
|
8306
|
+
readonly row: Row;
|
|
8307
|
+
/** `'updated'` means the statement landed on a row that already existed. */
|
|
8308
|
+
readonly outcome: 'inserted' | 'updated';
|
|
8309
|
+
}
|
|
8310
|
+
|
|
8246
8311
|
/**
|
|
8247
8312
|
* Upsert a row, typed the same way. `conflictColumns` is constrained to the
|
|
8248
8313
|
* table's own column names, so a typo'd conflict key is a compile error too.
|
|
@@ -8253,6 +8318,34 @@ export declare const upsertRow: <T extends AnyTable>(store: TypedUpsertStore, ta
|
|
|
8253
8318
|
readonly updateValues?: Readonly<Partial<Omit<InferRow<T>, "id">>>;
|
|
8254
8319
|
}) => Promise<InferRow<T>>;
|
|
8255
8320
|
|
|
8321
|
+
/**
|
|
8322
|
+
* `upsertRow`, plus whether the row was INSERTED or UPDATED.
|
|
8323
|
+
*
|
|
8324
|
+
* The reason this exists is one an app measured: to report "created" it had to
|
|
8325
|
+
* run a second query before every upsert — a round trip per row, and a window
|
|
8326
|
+
* in which another writer makes the answer wrong. The store already knows: it
|
|
8327
|
+
* mints the id before the statement, and on the conflict path every dialect
|
|
8328
|
+
* returns the EXISTING row's id.
|
|
8329
|
+
*
|
|
8330
|
+
* const { row, outcome } = await upsertRowOutcome(ctx.store, players, player, {
|
|
8331
|
+
* conflictColumns: ['tenantId', 'externalId'],
|
|
8332
|
+
* update: ['name', 'score'],
|
|
8333
|
+
* })
|
|
8334
|
+
* if (outcome === 'inserted') await notifyNewPlayer(row)
|
|
8335
|
+
*
|
|
8336
|
+
* `'inserted'` is never a stand-in for "could not tell". Where the id cannot
|
|
8337
|
+
* decide it — the caller supplied one, or the table's id is database-assigned —
|
|
8338
|
+
* the store reads the destination first and answers exactly.
|
|
8339
|
+
*/
|
|
8340
|
+
export declare const upsertRowOutcome: <T extends AnyTable>(store: TypedUpsertOutcomeStore, table: T, row: InferInsertRow<T>, options: {
|
|
8341
|
+
readonly conflictColumns: ReadonlyArray<keyof InferRow<T> & string>;
|
|
8342
|
+
readonly update?: ReadonlyArray<keyof InferRow<T> & string> | ((existing: InferRow<T>) => Readonly<Partial<InferRow<T>>>);
|
|
8343
|
+
readonly updateValues?: Readonly<Partial<Omit<InferRow<T>, "id">>>;
|
|
8344
|
+
}) => Promise<{
|
|
8345
|
+
readonly row: InferRow<T>;
|
|
8346
|
+
readonly outcome: "inserted" | "updated";
|
|
8347
|
+
}>;
|
|
8348
|
+
|
|
8256
8349
|
/** Conflict patch for stores/callback paths that already have the existing row. */
|
|
8257
8350
|
export declare const upsertUpdatePatch: (row: Row, existing: Row, options: UpsertOptions) => Row;
|
|
8258
8351
|
|
package/dist/index.js
CHANGED
|
@@ -2670,29 +2670,36 @@ ${e.all.map((e) => {
|
|
|
2670
2670
|
reason: "null"
|
|
2671
2671
|
}));
|
|
2672
2672
|
return a;
|
|
2673
|
-
}, ml = (e, t, n) => e.insert(t.tableName, n), hl = (e, t, n, r) => e.upsert(t.tableName, n, {
|
|
2673
|
+
}, ml = (e, t, n) => e.insert(t.tableName, n), hl = (e, t, n) => e.insertMany(t.tableName, n), gl = (e, t, n, r) => e.upsert(t.tableName, n, {
|
|
2674
2674
|
conflictColumns: r.conflictColumns,
|
|
2675
2675
|
...r.update === void 0 ? {} : { update: r.update },
|
|
2676
2676
|
...r.updateValues === void 0 ? {} : { updateValues: r.updateValues }
|
|
2677
|
-
}),
|
|
2677
|
+
}), _l = async (e, t, n, r) => {
|
|
2678
|
+
if (e.upsertWithOutcome === void 0) throw Error("upsertRowOutcome: this store does not implement `upsertWithOutcome`. It is provided by the framework's store wrapper, so `ctx.store` has it; a hand-written DataStore must add it.");
|
|
2679
|
+
return e.upsertWithOutcome(t.tableName, n, {
|
|
2680
|
+
conflictColumns: r.conflictColumns,
|
|
2681
|
+
...r.update === void 0 ? {} : { update: r.update },
|
|
2682
|
+
...r.updateValues === void 0 ? {} : { updateValues: r.updateValues }
|
|
2683
|
+
});
|
|
2684
|
+
}, vl = (e, t, n, r) => e.updateMany(t.tableName, n, { where: r.where }), yl = 512, bl = (e) => {
|
|
2678
2685
|
e.setMaxListeners(512);
|
|
2679
|
-
},
|
|
2686
|
+
}, xl = (e, t, n) => ({
|
|
2680
2687
|
_tag: "PrimaryKeyConflictError",
|
|
2681
2688
|
table: e,
|
|
2682
2689
|
key: t,
|
|
2683
2690
|
cause: n
|
|
2684
|
-
}),
|
|
2691
|
+
}), Sl = (e) => typeof e == "object" && !!e && e._tag === "PrimaryKeyConflictError", Cl = {
|
|
2685
2692
|
postgres: 5432,
|
|
2686
2693
|
mysql: 3306,
|
|
2687
2694
|
mariadb: 3306,
|
|
2688
2695
|
mssql: 1433
|
|
2689
|
-
},
|
|
2696
|
+
}, wl = /* @__PURE__ */ new Set([
|
|
2690
2697
|
"localhost",
|
|
2691
2698
|
"127.0.0.1",
|
|
2692
2699
|
"::1",
|
|
2693
2700
|
"[::1]",
|
|
2694
2701
|
"0.0.0.0"
|
|
2695
|
-
]),
|
|
2702
|
+
]), Tl = (e) => {
|
|
2696
2703
|
let t = e.host, n = e.port, r = e.database;
|
|
2697
2704
|
if (e.url !== void 0 && e.url !== "") try {
|
|
2698
2705
|
let i = new URL(e.url);
|
|
@@ -2701,29 +2708,29 @@ ${e.all.map((e) => {
|
|
|
2701
2708
|
return;
|
|
2702
2709
|
}
|
|
2703
2710
|
if (t === void 0 || t === "" || r === void 0 || r === "") return;
|
|
2704
|
-
let i = n ??
|
|
2711
|
+
let i = n ?? Cl[(e.dialect ?? "").toLowerCase()];
|
|
2705
2712
|
if (i === void 0 || !Number.isFinite(i)) return;
|
|
2706
2713
|
let a = t.toLowerCase();
|
|
2707
2714
|
return {
|
|
2708
|
-
host:
|
|
2715
|
+
host: wl.has(a) ? "localhost" : a,
|
|
2709
2716
|
port: i,
|
|
2710
2717
|
database: r.toLowerCase()
|
|
2711
2718
|
};
|
|
2712
|
-
},
|
|
2713
|
-
let t =
|
|
2719
|
+
}, El = (e) => {
|
|
2720
|
+
let t = Tl(e);
|
|
2714
2721
|
if (t !== void 0) return qt("sha256").update(`${t.host}\u0000${t.port}\u0000${t.database}`).digest("hex").slice(0, 32);
|
|
2715
|
-
},
|
|
2722
|
+
}, Dl = (e, t) => e === void 0 || t === void 0 ? "unknown" : e === t ? "same" : "different", Ol = {
|
|
2716
2723
|
app: 3,
|
|
2717
2724
|
plugin: 2,
|
|
2718
2725
|
framework: 1
|
|
2719
|
-
},
|
|
2726
|
+
}, kl = /* @__PURE__ */ new Map(), Al = [], jl = () => [...Al], Ml = (e) => {
|
|
2720
2727
|
if (!e.table || !e.timeColumn) throw Error("registerRetention: table + timeColumn are required");
|
|
2721
2728
|
if (!Number.isFinite(e.ttlMs) || e.ttlMs <= 0) throw Error(`registerRetention(${e.table}): ttlMs must be a positive number`);
|
|
2722
|
-
let t = e.source ?? "app", n =
|
|
2729
|
+
let t = e.source ?? "app", n = kl.get(e.table);
|
|
2723
2730
|
if (n !== void 0) {
|
|
2724
2731
|
let r = n.source ?? "app", i = n.ttlMs !== e.ttlMs || n.where !== void 0 != (e.where !== void 0);
|
|
2725
|
-
if (
|
|
2726
|
-
i &&
|
|
2732
|
+
if (Ol[t] < Ol[r]) {
|
|
2733
|
+
i && Al.push({
|
|
2727
2734
|
table: e.table,
|
|
2728
2735
|
kept: {
|
|
2729
2736
|
source: r,
|
|
@@ -2736,7 +2743,7 @@ ${e.all.map((e) => {
|
|
|
2736
2743
|
});
|
|
2737
2744
|
return;
|
|
2738
2745
|
}
|
|
2739
|
-
i && r !== t &&
|
|
2746
|
+
i && r !== t && Al.push({
|
|
2740
2747
|
table: e.table,
|
|
2741
2748
|
kept: {
|
|
2742
2749
|
source: t,
|
|
@@ -2748,13 +2755,13 @@ ${e.all.map((e) => {
|
|
|
2748
2755
|
}
|
|
2749
2756
|
});
|
|
2750
2757
|
}
|
|
2751
|
-
|
|
2758
|
+
kl.set(e.table, {
|
|
2752
2759
|
...e,
|
|
2753
2760
|
source: t
|
|
2754
2761
|
});
|
|
2755
|
-
},
|
|
2756
|
-
|
|
2757
|
-
},
|
|
2762
|
+
}, Nl = () => [...kl.values()], Pl = () => {
|
|
2763
|
+
kl.clear(), Al.length = 0;
|
|
2764
|
+
}, Fl = async (e, t, n, r = 2e4) => {
|
|
2758
2765
|
let i = new Date(t - e.ttlMs), a = 0;
|
|
2759
2766
|
try {
|
|
2760
2767
|
for (;;) {
|
|
@@ -2762,26 +2769,26 @@ ${e.all.map((e) => {
|
|
|
2762
2769
|
if (a += t, t < r) break;
|
|
2763
2770
|
}
|
|
2764
2771
|
} catch (t) {
|
|
2765
|
-
throw k.runSync(A.increment(A.tagged(
|
|
2772
|
+
throw k.runSync(A.increment(A.tagged(Ll, "table", e.table))), t;
|
|
2766
2773
|
}
|
|
2767
|
-
return a > 0 && k.runSync(A.incrementBy(A.tagged(
|
|
2768
|
-
},
|
|
2774
|
+
return a > 0 && k.runSync(A.incrementBy(A.tagged(Il, "table", e.table), a)), a;
|
|
2775
|
+
}, Il = A.counter("voltro_retention_swept_rows_total"), Ll = A.counter("voltro_retention_sweep_errors_total"), Rl = (e, t) => {
|
|
2769
2776
|
let n = Number(e ?? String(t));
|
|
2770
2777
|
return (Number.isFinite(n) && n > 0 ? n : t) * 36e5;
|
|
2771
|
-
},
|
|
2778
|
+
}, zl = "_voltro_cdc_offsets", Bl = T(zl, {
|
|
2772
2779
|
id: D({ prefix: "cdcoff" }),
|
|
2773
2780
|
replicaId: w(),
|
|
2774
2781
|
streamName: w(),
|
|
2775
2782
|
binlogFile: w(),
|
|
2776
2783
|
binlogPosition: w(),
|
|
2777
2784
|
updatedAt: E()
|
|
2778
|
-
}).index(["replicaId"]),
|
|
2785
|
+
}).index(["replicaId"]), Vl = T(zl, {
|
|
2779
2786
|
id: D({ prefix: "cdcoff" }),
|
|
2780
2787
|
replicaId: w(),
|
|
2781
2788
|
streamName: w(),
|
|
2782
2789
|
ctVersion: w(),
|
|
2783
2790
|
updatedAt: E()
|
|
2784
|
-
}).index(["replicaId"]),
|
|
2791
|
+
}).index(["replicaId"]), Hl = "_voltro_data_transfers", Ul = T(Hl, {
|
|
2785
2792
|
id: D({ prefix: "dimp" }),
|
|
2786
2793
|
startedAt: E().default("now"),
|
|
2787
2794
|
finishedAt: E().nullable(),
|
|
@@ -2794,13 +2801,13 @@ ${e.all.map((e) => {
|
|
|
2794
2801
|
rowsWritten: y().default(0),
|
|
2795
2802
|
failure: w().nullable(),
|
|
2796
2803
|
staged: p().nullable()
|
|
2797
|
-
}).renamedFrom("_voltro_data_imports").nonReactive(),
|
|
2804
|
+
}).renamedFrom("_voltro_data_imports").nonReactive(), Wl = (e) => {
|
|
2798
2805
|
let t = Number.isFinite(e.startedAt.getTime()) ? e.startedAt.toISOString() : "an unknown time", n = e.direction === "import" ? e.mode : `${e.direction} ${e.mode}`, r = e.failure === null ? e.finishedAt === null ? `${n} — started and never reported finishing` : e.direction === "backup" || e.direction === "restore" ? `${n} — finished${e.rowsWritten > 0 ? ` (${e.rowsWritten} blob(s))` : ""}` : `${n} — ${e.rowsWritten} row(s) across ${e.tablesWritten} table(s)` : `FAILED ${n} — ${e.failure}`, i = e.staged === null ? "" : e.staged ? " · staged (target untouched until the swap)" : " · NOT staged (target emptied first)";
|
|
2799
2806
|
return `${t} · ${r} · via ${e.via}${i}` + (e.bundle === null ? "" : ` · from ${e.bundle}`) + (e.sourceFingerprint === null ? "" : ` · source schema ${e.sourceFingerprint}`);
|
|
2800
|
-
},
|
|
2807
|
+
}, Gl = 255, Kl = (e) => e == null ? "null" : typeof e == "string" || typeof e == "number" || typeof e == "boolean" ? JSON.stringify(e) : Array.isArray(e) ? `[${e.map(Kl).join(",")}]` : typeof e == "object" ? `{${Object.entries(e).filter(([, e]) => e !== void 0).sort(([e], [t]) => e < t ? -1 : +(e > t)).map(([e, t]) => `${JSON.stringify(e)}:${Kl(t)}`).join(",")}}` : JSON.stringify(String(e)), ql = (e) => {
|
|
2801
2808
|
if (e == null) return null;
|
|
2802
|
-
let t = typeof e == "string" ? e :
|
|
2809
|
+
let t = typeof e == "string" ? e : Kl(e);
|
|
2803
2810
|
return t.length > 255 ? t.slice(0, 255) : t;
|
|
2804
|
-
},
|
|
2811
|
+
}, Jl = "postgres";
|
|
2805
2812
|
//#endregion
|
|
2806
|
-
export { ct as AUTO_FILLED_COLUMNS, an as BOUND_ENCRYPTED_PREFIX, cl as BULK_INSERT_LIMITS, Y as BranchNameInvalid, tc as BranchTransitionInvalid,
|
|
2813
|
+
export { ct as AUTO_FILLED_COLUMNS, an as BOUND_ENCRYPTED_PREFIX, cl as BULK_INSERT_LIMITS, Y as BranchNameInvalid, tc as BranchTransitionInvalid, zl as CDC_OFFSETS_TABLE, _o as CHANGE_CLAIM_TTL_ENV, yl as CHANGE_LISTENER_CEILING, Ze as ColumnBuilder, Hl as DATA_TRANSFERS_TABLE, ot as DEFAULT_ACQUIRE_TIMEOUT_MS, vo as DEFAULT_CHANGE_CLAIM_TTL_HOURS, ys as DEFAULT_EAGER_FALLBACK_WARN_INTERVAL_MS, vt as DEFAULT_SOFT_DROP_RETENTION_DAYS, pr as DEFAULT_SUBJECT_GRAPH_DEPTH, rn as ENCRYPTED_PREFIX, Jl as ENGINE, Br as EagerCardinalityError, xt as FILE_MIGRATION_PATTERN, it as FRAMEWORK_LIVE_TABLES, cn as FieldDecryptionError, Vo as ID_COLUMN_MAX_LENGTH, It as INITIAL_VERSION, Ha as MATCHES_NO_ROWS, wt as MAX_IDENTIFIER_LENGTH, As as MSSQL_TRANSIENT_NUMBERS, Os as MYSQL_TRANSIENT_CODES, go as OccurrenceCounter, ks as POSTGRES_TRANSIENT_STATES, Zc as REPLACE_IN_PROGRESS_TABLE, Gl as SCOPE_KEY_MAX_LENGTH, ae as SELF_REFERENCE_TARGET, js as SQLITE_TRANSIENT_CODES, $c as STAGING_STALE_MINUTES, ft as STAGING_TABLE_PREFIX, Xt as SqlClient, Ms as TURSO_TRANSIENT_MESSAGE, Us as TableStreamError, ei as TenantNamespaceInvalid, $r as TenantNamespaceUnresolved, bc as TenantRegionUnavailable, yc as TenantResidencyUnresolved, Ls as VOLTRO_EXPIRES_MIXIN_ID, zs as VOLTRO_LOCAL_FIRST_MIXIN_ID, Nt as VersionConflict, kt as WARN_IDENTIFIER_LENGTH, Jc as _voltroApiKeysTable, Bl as _voltroCdcOffsetsTable, Ul as _voltroDataTransfersTable, Kc as _voltroIdempotencyTable, qc as _voltroKvTable, Gc as _voltroMigrationPlansTable, Uc as _voltroMigrationsTable, Vl as _voltroMssqlCdcOffsetsTable, Qc as _voltroReplaceInProgressTable, Yc as _voltroReplicaObservationsTable, Wc as _voltroSeedsTable, Oa as actorsTable, mc as admitBranch, qe as agedSoftDropSnapshots, ye as allEnumRenames, ur as allRegisteredRelations, te as allRegisteredTables, Ka as and, Rr as applyJsonPatch, se as array, za as arrayContains, Va as arrayHas, Ba as arrayOverlaps, Hr as attachEagerLoads, Co as attributionFields, Do as attributionKey, Pc as auditAllTableIndexes, Nc as auditTableIndexes, Tt as avg, ve as avgOver, Io as beginLocalWrite, de as bigint, Oc as bindResidentStore, p as boolean, Qs as branchNamespaceName, ll as bulkInsertLimitsFor, ee as bytes, xn as causeBranches, lo as changeDelete, po as changeDigest, so as changeInsert, uo as changeSoftDelete, co as changeUpdate, dl as chunkRowsForInsert, Ao as claimPendingAttribution, jn as classifyConstraintViolation, d as clearEnumRenames, zo as clearPendingAttribution, fr as clearRelationsRegistry, wc as clearResidencyConfig, Pl as clearRetentions, De as clearTableRegistry, Jo as clearWriteRecorders, W as coercePredicateForSqlite, ci as coercePredicateValue, li as coercePredicateValues, ba as coerceValueForSqlite, io as collectSubqueries, u as column, Bn as columnSchema, ul as columnsPerRow, Ci as compileEagerJson, zr as compileJsonPatch, L as compilePredicate, ui as compileRawFragment, Si as compileSelect, mo as composeChangeKey, Js as computeEmbedding, El as connectionIdentity, La as contains, c as count, ce as countDistinct, ie as crdtDoc, he as crdtManagedColumns, jt as crdtManagedColumnsOf, a as crdtText, So as currentWriteAttribution, Qe as databaseHandle, Ce as date, _ as dbEnum, ps as dbMetricTagCacheSizeForTests, gs as dbOperationsInFlight, xe as decimal, l as declareEnumRename, pn as decodeFieldValue, Dr as decodeRowsFromSchema, yn as decryptFieldsOnRead, Vc as defineMigration, St as defineMixin, lt as defineSeed, n as denseRank, br as deriveSubjectGraph, ut as deriveTypeIdPrefix, Wo as derivedRowId, Go as derivedRowIdLength, Me as describeAgedSoftDropSnapshots, Pn as describeDriverError, Fn as describeRowBindings, Wl as describeTransferRun, nn as deserializeArraysOnRead, Fe as drainIdentifierWarnings, Te as dropped, dn as encodeFieldValue, kr as encodeRowForSchema, vn as encryptFieldsForWrite, gn as encryptedColumnsOf, Lo as endLocalWrite, dc as enforceBranchLimits, Ee as ensureTableRegistered, ka as eq, di as escapeLike, ro as evaluatePredicate, Xe as except, $a as exists, Rs as expires, oo as externalChangeEvent, wn as extractDbCause, on as fieldBinding, nt as fireSchemaChangeSeeds, Ge as fireTenantCreateSeeds, zc as formatIndexAuditIssue, xr as formatSubjectGraph, Xc as frameworkTables, rt as generateId, We as generateSnowflake, h as geography, re as geometry, le as getEnumRenames, lr as getRelation, cr as getRelations, Cc as getResidencyConfig, C as getTable, ja as gt, Ma as gte, Qr as hasEagerLoads, qs as hybridSearch, D as id, Fa as inSet, Za as inSubquery, $n as inferForeignKey, hl as insertManyRows, ml as insertRow, y as integer, nl as interruptedReplaceRefusal, x as intersect, Oe as interval, sn as isBoundCiphertext, $s as isBranchNamespace, Pr as isCompositeRowKey, Jn as isEmptyRelationsSpec, un as isEncrypted, ln as isFieldDecryptionError, Le as isFileMigration, Mn as isForeignKeyViolation, st as isFrameworkOwnedLiveTable, Vs as isLocalFirst, Hc as isMigrationDefinition, mt as isMysqlFamily, ac as isNeonConnection, Wa as isNotNull, Ua as isNull, Sl as isPrimaryKeyConflictError, Nn as isQueryTimeout, mn as isRawEncoding, Ec as isRegionServable, Yn as isRelationsSpec, Ue as isSeedDefinition, ht as isSoftDropSnapshotName, Ye as isSqliteFamily, Ie as isStagingTableName, fe as isTableReactive, Fs as isTransientContention, Pe as isView, S as json, Ya as jsonField, _t as jsonIndex, Fr as jsonPatchAssignments, oe as lag, ue as lead, jl as listRetentionConflicts, Nl as listRetentions, Bs as localFirst, Hs as localFirstTables, Na as lt, Pa as lte, Ss as makeEagerFallbackReporter, vc as makeNamespaceBranchExecutor, Zn as many, Qn as manyToMany, ke as materializeFields, f as max, Ve as migration, v as min, pl as missingConflictColumns, fl as missingRequiredColumns, Re as mixin, Aa as neq, nc as nextBranchState, Tl as normaliseTarget, Lr as normalizeJsonPatchValue, Ja as not, eo as notExists, Ia as notInSet, Qa as notInSubquery, pe as numeric, vs as observeDbOp, yo as occurrenceWindowMs, Xn as one, Vr as oneCardinalityMessage, qa as or, b as orderClausesOf, me as paginateBy, At as paginateById, ho as parseChangeKey, Bo as pendingAttributionCount, lc as planBranch, rc as planBranchProvision, ic as planBranchTeardown, uc as planBranchTeardownFor, sc as planNeonBranchProvision, cc as planNeonBranchTeardown, Mt as planVersionedUpdate, $e as pluginRef, r as pluginRefSpecOf, xl as primaryKeyConflictError, fc as provisionBranch, kc as provisionResidentTenant, ai as qualifyTable, i as queryFor, Dt as queryForView, Ne as quoteIdent, bl as raiseChangeListenerCeiling, Se as rank, t as raw, ze as readableByColumns, yt as real, _s as recordDbOp, $o as recordsTable, at as reference, Rn as refuseWrite, wa as registerCoreTables, sr as registerDiscoveredRelations, ko as registerPendingAttribution, or as registerRelations, Ml as registerRetention, e as registerTable, Ko as registerWriteRecorder, qn as relations, Ea as requireActors, Be as requireTable, Da as requireTenants, fs as resetDbMetricTagCacheForTests, je as resetSnowflake, Dc as residentPlacement, Qt as resolveActorSnapshot, oc as resolveBranchMechanism, xs as resolveEagerFallbackWarnIntervalMs, Ro as resolveEchoAttribution, g as resolveFullTextIndex, Ke as resolveIdScheme, He as resolveMixinGraph, Tc as resolveTenantHome, ii as resolveTenantNamespace, Rl as retentionTtlMsFromEnv, Mr as rowKeyColumns, Nr as rowKeyIdentity, be as rowNumber, Vn as rowSchema, Es as runRetryingTransaction, Ds as runStoreTransaction, xo as runWithWriteAttribution, es as runWriteRecorders, Dl as sameDatabase, ri as sanitizeIdentifierFragment, ql as scopeKeyOf, pt as selfReference, tn as serializeArraysForWrite, Je as serverOnlyColumns, Sc as setResidencyConfig, Ae as setSchemaChangeSeedHook, Ct as setTenantCreateSeedHook, Cs as settleTransactionExit, Ft as settleVersionedUpdate, et as softDropSnapshotStamp, Ga as spatialPredicate, il as stagingLeftoverReport, rl as stagingLeftovers, tl as stagingNamesOf, el as stagingStaleAfterMs, ol as stampGeneratedId, sl as stampGeneratedIds, Ra as startsWith, zn as storeRefusalOf, Ks as streamTable, we as sum, m as sumOver, Xo as suspendWriteRecorders, Zo as suspendWriteRecordersEffect, Fl as sweepRetention, T as table, pc as teardownBranch, w as text, E as timestamp, Rt as timestampMs, Pt as timestampMsOrNull, ne as union, dt as unionAll, bt as unregisterTable, qo as unregisterWriteRecorder, vl as updateManyRow, gl as upsertRow, _l as upsertRowOutcome, jr as upsertUpdatePatch, Ar as upsertUpdateValues, Ot as validateColumnName, _e as validateIndexName, dr as validateRegisteredRelations, rr as validateRelationConfig, s as validateTableName, Et as validateTypeIdPrefix, gt as vector, tt as vectorDistanceToOpclass, Ys as vectorEmbedding, Lt as versionColumnOf, ge as view, o as viewSql, ao as walkLeaves, Tn as wireSafeCause, wo as withCapturedAttribution, Qo as writeRecordersSuspended };
|
package/dist/sql.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { SqlError } from '@effect/sql';
|
|
|
7
7
|
import { SqlError as SqlError_2 } from '@effect/sql/SqlError';
|
|
8
8
|
import { Statement } from '@effect/sql';
|
|
9
9
|
|
|
10
|
-
export declare const acquireMigrationLock: (sql: SqlClient.SqlClient, scope?: MigrationLockScope) => Effect.Effect<
|
|
10
|
+
export declare const acquireMigrationLock: (sql: SqlClient.SqlClient, scope?: MigrationLockScope) => Effect.Effect<HeldMigrationLock, SqlError_2>;
|
|
11
11
|
|
|
12
12
|
declare interface AggregateColumn<TResult = number | Date | null> {
|
|
13
13
|
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';
|
|
@@ -126,6 +126,14 @@ export declare interface AppliedOp {
|
|
|
126
126
|
*/
|
|
127
127
|
export declare const applyNamespacedSchema: (tables: ReadonlyArray<AnyTable>, namespace: string, dialect?: DialectId, options?: SchemaApplyOptions) => Effect.Effect<void, never, SqlClient.SqlClient>;
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Apply a plan, holding the migration lock for the whole of it.
|
|
131
|
+
*
|
|
132
|
+
* `acquireUseRelease` rather than a `try/finally` in the body: Effect's own
|
|
133
|
+
* bracket runs its release on success, on failure, on a defect AND on
|
|
134
|
+
* interruption, which is exactly the set a JS `finally` inside `Effect.gen`
|
|
135
|
+
* does not cover.
|
|
136
|
+
*/
|
|
129
137
|
export declare const applyPlan: (sql: SqlClient.SqlClient, plan: MigrationPlan, ctx: ApplyPlanCtx) => Effect.Effect<AppliedMigration, SqlError_2, SqlClient.SqlClient>;
|
|
130
138
|
|
|
131
139
|
export declare interface ApplyPlanCtx {
|
|
@@ -1344,6 +1352,22 @@ export declare const formatBranchRehearsal: (report: BranchRehearsalReport) => s
|
|
|
1344
1352
|
/** Human report, or `undefined` when the database and the schema agree. */
|
|
1345
1353
|
export declare const formatReactiveTriggerDrift: (drift: ReactiveTriggerDrift) => string | undefined;
|
|
1346
1354
|
|
|
1355
|
+
/**
|
|
1356
|
+
* A lock that is being HELD, and the only way to let it go.
|
|
1357
|
+
*
|
|
1358
|
+
* The reserved connection lives inside this handle: `release` gives the lock
|
|
1359
|
+
* back and closes the reservation, in that order. Returning it as a value
|
|
1360
|
+
* rather than exposing a free `releaseMigrationLock(sql, scope)` is deliberate
|
|
1361
|
+
* — a free release cannot know WHICH connection took the lock, and on every
|
|
1362
|
+
* session-scoped dialect a release on the wrong connection is a no-op that
|
|
1363
|
+
* reports success.
|
|
1364
|
+
*/
|
|
1365
|
+
export declare interface HeldMigrationLock {
|
|
1366
|
+
/** Release the lock and return its connection to the pool. Idempotent only
|
|
1367
|
+
* in the sense that the dialect statements are; call it once. */
|
|
1368
|
+
readonly release: Effect.Effect<void, SqlError_2>;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1347
1371
|
/**
|
|
1348
1372
|
* Fully-resolved scheme stored on the `id` column definition AFTER
|
|
1349
1373
|
* `table()` walks the fields. For `typeid`, the prefix is always
|
|
@@ -2555,8 +2579,6 @@ export declare const rehearsedOperation: (planned: PlannedOperation) => Rehearse
|
|
|
2555
2579
|
*/
|
|
2556
2580
|
export declare const rehearseMigrationOnBranch: (ops: BranchRehearsalOps) => Promise<BranchRehearsalReport>;
|
|
2557
2581
|
|
|
2558
|
-
export declare const releaseMigrationLock: (sql: SqlClient.SqlClient, scope?: MigrationLockScope) => Effect.Effect<void, SqlError_2>;
|
|
2559
|
-
|
|
2560
2582
|
export declare const renderColumnMysql: (col: ColumnSnapshot) => string;
|
|
2561
2583
|
|
|
2562
2584
|
export declare const renderColumnPg: (col: ColumnSnapshot) => string;
|
|
@@ -3570,12 +3592,6 @@ declare interface WindowSpec {
|
|
|
3570
3592
|
}>;
|
|
3571
3593
|
}
|
|
3572
3594
|
|
|
3573
|
-
/**
|
|
3574
|
-
* Convenience wrapper: acquire → run `work` → release. Releases even
|
|
3575
|
-
* on failure via `Effect.ensuring`, but a process crash mid-work
|
|
3576
|
-
* leaves the postgres lock held until that connection closes (which
|
|
3577
|
-
* the pooled SqlClient does on Effect scope cleanup).
|
|
3578
|
-
*/
|
|
3579
3595
|
export declare const withMigrationLock: <A, E, R = never>(sql: SqlClient.SqlClient, work: Effect.Effect<A, E, R>, scope?: MigrationLockScope) => Effect.Effect<A, E | SqlError_2, R>;
|
|
3580
3596
|
|
|
3581
3597
|
/** Tree of relations to eager-load. */
|