@visorcraft/mongreldb 0.18.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/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # mongreldb-node
2
+
3
+ Native Node.js addon for MongrelDB via [NAPI](https://napi.rs) — the
4
+ **better-sqlite3 model**: in-process, no HTTP latency, so the ~6 µs single-row
5
+ write isn't dwarfed by a network round-trip. Exposes a **typed object/method
6
+ interface** (not SQL); TypeScript types are generated at build time.
7
+
8
+ This crate is built **separately** from the Rust workspace (it targets the NAPI
9
+ ABI and needs Node.js tooling). It is excluded from `cargo {test,clippy}
10
+ --workspace`.
11
+
12
+ ## Build
13
+
14
+ Requires Node.js ≥ 16 and `@napi-rs/cli`:
15
+
16
+ ```bash
17
+ cd crates/mongreldb-node
18
+ npm install
19
+ npm run build # → mongreldb.<platform>.node + index.d.ts
20
+ ```
21
+
22
+ ## API sketch (generated `index.d.ts`)
23
+
24
+ ```ts
25
+ class Database {
26
+ static withPath(path: string): Database
27
+ static open(path: string): Database
28
+ createTable(name: string, schema: SchemaSpec): bigint
29
+ table(name: string): TableHandle
30
+ begin(): Transaction
31
+ sql(sql: string): Promise<Buffer>
32
+ close(): void
33
+ }
34
+
35
+ class TableHandle {
36
+ put(cells: Cell[]): PutResult
37
+ putBatch(rows: Cell[][]): PutResult[]
38
+ bulkLoadTyped(columns: TypedColumn[]): bigint
39
+ commit(): bigint
40
+ flush(): bigint
41
+ count(): bigint // O(1)
42
+ countWhere(conditions: ConditionSpec[]): bigint
43
+ get(rowId: bigint): RowJs | null
44
+ query(conditions: ConditionSpec[]): RowJs[] // hybrid: bitmap ∩ range ∩ FM ∩ HNSW
45
+ queryArrow(conditions: ConditionSpec[]): Buffer
46
+ }
47
+ ```
48
+
49
+ ### Hybrid query — the differentiator
50
+
51
+ `query` intersects row-id sets from any combination of the six index types in a
52
+ single in-process call — something no HTTP vector DB or SQL FTS pipeline can do
53
+ in one hop:
54
+
55
+ ```ts
56
+ db.query([
57
+ { kind: ConditionKind.Ann, columnId: 5, embedding: queryVec, k: 50 },
58
+ { kind: ConditionKind.FmContains, columnId: 2, text: "rome" },
59
+ { kind: ConditionKind.BitmapIn, columnId: 3, values: ["eu", "na"] },
60
+ ])
61
+ ```
62
+
63
+ ## Notes
64
+
65
+ - Row ids / counts / epochs cross the FFI as JS `BigInt` (`u64`), so the full
66
+ 64-bit id space is lossless.
67
+ - Most blocking table methods also expose `*Async` Promise variants that run on
68
+ the NAPI blocking pool.
package/index.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ /* Hand-written wrapper around the NAPI-generated native.d.ts binding.
2
+ * Adds a retryable `Database.prototype.transaction` helper and the
3
+ * `ConflictError` class.
4
+ */
5
+
6
+ export * from './native';
7
+
8
+ /** Retryable write-write conflict. */
9
+ export declare class ConflictError extends Error {
10
+ constructor(message: string);
11
+ }
12
+
13
+ /** Callback used by `Database.prototype.transaction`. */
14
+ export type TransactionCallback = (txn: import('./native').Transaction) => void | Promise<void>;
15
+
16
+ /** Options for `Database.prototype.transaction`. */
17
+ export interface TransactionOptions {
18
+ /** Maximum number of conflict retries before giving up. Default: 3. */
19
+ maxRetries?: number;
20
+ /** Base backoff delay in milliseconds. Default: 2. */
21
+ baseDelayMs?: number;
22
+ }
23
+
24
+ export declare class Database extends import('./native').Database {
25
+ /**
26
+ * Run `fn(txn)` inside a cross-table transaction, retrying on conflict.
27
+ * `fn` may be sync or async; it must stage operations on `txn` but must not
28
+ * call `commit`/`rollback` itself.
29
+ */
30
+ transaction(fn: TransactionCallback, opts?: TransactionOptions): Promise<bigint>;
31
+ }
package/index.js ADDED
@@ -0,0 +1,70 @@
1
+ /* eslint-disable */
2
+ /* Hand-written wrapper around the NAPI-generated native.js binding.
3
+ * Adds a retryable `Database.prototype.transaction` helper and exports the
4
+ * `ConflictError` class so callers can distinguish retryable write conflicts.
5
+ */
6
+
7
+ const native = require('./native.js');
8
+
9
+ /** Retryable write-write conflict. */
10
+ class ConflictError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = 'ConflictError';
14
+ }
15
+ }
16
+
17
+ const CONFLICT_RE = /^__CONFLICT__:/;
18
+
19
+ function isConflict(err) {
20
+ return err != null && typeof err.message === 'string' && CONFLICT_RE.test(err.message);
21
+ }
22
+
23
+ /** Database wrapper that adds a `transaction(fn, opts?)` retry helper. */
24
+ class Database extends native.Database {
25
+ /**
26
+ * Run `fn(txn)` inside a cross-table transaction, retrying on conflict.
27
+ * `fn` may be sync or async; it must stage operations on `txn` but must not
28
+ * call `commit`/`rollback` itself.
29
+ */
30
+ transaction(fn, opts = {}) {
31
+ const maxRetries = opts.maxRetries ?? 3;
32
+ const baseDelayMs = opts.baseDelayMs ?? 2;
33
+
34
+ const runOnce = async () => {
35
+ const txn = this.begin();
36
+ try {
37
+ await fn(txn);
38
+ return txn.commit();
39
+ } catch (err) {
40
+ try {
41
+ txn.rollback();
42
+ } catch (_) {
43
+ // ignore rollback errors
44
+ }
45
+ throw err;
46
+ }
47
+ };
48
+
49
+ const attempt = async (retriesLeft) => {
50
+ try {
51
+ return await runOnce();
52
+ } catch (err) {
53
+ if (retriesLeft > 0 && isConflict(err)) {
54
+ const delay = baseDelayMs * (maxRetries - retriesLeft + 1);
55
+ await new Promise((resolve) => setTimeout(resolve, delay));
56
+ return attempt(retriesLeft - 1);
57
+ }
58
+ throw err;
59
+ }
60
+ };
61
+
62
+ return attempt(maxRetries);
63
+ }
64
+ }
65
+
66
+ module.exports = {
67
+ ...native,
68
+ Database,
69
+ ConflictError,
70
+ };
Binary file
package/native.d.ts ADDED
@@ -0,0 +1,426 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ export const enum ColumnType {
7
+ Bool = 0,
8
+ Int64 = 1,
9
+ Float64 = 2,
10
+ TimestampNanos = 3,
11
+ Date32 = 4,
12
+ Bytes = 5,
13
+ Embedding = 6
14
+ }
15
+ export const enum IndexKindSpec {
16
+ Bitmap = 0,
17
+ FmIndex = 1,
18
+ Ann = 2,
19
+ Sparse = 3,
20
+ MinHash = 4
21
+ }
22
+ export interface ColumnSpec {
23
+ id: number
24
+ name: string
25
+ ty: ColumnType
26
+ primaryKey: boolean
27
+ nullable: boolean
28
+ /** Required when `ty == Embedding`. */
29
+ embeddingDim?: number
30
+ /**
31
+ * Optional default value for schema-evolution back-fill. Currently only
32
+ * validated; applying defaults to existing rows is not yet implemented.
33
+ */
34
+ defaultValue?: Cell
35
+ /**
36
+ * Engine-managed monotonic identity allocator for an `Int64` primary key.
37
+ * When `true`, the engine assigns the next counter value on insert if the
38
+ * column is omitted/null, and explicit ids advance the counter past them.
39
+ * Mutually exclusive with `nullable`; requires `primary_key` and `Int64`.
40
+ * Defaults to `false` (omitted/null).
41
+ */
42
+ autoIncrement?: boolean
43
+ /** Encrypt this column's page payload at rest (requires an encrypted db). */
44
+ encrypted?: boolean
45
+ /**
46
+ * Encrypt the column but keep it queryable via deterministic equality
47
+ * tokens / order-preserving encoding (requires an encrypted db).
48
+ */
49
+ encryptedIndexable?: boolean
50
+ }
51
+ export interface IndexSpec {
52
+ name: string
53
+ columnId: number
54
+ kind: IndexKindSpec
55
+ }
56
+ export interface SchemaSpec {
57
+ columns: Array<ColumnSpec>
58
+ indexes: Array<IndexSpec>
59
+ }
60
+ /**
61
+ * A single cell value. Only the field matching the column type is read; the
62
+ * rest are ignored. `bytes` is raw; `text` is UTF-8 (use for `Bytes` columns
63
+ * when the value is a string).
64
+ */
65
+ export interface Cell {
66
+ columnId: number
67
+ int64?: bigint
68
+ float64?: number
69
+ boolean?: boolean
70
+ text?: string
71
+ bytes?: Buffer
72
+ embedding?: Array<number>
73
+ /**
74
+ * Sparse (SPLADE) token ids, paired with `sparse_weights`; bincoded into a
75
+ * Bytes value for a `Sparse` column on insert.
76
+ */
77
+ sparseTokens?: Array<number>
78
+ sparseWeights?: Array<number>
79
+ }
80
+ export const enum ConditionKind {
81
+ Pk = 0,
82
+ BitmapEq = 1,
83
+ RangeInt = 2,
84
+ RangeF64 = 3,
85
+ FmContains = 4,
86
+ Ann = 5,
87
+ PkInt64 = 6,
88
+ BitmapIn = 7,
89
+ IsNull = 8,
90
+ IsNotNull = 9,
91
+ FmContainsAll = 10,
92
+ SparseMatch = 11,
93
+ MinHashSimilar = 12
94
+ }
95
+ /**
96
+ * One predicate over the shared row-id space. Set the fields appropriate to
97
+ * `kind`; unused fields are ignored. A `query` takes a conjunction (AND) of
98
+ * these — the differentiator no SQL FTS pipeline can match.
99
+ */
100
+ export interface ConditionSpec {
101
+ kind: ConditionKind
102
+ columnId: number
103
+ int64Lo?: bigint
104
+ int64Hi?: bigint
105
+ float64Lo?: number
106
+ float64Hi?: number
107
+ text?: string
108
+ values?: Array<string>
109
+ embedding?: Array<number>
110
+ k?: number
111
+ /** SparseMatch query token ids (paired with `sparse_weights`). */
112
+ sparseTokens?: Array<number>
113
+ /** SparseMatch query token weights (paired with `sparse_tokens`). */
114
+ sparseWeights?: Array<number>
115
+ }
116
+ export interface RowJs {
117
+ rowId: bigint
118
+ cells: Array<Cell>
119
+ }
120
+ export interface OwnedRowJs {
121
+ cells: Array<Cell>
122
+ }
123
+ export interface UpsertResultJs {
124
+ action: string
125
+ row: OwnedRowJs
126
+ autoInc?: bigint
127
+ }
128
+ export interface RowUpdateJs {
129
+ rowId: bigint
130
+ cells: Array<Cell>
131
+ }
132
+ export interface TxnOpResultJs {
133
+ kind: string
134
+ autoInc?: bigint
135
+ row?: OwnedRowJs
136
+ rows?: Array<OwnedRowJs>
137
+ upsert?: UpsertResultJs
138
+ }
139
+ export interface CommitResultJs {
140
+ epoch: bigint
141
+ results: Array<TxnOpResultJs>
142
+ }
143
+ /**
144
+ * Result of an insert: the physical row id plus, when the engine allocated
145
+ * it, the `AUTO_INCREMENT` value written into the row.
146
+ */
147
+ export interface PutResult {
148
+ /** The storage row id (stable physical identity). */
149
+ rowId: bigint
150
+ /**
151
+ * The engine-assigned `AUTO_INCREMENT` value, when the column was omitted
152
+ * or null and the engine filled it. `null` for tables without an
153
+ * auto-increment column, or when the caller supplied an explicit value.
154
+ */
155
+ autoInc?: bigint
156
+ }
157
+ /** Phase 20.2: a typed column for bulk loading, wrapping JS typed-array data. */
158
+ export interface TypedColumn {
159
+ columnId: number
160
+ ty: ColumnType
161
+ /** Raw data bytes (Int64 = N×8 LE, Float64 = N×8 LE, Bytes = N+1 offsets + values). */
162
+ data: Buffer
163
+ /** Optional validity bitmap (1 byte per row, 1=non-null). */
164
+ validity?: Buffer
165
+ }
166
+ /**
167
+ * An open MongrelDB multi-table database. Each table is accessible via
168
+ * `table(name)`; SQL queries via `sql()`.
169
+ */
170
+ export declare class Database {
171
+ /** Create a fresh database at `path`. */
172
+ static withPath(path: string): Database
173
+ /** Open an existing database from disk. */
174
+ static open(path: string): Database
175
+ /** Create a new table with the given schema. */
176
+ createTable(name: string, schema: SchemaSpec): bigint
177
+ /** Drop a table by name. */
178
+ dropTable(name: string): void
179
+ /**
180
+ * Rename a live table. Fails if `name` does not exist, if `new_name` is
181
+ * empty, or if `new_name` is already in use. A no-op when `name == new_name`.
182
+ */
183
+ renameTable(name: string, newName: string): void
184
+ /** Get a handle to a table by name for typed put/get/query operations. */
185
+ getTable(name: string): TableHandle
186
+ /** Alias for [`Database::get_table`] matching the spec's `database.table(name)`. */
187
+ table(name: string): TableHandle
188
+ /** Begin a cross-table transaction (stage puts/deletes, then `commit`). */
189
+ begin(): Transaction
190
+ /** The current reader-visible epoch — the database-wide snapshot point. */
191
+ snapshotEpoch(): bigint
192
+ /** List all live table names. */
193
+ tableNames(): Array<string>
194
+ /**
195
+ * Return the column names of a table as it exists in the **database**
196
+ * (not the code-defined schema). Lets migrations check whether a column
197
+ * is already present before calling `add_column`.
198
+ */
199
+ tableColumns(name: string): Array<string>
200
+ /**
201
+ * Add a column to an existing table. The column must be nullable or supply
202
+ * a default value so existing rows can be evolved safely.
203
+ */
204
+ addColumn(table: string, column: ColumnSpec): bigint
205
+ /**
206
+ * Alter an existing column's native schema metadata. The source column is
207
+ * selected by `column_name`; the supplied column spec provides the target
208
+ * name, storage type, and flags while the stable engine column id is kept.
209
+ */
210
+ alterColumn(table: string, columnName: string, column: ColumnSpec): bigint
211
+ /** Verify database integrity. Returns a JSON-string summary. */
212
+ check(): string
213
+ /** Repair/quarantine corrupt tables. Returns a JSON-string summary. */
214
+ doctor(): string
215
+ /** Return the path passed to `withPath` / `open`. */
216
+ directory(): string
217
+ /** Run a cross-table SQL query. Returns Arrow IPC bytes. */
218
+ sql(sql: string): Promise<Buffer>
219
+ /** Flush + release. Optional — the `Database` also drops on GC. */
220
+ close(): void
221
+ /**
222
+ * Create a fresh encrypted database (page-level AES-256-GCM; the database
223
+ * KEK is derived from `passphrase` via Argon2id + HKDF).
224
+ */
225
+ static createEncrypted(path: string, passphrase: string): Database
226
+ /** Open an existing encrypted database with its passphrase. */
227
+ static openEncrypted(path: string, passphrase: string): Database
228
+ }
229
+ /** A handle to one table inside a [`Database`]. */
230
+ export declare class TableHandle {
231
+ /**
232
+ * Upsert one row. Returns the row id and, when the engine allocated it,
233
+ * the `AUTO_INCREMENT` value.
234
+ */
235
+ put(cells: Array<Cell>): PutResult
236
+ /** Group-commit this table's pending writes. */
237
+ commit(): bigint
238
+ /** Flush: commit + drain memtable to a sorted run. */
239
+ flush(): bigint
240
+ /** Live row count (O(1)). */
241
+ count(): bigint
242
+ /** Count rows matching a native conjunctive predicate without materializing rows when possible. */
243
+ countWhere(conditions: Array<ConditionSpec>): bigint
244
+ /** Point read by row id. */
245
+ get(rowId: bigint): RowJs | null
246
+ /** Point read by a text primary key. */
247
+ getByPkText(text: string): RowJs | null
248
+ /**
249
+ * Reserve (without inserting) the next `AUTO_INCREMENT` value for this
250
+ * table, advancing the engine's in-memory counter. Returns `null` if the
251
+ * table has no auto-increment column. Used by callers that stage a row with
252
+ * an explicit id inside a transaction; the reservation becomes durable when
253
+ * a row carrying the id commits, and a never-used reservation just leaves a
254
+ * gap. Far cheaper than a Kit-style sequence row — no hot row, no extra
255
+ * commit.
256
+ */
257
+ reserveAutoInc(): bigint | null
258
+ /** Point read by an Int64 primary key. */
259
+ getByPkInt64(value: bigint): RowJs | null
260
+ /** Delete a row by storage row id. */
261
+ delete(rowId: bigint): void
262
+ /** Truncate all rows in this table. Call `commit()` to make it durable. */
263
+ truncate(): void
264
+ /** Delete the first row matching a text primary key. */
265
+ deleteByPkText(text: string): void
266
+ /** Delete the first row matching an Int64 primary key. */
267
+ deleteByPkInt64(value: bigint): void
268
+ /** Hybrid index query. */
269
+ query(conditions: Array<ConditionSpec>): Array<RowJs>
270
+ /**
271
+ * Read every row of this table visible at commit `epoch` — a point-in-time
272
+ * (MVCC time-travel) read. `epoch` must not exceed the current visible
273
+ * epoch.
274
+ */
275
+ rowsAtEpoch(epoch: bigint): Array<RowJs>
276
+ /**
277
+ * Reservoir-sampled approximate aggregate (`count`/`sum`/`avg`) with a
278
+ * `z`-score confidence interval. Returns a JSON object, or `null` when the
279
+ * reservoir is empty. `columnId` is required for `sum`/`avg`.
280
+ */
281
+ approxAggregate(agg: string, columnId: number | undefined | null, z: number): string | null
282
+ /**
283
+ * Incrementally-maintained aggregate (`count`/`sum`/`min`/`max`/`avg`),
284
+ * optionally filtered by pushed-down `conditions`. Returns a JSON object
285
+ * `{value, incremental, delta_rows}`; the value is always exact. The engine
286
+ * caches per `(table, column, agg, conditions)` and folds in only the delta
287
+ * of newly-committed rows once data has spilled to runs.
288
+ */
289
+ incrementalAggregate(agg: string, columnId: number | undefined | null, conditions: Array<ConditionSpec>): string
290
+ /**
291
+ * Insert a batch of rows in one call. Returns each row's id and, when the
292
+ * engine allocated it, its `AUTO_INCREMENT` value, in order.
293
+ */
294
+ putBatch(rows: Array<Array<Cell>>): Array<PutResult>
295
+ /**
296
+ * Fastest ingest path: bulk-load typed columns (Int64/Float64/Bool) in one
297
+ * shot, bypassing the per-cell `Value` enum. Returns the commit epoch.
298
+ * Bytes/Embedding columns are not supported here — use `putBatch`.
299
+ */
300
+ bulkLoadTyped(columns: Array<TypedColumn>): bigint
301
+ /**
302
+ * Hybrid index query returning the matching rows as Arrow IPC bytes
303
+ * (columnar, zero-copy on the JS side). Requires at least one condition —
304
+ * use `Database.sql` for full scans.
305
+ */
306
+ queryArrow(conditions: Array<ConditionSpec>): Buffer
307
+ putAsync(cells: Array<Cell>): Promise<PutResult>
308
+ commitAsync(): Promise<bigint>
309
+ countAsync(): Promise<bigint>
310
+ countWhereAsync(conditions: Array<ConditionSpec>): Promise<bigint>
311
+ getAsync(rowId: bigint): Promise<RowJs | null>
312
+ queryAsync(conditions: Array<ConditionSpec>): Promise<Array<RowJs>>
313
+ flushAsync(): Promise<bigint>
314
+ queryArrowAsync(conditions: Array<ConditionSpec>): Promise<Buffer>
315
+ }
316
+ /**
317
+ * A cross-table transaction (P5.2). Stage puts/deletes across tables; commit
318
+ * atomically. On conflict, `commit` throws a `ConflictError`.
319
+ */
320
+ export declare class Transaction {
321
+ constructor(db: Database)
322
+ /**
323
+ * Stage a put on `table`. Returns the engine-assigned `AUTO_INCREMENT`
324
+ * value when the table has an auto-increment primary key and the column was
325
+ * omitted or null; returns `null` otherwise (explicit id, or no auto-inc
326
+ * column). The returned value is the id that will be written on commit.
327
+ */
328
+ put(table: string, cells: Array<Cell>): bigint | null
329
+ /** Stage a delete of `row_id` on `table`. */
330
+ delete(table: string, rowId: bigint): void
331
+ truncate(table: string): void
332
+ upsert(table: string, insertCells: Array<Cell>, updateCells?: Array<Cell> | undefined | null): void
333
+ updateMany(table: string, updates: Array<RowUpdateJs>): void
334
+ deleteMany(table: string, rowIds: Array<bigint>): void
335
+ /**
336
+ * Stage many puts on `table` from a compact little-endian buffer, skipping
337
+ * the per-cell NAPI `Cell` object marshalling that dominates a bulk load.
338
+ * Layout: `u32 rowCount`, then per row `u16 cellCount`, then per cell
339
+ * `u16 columnId`, `u8 tag`, payload — tag 0=null, 1=int64 (i64 LE),
340
+ * 2=float64 (f64 LE), 3=bool (u8), 4=bytes (u32 len + bytes; text is UTF-8).
341
+ * The decoded `(column_id, Value)` pairs are identical to what `put` builds.
342
+ */
343
+ putPacked(table: string, payload: Buffer): void
344
+ /**
345
+ * Stage many deletes on `table` from a compact buffer of row ids:
346
+ * `u32 count`, then `count` × `u64 LE` row id. One NAPI crossing instead
347
+ * of one per row.
348
+ */
349
+ deletePacked(table: string, payload: Buffer): void
350
+ /**
351
+ * Commit all staged ops atomically. Returns the commit epoch.
352
+ * Throws `ConflictError` on write-write conflict (retryable).
353
+ */
354
+ commit(): bigint
355
+ commitReturning(): CommitResultJs
356
+ /**
357
+ * Commit off the JS event loop (the durability fsync runs on the NAPI
358
+ * blocking pool). Throws `ConflictError` on write-write conflict.
359
+ */
360
+ commitAsync(): Promise<bigint>
361
+ /**
362
+ * Async commit that returns both the committed epoch and the affected row
363
+ * identities, off the JS event loop. Throws `ConflictError` on write-write
364
+ * conflict.
365
+ */
366
+ commitAsyncReturning(): Promise<CommitResultJs>
367
+ /** Discard all staged ops. */
368
+ rollback(): void
369
+ /**
370
+ * Scope subsequent ops to `table` via a `TxnTable`, so the table name
371
+ * isn't repeated on every `put`/`delete`. Pure sugar over the flat
372
+ * `put(table, …)` / `delete(table, …)` API — the sub-handle stages into
373
+ * THIS transaction, and this transaction's `commit`/`rollback` still drive
374
+ * durability.
375
+ */
376
+ table(name: string): TxnTable
377
+ }
378
+ /**
379
+ * A table-scoped view of a [`Transaction`] (returned by `transaction.table()`).
380
+ * Stages `put`/`delete` for its bound table into the parent transaction; the
381
+ * parent's `commit`/`rollback` still apply.
382
+ */
383
+ export declare class TxnTable {
384
+ /**
385
+ * Stage a put on this table. Returns the engine-assigned `AUTO_INCREMENT`
386
+ * value when applicable, or `null` otherwise.
387
+ */
388
+ put(cells: Array<Cell>): bigint | null
389
+ /** Stage a batch of puts on this table. */
390
+ putBatch(rows: Array<Array<Cell>>): void
391
+ /** Stage a delete of `row_id` on this table. */
392
+ delete(rowId: bigint): void
393
+ truncate(): void
394
+ upsert(insertCells: Array<Cell>, updateCells?: Array<Cell> | undefined | null): void
395
+ updateMany(updates: Array<RowUpdateJs>): void
396
+ deleteMany(rowIds: Array<bigint>): void
397
+ }
398
+ /**
399
+ * Opt-in write micro-batching over one table. Writes are **not durable until
400
+ * flush** — the contract is the opposite of `put()`.
401
+ */
402
+ export declare class WriteBuffer {
403
+ /** Create a new WriteBuffer over a table. `threshold` rows trigger an auto-flush. */
404
+ constructor(table: TableHandle, threshold?: number | undefined | null)
405
+ /**
406
+ * Buffer a write (not durable until `flush`). Auto-flushes when the
407
+ * threshold is reached, returning the new row id.
408
+ */
409
+ put(cells: Array<Cell>): bigint | null
410
+ /** Flush all buffered writes (durable after this call). Returns the new epoch. */
411
+ flush(): bigint
412
+ }
413
+ /**
414
+ * A daemon-backed database connection (Phase 19.4). Routes put/get/count/
415
+ * query/commit to a `mongreldb-server` instance over HTTP. Multiple Node
416
+ * processes can share one warm cache this way.
417
+ */
418
+ export declare class RemoteDatabase {
419
+ /** Connect to a `mongreldb-server` at `url` (e.g. `http://127.0.0.1:8453`). */
420
+ constructor(url: string)
421
+ health(): string
422
+ tableNames(): Array<string>
423
+ count(table: string): number
424
+ sql(sql: string): Buffer
425
+ commit(table: string): bigint
426
+ }