albedo-node 0.7.2 โ 0.8.2
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 +102 -15
- package/dist/index.d.ts +82 -15
- package/dist/index.js +186 -43
- package/native/albedo.aarch64_linux_gnu.node +0 -0
- package/native/albedo.aarch64_linux_musl.node +0 -0
- package/native/albedo.aarch64_macos.node +0 -0
- package/native/albedo.x86_64_linux_gnu.node +0 -0
- package/native/albedo.x86_64_linux_musl.node +0 -0
- package/native/albedo.x86_64_macos.node +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ This package wraps the core database engine with a concise TypeScript API, ships
|
|
|
9
9
|
- ๐งฑ Access to the full Albedo bucket API from Node.js or Bun
|
|
10
10
|
- ๐ฆ Precompiled native modules for Linux (glibc & musl), macOS, and arm64/x64
|
|
11
11
|
- ๐ Generator-based iterators for queries, transforms, and live subscriptions
|
|
12
|
-
- ๐
|
|
12
|
+
- ๐ WAL-based replication helpers with explicit cursors and batches
|
|
13
13
|
- ๐งช TypeScript typings and Bun-based test suite
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
@@ -75,6 +75,47 @@ bucket.close();
|
|
|
75
75
|
|
|
76
76
|
You can chain multiple `where` calls or combine them with `sortBy` and `sector`. For quick one-off predicates, the standalone `where(field, filter)` helper returns a `Query` instance that slots into any method accepting a query.
|
|
77
77
|
|
|
78
|
+
Logical groups are available as both instance methods and static constructors:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { Query, where } from "albedo-node";
|
|
82
|
+
|
|
83
|
+
const visibleUsers = Query.or(
|
|
84
|
+
where("role", "admin"),
|
|
85
|
+
Query.and(
|
|
86
|
+
where("role", "user"),
|
|
87
|
+
where("verified", true),
|
|
88
|
+
),
|
|
89
|
+
).nor(
|
|
90
|
+
where("deleted", true),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
for (const doc of bucket.list(visibleUsers)) {
|
|
94
|
+
console.log(doc);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This produces a query equivalent to:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
{
|
|
102
|
+
query: {
|
|
103
|
+
$or: [
|
|
104
|
+
{ role: "admin" },
|
|
105
|
+
{
|
|
106
|
+
$and: [
|
|
107
|
+
{ role: "user" },
|
|
108
|
+
{ verified: true },
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
$nor: [
|
|
113
|
+
{ deleted: true },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
78
119
|
### Transforming documents in place
|
|
79
120
|
|
|
80
121
|
```ts
|
|
@@ -131,25 +172,36 @@ Notes:
|
|
|
131
172
|
### Replication
|
|
132
173
|
|
|
133
174
|
```ts
|
|
134
|
-
const primary = Bucket.open("./primary.bucket"
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const batches: Uint8Array[] = [];
|
|
138
|
-
primary.setReplicationCallback((data) => {
|
|
139
|
-
batches.push(data);
|
|
175
|
+
const primary = Bucket.open("./primary.bucket", {
|
|
176
|
+
wal: true,
|
|
177
|
+
write_durability: "all",
|
|
140
178
|
});
|
|
179
|
+
const replica = Bucket.open("./replica.bucket", {
|
|
180
|
+
wal: true,
|
|
181
|
+
write_durability: "all",
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const cursor = primary.replicationCursor();
|
|
141
185
|
|
|
142
186
|
primary.insert({ name: "Replica", version: 1 });
|
|
143
|
-
primary.close();
|
|
144
187
|
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
replica.applyReplicationBatch(
|
|
188
|
+
const batch = primary.readReplicationBatch(cursor);
|
|
189
|
+
if (batch) {
|
|
190
|
+
const nextCursor = replica.applyReplicationBatch(batch);
|
|
191
|
+
console.log(nextCursor.next_frame_index);
|
|
148
192
|
}
|
|
149
193
|
|
|
194
|
+
primary.close();
|
|
150
195
|
replica.close();
|
|
151
196
|
```
|
|
152
197
|
|
|
198
|
+
Notes:
|
|
199
|
+
|
|
200
|
+
- Replication requires WAL mode to be enabled on both buckets.
|
|
201
|
+
- `replicationCursor()` snapshots the current position in the WAL stream.
|
|
202
|
+
- `readReplicationBatch(cursor, maxBytes?)` returns `null` when there is nothing new to send.
|
|
203
|
+
- `applyReplicationBatch(batch)` applies the batch and returns the replica's new cursor.
|
|
204
|
+
|
|
153
205
|
## Query objects and BSON payloads
|
|
154
206
|
|
|
155
207
|
Most bucket operations accept either:
|
|
@@ -162,8 +214,22 @@ Regardless of which form you use, the structure mirrors the underlying Albedo qu
|
|
|
162
214
|
|
|
163
215
|
- `{ query: { field: value } }` โ equality filters
|
|
164
216
|
- `{ query: { age: { "$gt": 40 } } }` โ comparison operators
|
|
217
|
+
- `{ query: { $or: [{ role: "admin" }, { public: true }], deleted: false } }` โ logical groups mixed with leaf filters
|
|
165
218
|
- `{ query: { _id: someId }, sector: { limit: 10, offset: 0 } }` โ pagination controls
|
|
166
219
|
|
|
220
|
+
Supported field operators in this binding include:
|
|
221
|
+
|
|
222
|
+
- `$eq`, `$ne`, `$lt`, `$lte`, `$gt`, `$gte`
|
|
223
|
+
- `$in`, `$between`
|
|
224
|
+
- `$startsWith`, `$endsWith`
|
|
225
|
+
- `$exists`, `$notExists`
|
|
226
|
+
|
|
227
|
+
Logical operators supported inside `query` are:
|
|
228
|
+
|
|
229
|
+
- `$or`
|
|
230
|
+
- `$and`
|
|
231
|
+
- `$nor`
|
|
232
|
+
|
|
167
233
|
For the exhaustive list of operators and document shapes, consult the [Albedo Query reference](https://github.com/klirix/albedo#readme). Whatever BSON document the core engine accepts can be provided here either as a plain object or as prebuilt BSON bytes.
|
|
168
234
|
|
|
169
235
|
### ObjectId support
|
|
@@ -181,22 +247,37 @@ Serialized documents that contain `_id` fields with a BSON ObjectId will be revi
|
|
|
181
247
|
## API reference
|
|
182
248
|
|
|
183
249
|
- `default` export โ raw Albedo native module
|
|
184
|
-
- `ObjectId`, `serialize`, `deserialize`, `open`, `close`, `insert`, `delete`, `list`, `transform`, `
|
|
250
|
+
- `ObjectId`, `serialize`, `deserialize`, `open`, `open_with_options`, `close`, `insert`, `checkpoint`, `delete`, `list`, `transform`, `replicationCursor`, `readReplicationBatch`, `applyReplicationBatch`, etc.
|
|
185
251
|
- `BSON.serialize(value)` / `BSON.deserialize(bytes)` โ helper wrappers
|
|
186
252
|
- `Bucket`
|
|
187
|
-
- `static open(path: string): Bucket`
|
|
253
|
+
- `static open(path: string, options?: OpenBucketOptions): Bucket`
|
|
188
254
|
- `insert(doc: object | Uint8Array)`
|
|
255
|
+
- `checkpoint()`
|
|
189
256
|
- `delete(query?: object | Query)`
|
|
190
257
|
- `list<T>(query?: object | Query): Generator<T>`
|
|
191
258
|
- `subscribe<T>(query?: object | Query, options?: { pollingTimeout?: number; batchSize?: number }): AsyncGenerator<SubscriptionEvent<T>>`
|
|
192
259
|
- `transformIterator<T>(query?: object | Query): Generator<T, undefined, object | null>`
|
|
260
|
+
- `transform<T>(query, fn)` / `update<T>(query, fn)`
|
|
261
|
+
- `all<T>(query?)` / `one<T>(query?)`
|
|
262
|
+
- `beginTransaction()` / `tx(fn)`
|
|
193
263
|
- `ensureIndex(name: string, options: { unique: boolean; sparse: boolean; reverse: boolean })`
|
|
194
264
|
- `dropIndex(name: string)`
|
|
195
265
|
- `indexes: Record<string, { name: string; unique: boolean; sparse: boolean; reverse: boolean }>`
|
|
196
|
-
- `
|
|
197
|
-
- `
|
|
266
|
+
- `replicationCursor(): { generation: bigint; next_frame_index: bigint }`
|
|
267
|
+
- `readReplicationBatch(cursor, maxBytes?): Uint8Array | null`
|
|
268
|
+
- `applyReplicationBatch(batch: Uint8Array): { generation: bigint; next_frame_index: bigint }`
|
|
198
269
|
- accepts raw BSON `Uint8Array` payloads anywhere a query or document object is expected
|
|
199
270
|
|
|
271
|
+
- `OpenBucketOptions`
|
|
272
|
+
- `buildIdIndex?: boolean`
|
|
273
|
+
- `mode?: string`
|
|
274
|
+
- `auto_vaccuum?: boolean`
|
|
275
|
+
- `page_cache_capacity?: number`
|
|
276
|
+
- `wal?: boolean`
|
|
277
|
+
- `write_durability?: "all" | "manual" | { periodic: number }`
|
|
278
|
+
- `read_durability?: "shared" | "process"`
|
|
279
|
+
- `wal_auto_checkpoint?: (defaults to 1000 pages)`
|
|
280
|
+
|
|
200
281
|
- `SubscriptionEvent<T>`
|
|
201
282
|
- `seqno: bigint`
|
|
202
283
|
- `op: "insert" | "update" | "delete"`
|
|
@@ -206,8 +287,14 @@ Serialized documents that contain `_id` fields with a BSON ObjectId will be revi
|
|
|
206
287
|
|
|
207
288
|
- `Query`
|
|
208
289
|
- `where(field, filter)` chains field predicates (e.g. `{ $eq: value }`, `{ $gt: 10 }`)
|
|
290
|
+
- `or(...clauses)` adds an `$or` group
|
|
291
|
+
- `and(...clauses)` adds an `$and` group
|
|
292
|
+
- `nor(...clauses)` adds a `$nor` group
|
|
209
293
|
- `sortBy(field, direction?)` sets sort order
|
|
210
294
|
- `sector(offset?, limit?)` applies pagination window
|
|
295
|
+
- `static or(...clauses): Query` creates a query with an `$or` group
|
|
296
|
+
- `static and(...clauses): Query` creates a query with an `$and` group
|
|
297
|
+
- `static nor(...clauses): Query` creates a query with a `$nor` group
|
|
211
298
|
|
|
212
299
|
- `where(field, filter): Query` โ convenience helper that creates a single-field `Query`
|
|
213
300
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
type ByteBuffer = Uint8Array;
|
|
2
2
|
type BucketHandle = object;
|
|
3
|
+
type TransactionHandle = object;
|
|
3
4
|
type ListIteratorHandle = object;
|
|
4
5
|
type TransformIteratorHandle = object;
|
|
5
6
|
type SubscriptionHandle = object;
|
|
7
|
+
export interface ReplicationCursor {
|
|
8
|
+
generation: bigint;
|
|
9
|
+
next_frame_index: bigint;
|
|
10
|
+
}
|
|
6
11
|
interface IndexOptions {
|
|
7
12
|
unique: boolean;
|
|
8
13
|
sparse: boolean;
|
|
@@ -69,19 +74,28 @@ interface AlbedoModule {
|
|
|
69
74
|
listClose(cursor: ListIteratorHandle): void;
|
|
70
75
|
listData(cursor: ListIteratorHandle): unknown | null;
|
|
71
76
|
insert(bucket: BucketHandle, doc: ByteBuffer | object): void;
|
|
77
|
+
checkpoint(bucket: BucketHandle): void;
|
|
78
|
+
transactionBegin(bucket: BucketHandle): TransactionHandle;
|
|
79
|
+
transactionInsert(tx: TransactionHandle, doc: ByteBuffer | object): void;
|
|
72
80
|
ensureIndex(bucket: BucketHandle, name: string, options: IndexOptions): void;
|
|
73
81
|
listIndexes(bucket: BucketHandle): Record<string, IndexInfo>;
|
|
74
82
|
dropIndex(bucket: BucketHandle, name: string): void;
|
|
75
83
|
delete(bucket: BucketHandle, query: object): void;
|
|
84
|
+
transactionDelete(tx: TransactionHandle, query: object): void;
|
|
76
85
|
transform(bucket: BucketHandle, query: object): TransformIteratorHandle;
|
|
86
|
+
transactionTransform(tx: TransactionHandle, query: object): TransformIteratorHandle;
|
|
77
87
|
transformClose(iter: TransformIteratorHandle): void;
|
|
78
88
|
transformData(iter: TransformIteratorHandle): unknown | null;
|
|
79
89
|
transformApply(iter: TransformIteratorHandle, replace: ByteBuffer | object | null): void;
|
|
90
|
+
transactionCommit(tx: TransactionHandle): void;
|
|
91
|
+
transactionRollback(tx: TransactionHandle): void;
|
|
92
|
+
transactionClose(tx: TransactionHandle): void;
|
|
80
93
|
subscribe(bucket: BucketHandle, query: object): SubscriptionHandle;
|
|
81
94
|
subscribePoll<T = unknown>(sub: SubscriptionHandle, maxEvents: number): SubscriptionBatch<T> | null;
|
|
82
95
|
subscribeClose(sub: SubscriptionHandle): void;
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
replicationCursor(bucket: BucketHandle): ReplicationCursor;
|
|
97
|
+
readReplicationBatch(bucket: BucketHandle, cursor: ReplicationCursor, maxBytes: number): ByteBuffer | null;
|
|
98
|
+
applyReplicationBatch(bucket: BucketHandle, data: ByteBuffer): ReplicationCursor;
|
|
85
99
|
}
|
|
86
100
|
export declare const albedo: AlbedoModule;
|
|
87
101
|
export default albedo;
|
|
@@ -99,6 +113,50 @@ export declare const BSON: {
|
|
|
99
113
|
* ```
|
|
100
114
|
*/
|
|
101
115
|
export declare const ObjectId: ObjectIdConstructor;
|
|
116
|
+
type QueryInput = object | Query;
|
|
117
|
+
type TransformReplacement<T extends object> = T | ByteBuffer | null;
|
|
118
|
+
/**
|
|
119
|
+
* Wrapper around a native transaction handle providing
|
|
120
|
+
* write operations that are committed or rolled back together.
|
|
121
|
+
*/
|
|
122
|
+
export declare class Transaction {
|
|
123
|
+
private handle;
|
|
124
|
+
constructor(handle: object);
|
|
125
|
+
private get nativeHandle();
|
|
126
|
+
/**
|
|
127
|
+
* Insert a document or raw byte buffer into the transaction.
|
|
128
|
+
*/
|
|
129
|
+
insert(doc: object | ByteBuffer): void;
|
|
130
|
+
/**
|
|
131
|
+
* Delete documents matching the query from the transaction.
|
|
132
|
+
*/
|
|
133
|
+
delete(query?: QueryInput): void;
|
|
134
|
+
/**
|
|
135
|
+
* Generator that allows reading and modifying matching documents
|
|
136
|
+
* within the transaction.
|
|
137
|
+
*/
|
|
138
|
+
transformIterator<T extends object>(query?: QueryInput): Generator<T, undefined, TransformReplacement<T>>;
|
|
139
|
+
/**
|
|
140
|
+
* Apply a transformation function to matching documents in the transaction.
|
|
141
|
+
*/
|
|
142
|
+
transform<T extends object>(query: QueryInput | undefined, fn: (doc: T) => TransformReplacement<T>): void;
|
|
143
|
+
/**
|
|
144
|
+
* Alias for `transform` that reads more naturally for document updates.
|
|
145
|
+
*/
|
|
146
|
+
update<T extends object>(query: QueryInput | undefined, fn: (doc: T) => TransformReplacement<T>): void;
|
|
147
|
+
/**
|
|
148
|
+
* Commit the transaction.
|
|
149
|
+
*/
|
|
150
|
+
commit(): void;
|
|
151
|
+
/**
|
|
152
|
+
* Roll back the transaction.
|
|
153
|
+
*/
|
|
154
|
+
rollback(): void;
|
|
155
|
+
/**
|
|
156
|
+
* Close the transaction and release native resources.
|
|
157
|
+
*/
|
|
158
|
+
close(): void;
|
|
159
|
+
}
|
|
102
160
|
/**
|
|
103
161
|
* Wrapper around a native Albedo bucket handle providing
|
|
104
162
|
* methods for CRUD operations, indexing, iteration, and
|
|
@@ -157,6 +215,21 @@ export declare class Bucket {
|
|
|
157
215
|
* ```
|
|
158
216
|
*/
|
|
159
217
|
insert(doc: object | ByteBuffer): void;
|
|
218
|
+
/**
|
|
219
|
+
* Flush buffered bucket state through the native checkpoint mechanism.
|
|
220
|
+
*/
|
|
221
|
+
checkpoint(): void;
|
|
222
|
+
/**
|
|
223
|
+
* Begin a manual transaction on this bucket.
|
|
224
|
+
*/
|
|
225
|
+
beginTransaction(): Transaction;
|
|
226
|
+
/**
|
|
227
|
+
* Run a callback inside a transaction and commit it on success.
|
|
228
|
+
*
|
|
229
|
+
* If the callback throws, the transaction is rolled back before the
|
|
230
|
+
* original error is re-thrown.
|
|
231
|
+
*/
|
|
232
|
+
tx<T>(fn: (tx: Transaction) => T): T;
|
|
160
233
|
/**
|
|
161
234
|
* Delete documents matching the query. If no query is provided,
|
|
162
235
|
* all documents will be removed.
|
|
@@ -275,7 +348,7 @@ export declare class Bucket {
|
|
|
275
348
|
* }
|
|
276
349
|
* ```
|
|
277
350
|
*/
|
|
278
|
-
transformIterator<T>(query?: object | Query): Generator<T, undefined,
|
|
351
|
+
transformIterator<T extends object>(query?: object | Query): Generator<T, undefined, TransformReplacement<T>>;
|
|
279
352
|
/**
|
|
280
353
|
* Apply a transformation function to each document matching the
|
|
281
354
|
* provided query. The predicate receives the current document and
|
|
@@ -294,19 +367,13 @@ export declare class Bucket {
|
|
|
294
367
|
* });
|
|
295
368
|
* ```
|
|
296
369
|
*/
|
|
297
|
-
transform<T extends object>(query: object | Query | undefined, fn: (doc: T) => T
|
|
370
|
+
transform<T extends object>(query: object | Query | undefined, fn: (doc: T) => TransformReplacement<T>): void;
|
|
298
371
|
/**
|
|
299
|
-
*
|
|
300
|
-
* bucket.
|
|
301
|
-
* @param callback - invoked with raw replication bytes
|
|
302
|
-
* @example
|
|
303
|
-
* ```ts
|
|
304
|
-
* bucket.setReplicationCallback(bytes => {
|
|
305
|
-
* console.log('got replication', bytes.length);
|
|
306
|
-
* });
|
|
307
|
-
* ```
|
|
372
|
+
* Alias for `transform` that reads more naturally for document updates.
|
|
308
373
|
*/
|
|
309
|
-
|
|
374
|
+
update<T extends object>(query: object | Query | undefined, fn: (doc: T) => TransformReplacement<T>): void;
|
|
375
|
+
replicationCursor(): ReplicationCursor;
|
|
376
|
+
readReplicationBatch(cursor: ReplicationCursor, maxBytes?: number): Uint8Array | null;
|
|
310
377
|
/**
|
|
311
378
|
* Apply a batch of replication operations to this bucket.
|
|
312
379
|
* @param data - bytes produced by another bucket's replication
|
|
@@ -315,7 +382,7 @@ export declare class Bucket {
|
|
|
315
382
|
* bucket.applyReplicationBatch(remoteBytes);
|
|
316
383
|
* ```
|
|
317
384
|
*/
|
|
318
|
-
applyReplicationBatch(data: Uint8Array):
|
|
385
|
+
applyReplicationBatch(data: Uint8Array): ReplicationCursor;
|
|
319
386
|
}
|
|
320
387
|
type BSONValue = any;
|
|
321
388
|
type FilterOperators = {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Query = exports.Bucket = exports.ObjectId = exports.BSON = exports.albedo = void 0;
|
|
3
|
+
exports.Query = exports.Bucket = exports.Transaction = exports.ObjectId = exports.BSON = exports.albedo = void 0;
|
|
4
4
|
exports.where = where;
|
|
5
5
|
const detect_libc_1 = require("detect-libc");
|
|
6
6
|
function getNativeBinding() {
|
|
@@ -47,6 +47,106 @@ exports.BSON = {
|
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
49
|
exports.ObjectId = exports.albedo.ObjectId;
|
|
50
|
+
function convertToQuery(query) {
|
|
51
|
+
if (query instanceof Query) {
|
|
52
|
+
return query.query;
|
|
53
|
+
}
|
|
54
|
+
return query || {};
|
|
55
|
+
}
|
|
56
|
+
function* iterateTransform(iter) {
|
|
57
|
+
try {
|
|
58
|
+
let data;
|
|
59
|
+
while ((data = exports.albedo.transformData(iter)) !== undefined) {
|
|
60
|
+
const newDoc = yield data;
|
|
61
|
+
exports.albedo.transformApply(iter, newDoc);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
exports.albedo.transformClose(iter);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function applyTransform(iter, fn) {
|
|
69
|
+
try {
|
|
70
|
+
let data;
|
|
71
|
+
while ((data = exports.albedo.transformData(iter)) !== undefined) {
|
|
72
|
+
exports.albedo.transformApply(iter, fn(data));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
exports.albedo.transformClose(iter);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function aggregateErrors(message, errors) {
|
|
80
|
+
return new AggregateError(errors, message);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Wrapper around a native transaction handle providing
|
|
84
|
+
* write operations that are committed or rolled back together.
|
|
85
|
+
*/
|
|
86
|
+
class Transaction {
|
|
87
|
+
handle;
|
|
88
|
+
constructor(handle) {
|
|
89
|
+
this.handle = handle;
|
|
90
|
+
}
|
|
91
|
+
get nativeHandle() {
|
|
92
|
+
if (this.handle === null) {
|
|
93
|
+
throw new Error("Transaction is closed");
|
|
94
|
+
}
|
|
95
|
+
return this.handle;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Insert a document or raw byte buffer into the transaction.
|
|
99
|
+
*/
|
|
100
|
+
insert(doc) {
|
|
101
|
+
exports.albedo.transactionInsert(this.nativeHandle, doc);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Delete documents matching the query from the transaction.
|
|
105
|
+
*/
|
|
106
|
+
delete(query) {
|
|
107
|
+
exports.albedo.transactionDelete(this.nativeHandle, convertToQuery(query));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Generator that allows reading and modifying matching documents
|
|
111
|
+
* within the transaction.
|
|
112
|
+
*/
|
|
113
|
+
transformIterator(query) {
|
|
114
|
+
return iterateTransform(exports.albedo.transactionTransform(this.nativeHandle, convertToQuery(query)));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Apply a transformation function to matching documents in the transaction.
|
|
118
|
+
*/
|
|
119
|
+
transform(query, fn) {
|
|
120
|
+
applyTransform(exports.albedo.transactionTransform(this.nativeHandle, convertToQuery(query)), fn);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Alias for `transform` that reads more naturally for document updates.
|
|
124
|
+
*/
|
|
125
|
+
update(query, fn) {
|
|
126
|
+
this.transform(query, fn);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Commit the transaction.
|
|
130
|
+
*/
|
|
131
|
+
commit() {
|
|
132
|
+
exports.albedo.transactionCommit(this.nativeHandle);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Roll back the transaction.
|
|
136
|
+
*/
|
|
137
|
+
rollback() {
|
|
138
|
+
exports.albedo.transactionRollback(this.nativeHandle);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Close the transaction and release native resources.
|
|
142
|
+
*/
|
|
143
|
+
close() {
|
|
144
|
+
const handle = this.nativeHandle;
|
|
145
|
+
exports.albedo.transactionClose(handle);
|
|
146
|
+
this.handle = null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
exports.Transaction = Transaction;
|
|
50
150
|
/**
|
|
51
151
|
* Wrapper around a native Albedo bucket handle providing
|
|
52
152
|
* methods for CRUD operations, indexing, iteration, and
|
|
@@ -114,6 +214,75 @@ class Bucket {
|
|
|
114
214
|
insert(doc) {
|
|
115
215
|
exports.albedo.insert(this.handle, doc);
|
|
116
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Flush buffered bucket state through the native checkpoint mechanism.
|
|
219
|
+
*/
|
|
220
|
+
checkpoint() {
|
|
221
|
+
exports.albedo.checkpoint(this.handle);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Begin a manual transaction on this bucket.
|
|
225
|
+
*/
|
|
226
|
+
beginTransaction() {
|
|
227
|
+
return new Transaction(exports.albedo.transactionBegin(this.handle));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Run a callback inside a transaction and commit it on success.
|
|
231
|
+
*
|
|
232
|
+
* If the callback throws, the transaction is rolled back before the
|
|
233
|
+
* original error is re-thrown.
|
|
234
|
+
*/
|
|
235
|
+
tx(fn) {
|
|
236
|
+
const tx = this.beginTransaction();
|
|
237
|
+
let result;
|
|
238
|
+
try {
|
|
239
|
+
result = fn(tx);
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
try {
|
|
243
|
+
tx.rollback();
|
|
244
|
+
}
|
|
245
|
+
catch (rollbackError) {
|
|
246
|
+
try {
|
|
247
|
+
tx.close();
|
|
248
|
+
}
|
|
249
|
+
catch (closeError) {
|
|
250
|
+
throw aggregateErrors("Transaction failed, rollback failed, and close failed", [error, rollbackError, closeError]);
|
|
251
|
+
}
|
|
252
|
+
throw aggregateErrors("Transaction failed and rollback failed", [
|
|
253
|
+
error,
|
|
254
|
+
rollbackError,
|
|
255
|
+
]);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
tx.close();
|
|
259
|
+
}
|
|
260
|
+
catch (closeError) {
|
|
261
|
+
throw aggregateErrors("Transaction failed and close failed", [
|
|
262
|
+
error,
|
|
263
|
+
closeError,
|
|
264
|
+
]);
|
|
265
|
+
}
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
tx.commit();
|
|
270
|
+
}
|
|
271
|
+
catch (commitError) {
|
|
272
|
+
try {
|
|
273
|
+
tx.close();
|
|
274
|
+
}
|
|
275
|
+
catch (closeError) {
|
|
276
|
+
throw aggregateErrors("Transaction commit and close both failed", [
|
|
277
|
+
commitError,
|
|
278
|
+
closeError,
|
|
279
|
+
]);
|
|
280
|
+
}
|
|
281
|
+
throw commitError;
|
|
282
|
+
}
|
|
283
|
+
tx.close();
|
|
284
|
+
return result;
|
|
285
|
+
}
|
|
117
286
|
/**
|
|
118
287
|
* Delete documents matching the query. If no query is provided,
|
|
119
288
|
* all documents will be removed.
|
|
@@ -126,7 +295,7 @@ class Bucket {
|
|
|
126
295
|
* ```
|
|
127
296
|
*/
|
|
128
297
|
delete(query) {
|
|
129
|
-
exports.albedo.delete(this.handle,
|
|
298
|
+
exports.albedo.delete(this.handle, convertToQuery(query));
|
|
130
299
|
}
|
|
131
300
|
/**
|
|
132
301
|
* Retrieve information about all indexes defined on the bucket.
|
|
@@ -172,7 +341,7 @@ class Bucket {
|
|
|
172
341
|
* ```
|
|
173
342
|
*/
|
|
174
343
|
*list(query) {
|
|
175
|
-
const cursor = exports.albedo.list(this.handle,
|
|
344
|
+
const cursor = exports.albedo.list(this.handle, convertToQuery(query));
|
|
176
345
|
try {
|
|
177
346
|
let data;
|
|
178
347
|
while ((data = exports.albedo.listData(cursor)) !== null) {
|
|
@@ -206,7 +375,7 @@ class Bucket {
|
|
|
206
375
|
async *subscribe(query, options) {
|
|
207
376
|
const pollingTimeout = options?.pollingTimeout ?? 50;
|
|
208
377
|
const batchSize = options?.batchSize ?? 64;
|
|
209
|
-
const subscription = exports.albedo.subscribe(this.handle,
|
|
378
|
+
const subscription = exports.albedo.subscribe(this.handle, convertToQuery(query));
|
|
210
379
|
try {
|
|
211
380
|
while (true) {
|
|
212
381
|
const batch = exports.albedo.subscribePoll(subscription, batchSize);
|
|
@@ -262,10 +431,7 @@ class Bucket {
|
|
|
262
431
|
* ```
|
|
263
432
|
*/
|
|
264
433
|
static convertToQuery(query) {
|
|
265
|
-
|
|
266
|
-
return query.query;
|
|
267
|
-
}
|
|
268
|
-
return query || {};
|
|
434
|
+
return convertToQuery(query);
|
|
269
435
|
}
|
|
270
436
|
/**
|
|
271
437
|
* Generator that allows reading and optionally modifying each
|
|
@@ -284,18 +450,7 @@ class Bucket {
|
|
|
284
450
|
* ```
|
|
285
451
|
*/
|
|
286
452
|
*transformIterator(query) {
|
|
287
|
-
|
|
288
|
-
const iter = exports.albedo.transform(this.handle, queryObj);
|
|
289
|
-
try {
|
|
290
|
-
let data;
|
|
291
|
-
while ((data = exports.albedo.transformData(iter)) !== undefined) {
|
|
292
|
-
const newDoc = yield data;
|
|
293
|
-
exports.albedo.transformApply(iter, newDoc);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
finally {
|
|
297
|
-
exports.albedo.transformClose(iter);
|
|
298
|
-
}
|
|
453
|
+
yield* iterateTransform(exports.albedo.transform(this.handle, convertToQuery(query)));
|
|
299
454
|
}
|
|
300
455
|
/**
|
|
301
456
|
* Apply a transformation function to each document matching the
|
|
@@ -316,31 +471,19 @@ class Bucket {
|
|
|
316
471
|
* ```
|
|
317
472
|
*/
|
|
318
473
|
transform(query, fn) {
|
|
319
|
-
|
|
320
|
-
const iter = exports.albedo.transform(this.handle, queryObj);
|
|
321
|
-
try {
|
|
322
|
-
let data;
|
|
323
|
-
while ((data = exports.albedo.transformData(iter)) !== undefined) {
|
|
324
|
-
exports.albedo.transformApply(iter, fn(data));
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
finally {
|
|
328
|
-
exports.albedo.transformClose(iter);
|
|
329
|
-
}
|
|
474
|
+
applyTransform(exports.albedo.transform(this.handle, convertToQuery(query)), fn);
|
|
330
475
|
}
|
|
331
476
|
/**
|
|
332
|
-
*
|
|
333
|
-
* bucket.
|
|
334
|
-
* @param callback - invoked with raw replication bytes
|
|
335
|
-
* @example
|
|
336
|
-
* ```ts
|
|
337
|
-
* bucket.setReplicationCallback(bytes => {
|
|
338
|
-
* console.log('got replication', bytes.length);
|
|
339
|
-
* });
|
|
340
|
-
* ```
|
|
477
|
+
* Alias for `transform` that reads more naturally for document updates.
|
|
341
478
|
*/
|
|
342
|
-
|
|
343
|
-
|
|
479
|
+
update(query, fn) {
|
|
480
|
+
this.transform(query, fn);
|
|
481
|
+
}
|
|
482
|
+
replicationCursor() {
|
|
483
|
+
return exports.albedo.replicationCursor(this.handle);
|
|
484
|
+
}
|
|
485
|
+
readReplicationBatch(cursor, maxBytes = 0) {
|
|
486
|
+
return exports.albedo.readReplicationBatch(this.handle, cursor, maxBytes);
|
|
344
487
|
}
|
|
345
488
|
/**
|
|
346
489
|
* Apply a batch of replication operations to this bucket.
|
|
@@ -351,7 +494,7 @@ class Bucket {
|
|
|
351
494
|
* ```
|
|
352
495
|
*/
|
|
353
496
|
applyReplicationBatch(data) {
|
|
354
|
-
exports.albedo.applyReplicationBatch(this.handle, data);
|
|
497
|
+
return exports.albedo.applyReplicationBatch(this.handle, data);
|
|
355
498
|
}
|
|
356
499
|
}
|
|
357
500
|
exports.Bucket = Bucket;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|