serializable-bptree 6.1.1 → 6.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 +34 -2
- package/dist/cjs/index.cjs +348 -202
- package/dist/esm/index.mjs +348 -202
- package/dist/types/BPTreeAsync.d.ts +11 -3
- package/dist/types/BPTreeSync.d.ts +11 -3
- package/dist/types/base/BPTree.d.ts +37 -3
- package/package.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -432,7 +432,7 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
|
432
432
|
};
|
|
433
433
|
|
|
434
434
|
// src/base/BPTree.ts
|
|
435
|
-
var BPTree = class {
|
|
435
|
+
var BPTree = class _BPTree {
|
|
436
436
|
_cachedRegexp;
|
|
437
437
|
strategy;
|
|
438
438
|
comparator;
|
|
@@ -544,6 +544,82 @@ var BPTree = class {
|
|
|
544
544
|
primaryOr: false,
|
|
545
545
|
like: false
|
|
546
546
|
};
|
|
547
|
+
/**
|
|
548
|
+
* Priority map for condition types.
|
|
549
|
+
* Higher value = higher selectivity (fewer expected results).
|
|
550
|
+
* Used by `chooseDriver` to select the most selective index.
|
|
551
|
+
*/
|
|
552
|
+
static conditionPriority = {
|
|
553
|
+
equal: 100,
|
|
554
|
+
primaryEqual: 100,
|
|
555
|
+
or: 80,
|
|
556
|
+
primaryOr: 80,
|
|
557
|
+
gt: 50,
|
|
558
|
+
gte: 50,
|
|
559
|
+
lt: 50,
|
|
560
|
+
lte: 50,
|
|
561
|
+
primaryGt: 50,
|
|
562
|
+
primaryGte: 50,
|
|
563
|
+
primaryLt: 50,
|
|
564
|
+
primaryLte: 50,
|
|
565
|
+
like: 30,
|
|
566
|
+
notEqual: 10,
|
|
567
|
+
primaryNotEqual: 10
|
|
568
|
+
};
|
|
569
|
+
/**
|
|
570
|
+
* Selects the best driver tree from multiple tree/condition pairs.
|
|
571
|
+
* Uses rule-based optimization to choose the tree with highest estimated selectivity.
|
|
572
|
+
*
|
|
573
|
+
* @param candidates Array of { tree, condition } pairs to evaluate
|
|
574
|
+
* @returns The candidate with highest priority condition, or null if empty
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```typescript
|
|
578
|
+
* const driver = BPTreeSync.chooseDriver([
|
|
579
|
+
* { tree: idxId, condition: { equal: 100 } },
|
|
580
|
+
* { tree: idxAge, condition: { gt: 20 } }
|
|
581
|
+
* ])
|
|
582
|
+
* // Returns { tree: idxId, condition: { equal: 100 } } because 'equal' has higher priority
|
|
583
|
+
* ```
|
|
584
|
+
*/
|
|
585
|
+
static ChooseDriver(candidates) {
|
|
586
|
+
if (candidates.length === 0) return null;
|
|
587
|
+
if (candidates.length === 1) return candidates[0];
|
|
588
|
+
let best = candidates[0];
|
|
589
|
+
let bestScore = 0;
|
|
590
|
+
for (const candidate of candidates) {
|
|
591
|
+
let score = 0;
|
|
592
|
+
for (const key in candidate.condition) {
|
|
593
|
+
const condKey = key;
|
|
594
|
+
const priority = _BPTree.conditionPriority[condKey] ?? 0;
|
|
595
|
+
if (priority > score) {
|
|
596
|
+
score = priority;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
if (score > bestScore) {
|
|
600
|
+
bestScore = score;
|
|
601
|
+
best = candidate;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return best;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Verified if the value satisfies the condition.
|
|
608
|
+
*
|
|
609
|
+
* @param nodeValue The value to verify.
|
|
610
|
+
* @param condition The condition to verify against.
|
|
611
|
+
* @returns Returns true if the value satisfies the condition.
|
|
612
|
+
*/
|
|
613
|
+
verify(nodeValue, condition) {
|
|
614
|
+
for (const key in condition) {
|
|
615
|
+
const verify = this.verifierMap[key];
|
|
616
|
+
const condValue = condition[key];
|
|
617
|
+
if (!verify(nodeValue, condValue)) {
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
547
623
|
constructor(strategy, comparator, option) {
|
|
548
624
|
this.strategy = strategy;
|
|
549
625
|
this.comparator = comparator;
|
|
@@ -664,8 +740,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
664
740
|
capacity: this.option.capacity ?? 1e3
|
|
665
741
|
});
|
|
666
742
|
}
|
|
667
|
-
|
|
668
|
-
const pairs = [];
|
|
743
|
+
*getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
669
744
|
let node = startNode;
|
|
670
745
|
let done = false;
|
|
671
746
|
let hasMatched = false;
|
|
@@ -674,71 +749,52 @@ var BPTreeSync = class extends BPTree {
|
|
|
674
749
|
done = true;
|
|
675
750
|
break;
|
|
676
751
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
752
|
+
const len = node.values.length;
|
|
753
|
+
if (direction === 1) {
|
|
754
|
+
for (let i = 0; i < len; i++) {
|
|
755
|
+
const nValue = node.values[i];
|
|
756
|
+
const keys = node.keys[i];
|
|
757
|
+
if (comparator(nValue, value)) {
|
|
758
|
+
hasMatched = true;
|
|
759
|
+
for (let j = 0; j < keys.length; j++) {
|
|
760
|
+
yield [keys[j], nValue];
|
|
761
|
+
}
|
|
762
|
+
} else if (earlyTerminate && hasMatched) {
|
|
763
|
+
done = true;
|
|
764
|
+
break;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
} else {
|
|
768
|
+
let i = len;
|
|
769
|
+
while (i--) {
|
|
770
|
+
const nValue = node.values[i];
|
|
771
|
+
const keys = node.keys[i];
|
|
772
|
+
if (comparator(nValue, value)) {
|
|
773
|
+
hasMatched = true;
|
|
774
|
+
let j = keys.length;
|
|
775
|
+
while (j--) {
|
|
776
|
+
yield [keys[j], nValue];
|
|
777
|
+
}
|
|
778
|
+
} else if (earlyTerminate && hasMatched) {
|
|
779
|
+
done = true;
|
|
780
|
+
break;
|
|
686
781
|
}
|
|
687
|
-
} else if (earlyTerminate && hasMatched) {
|
|
688
|
-
done = true;
|
|
689
|
-
break;
|
|
690
782
|
}
|
|
691
783
|
}
|
|
692
784
|
if (done) break;
|
|
693
|
-
if (
|
|
694
|
-
|
|
695
|
-
break;
|
|
696
|
-
}
|
|
697
|
-
node = this.getNode(node.prev);
|
|
698
|
-
}
|
|
699
|
-
return new Map(pairs.reverse());
|
|
700
|
-
}
|
|
701
|
-
getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
702
|
-
const pairs = [];
|
|
703
|
-
let node = startNode;
|
|
704
|
-
let done = false;
|
|
705
|
-
let hasMatched = false;
|
|
706
|
-
while (!done) {
|
|
707
|
-
if (endNode && node.id === endNode.id) {
|
|
708
|
-
done = true;
|
|
709
|
-
break;
|
|
710
|
-
}
|
|
711
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
712
|
-
const nValue = node.values[i];
|
|
713
|
-
const keys = node.keys[i];
|
|
714
|
-
if (comparator(nValue, value)) {
|
|
715
|
-
hasMatched = true;
|
|
716
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
717
|
-
const key = keys[j];
|
|
718
|
-
pairs.push([key, nValue]);
|
|
719
|
-
}
|
|
720
|
-
} else if (earlyTerminate && hasMatched) {
|
|
785
|
+
if (direction === 1) {
|
|
786
|
+
if (!node.next) {
|
|
721
787
|
done = true;
|
|
722
788
|
break;
|
|
723
789
|
}
|
|
790
|
+
node = this.getNode(node.next);
|
|
791
|
+
} else {
|
|
792
|
+
if (!node.prev) {
|
|
793
|
+
done = true;
|
|
794
|
+
break;
|
|
795
|
+
}
|
|
796
|
+
node = this.getNode(node.prev);
|
|
724
797
|
}
|
|
725
|
-
if (done) break;
|
|
726
|
-
if (!node.next) {
|
|
727
|
-
done = true;
|
|
728
|
-
break;
|
|
729
|
-
}
|
|
730
|
-
node = this.getNode(node.next);
|
|
731
|
-
}
|
|
732
|
-
return new Map(pairs);
|
|
733
|
-
}
|
|
734
|
-
getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
735
|
-
switch (direction) {
|
|
736
|
-
case -1:
|
|
737
|
-
return this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
738
|
-
case 1:
|
|
739
|
-
return this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
740
|
-
default:
|
|
741
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
742
798
|
}
|
|
743
799
|
}
|
|
744
800
|
_createNodeId(isLeaf) {
|
|
@@ -1194,55 +1250,109 @@ var BPTreeSync = class extends BPTree {
|
|
|
1194
1250
|
}
|
|
1195
1251
|
this._nodeDeleteBuffer.clear();
|
|
1196
1252
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
if (
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1253
|
+
/**
|
|
1254
|
+
* Retrieves the value associated with the given key (PK).
|
|
1255
|
+
* Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
|
|
1256
|
+
*
|
|
1257
|
+
* @param key The key to search for.
|
|
1258
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
1259
|
+
*/
|
|
1260
|
+
get(key) {
|
|
1261
|
+
let node = this.leftestNode();
|
|
1262
|
+
while (true) {
|
|
1263
|
+
if (node.values) {
|
|
1264
|
+
const len = node.values.length;
|
|
1265
|
+
for (let i = 0; i < len; i++) {
|
|
1266
|
+
const keys = node.keys[i];
|
|
1267
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1268
|
+
if (keys[j] === key) {
|
|
1269
|
+
return node.values[i];
|
|
1270
|
+
}
|
|
1215
1271
|
}
|
|
1216
1272
|
}
|
|
1217
|
-
filterValues = intersections;
|
|
1218
1273
|
}
|
|
1274
|
+
if (!node.next) break;
|
|
1275
|
+
node = this.getNode(node.next);
|
|
1219
1276
|
}
|
|
1220
|
-
return
|
|
1277
|
+
return void 0;
|
|
1221
1278
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1279
|
+
*keysStream(condition, filterValues, limit) {
|
|
1280
|
+
const stream = this.whereStream(condition, limit);
|
|
1281
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
1282
|
+
for (const [key] of stream) {
|
|
1283
|
+
if (intersection && !intersection.has(key)) {
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
yield key;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
*whereStream(condition, limit) {
|
|
1290
|
+
let driverKey = null;
|
|
1291
|
+
if ("primaryEqual" in condition) driverKey = "primaryEqual";
|
|
1292
|
+
else if ("equal" in condition) driverKey = "equal";
|
|
1293
|
+
else if ("gt" in condition) driverKey = "gt";
|
|
1294
|
+
else if ("gte" in condition) driverKey = "gte";
|
|
1295
|
+
else if ("lt" in condition) driverKey = "lt";
|
|
1296
|
+
else if ("lte" in condition) driverKey = "lte";
|
|
1297
|
+
else if ("primaryGt" in condition) driverKey = "primaryGt";
|
|
1298
|
+
else if ("primaryGte" in condition) driverKey = "primaryGte";
|
|
1299
|
+
else if ("primaryLt" in condition) driverKey = "primaryLt";
|
|
1300
|
+
else if ("primaryLte" in condition) driverKey = "primaryLte";
|
|
1301
|
+
else if ("like" in condition) driverKey = "like";
|
|
1302
|
+
else if ("notEqual" in condition) driverKey = "notEqual";
|
|
1303
|
+
else if ("primaryNotEqual" in condition) driverKey = "primaryNotEqual";
|
|
1304
|
+
else if ("or" in condition) driverKey = "or";
|
|
1305
|
+
else if ("primaryOr" in condition) driverKey = "primaryOr";
|
|
1306
|
+
if (!driverKey) return;
|
|
1307
|
+
const value = condition[driverKey];
|
|
1308
|
+
const startNode = this.verifierStartNode[driverKey](value);
|
|
1309
|
+
const endNode = this.verifierEndNode[driverKey](value);
|
|
1310
|
+
const direction = this.verifierDirection[driverKey];
|
|
1311
|
+
const comparator = this.verifierMap[driverKey];
|
|
1312
|
+
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
1313
|
+
const generator = this.getPairsGenerator(
|
|
1314
|
+
value,
|
|
1315
|
+
startNode,
|
|
1316
|
+
endNode,
|
|
1317
|
+
comparator,
|
|
1318
|
+
direction,
|
|
1319
|
+
earlyTerminate
|
|
1320
|
+
);
|
|
1321
|
+
let count = 0;
|
|
1322
|
+
for (const pair of generator) {
|
|
1323
|
+
const [k, v] = pair;
|
|
1324
|
+
let isMatch = true;
|
|
1325
|
+
for (const key in condition) {
|
|
1326
|
+
if (key === driverKey) continue;
|
|
1327
|
+
const verify = this.verifierMap[key];
|
|
1328
|
+
const condValue = condition[key];
|
|
1329
|
+
if (!verify(v, condValue)) {
|
|
1330
|
+
isMatch = false;
|
|
1331
|
+
break;
|
|
1241
1332
|
}
|
|
1242
|
-
result = intersection;
|
|
1243
1333
|
}
|
|
1334
|
+
if (isMatch) {
|
|
1335
|
+
yield pair;
|
|
1336
|
+
count++;
|
|
1337
|
+
if (limit !== void 0 && count >= limit) {
|
|
1338
|
+
break;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
keys(condition, filterValues) {
|
|
1344
|
+
const set = /* @__PURE__ */ new Set();
|
|
1345
|
+
for (const key of this.keysStream(condition, filterValues)) {
|
|
1346
|
+
set.add(key);
|
|
1244
1347
|
}
|
|
1245
|
-
return
|
|
1348
|
+
return set;
|
|
1349
|
+
}
|
|
1350
|
+
where(condition) {
|
|
1351
|
+
const map = /* @__PURE__ */ new Map();
|
|
1352
|
+
for (const [key, value] of this.whereStream(condition)) {
|
|
1353
|
+
map.set(key, value);
|
|
1354
|
+
}
|
|
1355
|
+
return map;
|
|
1246
1356
|
}
|
|
1247
1357
|
insert(key, value) {
|
|
1248
1358
|
const before = this.insertableNode(value);
|
|
@@ -1617,8 +1727,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1617
1727
|
this.lock.writeUnlock(lockId);
|
|
1618
1728
|
});
|
|
1619
1729
|
}
|
|
1620
|
-
async
|
|
1621
|
-
const pairs = [];
|
|
1730
|
+
async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1622
1731
|
let node = startNode;
|
|
1623
1732
|
let done = false;
|
|
1624
1733
|
let hasMatched = false;
|
|
@@ -1627,71 +1736,52 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1627
1736
|
done = true;
|
|
1628
1737
|
break;
|
|
1629
1738
|
}
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1739
|
+
const len = node.values.length;
|
|
1740
|
+
if (direction === 1) {
|
|
1741
|
+
for (let i = 0; i < len; i++) {
|
|
1742
|
+
const nValue = node.values[i];
|
|
1743
|
+
const keys = node.keys[i];
|
|
1744
|
+
if (comparator(nValue, value)) {
|
|
1745
|
+
hasMatched = true;
|
|
1746
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1747
|
+
yield [keys[j], nValue];
|
|
1748
|
+
}
|
|
1749
|
+
} else if (earlyTerminate && hasMatched) {
|
|
1750
|
+
done = true;
|
|
1751
|
+
break;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
} else {
|
|
1755
|
+
let i = len;
|
|
1756
|
+
while (i--) {
|
|
1757
|
+
const nValue = node.values[i];
|
|
1758
|
+
const keys = node.keys[i];
|
|
1759
|
+
if (comparator(nValue, value)) {
|
|
1760
|
+
hasMatched = true;
|
|
1761
|
+
let j = keys.length;
|
|
1762
|
+
while (j--) {
|
|
1763
|
+
yield [keys[j], nValue];
|
|
1764
|
+
}
|
|
1765
|
+
} else if (earlyTerminate && hasMatched) {
|
|
1766
|
+
done = true;
|
|
1767
|
+
break;
|
|
1639
1768
|
}
|
|
1640
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1641
|
-
done = true;
|
|
1642
|
-
break;
|
|
1643
1769
|
}
|
|
1644
1770
|
}
|
|
1645
1771
|
if (done) break;
|
|
1646
|
-
if (
|
|
1647
|
-
|
|
1648
|
-
break;
|
|
1649
|
-
}
|
|
1650
|
-
node = await this.getNode(node.prev);
|
|
1651
|
-
}
|
|
1652
|
-
return new Map(pairs.reverse());
|
|
1653
|
-
}
|
|
1654
|
-
async getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
1655
|
-
const pairs = [];
|
|
1656
|
-
let node = startNode;
|
|
1657
|
-
let done = false;
|
|
1658
|
-
let hasMatched = false;
|
|
1659
|
-
while (!done) {
|
|
1660
|
-
if (endNode && node.id === endNode.id) {
|
|
1661
|
-
done = true;
|
|
1662
|
-
break;
|
|
1663
|
-
}
|
|
1664
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
1665
|
-
const nValue = node.values[i];
|
|
1666
|
-
const keys = node.keys[i];
|
|
1667
|
-
if (comparator(nValue, value)) {
|
|
1668
|
-
hasMatched = true;
|
|
1669
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
1670
|
-
const key = keys[j];
|
|
1671
|
-
pairs.push([key, nValue]);
|
|
1672
|
-
}
|
|
1673
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1772
|
+
if (direction === 1) {
|
|
1773
|
+
if (!node.next) {
|
|
1674
1774
|
done = true;
|
|
1675
1775
|
break;
|
|
1676
1776
|
}
|
|
1777
|
+
node = await this.getNode(node.next);
|
|
1778
|
+
} else {
|
|
1779
|
+
if (!node.prev) {
|
|
1780
|
+
done = true;
|
|
1781
|
+
break;
|
|
1782
|
+
}
|
|
1783
|
+
node = await this.getNode(node.prev);
|
|
1677
1784
|
}
|
|
1678
|
-
if (done) break;
|
|
1679
|
-
if (!node.next) {
|
|
1680
|
-
done = true;
|
|
1681
|
-
break;
|
|
1682
|
-
}
|
|
1683
|
-
node = await this.getNode(node.next);
|
|
1684
|
-
}
|
|
1685
|
-
return new Map(pairs);
|
|
1686
|
-
}
|
|
1687
|
-
async getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1688
|
-
switch (direction) {
|
|
1689
|
-
case -1:
|
|
1690
|
-
return await this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
1691
|
-
case 1:
|
|
1692
|
-
return await this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
1693
|
-
default:
|
|
1694
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
1695
1785
|
}
|
|
1696
1786
|
}
|
|
1697
1787
|
async _createNodeId(isLeaf) {
|
|
@@ -2147,58 +2237,114 @@ var BPTreeAsync = class extends BPTree {
|
|
|
2147
2237
|
}
|
|
2148
2238
|
this._nodeDeleteBuffer.clear();
|
|
2149
2239
|
}
|
|
2150
|
-
|
|
2240
|
+
/**
|
|
2241
|
+
* Retrieves the value associated with the given key (PK).
|
|
2242
|
+
* Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
|
|
2243
|
+
*
|
|
2244
|
+
* @param key The key to search for.
|
|
2245
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
2246
|
+
*/
|
|
2247
|
+
async get(key) {
|
|
2151
2248
|
return this.readLock(async () => {
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
filterValues = new Set(pairs.keys());
|
|
2163
|
-
} else {
|
|
2164
|
-
const intersections = /* @__PURE__ */ new Set();
|
|
2165
|
-
for (const key2 of filterValues) {
|
|
2166
|
-
const has = pairs.has(key2);
|
|
2167
|
-
if (has) {
|
|
2168
|
-
intersections.add(key2);
|
|
2249
|
+
let node = await this.leftestNode();
|
|
2250
|
+
while (true) {
|
|
2251
|
+
if (node.values) {
|
|
2252
|
+
const len = node.values.length;
|
|
2253
|
+
for (let i = 0; i < len; i++) {
|
|
2254
|
+
const keys = node.keys[i];
|
|
2255
|
+
for (let j = 0; j < keys.length; j++) {
|
|
2256
|
+
if (keys[j] === key) {
|
|
2257
|
+
return node.values[i];
|
|
2258
|
+
}
|
|
2169
2259
|
}
|
|
2170
2260
|
}
|
|
2171
|
-
filterValues = intersections;
|
|
2172
2261
|
}
|
|
2262
|
+
if (!node.next) break;
|
|
2263
|
+
node = await this.getNode(node.next);
|
|
2173
2264
|
}
|
|
2174
|
-
return
|
|
2265
|
+
return void 0;
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
async *keysStream(condition, filterValues, limit) {
|
|
2269
|
+
const stream = this.whereStream(condition, limit);
|
|
2270
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2271
|
+
for await (const [key] of stream) {
|
|
2272
|
+
if (intersection && !intersection.has(key)) {
|
|
2273
|
+
continue;
|
|
2274
|
+
}
|
|
2275
|
+
yield key;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
async *whereStream(condition, limit) {
|
|
2279
|
+
let driverKey = null;
|
|
2280
|
+
if ("primaryEqual" in condition) driverKey = "primaryEqual";
|
|
2281
|
+
else if ("equal" in condition) driverKey = "equal";
|
|
2282
|
+
else if ("gt" in condition) driverKey = "gt";
|
|
2283
|
+
else if ("gte" in condition) driverKey = "gte";
|
|
2284
|
+
else if ("lt" in condition) driverKey = "lt";
|
|
2285
|
+
else if ("lte" in condition) driverKey = "lte";
|
|
2286
|
+
else if ("primaryGt" in condition) driverKey = "primaryGt";
|
|
2287
|
+
else if ("primaryGte" in condition) driverKey = "primaryGte";
|
|
2288
|
+
else if ("primaryLt" in condition) driverKey = "primaryLt";
|
|
2289
|
+
else if ("primaryLte" in condition) driverKey = "primaryLte";
|
|
2290
|
+
else if ("like" in condition) driverKey = "like";
|
|
2291
|
+
else if ("notEqual" in condition) driverKey = "notEqual";
|
|
2292
|
+
else if ("primaryNotEqual" in condition) driverKey = "primaryNotEqual";
|
|
2293
|
+
else if ("or" in condition) driverKey = "or";
|
|
2294
|
+
else if ("primaryOr" in condition) driverKey = "primaryOr";
|
|
2295
|
+
if (!driverKey) return;
|
|
2296
|
+
const value = condition[driverKey];
|
|
2297
|
+
const startNode = await this.verifierStartNode[driverKey](value);
|
|
2298
|
+
const endNode = await this.verifierEndNode[driverKey](value);
|
|
2299
|
+
const direction = this.verifierDirection[driverKey];
|
|
2300
|
+
const comparator = this.verifierMap[driverKey];
|
|
2301
|
+
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
2302
|
+
const generator = this.getPairsGenerator(
|
|
2303
|
+
value,
|
|
2304
|
+
startNode,
|
|
2305
|
+
endNode,
|
|
2306
|
+
comparator,
|
|
2307
|
+
direction,
|
|
2308
|
+
earlyTerminate
|
|
2309
|
+
);
|
|
2310
|
+
let count = 0;
|
|
2311
|
+
for await (const pair of generator) {
|
|
2312
|
+
const [k, v] = pair;
|
|
2313
|
+
let isMatch = true;
|
|
2314
|
+
for (const key in condition) {
|
|
2315
|
+
if (key === driverKey) continue;
|
|
2316
|
+
const verify = this.verifierMap[key];
|
|
2317
|
+
const condValue = condition[key];
|
|
2318
|
+
if (!verify(v, condValue)) {
|
|
2319
|
+
isMatch = false;
|
|
2320
|
+
break;
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
if (isMatch) {
|
|
2324
|
+
yield pair;
|
|
2325
|
+
count++;
|
|
2326
|
+
if (limit !== void 0 && count >= limit) {
|
|
2327
|
+
break;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
async keys(condition, filterValues) {
|
|
2333
|
+
return this.readLock(async () => {
|
|
2334
|
+
const set = /* @__PURE__ */ new Set();
|
|
2335
|
+
for await (const key of this.keysStream(condition, filterValues)) {
|
|
2336
|
+
set.add(key);
|
|
2337
|
+
}
|
|
2338
|
+
return set;
|
|
2175
2339
|
});
|
|
2176
2340
|
}
|
|
2177
2341
|
async where(condition) {
|
|
2178
2342
|
return this.readLock(async () => {
|
|
2179
|
-
|
|
2180
|
-
for (const
|
|
2181
|
-
|
|
2182
|
-
const value = condition[key];
|
|
2183
|
-
const startNode = await this.verifierStartNode[key](value);
|
|
2184
|
-
const endNode = await this.verifierEndNode[key](value);
|
|
2185
|
-
const direction = this.verifierDirection[key];
|
|
2186
|
-
const comparator = this.verifierMap[key];
|
|
2187
|
-
const earlyTerminate = this.verifierEarlyTerminate[key];
|
|
2188
|
-
const pairs = await this.getPairs(value, startNode, endNode, comparator, direction, earlyTerminate);
|
|
2189
|
-
if (result === null) {
|
|
2190
|
-
result = pairs;
|
|
2191
|
-
} else {
|
|
2192
|
-
const intersection = /* @__PURE__ */ new Map();
|
|
2193
|
-
for (const [k2, v] of pairs) {
|
|
2194
|
-
if (result.has(k2)) {
|
|
2195
|
-
intersection.set(k2, v);
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
result = intersection;
|
|
2199
|
-
}
|
|
2343
|
+
const map = /* @__PURE__ */ new Map();
|
|
2344
|
+
for await (const [key, value] of this.whereStream(condition)) {
|
|
2345
|
+
map.set(key, value);
|
|
2200
2346
|
}
|
|
2201
|
-
return
|
|
2347
|
+
return map;
|
|
2202
2348
|
});
|
|
2203
2349
|
}
|
|
2204
2350
|
async insert(key, value) {
|
|
@@ -10,9 +10,7 @@ export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
|
|
|
10
10
|
private _createCachedNode;
|
|
11
11
|
protected readLock<T>(callback: () => Promise<T>): Promise<T>;
|
|
12
12
|
protected writeLock<T>(callback: () => Promise<T>): Promise<T>;
|
|
13
|
-
protected
|
|
14
|
-
protected getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean, earlyTerminate: boolean): Promise<BPTreePair<K, V>>;
|
|
15
|
-
protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1, earlyTerminate: boolean): Promise<BPTreePair<K, V>>;
|
|
13
|
+
protected getPairsGenerator(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1, earlyTerminate: boolean): AsyncGenerator<[K, V]>;
|
|
16
14
|
protected _createNodeId(isLeaf: boolean): Promise<string>;
|
|
17
15
|
protected _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): Promise<BPTreeUnknownNode<K, V>>;
|
|
18
16
|
protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): Promise<void>;
|
|
@@ -34,6 +32,16 @@ export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
|
|
|
34
32
|
protected commitNodeCreateBuffer(): Promise<void>;
|
|
35
33
|
protected commitNodeUpdateBuffer(): Promise<void>;
|
|
36
34
|
protected commitNodeDeleteBuffer(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Retrieves the value associated with the given key (PK).
|
|
37
|
+
* Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
|
|
38
|
+
*
|
|
39
|
+
* @param key The key to search for.
|
|
40
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
41
|
+
*/
|
|
42
|
+
get(key: K): Promise<V | undefined>;
|
|
43
|
+
keysStream(condition: BPTreeCondition<V>, filterValues?: Set<K>, limit?: number): AsyncGenerator<K>;
|
|
44
|
+
whereStream(condition: BPTreeCondition<V>, limit?: number): AsyncGenerator<[K, V]>;
|
|
37
45
|
keys(condition: BPTreeCondition<V>, filterValues?: Set<K>): Promise<Set<K>>;
|
|
38
46
|
where(condition: BPTreeCondition<V>): Promise<BPTreePair<K, V>>;
|
|
39
47
|
insert(key: K, value: V): Promise<void>;
|