serializable-bptree 8.1.6 → 8.2.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 +4 -2
- package/dist/cjs/index.cjs +83 -32
- package/dist/esm/index.mjs +83 -32
- package/dist/types/BPTreeAsync.d.ts +1 -1
- package/dist/types/BPTreeSync.d.ts +1 -1
- package/dist/types/base/BPTreeTransaction.d.ts +35 -11
- package/dist/types/transaction/BPTreeAsyncTransaction.d.ts +6 -6
- package/dist/types/transaction/BPTreeSyncTransaction.d.ts +6 -6
- package/dist/types/types/index.d.ts +5 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
This is a B+tree that's totally okay with duplicate values. If you need to keep track of the B+ tree's state, don't just leave it in memory - make sure you write it down.
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
|
-
import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'fs'
|
|
10
|
+
import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'node:fs'
|
|
11
11
|
import {
|
|
12
12
|
BPTreeSync,
|
|
13
13
|
SerializeStrategySync,
|
|
@@ -91,6 +91,8 @@ Additionally, this library supports asynchronous operations and rule-based query
|
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
93
|
npm i serializable-bptree
|
|
94
|
+
# or
|
|
95
|
+
npx jsr add @izure/serializable-bptree
|
|
94
96
|
```
|
|
95
97
|
|
|
96
98
|
```typescript
|
|
@@ -156,7 +158,7 @@ const others = candidates.filter((c) => driver.tree !== c.tree)
|
|
|
156
158
|
// 2. Execute query using the selected driver
|
|
157
159
|
let keys = driver.tree.keys(driver.condition)
|
|
158
160
|
for (const { tree, condition } of others) {
|
|
159
|
-
keys = tree.keys(condition, keys)
|
|
161
|
+
keys = tree.keys(condition, { filterValues: keys })
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
console.log('Found: ', keys)
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -343,6 +343,30 @@ var MVCCTransaction = class {
|
|
|
343
343
|
deleted
|
|
344
344
|
};
|
|
345
345
|
}
|
|
346
|
+
/**
|
|
347
|
+
* Checks for conflicts among multiple transactions.
|
|
348
|
+
* A conflict occurs if two or more transactions modify (write or delete) the same key.
|
|
349
|
+
* @param transactions Array of transactions to check.
|
|
350
|
+
* @returns An array of keys that are in conflict.
|
|
351
|
+
*/
|
|
352
|
+
static CheckConflicts(transactions) {
|
|
353
|
+
const modifiedKeys = /* @__PURE__ */ new Map();
|
|
354
|
+
const conflicts = /* @__PURE__ */ new Set();
|
|
355
|
+
for (const tx of transactions) {
|
|
356
|
+
const txModified = /* @__PURE__ */ new Set([
|
|
357
|
+
...tx.writeBuffer.keys(),
|
|
358
|
+
...tx.deleteBuffer
|
|
359
|
+
]);
|
|
360
|
+
for (const key of txModified) {
|
|
361
|
+
const count = modifiedKeys.get(key) ?? 0;
|
|
362
|
+
if (count > 0) {
|
|
363
|
+
conflicts.add(key);
|
|
364
|
+
}
|
|
365
|
+
modifiedKeys.set(key, count + 1);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return Array.from(conflicts);
|
|
369
|
+
}
|
|
346
370
|
/**
|
|
347
371
|
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
348
372
|
* Root transactions call this after commit to reclaim memory.
|
|
@@ -1632,6 +1656,15 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1632
1656
|
}
|
|
1633
1657
|
return best;
|
|
1634
1658
|
}
|
|
1659
|
+
/**
|
|
1660
|
+
* Checks for conflicts between multiple transactions.
|
|
1661
|
+
*
|
|
1662
|
+
* @param transactions Array of BPTreeTransaction instances to check
|
|
1663
|
+
* @returns An array of keys that are in conflict. Empty array if no conflicts.
|
|
1664
|
+
*/
|
|
1665
|
+
static CheckConflicts(transactions) {
|
|
1666
|
+
return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
|
|
1667
|
+
}
|
|
1635
1668
|
/**
|
|
1636
1669
|
* Returns the ID of the root node.
|
|
1637
1670
|
* @returns The root node ID.
|
|
@@ -2084,11 +2117,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2084
2117
|
const { root, order } = head;
|
|
2085
2118
|
this.strategy.head = head;
|
|
2086
2119
|
this.order = order;
|
|
2087
|
-
this.
|
|
2088
|
-
root,
|
|
2089
|
-
order: this.order,
|
|
2090
|
-
data: this.strategy.head.data
|
|
2091
|
-
});
|
|
2120
|
+
this.rootId = root;
|
|
2092
2121
|
}
|
|
2093
2122
|
if (this.order < 3) {
|
|
2094
2123
|
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
@@ -2125,17 +2154,24 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2125
2154
|
}
|
|
2126
2155
|
return void 0;
|
|
2127
2156
|
}
|
|
2128
|
-
*keysStream(condition,
|
|
2129
|
-
const
|
|
2157
|
+
*keysStream(condition, options) {
|
|
2158
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2159
|
+
const stream = this.whereStream(condition, options);
|
|
2130
2160
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2161
|
+
let count = 0;
|
|
2131
2162
|
for (const [key] of stream) {
|
|
2132
2163
|
if (intersection && !intersection.has(key)) {
|
|
2133
2164
|
continue;
|
|
2134
2165
|
}
|
|
2135
2166
|
yield key;
|
|
2167
|
+
count++;
|
|
2168
|
+
if (limit !== void 0 && count >= limit) {
|
|
2169
|
+
break;
|
|
2170
|
+
}
|
|
2136
2171
|
}
|
|
2137
2172
|
}
|
|
2138
|
-
*whereStream(condition,
|
|
2173
|
+
*whereStream(condition, options) {
|
|
2174
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2139
2175
|
const driverKey = this.getDriverKey(condition);
|
|
2140
2176
|
if (!driverKey) return;
|
|
2141
2177
|
const value = condition[driverKey];
|
|
@@ -2158,8 +2194,12 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2158
2194
|
earlyTerminate
|
|
2159
2195
|
);
|
|
2160
2196
|
let count = 0;
|
|
2197
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2161
2198
|
for (const pair of generator) {
|
|
2162
2199
|
const [k, v] = pair;
|
|
2200
|
+
if (intersection && !intersection.has(k)) {
|
|
2201
|
+
continue;
|
|
2202
|
+
}
|
|
2163
2203
|
let isMatch = true;
|
|
2164
2204
|
for (const key in condition) {
|
|
2165
2205
|
if (key === driverKey) continue;
|
|
@@ -2179,16 +2219,16 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2179
2219
|
}
|
|
2180
2220
|
}
|
|
2181
2221
|
}
|
|
2182
|
-
keys(condition,
|
|
2222
|
+
keys(condition, options) {
|
|
2183
2223
|
const set = /* @__PURE__ */ new Set();
|
|
2184
|
-
for (const key of this.keysStream(condition,
|
|
2224
|
+
for (const key of this.keysStream(condition, options)) {
|
|
2185
2225
|
set.add(key);
|
|
2186
2226
|
}
|
|
2187
2227
|
return set;
|
|
2188
2228
|
}
|
|
2189
|
-
where(condition,
|
|
2229
|
+
where(condition, options) {
|
|
2190
2230
|
const map = /* @__PURE__ */ new Map();
|
|
2191
|
-
for (const [key, value] of this.whereStream(condition,
|
|
2231
|
+
for (const [key, value] of this.whereStream(condition, options)) {
|
|
2192
2232
|
map.set(key, value);
|
|
2193
2233
|
}
|
|
2194
2234
|
return map;
|
|
@@ -2414,6 +2454,12 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2414
2454
|
return node;
|
|
2415
2455
|
}
|
|
2416
2456
|
delete(key, value) {
|
|
2457
|
+
if (value === void 0) {
|
|
2458
|
+
value = this.get(key);
|
|
2459
|
+
}
|
|
2460
|
+
if (value === void 0) {
|
|
2461
|
+
return;
|
|
2462
|
+
}
|
|
2417
2463
|
let node = this.insertableNodeByPrimary(value);
|
|
2418
2464
|
let found = false;
|
|
2419
2465
|
while (true) {
|
|
@@ -2865,14 +2911,6 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2865
2911
|
next,
|
|
2866
2912
|
prev
|
|
2867
2913
|
};
|
|
2868
|
-
const head = await this._readHead();
|
|
2869
|
-
if (head) {
|
|
2870
|
-
await this._writeHead({
|
|
2871
|
-
root: head.root,
|
|
2872
|
-
order: head.order,
|
|
2873
|
-
data: this.strategy.head.data
|
|
2874
|
-
});
|
|
2875
|
-
}
|
|
2876
2914
|
await this.mvcc.create(id, node);
|
|
2877
2915
|
return node;
|
|
2878
2916
|
}
|
|
@@ -3165,11 +3203,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3165
3203
|
const { root, order } = head;
|
|
3166
3204
|
this.strategy.head = head;
|
|
3167
3205
|
this.order = order;
|
|
3168
|
-
|
|
3169
|
-
root,
|
|
3170
|
-
order: this.order,
|
|
3171
|
-
data: this.strategy.head.data
|
|
3172
|
-
});
|
|
3206
|
+
this.rootId = root;
|
|
3173
3207
|
}
|
|
3174
3208
|
if (this.order < 3) {
|
|
3175
3209
|
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
@@ -3206,17 +3240,24 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3206
3240
|
}
|
|
3207
3241
|
return void 0;
|
|
3208
3242
|
}
|
|
3209
|
-
async *keysStream(condition,
|
|
3210
|
-
const
|
|
3243
|
+
async *keysStream(condition, options) {
|
|
3244
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
3245
|
+
const stream = this.whereStream(condition, options);
|
|
3211
3246
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3247
|
+
let count = 0;
|
|
3212
3248
|
for await (const [key] of stream) {
|
|
3213
3249
|
if (intersection && !intersection.has(key)) {
|
|
3214
3250
|
continue;
|
|
3215
3251
|
}
|
|
3216
3252
|
yield key;
|
|
3253
|
+
count++;
|
|
3254
|
+
if (limit !== void 0 && count >= limit) {
|
|
3255
|
+
break;
|
|
3256
|
+
}
|
|
3217
3257
|
}
|
|
3218
3258
|
}
|
|
3219
|
-
async *whereStream(condition,
|
|
3259
|
+
async *whereStream(condition, options) {
|
|
3260
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
3220
3261
|
const driverKey = this.getDriverKey(condition);
|
|
3221
3262
|
if (!driverKey) return;
|
|
3222
3263
|
const value = condition[driverKey];
|
|
@@ -3239,8 +3280,12 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3239
3280
|
earlyTerminate
|
|
3240
3281
|
);
|
|
3241
3282
|
let count = 0;
|
|
3283
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3242
3284
|
for await (const pair of generator) {
|
|
3243
3285
|
const [k, v] = pair;
|
|
3286
|
+
if (intersection && !intersection.has(k)) {
|
|
3287
|
+
continue;
|
|
3288
|
+
}
|
|
3244
3289
|
let isMatch = true;
|
|
3245
3290
|
for (const key in condition) {
|
|
3246
3291
|
if (key === driverKey) continue;
|
|
@@ -3260,16 +3305,16 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3260
3305
|
}
|
|
3261
3306
|
}
|
|
3262
3307
|
}
|
|
3263
|
-
async keys(condition,
|
|
3308
|
+
async keys(condition, options) {
|
|
3264
3309
|
const set = /* @__PURE__ */ new Set();
|
|
3265
|
-
for await (const key of this.keysStream(condition,
|
|
3310
|
+
for await (const key of this.keysStream(condition, options)) {
|
|
3266
3311
|
set.add(key);
|
|
3267
3312
|
}
|
|
3268
3313
|
return set;
|
|
3269
3314
|
}
|
|
3270
|
-
async where(condition,
|
|
3315
|
+
async where(condition, options) {
|
|
3271
3316
|
const map = /* @__PURE__ */ new Map();
|
|
3272
|
-
for await (const [key, value] of this.whereStream(condition,
|
|
3317
|
+
for await (const [key, value] of this.whereStream(condition, options)) {
|
|
3273
3318
|
map.set(key, value);
|
|
3274
3319
|
}
|
|
3275
3320
|
return map;
|
|
@@ -3498,6 +3543,12 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3498
3543
|
}
|
|
3499
3544
|
async delete(key, value) {
|
|
3500
3545
|
return this.writeLock(0, async () => {
|
|
3546
|
+
if (value === void 0) {
|
|
3547
|
+
value = await this.get(key);
|
|
3548
|
+
}
|
|
3549
|
+
if (value === void 0) {
|
|
3550
|
+
return;
|
|
3551
|
+
}
|
|
3501
3552
|
let node = await this.insertableNodeByPrimary(value);
|
|
3502
3553
|
let found = false;
|
|
3503
3554
|
while (true) {
|
package/dist/esm/index.mjs
CHANGED
|
@@ -307,6 +307,30 @@ var MVCCTransaction = class {
|
|
|
307
307
|
deleted
|
|
308
308
|
};
|
|
309
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Checks for conflicts among multiple transactions.
|
|
312
|
+
* A conflict occurs if two or more transactions modify (write or delete) the same key.
|
|
313
|
+
* @param transactions Array of transactions to check.
|
|
314
|
+
* @returns An array of keys that are in conflict.
|
|
315
|
+
*/
|
|
316
|
+
static CheckConflicts(transactions) {
|
|
317
|
+
const modifiedKeys = /* @__PURE__ */ new Map();
|
|
318
|
+
const conflicts = /* @__PURE__ */ new Set();
|
|
319
|
+
for (const tx of transactions) {
|
|
320
|
+
const txModified = /* @__PURE__ */ new Set([
|
|
321
|
+
...tx.writeBuffer.keys(),
|
|
322
|
+
...tx.deleteBuffer
|
|
323
|
+
]);
|
|
324
|
+
for (const key of txModified) {
|
|
325
|
+
const count = modifiedKeys.get(key) ?? 0;
|
|
326
|
+
if (count > 0) {
|
|
327
|
+
conflicts.add(key);
|
|
328
|
+
}
|
|
329
|
+
modifiedKeys.set(key, count + 1);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return Array.from(conflicts);
|
|
333
|
+
}
|
|
310
334
|
/**
|
|
311
335
|
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
312
336
|
* Root transactions call this after commit to reclaim memory.
|
|
@@ -1596,6 +1620,15 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1596
1620
|
}
|
|
1597
1621
|
return best;
|
|
1598
1622
|
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Checks for conflicts between multiple transactions.
|
|
1625
|
+
*
|
|
1626
|
+
* @param transactions Array of BPTreeTransaction instances to check
|
|
1627
|
+
* @returns An array of keys that are in conflict. Empty array if no conflicts.
|
|
1628
|
+
*/
|
|
1629
|
+
static CheckConflicts(transactions) {
|
|
1630
|
+
return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
|
|
1631
|
+
}
|
|
1599
1632
|
/**
|
|
1600
1633
|
* Returns the ID of the root node.
|
|
1601
1634
|
* @returns The root node ID.
|
|
@@ -2048,11 +2081,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2048
2081
|
const { root, order } = head;
|
|
2049
2082
|
this.strategy.head = head;
|
|
2050
2083
|
this.order = order;
|
|
2051
|
-
this.
|
|
2052
|
-
root,
|
|
2053
|
-
order: this.order,
|
|
2054
|
-
data: this.strategy.head.data
|
|
2055
|
-
});
|
|
2084
|
+
this.rootId = root;
|
|
2056
2085
|
}
|
|
2057
2086
|
if (this.order < 3) {
|
|
2058
2087
|
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
@@ -2089,17 +2118,24 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2089
2118
|
}
|
|
2090
2119
|
return void 0;
|
|
2091
2120
|
}
|
|
2092
|
-
*keysStream(condition,
|
|
2093
|
-
const
|
|
2121
|
+
*keysStream(condition, options) {
|
|
2122
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2123
|
+
const stream = this.whereStream(condition, options);
|
|
2094
2124
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2125
|
+
let count = 0;
|
|
2095
2126
|
for (const [key] of stream) {
|
|
2096
2127
|
if (intersection && !intersection.has(key)) {
|
|
2097
2128
|
continue;
|
|
2098
2129
|
}
|
|
2099
2130
|
yield key;
|
|
2131
|
+
count++;
|
|
2132
|
+
if (limit !== void 0 && count >= limit) {
|
|
2133
|
+
break;
|
|
2134
|
+
}
|
|
2100
2135
|
}
|
|
2101
2136
|
}
|
|
2102
|
-
*whereStream(condition,
|
|
2137
|
+
*whereStream(condition, options) {
|
|
2138
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2103
2139
|
const driverKey = this.getDriverKey(condition);
|
|
2104
2140
|
if (!driverKey) return;
|
|
2105
2141
|
const value = condition[driverKey];
|
|
@@ -2122,8 +2158,12 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2122
2158
|
earlyTerminate
|
|
2123
2159
|
);
|
|
2124
2160
|
let count = 0;
|
|
2161
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2125
2162
|
for (const pair of generator) {
|
|
2126
2163
|
const [k, v] = pair;
|
|
2164
|
+
if (intersection && !intersection.has(k)) {
|
|
2165
|
+
continue;
|
|
2166
|
+
}
|
|
2127
2167
|
let isMatch = true;
|
|
2128
2168
|
for (const key in condition) {
|
|
2129
2169
|
if (key === driverKey) continue;
|
|
@@ -2143,16 +2183,16 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2143
2183
|
}
|
|
2144
2184
|
}
|
|
2145
2185
|
}
|
|
2146
|
-
keys(condition,
|
|
2186
|
+
keys(condition, options) {
|
|
2147
2187
|
const set = /* @__PURE__ */ new Set();
|
|
2148
|
-
for (const key of this.keysStream(condition,
|
|
2188
|
+
for (const key of this.keysStream(condition, options)) {
|
|
2149
2189
|
set.add(key);
|
|
2150
2190
|
}
|
|
2151
2191
|
return set;
|
|
2152
2192
|
}
|
|
2153
|
-
where(condition,
|
|
2193
|
+
where(condition, options) {
|
|
2154
2194
|
const map = /* @__PURE__ */ new Map();
|
|
2155
|
-
for (const [key, value] of this.whereStream(condition,
|
|
2195
|
+
for (const [key, value] of this.whereStream(condition, options)) {
|
|
2156
2196
|
map.set(key, value);
|
|
2157
2197
|
}
|
|
2158
2198
|
return map;
|
|
@@ -2378,6 +2418,12 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2378
2418
|
return node;
|
|
2379
2419
|
}
|
|
2380
2420
|
delete(key, value) {
|
|
2421
|
+
if (value === void 0) {
|
|
2422
|
+
value = this.get(key);
|
|
2423
|
+
}
|
|
2424
|
+
if (value === void 0) {
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2381
2427
|
let node = this.insertableNodeByPrimary(value);
|
|
2382
2428
|
let found = false;
|
|
2383
2429
|
while (true) {
|
|
@@ -2829,14 +2875,6 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2829
2875
|
next,
|
|
2830
2876
|
prev
|
|
2831
2877
|
};
|
|
2832
|
-
const head = await this._readHead();
|
|
2833
|
-
if (head) {
|
|
2834
|
-
await this._writeHead({
|
|
2835
|
-
root: head.root,
|
|
2836
|
-
order: head.order,
|
|
2837
|
-
data: this.strategy.head.data
|
|
2838
|
-
});
|
|
2839
|
-
}
|
|
2840
2878
|
await this.mvcc.create(id, node);
|
|
2841
2879
|
return node;
|
|
2842
2880
|
}
|
|
@@ -3129,11 +3167,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3129
3167
|
const { root, order } = head;
|
|
3130
3168
|
this.strategy.head = head;
|
|
3131
3169
|
this.order = order;
|
|
3132
|
-
|
|
3133
|
-
root,
|
|
3134
|
-
order: this.order,
|
|
3135
|
-
data: this.strategy.head.data
|
|
3136
|
-
});
|
|
3170
|
+
this.rootId = root;
|
|
3137
3171
|
}
|
|
3138
3172
|
if (this.order < 3) {
|
|
3139
3173
|
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
@@ -3170,17 +3204,24 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3170
3204
|
}
|
|
3171
3205
|
return void 0;
|
|
3172
3206
|
}
|
|
3173
|
-
async *keysStream(condition,
|
|
3174
|
-
const
|
|
3207
|
+
async *keysStream(condition, options) {
|
|
3208
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
3209
|
+
const stream = this.whereStream(condition, options);
|
|
3175
3210
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3211
|
+
let count = 0;
|
|
3176
3212
|
for await (const [key] of stream) {
|
|
3177
3213
|
if (intersection && !intersection.has(key)) {
|
|
3178
3214
|
continue;
|
|
3179
3215
|
}
|
|
3180
3216
|
yield key;
|
|
3217
|
+
count++;
|
|
3218
|
+
if (limit !== void 0 && count >= limit) {
|
|
3219
|
+
break;
|
|
3220
|
+
}
|
|
3181
3221
|
}
|
|
3182
3222
|
}
|
|
3183
|
-
async *whereStream(condition,
|
|
3223
|
+
async *whereStream(condition, options) {
|
|
3224
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
3184
3225
|
const driverKey = this.getDriverKey(condition);
|
|
3185
3226
|
if (!driverKey) return;
|
|
3186
3227
|
const value = condition[driverKey];
|
|
@@ -3203,8 +3244,12 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3203
3244
|
earlyTerminate
|
|
3204
3245
|
);
|
|
3205
3246
|
let count = 0;
|
|
3247
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3206
3248
|
for await (const pair of generator) {
|
|
3207
3249
|
const [k, v] = pair;
|
|
3250
|
+
if (intersection && !intersection.has(k)) {
|
|
3251
|
+
continue;
|
|
3252
|
+
}
|
|
3208
3253
|
let isMatch = true;
|
|
3209
3254
|
for (const key in condition) {
|
|
3210
3255
|
if (key === driverKey) continue;
|
|
@@ -3224,16 +3269,16 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3224
3269
|
}
|
|
3225
3270
|
}
|
|
3226
3271
|
}
|
|
3227
|
-
async keys(condition,
|
|
3272
|
+
async keys(condition, options) {
|
|
3228
3273
|
const set = /* @__PURE__ */ new Set();
|
|
3229
|
-
for await (const key of this.keysStream(condition,
|
|
3274
|
+
for await (const key of this.keysStream(condition, options)) {
|
|
3230
3275
|
set.add(key);
|
|
3231
3276
|
}
|
|
3232
3277
|
return set;
|
|
3233
3278
|
}
|
|
3234
|
-
async where(condition,
|
|
3279
|
+
async where(condition, options) {
|
|
3235
3280
|
const map = /* @__PURE__ */ new Map();
|
|
3236
|
-
for await (const [key, value] of this.whereStream(condition,
|
|
3281
|
+
for await (const [key, value] of this.whereStream(condition, options)) {
|
|
3237
3282
|
map.set(key, value);
|
|
3238
3283
|
}
|
|
3239
3284
|
return map;
|
|
@@ -3462,6 +3507,12 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3462
3507
|
}
|
|
3463
3508
|
async delete(key, value) {
|
|
3464
3509
|
return this.writeLock(0, async () => {
|
|
3510
|
+
if (value === void 0) {
|
|
3511
|
+
value = await this.get(key);
|
|
3512
|
+
}
|
|
3513
|
+
if (value === void 0) {
|
|
3514
|
+
return;
|
|
3515
|
+
}
|
|
3465
3516
|
let node = await this.insertableNodeByPrimary(value);
|
|
3466
3517
|
let found = false;
|
|
3467
3518
|
while (true) {
|
|
@@ -10,5 +10,5 @@ export declare class BPTreeAsync<K, V> extends BPTreeAsyncTransaction<K, V> {
|
|
|
10
10
|
*/
|
|
11
11
|
createTransaction(): Promise<BPTreeAsyncTransaction<K, V>>;
|
|
12
12
|
insert(key: K, value: V): Promise<void>;
|
|
13
|
-
delete(key: K, value
|
|
13
|
+
delete(key: K, value?: V): Promise<void>;
|
|
14
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TransactionEntry, TransactionResult } from 'mvcc-api';
|
|
2
|
-
import type { BPTreeCondition, BPTreeConstructorOption, BPTreeUnknownNode, Deferred, BPTreeLeafNode, BPTreeNodeKey, BPTreePair, SerializableData, BPTreeNode, BPTreeMVCC } from '../types';
|
|
2
|
+
import type { BPTreeCondition, BPTreeConstructorOption, BPTreeUnknownNode, Deferred, BPTreeLeafNode, BPTreeNodeKey, BPTreePair, SerializableData, BPTreeNode, BPTreeMVCC, BPTreeSearchOption } from '../types';
|
|
3
3
|
import { ValueComparator } from './ValueComparator';
|
|
4
4
|
import { SerializeStrategy } from './SerializeStrategy';
|
|
5
5
|
export declare abstract class BPTreeTransaction<K, V> {
|
|
@@ -55,6 +55,13 @@ export declare abstract class BPTreeTransaction<K, V> {
|
|
|
55
55
|
tree: T;
|
|
56
56
|
condition: BPTreeCondition<unknown>;
|
|
57
57
|
} | null;
|
|
58
|
+
/**
|
|
59
|
+
* Checks for conflicts between multiple transactions.
|
|
60
|
+
*
|
|
61
|
+
* @param transactions Array of BPTreeTransaction instances to check
|
|
62
|
+
* @returns An array of keys that are in conflict. Empty array if no conflicts.
|
|
63
|
+
*/
|
|
64
|
+
static CheckConflicts<K, V>(transactions: BPTreeTransaction<K, V>[]): string[];
|
|
58
65
|
/**
|
|
59
66
|
* Returns the ID of the root node.
|
|
60
67
|
* @returns The root node ID.
|
|
@@ -100,28 +107,44 @@ export declare abstract class BPTreeTransaction<K, V> {
|
|
|
100
107
|
* This method is used to initialize the stored tree and recover data.
|
|
101
108
|
* If it is not called, the tree will not function.
|
|
102
109
|
*/
|
|
110
|
+
abstract init(): Deferred<void>;
|
|
103
111
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
112
|
+
* Retrieves the value associated with the given key.
|
|
113
|
+
* @param key The key to search for.
|
|
114
|
+
* @returns A Deferred that resolves to the value if found, or undefined if not found.
|
|
107
115
|
*/
|
|
108
|
-
abstract
|
|
116
|
+
abstract get(key: K): Deferred<V | undefined>;
|
|
117
|
+
/**
|
|
118
|
+
* Returns a generator that yields keys satisfying the given condition.
|
|
119
|
+
* This is a memory-efficient way to iterate through keys when dealing with large result sets.
|
|
120
|
+
* @param condition The search condition (e.g., gt, lt, equal, like).
|
|
121
|
+
* @param options Search options including filterValues, limit, and order.
|
|
122
|
+
* @returns An async or synchronous generator yielding keys of type K.
|
|
123
|
+
*/
|
|
124
|
+
abstract keysStream(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): AsyncGenerator<K> | Generator<K>;
|
|
125
|
+
/**
|
|
126
|
+
* Returns a generator that yields [key, value] pairs satisfying the given condition.
|
|
127
|
+
* This is a memory-efficient way to iterate through pairs when dealing with large result sets.
|
|
128
|
+
* @param condition The search condition (e.g., gt, lt, equal, like).
|
|
129
|
+
* @param options Search options including filterValues, limit, and order.
|
|
130
|
+
* @returns An async or synchronous generator yielding [K, V] tuples.
|
|
131
|
+
*/
|
|
132
|
+
abstract whereStream(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): AsyncGenerator<[K, V]> | Generator<[K, V]>;
|
|
109
133
|
/**
|
|
110
134
|
* It searches for a key within the tree. The result is returned as an array sorted in ascending order based on the value.
|
|
111
135
|
* The result is key set instance, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
|
|
112
136
|
* This method operates much faster than first searching with `where` and then retrieving only the key list.
|
|
113
137
|
* @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
|
|
114
|
-
* @param
|
|
115
|
-
* Returns a `Set` containing values that are common to both the input `Set` and the intersection `Set`.
|
|
116
|
-
* If this parameter is not provided, it searches for all keys inserted into the tree.
|
|
138
|
+
* @param options Search options including filterValues, limit, and order.
|
|
117
139
|
*/
|
|
118
|
-
abstract keys(condition: BPTreeCondition<V>,
|
|
140
|
+
abstract keys(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Deferred<Set<K>>;
|
|
119
141
|
/**
|
|
120
142
|
* It searches for a value within the tree. The result is returned as an array sorted in ascending order based on the value.
|
|
121
143
|
* The result includes the key and value attributes, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
|
|
122
144
|
* @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
|
|
145
|
+
* @param options Search options including filterValues, limit, and order.
|
|
123
146
|
*/
|
|
124
|
-
abstract where(condition: BPTreeCondition<V>): Deferred<BPTreePair<K, V>>;
|
|
147
|
+
abstract where(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Deferred<BPTreePair<K, V>>;
|
|
125
148
|
/**
|
|
126
149
|
* You enter the key and value as a pair. You can later search for the pair by value.
|
|
127
150
|
* This data is stored in the tree, sorted in ascending order of value.
|
|
@@ -133,8 +156,9 @@ export declare abstract class BPTreeTransaction<K, V> {
|
|
|
133
156
|
* Deletes the pair that matches the key and value.
|
|
134
157
|
* @param key The key of the pair. This key must be unique.
|
|
135
158
|
* @param value The value of the pair.
|
|
159
|
+
* @warning If the 'value' is not specified, a full scan will be performed to find the value associated with the key, which may lead to performance degradation.
|
|
136
160
|
*/
|
|
137
|
-
abstract delete(key: K, value
|
|
161
|
+
abstract delete(key: K, value?: V): Deferred<void>;
|
|
138
162
|
/**
|
|
139
163
|
* It returns whether there is a value in the tree.
|
|
140
164
|
* @param key The key value to search for. This key must be unique.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TransactionResult } from 'mvcc-api';
|
|
2
|
-
import type { AsyncBPTreeMVCC, BPTreeCondition, BPTreeConstructorOption, BPTreeLeafNode, BPTreeNode, BPTreeNodeKey,
|
|
2
|
+
import type { AsyncBPTreeMVCC, BPTreeCondition, BPTreeConstructorOption, BPTreeLeafNode, BPTreeNode, BPTreeNodeKey, BPTreePair, BPTreeUnknownNode, SerializableData, SerializeStrategyHead, BPTreeSearchOption } from '../types';
|
|
3
3
|
import { Ryoiki } from 'ryoiki';
|
|
4
4
|
import { BPTreeTransaction } from '../base/BPTreeTransaction';
|
|
5
5
|
import { SerializeStrategyAsync } from '../SerializeStrategyAsync';
|
|
@@ -37,13 +37,13 @@ export declare class BPTreeAsyncTransaction<K, V> extends BPTreeTransaction<K, V
|
|
|
37
37
|
protected _initInternal(): Promise<void>;
|
|
38
38
|
exists(key: K, value: V): Promise<boolean>;
|
|
39
39
|
get(key: K): Promise<V | undefined>;
|
|
40
|
-
keysStream(condition: BPTreeCondition<V>,
|
|
41
|
-
whereStream(condition: BPTreeCondition<V>,
|
|
42
|
-
keys(condition: BPTreeCondition<V>,
|
|
43
|
-
where(condition: BPTreeCondition<V>,
|
|
40
|
+
keysStream(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): AsyncGenerator<K>;
|
|
41
|
+
whereStream(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): AsyncGenerator<[K, V]>;
|
|
42
|
+
keys(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Promise<Set<K>>;
|
|
43
|
+
where(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Promise<BPTreePair<K, V>>;
|
|
44
44
|
insert(key: K, value: V): Promise<void>;
|
|
45
45
|
protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>): Promise<BPTreeUnknownNode<K, V>>;
|
|
46
|
-
delete(key: K, value
|
|
46
|
+
delete(key: K, value?: V): Promise<void>;
|
|
47
47
|
getHeadData(): Promise<SerializableData>;
|
|
48
48
|
setHeadData(data: SerializableData): Promise<void>;
|
|
49
49
|
commit(label?: string): Promise<TransactionResult<string, BPTreeNode<K, V>>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TransactionResult } from 'mvcc-api';
|
|
2
|
-
import type { BPTreeCondition, BPTreeConstructorOption, BPTreeLeafNode, BPTreeNode, BPTreeNodeKey,
|
|
2
|
+
import type { BPTreeCondition, BPTreeConstructorOption, BPTreeLeafNode, BPTreeNode, BPTreeNodeKey, BPTreePair, BPTreeUnknownNode, SerializableData, SerializeStrategyHead, SyncBPTreeMVCC, BPTreeSearchOption } from '../types';
|
|
3
3
|
import { BPTreeTransaction } from '../base/BPTreeTransaction';
|
|
4
4
|
import { SerializeStrategySync } from '../SerializeStrategySync';
|
|
5
5
|
import { ValueComparator } from '../base/ValueComparator';
|
|
@@ -34,13 +34,13 @@ export declare class BPTreeSyncTransaction<K, V> extends BPTreeTransaction<K, V>
|
|
|
34
34
|
protected _initInternal(): void;
|
|
35
35
|
exists(key: K, value: V): boolean;
|
|
36
36
|
get(key: K): V | undefined;
|
|
37
|
-
keysStream(condition: BPTreeCondition<V>,
|
|
38
|
-
whereStream(condition: BPTreeCondition<V>,
|
|
39
|
-
keys(condition: BPTreeCondition<V>,
|
|
40
|
-
where(condition: BPTreeCondition<V>,
|
|
37
|
+
keysStream(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Generator<K>;
|
|
38
|
+
whereStream(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Generator<[K, V]>;
|
|
39
|
+
keys(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Set<K>;
|
|
40
|
+
where(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): BPTreePair<K, V>;
|
|
41
41
|
insert(key: K, value: V): void;
|
|
42
42
|
protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>): BPTreeUnknownNode<K, V>;
|
|
43
|
-
delete(key: K, value
|
|
43
|
+
delete(key: K, value?: V): void;
|
|
44
44
|
getHeadData(): SerializableData;
|
|
45
45
|
setHeadData(data: SerializableData): void;
|
|
46
46
|
commit(label?: string): TransactionResult<string, BPTreeNode<K, V>>;
|
|
@@ -52,6 +52,11 @@ export type BPTreeCondition<V> = Partial<{
|
|
|
52
52
|
* - `'desc'`: Descending order - traverses from right to left
|
|
53
53
|
*/
|
|
54
54
|
export type BPTreeOrder = 'asc' | 'desc';
|
|
55
|
+
export interface BPTreeSearchOption<K> {
|
|
56
|
+
filterValues?: Set<K>;
|
|
57
|
+
limit?: number;
|
|
58
|
+
order?: BPTreeOrder;
|
|
59
|
+
}
|
|
55
60
|
export type BPTreePair<K, V> = Map<K, V>;
|
|
56
61
|
export type BPTreeUnknownNode<K, V> = BPTreeInternalNode<K, V> | BPTreeLeafNode<K, V>;
|
|
57
62
|
export interface BPTreeConstructorOption {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serializable-bptree",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.2.0",
|
|
4
4
|
"description": "Store the B+tree flexibly, not only in-memory.",
|
|
5
5
|
"types": "./dist/types/index.d.ts",
|
|
6
6
|
"main": "./dist/cjs/index.cjs",
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/jest": "^30.0.0",
|
|
41
|
-
"esbuild": "^0.27.
|
|
41
|
+
"esbuild": "^0.27.3",
|
|
42
42
|
"jest": "^30.2.0",
|
|
43
43
|
"ts-jest": "^29.4.6",
|
|
44
44
|
"typescript": "^5.9.3"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"mvcc-api": "^1.3.
|
|
47
|
+
"mvcc-api": "^1.3.4",
|
|
48
48
|
"ryoiki": "^1.2.0"
|
|
49
49
|
}
|
|
50
50
|
}
|