@minnowdb/core 0.5.0 → 0.6.1
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/README.md +3 -2
- package/dist/engine/cancellation.d.ts +2 -0
- package/dist/engine/cancellation.js +4 -0
- package/dist/engine/catalog.d.ts +3 -1
- package/dist/engine/catalog.js +1 -0
- package/dist/engine/client.d.ts +32 -4
- package/dist/engine/client.js +82 -15
- package/dist/engine/database.d.ts +23 -14
- package/dist/engine/database.js +528 -79
- package/dist/engine/defaults.js +11 -0
- package/dist/engine/errors.d.ts +13 -0
- package/dist/engine/errors.js +22 -0
- package/dist/engine/fts.d.ts +2 -15
- package/dist/engine/live.d.ts +1 -7
- package/dist/engine/live.js +2 -12
- package/dist/engine/optimizer.d.ts +7 -0
- package/dist/engine/optimizer.js +1349 -76
- package/dist/engine/query.d.ts +11 -278
- package/dist/engine/query.js +178 -49
- package/dist/engine/schema-wire.d.ts +7 -1
- package/dist/engine/schema-wire.js +4 -0
- package/dist/engine/schema.d.ts +67 -33
- package/dist/engine/schema.js +138 -7
- package/dist/engine/sql-domains.d.ts +8 -0
- package/dist/engine/sql-domains.js +25 -0
- package/dist/engine/sql-json.js +22 -3
- package/dist/engine/vector.d.ts +2 -2
- package/dist/engine/vector.js +369 -43
- package/dist/engine/worker-host.js +119 -44
- package/dist/plan/index.d.ts +5 -4
- package/dist/plan/index.js +3 -3
- package/dist/plan/model.d.ts +224 -0
- package/dist/plan/model.js +1 -0
- package/dist/storage/types.d.ts +7 -0
- package/dist/storage/types.js +16 -0
- package/dist/transactions/index.d.ts +5 -3
- package/dist/transactions/index.js +58 -8
- package/dist/worker-protocol/index.d.ts +6 -1
- package/dist/worker-protocol/index.js +5 -2
- package/package.json +1 -1
- package/postgres-feature-profile.json +5 -0
- package/sql-feature-matrix.json +89 -21
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@ npm install @minnowdb/core
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
- Direct SQL through `MinnowDatabase.query()` and `execute()`.
|
|
11
|
-
- Joins, CTEs, window functions, grouping sets,
|
|
12
|
-
|
|
11
|
+
- Joins, CTEs, window functions, grouping sets, nested correlated subqueries, subquery-backed
|
|
12
|
+
mutations, upserts, `RETURNING`, triggers, exact decimals, nested JSON/JSONB, stored generated
|
|
13
|
+
columns, zoneless DATE, arrays, enums, sequences, and savepoints.
|
|
13
14
|
- Compressed column storage, secondary indexes, full-text search, and snapshot reads.
|
|
14
15
|
- Atomic writes across tabs through IndexedDB or OPFS, strict durability by default, and explicit
|
|
15
16
|
origin-eviction persistence policy.
|
package/dist/engine/catalog.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ColumnDefault, type SecondaryIndexState, type SimpleDataType, type SqlDomain, type TableRecord } from "../storage/types.js";
|
|
1
|
+
import { type ColumnDefault, type ColumnGenerated, type SecondaryIndexState, type SimpleDataType, type SqlDomain, type TableRecord } from "../storage/types.js";
|
|
2
2
|
/**
|
|
3
3
|
* The published shape of the catalog: everything a schema tool needs to diff a live database
|
|
4
4
|
* against a desired schema, without reading engine internals.
|
|
@@ -20,6 +20,8 @@ export interface CatalogColumn {
|
|
|
20
20
|
readonly nullable: boolean;
|
|
21
21
|
/** Filled for omitted or SQL DEFAULT insert slots; never applied at read time. */
|
|
22
22
|
readonly defaultValue?: ColumnDefault;
|
|
23
|
+
/** Stored expression maintained by the engine; callers cannot assign this column. */
|
|
24
|
+
readonly generatedValue?: ColumnGenerated;
|
|
23
25
|
/** String columns only: the closed set of values writes may draw from. */
|
|
24
26
|
readonly enumValues?: readonly string[];
|
|
25
27
|
/** Derived from the default spec, because a planner should not have to decode one. */
|
package/dist/engine/catalog.js
CHANGED
|
@@ -9,6 +9,7 @@ function toCatalogColumn(column) {
|
|
|
9
9
|
...(column.sqlDomain === undefined ? {} : { sqlDomain: structuredClone(column.sqlDomain) }),
|
|
10
10
|
nullable: column.nullable,
|
|
11
11
|
...(column.defaultValue === undefined ? {} : { defaultValue: column.defaultValue }),
|
|
12
|
+
...(column.generatedValue === undefined ? {} : { generatedValue: column.generatedValue }),
|
|
12
13
|
...(column.enumValues === undefined ? {} : { enumValues: [...column.enumValues] }),
|
|
13
14
|
...(column.backfill === undefined
|
|
14
15
|
? {}
|
package/dist/engine/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CompactionJobRecord, type GarbageCollectionJobRecord, type StorageIntegrityMode, type StorageIntegrityReport, type StorageStats, type InterruptedSnapshotImport, type InterruptedSnapshotImportAbortResult } from "../storage/types.js";
|
|
2
2
|
import { type BatchRow, type InsertBatchInput } from "./batch.js";
|
|
3
3
|
import type { Catalog } from "./catalog.js";
|
|
4
|
-
import type { BatchValue, BufferPoolStats, StagedWriteResult, BufferedFlushResult, BufferedWriterOptions, CancelCompactionJobResult, CollectGarbageOptions, CollectGarbageStepOptions, CompactTableOptions, CompactTableResult, CompactTableStepOptions, CompactionJobProgress, CreateTableInput, DatabaseRow, MigrateOptions, DeleteBatchInput, DeleteBatchResult, ExecuteResult, GarbageCollectionProgress, GarbageCollectionResult, MaintenanceStatus, InsertBatchResult, QueryOptions, QueryCursorOptions, QuerySpillCleanupOptions, QuerySpillCleanupResult, ReadTableOptions, RunStatementOptions, SnapshotExportOptions, SnapshotImportOptions, TableDefinition, UpdateBatchInput, UpdateBatchResult, UpsertBatchResult, UpsertOptions, VisibleSegmentPage, VisibleSegmentPageOptions } from "./database.js";
|
|
4
|
+
import type { BatchValue, BufferPoolStats, StagedWriteResult, BufferedFlushResult, BufferedWriterOptions, CancelCompactionJobResult, CollectGarbageOptions, CollectGarbageStepOptions, CompactTableOptions, CompactTableResult, CompactTableStepOptions, CompactionJobProgress, CreateTableInput, DatabaseRow, MigrateOptions, DeleteBatchInput, DeleteBatchResult, ExecuteResult, GarbageCollectionProgress, GarbageCollectionResult, MaintenanceStatus, InsertBatchResult, QueryOptions, QueryExecutionStats, QueryCursorOptions, QuerySpillCleanupOptions, QuerySpillCleanupResult, ReadTableOptions, RunStatementOptions, SnapshotExportOptions, SnapshotImportOptions, TableDefinition, UpdateBatchInput, UpdateBatchResult, UpsertBatchResult, UpsertOptions, VisibleSegmentPage, VisibleSegmentPageOptions } from "./database.js";
|
|
5
5
|
import type { LiveQueryInput, LiveQueryInvalidation, LiveQueryObserveOptions, LiveQueryStats, LiveQuerySubscribeOptions } from "./live.js";
|
|
6
6
|
import type { CompiledQuery, CompiledStatement, QueryResult, QueryValue } from "./query.js";
|
|
7
7
|
import type { AnyTable, SchemaDefinition } from "./schema.js";
|
|
@@ -65,6 +65,11 @@ interface EventRoute {
|
|
|
65
65
|
onComplete?: () => void;
|
|
66
66
|
/** Payload shape is the handle's own; only snapshot loads emit these today. */
|
|
67
67
|
onProgress?: (progress: unknown) => void;
|
|
68
|
+
onStats?: (stats: QueryExecutionStats) => void;
|
|
69
|
+
}
|
|
70
|
+
interface RpcCallControls {
|
|
71
|
+
signal?: AbortSignal | undefined;
|
|
72
|
+
onStats?: ((stats: QueryExecutionStats) => void) | undefined;
|
|
68
73
|
}
|
|
69
74
|
export declare class MinnowDatabaseClient {
|
|
70
75
|
#private;
|
|
@@ -72,6 +77,29 @@ export declare class MinnowDatabaseClient {
|
|
|
72
77
|
/** Resolves once the worker has opened the store and constructed the database. */
|
|
73
78
|
ready(): Promise<void>;
|
|
74
79
|
createTable(input: CreateTableInput): Promise<void>;
|
|
80
|
+
createView(name: string, sql: string, options?: {
|
|
81
|
+
orReplace?: boolean;
|
|
82
|
+
managed?: boolean;
|
|
83
|
+
}): Promise<void>;
|
|
84
|
+
dropView(name: string, options?: {
|
|
85
|
+
ifExists?: boolean;
|
|
86
|
+
}): Promise<boolean>;
|
|
87
|
+
dropColumn(tableName: string, columnName: string, options?: {
|
|
88
|
+
ifExists?: boolean;
|
|
89
|
+
}): Promise<boolean>;
|
|
90
|
+
dropTable(tableName: string, options?: {
|
|
91
|
+
ifExists?: boolean;
|
|
92
|
+
}): Promise<boolean>;
|
|
93
|
+
createIndex(indexName: string, tableName: string, requestedColumns: string | ReadonlyArray<{
|
|
94
|
+
name: string;
|
|
95
|
+
direction: "asc" | "desc";
|
|
96
|
+
}>, options?: {
|
|
97
|
+
unique?: boolean;
|
|
98
|
+
}): Promise<void>;
|
|
99
|
+
dropIndex(indexName: string, options?: {
|
|
100
|
+
ifExists?: boolean;
|
|
101
|
+
}): Promise<boolean>;
|
|
102
|
+
buildFtsIndex(tableName: string, columnName: string): Promise<void>;
|
|
75
103
|
/** The published catalog; see `MinnowDatabase.introspect()`. */
|
|
76
104
|
introspect(): Promise<Catalog>;
|
|
77
105
|
listTables(): Promise<TableDefinition[]>;
|
|
@@ -166,6 +194,8 @@ export declare class MinnowDatabaseClient {
|
|
|
166
194
|
/** @internal */
|
|
167
195
|
_invoke(handleId: string, method: string, args: unknown[]): Promise<unknown>;
|
|
168
196
|
/** @internal */
|
|
197
|
+
_invokeControlled(handleId: string, method: string, args: unknown[], controls: RpcCallControls): Promise<unknown>;
|
|
198
|
+
/** @internal */
|
|
169
199
|
_routeEvents(handleId: string, route: EventRoute): void;
|
|
170
200
|
/** @internal */
|
|
171
201
|
_unrouteEvents(handleId: string): void;
|
|
@@ -177,9 +207,7 @@ export declare class MinnowDatabaseClient {
|
|
|
177
207
|
/** The scope handed to the client `write()`; mirrors the in-worker WriteSession. */
|
|
178
208
|
export interface ClientWriteSession {
|
|
179
209
|
/** Read-your-writes: observes the pre-scope snapshot plus everything staged so far. */
|
|
180
|
-
query(sql: string, options?:
|
|
181
|
-
params?: QueryValue[];
|
|
182
|
-
}): Promise<QueryResult>;
|
|
210
|
+
query(sql: string, options?: QueryOptions): Promise<QueryResult>;
|
|
183
211
|
execute(sql: string, params?: readonly QueryValue[]): Promise<ExecuteResult>;
|
|
184
212
|
insertBatch(tableName: string, input: InsertBatchInput): Promise<StagedWriteResult>;
|
|
185
213
|
upsertBatch(tableName: string, input: InsertBatchInput): Promise<StagedWriteResult>;
|
package/dist/engine/client.js
CHANGED
|
@@ -2,7 +2,7 @@ import { BlockReadBatchTooLargeError, CompactionBacklogError, CompactionJobConfl
|
|
|
2
2
|
import { MAX_SNAPSHOT_STREAM_CHUNK_BYTES } from "../storage/snapshot.js";
|
|
3
3
|
import { parseRpcResponse, MAX_DATABASE_RPC_IN_FLIGHT, protocolVersion, } from "../worker-protocol/index.js";
|
|
4
4
|
import { toColumnarBatch } from "./batch.js";
|
|
5
|
-
import { CompactionJobCancelledError, CompactionMemoryBudgetError, CompactionWriteAmplificationError, MaintenanceBacklogError, MissingKeyError, SqlCompileError, UnknownTableError, UniqueConstraintError, VisibleSegmentCursorStaleError, } from "./errors.js";
|
|
5
|
+
import { CompactionJobCancelledError, CompactionMemoryBudgetError, CompactionWriteAmplificationError, MaintenanceBacklogError, DatabaseReadBacklogError, LiveQueryLimitError, MissingKeyError, SqlCompileError, UnknownTableError, UniqueConstraintError, VisibleSegmentCursorStaleError, } from "./errors.js";
|
|
6
6
|
import { QueryMemoryBudgetError } from "./memory.js";
|
|
7
7
|
import { decodeQueryResult } from "./result-wire.js";
|
|
8
8
|
import { serializeSchema } from "./schema-wire.js";
|
|
@@ -36,6 +36,8 @@ const errorRegistry = new Map([
|
|
|
36
36
|
CompactionWriteAmplificationError,
|
|
37
37
|
CompactionJobCancelledError,
|
|
38
38
|
MaintenanceBacklogError,
|
|
39
|
+
DatabaseReadBacklogError,
|
|
40
|
+
LiveQueryLimitError,
|
|
39
41
|
SqlCompileError,
|
|
40
42
|
QueryMemoryBudgetError,
|
|
41
43
|
VisibleSegmentCursorStaleError,
|
|
@@ -142,6 +144,27 @@ export class MinnowDatabaseClient {
|
|
|
142
144
|
async createTable(input) {
|
|
143
145
|
await this.#call("createTable", [input]);
|
|
144
146
|
}
|
|
147
|
+
async createView(name, sql, options = {}) {
|
|
148
|
+
await this.#call("createView", [name, sql, options]);
|
|
149
|
+
}
|
|
150
|
+
async dropView(name, options = {}) {
|
|
151
|
+
return (await this.#call("dropView", [name, options]));
|
|
152
|
+
}
|
|
153
|
+
async dropColumn(tableName, columnName, options = {}) {
|
|
154
|
+
return (await this.#call("dropColumn", [tableName, columnName, options]));
|
|
155
|
+
}
|
|
156
|
+
async dropTable(tableName, options = {}) {
|
|
157
|
+
return (await this.#call("dropTable", [tableName, options]));
|
|
158
|
+
}
|
|
159
|
+
async createIndex(indexName, tableName, requestedColumns, options = {}) {
|
|
160
|
+
await this.#call("createIndex", [indexName, tableName, requestedColumns, options]);
|
|
161
|
+
}
|
|
162
|
+
async dropIndex(indexName, options = {}) {
|
|
163
|
+
return (await this.#call("dropIndex", [indexName, options]));
|
|
164
|
+
}
|
|
165
|
+
async buildFtsIndex(tableName, columnName) {
|
|
166
|
+
await this.#call("buildFtsIndex", [tableName, columnName]);
|
|
167
|
+
}
|
|
145
168
|
/** The published catalog; see `MinnowDatabase.introspect()`. */
|
|
146
169
|
async introspect() {
|
|
147
170
|
return (await this.#call("introspect", []));
|
|
@@ -201,17 +224,17 @@ export class MinnowDatabaseClient {
|
|
|
201
224
|
* datetimes) and are rebuilt into row objects here; see `result-wire.ts`.
|
|
202
225
|
*/
|
|
203
226
|
async query(sql, options) {
|
|
204
|
-
|
|
227
|
+
const { signal, onStats, ...wireOptions } = options ?? {};
|
|
228
|
+
return decodeQueryResult(await this.#call("query", [sql, wireOptions, onStats !== undefined], { signal, onStats }));
|
|
205
229
|
}
|
|
206
230
|
/** Pulls one transferred columnar page at a time, preserving worker backpressure. */
|
|
207
231
|
queryCursor(sql, options = {}) {
|
|
208
232
|
const call = this.#call.bind(this);
|
|
209
233
|
const invoke = this._invoke.bind(this);
|
|
234
|
+
const routeEvents = this._routeEvents.bind(this);
|
|
235
|
+
const unrouteEvents = this._unrouteEvents.bind(this);
|
|
210
236
|
const handleId = crypto.randomUUID();
|
|
211
237
|
const { signal, onStats, ...wireOptions } = options;
|
|
212
|
-
if (onStats !== undefined) {
|
|
213
|
-
throw new TypeError("Query cursor onStats callbacks are not available across a worker");
|
|
214
|
-
}
|
|
215
238
|
async function* batches() {
|
|
216
239
|
let opened = false;
|
|
217
240
|
let closing;
|
|
@@ -225,9 +248,11 @@ export class MinnowDatabaseClient {
|
|
|
225
248
|
void close();
|
|
226
249
|
};
|
|
227
250
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
251
|
+
if (onStats !== undefined)
|
|
252
|
+
routeEvents(handleId, { onStats });
|
|
228
253
|
try {
|
|
229
254
|
signal?.throwIfAborted();
|
|
230
|
-
await call("queryCursorOpen", [handleId, sql, wireOptions]);
|
|
255
|
+
await call("queryCursorOpen", [handleId, sql, wireOptions, onStats !== undefined]);
|
|
231
256
|
opened = true;
|
|
232
257
|
if (signal?.aborted === true) {
|
|
233
258
|
await close();
|
|
@@ -243,6 +268,7 @@ export class MinnowDatabaseClient {
|
|
|
243
268
|
finally {
|
|
244
269
|
signal?.removeEventListener("abort", onAbort);
|
|
245
270
|
await close();
|
|
271
|
+
unrouteEvents(handleId);
|
|
246
272
|
}
|
|
247
273
|
}
|
|
248
274
|
return batches();
|
|
@@ -291,7 +317,10 @@ export class MinnowDatabaseClient {
|
|
|
291
317
|
const opened = (await this.#call("writeOpen", []));
|
|
292
318
|
const stage = (op, tableName, input) => this._invoke(opened.handleId, "stage", [op, tableName, input]);
|
|
293
319
|
const session = {
|
|
294
|
-
query: async (sql, options) =>
|
|
320
|
+
query: async (sql, options = {}) => {
|
|
321
|
+
const { signal, onStats, ...wireOptions } = options;
|
|
322
|
+
return decodeQueryResult(await this._invokeControlled(opened.handleId, "query", [sql, wireOptions, onStats !== undefined], { signal, onStats }));
|
|
323
|
+
},
|
|
295
324
|
execute: (sql, params) => this._invoke(opened.handleId, "execute", params === undefined ? [sql] : [sql, params]),
|
|
296
325
|
insertBatch: (tableName, input) => stage("insertBatch", tableName, input),
|
|
297
326
|
upsertBatch: (tableName, input) => stage("upsertBatch", tableName, input),
|
|
@@ -502,6 +531,12 @@ export class MinnowDatabaseClient {
|
|
|
502
531
|
return this.#post("rpc-call", handleId, method, args);
|
|
503
532
|
}
|
|
504
533
|
/** @internal */
|
|
534
|
+
async _invokeControlled(handleId, method, args, controls) {
|
|
535
|
+
if (this.#closed)
|
|
536
|
+
throw new Error("Database client is closed");
|
|
537
|
+
return this.#post("rpc-call", handleId, method, args, undefined, false, controls);
|
|
538
|
+
}
|
|
539
|
+
/** @internal */
|
|
505
540
|
_routeEvents(handleId, route) {
|
|
506
541
|
this.#events.set(handleId, route);
|
|
507
542
|
}
|
|
@@ -509,23 +544,49 @@ export class MinnowDatabaseClient {
|
|
|
509
544
|
_unrouteEvents(handleId) {
|
|
510
545
|
this.#events.delete(handleId);
|
|
511
546
|
}
|
|
512
|
-
async #call(method, args) {
|
|
547
|
+
async #call(method, args, controls = {}) {
|
|
513
548
|
if (this.#closed)
|
|
514
549
|
throw new Error("Database client is closed");
|
|
515
|
-
return this.#post("rpc-call", null, method, args);
|
|
550
|
+
return this.#post("rpc-call", null, method, args, undefined, false, controls);
|
|
516
551
|
}
|
|
517
|
-
async #post(kind, handleId, method, args, transfer, bypassLimit = kind === "rpc-init" || method === "dispose") {
|
|
552
|
+
async #post(kind, handleId, method, args, transfer, bypassLimit = kind === "rpc-init" || method === "dispose", controls = {}) {
|
|
518
553
|
if (this.#fatal !== undefined)
|
|
519
554
|
throw this.#fatal;
|
|
555
|
+
controls.signal?.throwIfAborted();
|
|
520
556
|
if (!bypassLimit && this.#pending.size >= MAX_DATABASE_RPC_IN_FLIGHT) {
|
|
521
557
|
throw new RangeError(`A database worker connection cannot hold more than ${String(MAX_DATABASE_RPC_IN_FLIGHT)} in-flight requests`);
|
|
522
558
|
}
|
|
523
559
|
const requestId = crypto.randomUUID();
|
|
524
560
|
return new Promise((resolve, reject) => {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
561
|
+
const onAbort = () => {
|
|
562
|
+
try {
|
|
563
|
+
this.#transport.postMessage({ version: protocolVersion, requestId, kind: "rpc-cancel" });
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
// The original RPC still owns completion. A transport failure also reaches #fail via
|
|
567
|
+
// its error event; throwing from an AbortSignal listener would only be unhandled noise.
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
const cleanup = () => {
|
|
571
|
+
controls.signal?.removeEventListener("abort", onAbort);
|
|
572
|
+
if (controls.onStats !== undefined)
|
|
573
|
+
this.#events.delete(requestId);
|
|
574
|
+
};
|
|
575
|
+
controls.signal?.addEventListener("abort", onAbort, { once: true });
|
|
576
|
+
if (controls.onStats !== undefined) {
|
|
577
|
+
this.#events.set(requestId, { onStats: controls.onStats });
|
|
578
|
+
}
|
|
579
|
+
this.#pending.set(requestId, { resolve, reject, cleanup });
|
|
580
|
+
try {
|
|
581
|
+
this.#transport.postMessage(kind === "rpc-init"
|
|
582
|
+
? { version: protocolVersion, requestId, kind, payload: args[0] }
|
|
583
|
+
: { version: protocolVersion, requestId, kind, handleId, method, args }, transfer === undefined ? undefined : { transfer });
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
this.#pending.delete(requestId);
|
|
587
|
+
cleanup();
|
|
588
|
+
reject(error instanceof Error ? error : new Error("Database request failed", { cause: error }));
|
|
589
|
+
}
|
|
529
590
|
});
|
|
530
591
|
}
|
|
531
592
|
#receive(message) {
|
|
@@ -546,6 +607,9 @@ export class MinnowDatabaseClient {
|
|
|
546
607
|
}
|
|
547
608
|
else if (response.event === "progress")
|
|
548
609
|
route.onProgress?.(response.payload);
|
|
610
|
+
else if (response.event === "stats") {
|
|
611
|
+
route.onStats?.(response.payload);
|
|
612
|
+
}
|
|
549
613
|
else if (response.event === "complete") {
|
|
550
614
|
this.#events.delete(response.handleId);
|
|
551
615
|
route.onComplete?.();
|
|
@@ -556,6 +620,7 @@ export class MinnowDatabaseClient {
|
|
|
556
620
|
if (pending === undefined)
|
|
557
621
|
return;
|
|
558
622
|
this.#pending.delete(response.requestId);
|
|
623
|
+
pending.cleanup?.();
|
|
559
624
|
if (response.kind === "rpc-result")
|
|
560
625
|
pending.resolve(response.result);
|
|
561
626
|
else
|
|
@@ -566,8 +631,10 @@ export class MinnowDatabaseClient {
|
|
|
566
631
|
const pending = [...this.#pending.values()];
|
|
567
632
|
this.#pending.clear();
|
|
568
633
|
this.#events.clear();
|
|
569
|
-
for (const call of pending)
|
|
634
|
+
for (const call of pending) {
|
|
635
|
+
call.cleanup?.();
|
|
570
636
|
call.reject(error);
|
|
637
|
+
}
|
|
571
638
|
}
|
|
572
639
|
}
|
|
573
640
|
/**
|
|
@@ -2,8 +2,9 @@ import { type BatchRow, type BatchValue, type InsertBatchInput } from "./batch.j
|
|
|
2
2
|
import { BufferedTableWriter, type BufferedWriterOptions } from "./buffered-writer.js";
|
|
3
3
|
export { attachLifecycleFlush, BufferedTableWriter, MAX_BUFFERED_WRITER_PENDING_ADDS, type BufferedFlushResult, type BufferedWriterOptions, type LifecycleDocumentTarget, type LifecycleFlushOptions, type LifecycleFlushRequester, type LifecyclePageTarget, } from "./buffered-writer.js";
|
|
4
4
|
import { CompactionJobCancelledError, CompactionMemoryBudgetError, CompactionWriteAmplificationError, MaintenanceBacklogError, MissingKeyError, SqlCompileError, UnknownTableError, UniqueConstraintError, VisibleSegmentCursorStaleError } from "./errors.js";
|
|
5
|
+
export { DatabaseReadBacklogError } from "./errors.js";
|
|
5
6
|
import { type Compression } from "../block-format/index.js";
|
|
6
|
-
import { type BlockStore, type ColumnDefault, CompactionBacklogError, type CompactionJobRecord, type CompactionJobState, type GarbageCollectionJobRecord, type GarbageCollectionJobState, type SimpleDataType, type SqlDomain, type StorageIntegrityMode, type StorageIntegrityReport, type StorageStats, type InterruptedSnapshotImport, type InterruptedSnapshotImportAbortResult, TableInUseError } from "../storage/types.js";
|
|
7
|
+
import { type BlockStore, type ColumnDefault, type ColumnGenerated, CompactionBacklogError, type CompactionJobRecord, type CompactionJobState, type GarbageCollectionJobRecord, type GarbageCollectionJobState, type SimpleDataType, type SqlDomain, type StorageIntegrityMode, type StorageIntegrityReport, type StorageStats, type InterruptedSnapshotImport, type InterruptedSnapshotImportAbortResult, TableInUseError } from "../storage/types.js";
|
|
7
8
|
import type { SnapshotExportProgress, SnapshotLoadProgress } from "../storage/snapshot.js";
|
|
8
9
|
import { type ComparisonOperator, type CompiledQuery, type CompiledStatement, type ForeignKeyDefinition, type QueryResult, type QueryRow, type QueryValue, type UniqueConstraintDefinition } from "./query.js";
|
|
9
10
|
import { LiveQuerySet, type LiveQuerySetOptions } from "./live.js";
|
|
@@ -16,11 +17,6 @@ export declare const MAX_TRANSACTION_SAVEPOINT_BYTES: number;
|
|
|
16
17
|
export declare const MAX_DATABASE_PENDING_WRITES = 64;
|
|
17
18
|
/** Concurrent direct reads retained by one database instance. Reads still execute in parallel. */
|
|
18
19
|
export declare const MAX_DATABASE_ACTIVE_READS = 256;
|
|
19
|
-
export declare class DatabaseReadBacklogError extends Error {
|
|
20
|
-
readonly limit: number;
|
|
21
|
-
readonly name = "DatabaseReadBacklogError";
|
|
22
|
-
constructor(limit?: number);
|
|
23
|
-
}
|
|
24
20
|
export interface ColumnDefinition {
|
|
25
21
|
name: string;
|
|
26
22
|
type: SimpleDataType;
|
|
@@ -31,6 +27,8 @@ export interface ColumnDefinition {
|
|
|
31
27
|
nullable?: boolean;
|
|
32
28
|
/** Fills omitted or SQL DEFAULT slots at insert time; never applied at read time. */
|
|
33
29
|
defaultValue?: ColumnDefault;
|
|
30
|
+
/** Stored expression over sibling columns; callers cannot assign this column. */
|
|
31
|
+
generatedValue?: ColumnGenerated;
|
|
34
32
|
/** String columns only: the closed set of values writes must draw from. */
|
|
35
33
|
enumValues?: readonly string[];
|
|
36
34
|
/** What rows written before this column existed read as, instead of NULL. */
|
|
@@ -125,6 +123,8 @@ export interface UpdateBatchResult {
|
|
|
125
123
|
storedBytes: number;
|
|
126
124
|
version: number;
|
|
127
125
|
metrics: WriteMetrics;
|
|
126
|
+
/** Recomputed generated-column vectors in input key order. */
|
|
127
|
+
generatedColumns?: Record<string, BatchValue[]>;
|
|
128
128
|
}
|
|
129
129
|
export interface WriteMetrics {
|
|
130
130
|
logicalBytes: number;
|
|
@@ -230,6 +230,11 @@ export interface MaintenanceStatus {
|
|
|
230
230
|
} | null;
|
|
231
231
|
}
|
|
232
232
|
export interface QueryOptions {
|
|
233
|
+
/**
|
|
234
|
+
* Stops a read between bounded execution or storage batches. An abort never returns a partial
|
|
235
|
+
* result and releases any reader lease and temporary spill owner before the promise rejects.
|
|
236
|
+
*/
|
|
237
|
+
readonly signal?: AbortSignal;
|
|
233
238
|
/**
|
|
234
239
|
* Called once with what this execution cost, before the result is returned. Additive and
|
|
235
240
|
* optional: the engine can report its own memory because it reserves before it allocates,
|
|
@@ -268,8 +273,6 @@ export interface QueryOptions {
|
|
|
268
273
|
export interface QueryCursorOptions extends QueryOptions {
|
|
269
274
|
/** Maximum rows in one yielded result batch. Defaults to the vector scan batch size. */
|
|
270
275
|
readonly batchRows?: number;
|
|
271
|
-
/** Cancels the scan and releases its snapshot lease. */
|
|
272
|
-
readonly signal?: AbortSignal;
|
|
273
276
|
}
|
|
274
277
|
export interface DeleteBatchInput {
|
|
275
278
|
/** Stable ordinary array; do not mutate or expose changing accessors until the write settles. */
|
|
@@ -584,26 +587,30 @@ export type ExecuteResult = {
|
|
|
584
587
|
} | {
|
|
585
588
|
kind: "drop-trigger";
|
|
586
589
|
name: string;
|
|
587
|
-
} | {
|
|
590
|
+
} | ({
|
|
588
591
|
kind: "insert";
|
|
589
592
|
table: string;
|
|
590
593
|
rowCount: number;
|
|
591
594
|
/** Absent when the statement affected no rows (an INSERT ... SELECT of an empty set). */
|
|
592
595
|
version?: number;
|
|
593
|
-
|
|
594
|
-
} | {
|
|
596
|
+
} & ReturningExecuteFields) | ({
|
|
595
597
|
kind: "update";
|
|
596
598
|
table: string;
|
|
597
599
|
rowCount: number;
|
|
598
600
|
version?: number;
|
|
599
|
-
|
|
600
|
-
} | {
|
|
601
|
+
} & ReturningExecuteFields) | ({
|
|
601
602
|
kind: "delete";
|
|
602
603
|
table: string;
|
|
603
604
|
rowCount: number;
|
|
604
605
|
version?: number | null;
|
|
606
|
+
} & ReturningExecuteFields);
|
|
607
|
+
interface ReturningExecuteFields {
|
|
605
608
|
returnedRows?: QueryRow[];
|
|
606
|
-
|
|
609
|
+
/** RETURNING projection order; present with returnedRows, including for an empty result. */
|
|
610
|
+
returnedColumns?: string[];
|
|
611
|
+
/** Logical domains aligned with returnedColumns. */
|
|
612
|
+
returnedColumnDomains?: Array<SqlDomain | null>;
|
|
613
|
+
}
|
|
607
614
|
export interface RunStatementOptions {
|
|
608
615
|
/**
|
|
609
616
|
* Projects the affected rows back: column names, or "*" for every table column. Inserts echo
|
|
@@ -740,6 +747,8 @@ export declare class MinnowDatabase {
|
|
|
740
747
|
upsert(tableName: string, row: BatchRow, options?: UpsertOptions): Promise<UpsertBatchResult>;
|
|
741
748
|
updateBatch(tableName: string, input: UpdateBatchInput): Promise<UpdateBatchResult>;
|
|
742
749
|
update(tableName: string, key: Exclude<BatchValue, null>, changes: Readonly<Record<string, BatchValue>>): Promise<UpdateBatchResult>;
|
|
750
|
+
/** Deletes one row by the table's unique key. */
|
|
751
|
+
delete(tableName: string, key: Exclude<BatchValue, null>): Promise<DeleteBatchResult>;
|
|
743
752
|
deleteBatch(tableName: string, input: DeleteBatchInput): Promise<DeleteBatchResult>;
|
|
744
753
|
bufferedWriter(tableName: string, options?: BufferedWriterOptions): BufferedTableWriter;
|
|
745
754
|
readTable(tableName: string, versionOrOptions?: number | ReadTableOptions): Promise<DatabaseRow[]>;
|