serializable-bptree 6.1.0 → 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 +443 -207
- package/dist/esm/index.mjs +443 -207
- package/dist/types/BPTreeAsync.d.ts +13 -3
- package/dist/types/BPTreeSync.d.ts +13 -3
- package/dist/types/base/BPTree.d.ts +53 -3
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -466,7 +466,7 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
|
466
466
|
};
|
|
467
467
|
|
|
468
468
|
// src/base/BPTree.ts
|
|
469
|
-
var BPTree = class {
|
|
469
|
+
var BPTree = class _BPTree {
|
|
470
470
|
_cachedRegexp;
|
|
471
471
|
strategy;
|
|
472
472
|
comparator;
|
|
@@ -483,9 +483,15 @@ var BPTree = class {
|
|
|
483
483
|
lt: (nv, v) => this.comparator.isLower(nv, v),
|
|
484
484
|
lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
|
|
485
485
|
equal: (nv, v) => this.comparator.isSame(nv, v),
|
|
486
|
-
primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
|
|
487
486
|
notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
|
|
488
487
|
or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
|
|
488
|
+
primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
|
|
489
|
+
primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
490
|
+
primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
|
|
491
|
+
primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
492
|
+
primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
|
|
493
|
+
primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
|
|
494
|
+
primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
|
|
489
495
|
like: (nv, v) => {
|
|
490
496
|
const nodeValue = this.comparator.match(nv);
|
|
491
497
|
const value = this.comparator.match(v);
|
|
@@ -500,9 +506,15 @@ var BPTree = class {
|
|
|
500
506
|
lt: (v) => this.insertableNode(v),
|
|
501
507
|
lte: (v) => this.insertableNode(v),
|
|
502
508
|
equal: (v) => this.insertableNode(v),
|
|
503
|
-
primaryEqual: (v) => this.insertableNodeByPrimary(v),
|
|
504
509
|
notEqual: (v) => this.leftestNode(),
|
|
505
510
|
or: (v) => this.insertableNode(this.lowestValue(this.ensureValues(v))),
|
|
511
|
+
primaryGt: (v) => this.insertableNodeByPrimary(v),
|
|
512
|
+
primaryGte: (v) => this.insertableNodeByPrimary(v),
|
|
513
|
+
primaryLt: (v) => this.insertableNodeByPrimary(v),
|
|
514
|
+
primaryLte: (v) => this.insertableRightestNodeByPrimary(v),
|
|
515
|
+
primaryEqual: (v) => this.insertableNodeByPrimary(v),
|
|
516
|
+
primaryNotEqual: (v) => this.leftestNode(),
|
|
517
|
+
primaryOr: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
|
|
506
518
|
like: (v) => this.leftestNode()
|
|
507
519
|
};
|
|
508
520
|
verifierEndNode = {
|
|
@@ -511,12 +523,20 @@ var BPTree = class {
|
|
|
511
523
|
lt: (v) => null,
|
|
512
524
|
lte: (v) => null,
|
|
513
525
|
equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
|
|
514
|
-
primaryEqual: (v) => null,
|
|
515
526
|
notEqual: (v) => null,
|
|
516
527
|
or: (v) => this.insertableEndNode(
|
|
517
528
|
this.highestValue(this.ensureValues(v)),
|
|
518
529
|
this.verifierDirection.or
|
|
519
530
|
),
|
|
531
|
+
primaryGt: (v) => null,
|
|
532
|
+
primaryGte: (v) => null,
|
|
533
|
+
primaryLt: (v) => null,
|
|
534
|
+
primaryLte: (v) => null,
|
|
535
|
+
primaryEqual: (v) => null,
|
|
536
|
+
primaryNotEqual: (v) => null,
|
|
537
|
+
primaryOr: (v) => this.insertableRightestEndNodeByPrimary(
|
|
538
|
+
this.highestPrimaryValue(this.ensureValues(v))
|
|
539
|
+
),
|
|
520
540
|
like: (v) => null
|
|
521
541
|
};
|
|
522
542
|
verifierDirection = {
|
|
@@ -525,9 +545,15 @@ var BPTree = class {
|
|
|
525
545
|
lt: -1,
|
|
526
546
|
lte: -1,
|
|
527
547
|
equal: 1,
|
|
528
|
-
primaryEqual: 1,
|
|
529
548
|
notEqual: 1,
|
|
530
549
|
or: 1,
|
|
550
|
+
primaryGt: 1,
|
|
551
|
+
primaryGte: 1,
|
|
552
|
+
primaryLt: -1,
|
|
553
|
+
primaryLte: -1,
|
|
554
|
+
primaryEqual: 1,
|
|
555
|
+
primaryNotEqual: 1,
|
|
556
|
+
primaryOr: 1,
|
|
531
557
|
like: 1
|
|
532
558
|
};
|
|
533
559
|
/**
|
|
@@ -541,11 +567,93 @@ var BPTree = class {
|
|
|
541
567
|
lt: false,
|
|
542
568
|
lte: false,
|
|
543
569
|
equal: true,
|
|
544
|
-
primaryEqual: true,
|
|
545
570
|
notEqual: false,
|
|
546
571
|
or: false,
|
|
572
|
+
primaryGt: false,
|
|
573
|
+
primaryGte: false,
|
|
574
|
+
primaryLt: false,
|
|
575
|
+
primaryLte: false,
|
|
576
|
+
primaryEqual: true,
|
|
577
|
+
primaryNotEqual: false,
|
|
578
|
+
primaryOr: false,
|
|
547
579
|
like: false
|
|
548
580
|
};
|
|
581
|
+
/**
|
|
582
|
+
* Priority map for condition types.
|
|
583
|
+
* Higher value = higher selectivity (fewer expected results).
|
|
584
|
+
* Used by `chooseDriver` to select the most selective index.
|
|
585
|
+
*/
|
|
586
|
+
static conditionPriority = {
|
|
587
|
+
equal: 100,
|
|
588
|
+
primaryEqual: 100,
|
|
589
|
+
or: 80,
|
|
590
|
+
primaryOr: 80,
|
|
591
|
+
gt: 50,
|
|
592
|
+
gte: 50,
|
|
593
|
+
lt: 50,
|
|
594
|
+
lte: 50,
|
|
595
|
+
primaryGt: 50,
|
|
596
|
+
primaryGte: 50,
|
|
597
|
+
primaryLt: 50,
|
|
598
|
+
primaryLte: 50,
|
|
599
|
+
like: 30,
|
|
600
|
+
notEqual: 10,
|
|
601
|
+
primaryNotEqual: 10
|
|
602
|
+
};
|
|
603
|
+
/**
|
|
604
|
+
* Selects the best driver tree from multiple tree/condition pairs.
|
|
605
|
+
* Uses rule-based optimization to choose the tree with highest estimated selectivity.
|
|
606
|
+
*
|
|
607
|
+
* @param candidates Array of { tree, condition } pairs to evaluate
|
|
608
|
+
* @returns The candidate with highest priority condition, or null if empty
|
|
609
|
+
*
|
|
610
|
+
* @example
|
|
611
|
+
* ```typescript
|
|
612
|
+
* const driver = BPTreeSync.chooseDriver([
|
|
613
|
+
* { tree: idxId, condition: { equal: 100 } },
|
|
614
|
+
* { tree: idxAge, condition: { gt: 20 } }
|
|
615
|
+
* ])
|
|
616
|
+
* // Returns { tree: idxId, condition: { equal: 100 } } because 'equal' has higher priority
|
|
617
|
+
* ```
|
|
618
|
+
*/
|
|
619
|
+
static ChooseDriver(candidates) {
|
|
620
|
+
if (candidates.length === 0) return null;
|
|
621
|
+
if (candidates.length === 1) return candidates[0];
|
|
622
|
+
let best = candidates[0];
|
|
623
|
+
let bestScore = 0;
|
|
624
|
+
for (const candidate of candidates) {
|
|
625
|
+
let score = 0;
|
|
626
|
+
for (const key in candidate.condition) {
|
|
627
|
+
const condKey = key;
|
|
628
|
+
const priority = _BPTree.conditionPriority[condKey] ?? 0;
|
|
629
|
+
if (priority > score) {
|
|
630
|
+
score = priority;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (score > bestScore) {
|
|
634
|
+
bestScore = score;
|
|
635
|
+
best = candidate;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return best;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Verified if the value satisfies the condition.
|
|
642
|
+
*
|
|
643
|
+
* @param nodeValue The value to verify.
|
|
644
|
+
* @param condition The condition to verify against.
|
|
645
|
+
* @returns Returns true if the value satisfies the condition.
|
|
646
|
+
*/
|
|
647
|
+
verify(nodeValue, condition) {
|
|
648
|
+
for (const key in condition) {
|
|
649
|
+
const verify = this.verifierMap[key];
|
|
650
|
+
const condValue = condition[key];
|
|
651
|
+
if (!verify(nodeValue, condValue)) {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
549
657
|
constructor(strategy, comparator, option) {
|
|
550
658
|
this.strategy = strategy;
|
|
551
659
|
this.comparator = comparator;
|
|
@@ -579,6 +687,14 @@ var BPTree = class {
|
|
|
579
687
|
const i = v.length - 1;
|
|
580
688
|
return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
|
|
581
689
|
}
|
|
690
|
+
lowestPrimaryValue(v) {
|
|
691
|
+
const i = 0;
|
|
692
|
+
return [...v].sort((a, b) => this.comparator.primaryAsc(a, b))[i];
|
|
693
|
+
}
|
|
694
|
+
highestPrimaryValue(v) {
|
|
695
|
+
const i = v.length - 1;
|
|
696
|
+
return [...v].sort((a, b) => this.comparator.primaryAsc(a, b))[i];
|
|
697
|
+
}
|
|
582
698
|
_insertAtLeaf(node, key, value) {
|
|
583
699
|
if (node.values.length) {
|
|
584
700
|
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
@@ -658,8 +774,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
658
774
|
capacity: this.option.capacity ?? 1e3
|
|
659
775
|
});
|
|
660
776
|
}
|
|
661
|
-
|
|
662
|
-
const pairs = [];
|
|
777
|
+
*getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
663
778
|
let node = startNode;
|
|
664
779
|
let done = false;
|
|
665
780
|
let hasMatched = false;
|
|
@@ -668,71 +783,52 @@ var BPTreeSync = class extends BPTree {
|
|
|
668
783
|
done = true;
|
|
669
784
|
break;
|
|
670
785
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
786
|
+
const len = node.values.length;
|
|
787
|
+
if (direction === 1) {
|
|
788
|
+
for (let i = 0; i < len; i++) {
|
|
789
|
+
const nValue = node.values[i];
|
|
790
|
+
const keys = node.keys[i];
|
|
791
|
+
if (comparator(nValue, value)) {
|
|
792
|
+
hasMatched = true;
|
|
793
|
+
for (let j = 0; j < keys.length; j++) {
|
|
794
|
+
yield [keys[j], nValue];
|
|
795
|
+
}
|
|
796
|
+
} else if (earlyTerminate && hasMatched) {
|
|
797
|
+
done = true;
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
} else {
|
|
802
|
+
let i = len;
|
|
803
|
+
while (i--) {
|
|
804
|
+
const nValue = node.values[i];
|
|
805
|
+
const keys = node.keys[i];
|
|
806
|
+
if (comparator(nValue, value)) {
|
|
807
|
+
hasMatched = true;
|
|
808
|
+
let j = keys.length;
|
|
809
|
+
while (j--) {
|
|
810
|
+
yield [keys[j], nValue];
|
|
811
|
+
}
|
|
812
|
+
} else if (earlyTerminate && hasMatched) {
|
|
813
|
+
done = true;
|
|
814
|
+
break;
|
|
680
815
|
}
|
|
681
|
-
} else if (earlyTerminate && hasMatched) {
|
|
682
|
-
done = true;
|
|
683
|
-
break;
|
|
684
816
|
}
|
|
685
817
|
}
|
|
686
818
|
if (done) break;
|
|
687
|
-
if (
|
|
688
|
-
|
|
689
|
-
break;
|
|
690
|
-
}
|
|
691
|
-
node = this.getNode(node.prev);
|
|
692
|
-
}
|
|
693
|
-
return new Map(pairs.reverse());
|
|
694
|
-
}
|
|
695
|
-
getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
696
|
-
const pairs = [];
|
|
697
|
-
let node = startNode;
|
|
698
|
-
let done = false;
|
|
699
|
-
let hasMatched = false;
|
|
700
|
-
while (!done) {
|
|
701
|
-
if (endNode && node.id === endNode.id) {
|
|
702
|
-
done = true;
|
|
703
|
-
break;
|
|
704
|
-
}
|
|
705
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
706
|
-
const nValue = node.values[i];
|
|
707
|
-
const keys = node.keys[i];
|
|
708
|
-
if (comparator(nValue, value)) {
|
|
709
|
-
hasMatched = true;
|
|
710
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
711
|
-
const key = keys[j];
|
|
712
|
-
pairs.push([key, nValue]);
|
|
713
|
-
}
|
|
714
|
-
} else if (earlyTerminate && hasMatched) {
|
|
819
|
+
if (direction === 1) {
|
|
820
|
+
if (!node.next) {
|
|
715
821
|
done = true;
|
|
716
822
|
break;
|
|
717
823
|
}
|
|
824
|
+
node = this.getNode(node.next);
|
|
825
|
+
} else {
|
|
826
|
+
if (!node.prev) {
|
|
827
|
+
done = true;
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
node = this.getNode(node.prev);
|
|
718
831
|
}
|
|
719
|
-
if (done) break;
|
|
720
|
-
if (!node.next) {
|
|
721
|
-
done = true;
|
|
722
|
-
break;
|
|
723
|
-
}
|
|
724
|
-
node = this.getNode(node.next);
|
|
725
|
-
}
|
|
726
|
-
return new Map(pairs);
|
|
727
|
-
}
|
|
728
|
-
getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
729
|
-
switch (direction) {
|
|
730
|
-
case -1:
|
|
731
|
-
return this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
732
|
-
case 1:
|
|
733
|
-
return this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
734
|
-
default:
|
|
735
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
736
832
|
}
|
|
737
833
|
}
|
|
738
834
|
_createNodeId(isLeaf) {
|
|
@@ -1103,6 +1199,31 @@ var BPTreeSync = class extends BPTree {
|
|
|
1103
1199
|
}
|
|
1104
1200
|
return node;
|
|
1105
1201
|
}
|
|
1202
|
+
insertableRightestNodeByPrimary(value) {
|
|
1203
|
+
let node = this.getNode(this.root.id);
|
|
1204
|
+
while (!node.leaf) {
|
|
1205
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
1206
|
+
const nValue = node.values[i];
|
|
1207
|
+
const k = node.keys;
|
|
1208
|
+
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
1209
|
+
node = this.getNode(k[i]);
|
|
1210
|
+
break;
|
|
1211
|
+
}
|
|
1212
|
+
if (i + 1 === node.values.length) {
|
|
1213
|
+
node = this.getNode(k[i + 1]);
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
return node;
|
|
1219
|
+
}
|
|
1220
|
+
insertableRightestEndNodeByPrimary(value) {
|
|
1221
|
+
const node = this.insertableRightestNodeByPrimary(value);
|
|
1222
|
+
if (!node.next) {
|
|
1223
|
+
return null;
|
|
1224
|
+
}
|
|
1225
|
+
return this.getNode(node.next);
|
|
1226
|
+
}
|
|
1106
1227
|
insertableEndNode(value, direction) {
|
|
1107
1228
|
const insertableNode = this.insertableNode(value);
|
|
1108
1229
|
let key;
|
|
@@ -1163,55 +1284,109 @@ var BPTreeSync = class extends BPTree {
|
|
|
1163
1284
|
}
|
|
1164
1285
|
this._nodeDeleteBuffer.clear();
|
|
1165
1286
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
if (
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1287
|
+
/**
|
|
1288
|
+
* Retrieves the value associated with the given key (PK).
|
|
1289
|
+
* Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
|
|
1290
|
+
*
|
|
1291
|
+
* @param key The key to search for.
|
|
1292
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
1293
|
+
*/
|
|
1294
|
+
get(key) {
|
|
1295
|
+
let node = this.leftestNode();
|
|
1296
|
+
while (true) {
|
|
1297
|
+
if (node.values) {
|
|
1298
|
+
const len = node.values.length;
|
|
1299
|
+
for (let i = 0; i < len; i++) {
|
|
1300
|
+
const keys = node.keys[i];
|
|
1301
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1302
|
+
if (keys[j] === key) {
|
|
1303
|
+
return node.values[i];
|
|
1304
|
+
}
|
|
1184
1305
|
}
|
|
1185
1306
|
}
|
|
1186
|
-
filterValues = intersections;
|
|
1187
1307
|
}
|
|
1308
|
+
if (!node.next) break;
|
|
1309
|
+
node = this.getNode(node.next);
|
|
1188
1310
|
}
|
|
1189
|
-
return
|
|
1311
|
+
return void 0;
|
|
1190
1312
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1313
|
+
*keysStream(condition, filterValues, limit) {
|
|
1314
|
+
const stream = this.whereStream(condition, limit);
|
|
1315
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
1316
|
+
for (const [key] of stream) {
|
|
1317
|
+
if (intersection && !intersection.has(key)) {
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
yield key;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
*whereStream(condition, limit) {
|
|
1324
|
+
let driverKey = null;
|
|
1325
|
+
if ("primaryEqual" in condition) driverKey = "primaryEqual";
|
|
1326
|
+
else if ("equal" in condition) driverKey = "equal";
|
|
1327
|
+
else if ("gt" in condition) driverKey = "gt";
|
|
1328
|
+
else if ("gte" in condition) driverKey = "gte";
|
|
1329
|
+
else if ("lt" in condition) driverKey = "lt";
|
|
1330
|
+
else if ("lte" in condition) driverKey = "lte";
|
|
1331
|
+
else if ("primaryGt" in condition) driverKey = "primaryGt";
|
|
1332
|
+
else if ("primaryGte" in condition) driverKey = "primaryGte";
|
|
1333
|
+
else if ("primaryLt" in condition) driverKey = "primaryLt";
|
|
1334
|
+
else if ("primaryLte" in condition) driverKey = "primaryLte";
|
|
1335
|
+
else if ("like" in condition) driverKey = "like";
|
|
1336
|
+
else if ("notEqual" in condition) driverKey = "notEqual";
|
|
1337
|
+
else if ("primaryNotEqual" in condition) driverKey = "primaryNotEqual";
|
|
1338
|
+
else if ("or" in condition) driverKey = "or";
|
|
1339
|
+
else if ("primaryOr" in condition) driverKey = "primaryOr";
|
|
1340
|
+
if (!driverKey) return;
|
|
1341
|
+
const value = condition[driverKey];
|
|
1342
|
+
const startNode = this.verifierStartNode[driverKey](value);
|
|
1343
|
+
const endNode = this.verifierEndNode[driverKey](value);
|
|
1344
|
+
const direction = this.verifierDirection[driverKey];
|
|
1345
|
+
const comparator = this.verifierMap[driverKey];
|
|
1346
|
+
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
1347
|
+
const generator = this.getPairsGenerator(
|
|
1348
|
+
value,
|
|
1349
|
+
startNode,
|
|
1350
|
+
endNode,
|
|
1351
|
+
comparator,
|
|
1352
|
+
direction,
|
|
1353
|
+
earlyTerminate
|
|
1354
|
+
);
|
|
1355
|
+
let count = 0;
|
|
1356
|
+
for (const pair of generator) {
|
|
1357
|
+
const [k, v] = pair;
|
|
1358
|
+
let isMatch = true;
|
|
1359
|
+
for (const key in condition) {
|
|
1360
|
+
if (key === driverKey) continue;
|
|
1361
|
+
const verify = this.verifierMap[key];
|
|
1362
|
+
const condValue = condition[key];
|
|
1363
|
+
if (!verify(v, condValue)) {
|
|
1364
|
+
isMatch = false;
|
|
1365
|
+
break;
|
|
1210
1366
|
}
|
|
1211
|
-
result = intersection;
|
|
1212
1367
|
}
|
|
1368
|
+
if (isMatch) {
|
|
1369
|
+
yield pair;
|
|
1370
|
+
count++;
|
|
1371
|
+
if (limit !== void 0 && count >= limit) {
|
|
1372
|
+
break;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
keys(condition, filterValues) {
|
|
1378
|
+
const set = /* @__PURE__ */ new Set();
|
|
1379
|
+
for (const key of this.keysStream(condition, filterValues)) {
|
|
1380
|
+
set.add(key);
|
|
1381
|
+
}
|
|
1382
|
+
return set;
|
|
1383
|
+
}
|
|
1384
|
+
where(condition) {
|
|
1385
|
+
const map = /* @__PURE__ */ new Map();
|
|
1386
|
+
for (const [key, value] of this.whereStream(condition)) {
|
|
1387
|
+
map.set(key, value);
|
|
1213
1388
|
}
|
|
1214
|
-
return
|
|
1389
|
+
return map;
|
|
1215
1390
|
}
|
|
1216
1391
|
insert(key, value) {
|
|
1217
1392
|
const before = this.insertableNode(value);
|
|
@@ -1586,8 +1761,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1586
1761
|
this.lock.writeUnlock(lockId);
|
|
1587
1762
|
});
|
|
1588
1763
|
}
|
|
1589
|
-
async
|
|
1590
|
-
const pairs = [];
|
|
1764
|
+
async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1591
1765
|
let node = startNode;
|
|
1592
1766
|
let done = false;
|
|
1593
1767
|
let hasMatched = false;
|
|
@@ -1596,71 +1770,52 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1596
1770
|
done = true;
|
|
1597
1771
|
break;
|
|
1598
1772
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1773
|
+
const len = node.values.length;
|
|
1774
|
+
if (direction === 1) {
|
|
1775
|
+
for (let i = 0; i < len; i++) {
|
|
1776
|
+
const nValue = node.values[i];
|
|
1777
|
+
const keys = node.keys[i];
|
|
1778
|
+
if (comparator(nValue, value)) {
|
|
1779
|
+
hasMatched = true;
|
|
1780
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1781
|
+
yield [keys[j], nValue];
|
|
1782
|
+
}
|
|
1783
|
+
} else if (earlyTerminate && hasMatched) {
|
|
1784
|
+
done = true;
|
|
1785
|
+
break;
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
} else {
|
|
1789
|
+
let i = len;
|
|
1790
|
+
while (i--) {
|
|
1791
|
+
const nValue = node.values[i];
|
|
1792
|
+
const keys = node.keys[i];
|
|
1793
|
+
if (comparator(nValue, value)) {
|
|
1794
|
+
hasMatched = true;
|
|
1795
|
+
let j = keys.length;
|
|
1796
|
+
while (j--) {
|
|
1797
|
+
yield [keys[j], nValue];
|
|
1798
|
+
}
|
|
1799
|
+
} else if (earlyTerminate && hasMatched) {
|
|
1800
|
+
done = true;
|
|
1801
|
+
break;
|
|
1608
1802
|
}
|
|
1609
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1610
|
-
done = true;
|
|
1611
|
-
break;
|
|
1612
1803
|
}
|
|
1613
1804
|
}
|
|
1614
1805
|
if (done) break;
|
|
1615
|
-
if (
|
|
1616
|
-
|
|
1617
|
-
break;
|
|
1618
|
-
}
|
|
1619
|
-
node = await this.getNode(node.prev);
|
|
1620
|
-
}
|
|
1621
|
-
return new Map(pairs.reverse());
|
|
1622
|
-
}
|
|
1623
|
-
async getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
1624
|
-
const pairs = [];
|
|
1625
|
-
let node = startNode;
|
|
1626
|
-
let done = false;
|
|
1627
|
-
let hasMatched = false;
|
|
1628
|
-
while (!done) {
|
|
1629
|
-
if (endNode && node.id === endNode.id) {
|
|
1630
|
-
done = true;
|
|
1631
|
-
break;
|
|
1632
|
-
}
|
|
1633
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
1634
|
-
const nValue = node.values[i];
|
|
1635
|
-
const keys = node.keys[i];
|
|
1636
|
-
if (comparator(nValue, value)) {
|
|
1637
|
-
hasMatched = true;
|
|
1638
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
1639
|
-
const key = keys[j];
|
|
1640
|
-
pairs.push([key, nValue]);
|
|
1641
|
-
}
|
|
1642
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1806
|
+
if (direction === 1) {
|
|
1807
|
+
if (!node.next) {
|
|
1643
1808
|
done = true;
|
|
1644
1809
|
break;
|
|
1645
1810
|
}
|
|
1811
|
+
node = await this.getNode(node.next);
|
|
1812
|
+
} else {
|
|
1813
|
+
if (!node.prev) {
|
|
1814
|
+
done = true;
|
|
1815
|
+
break;
|
|
1816
|
+
}
|
|
1817
|
+
node = await this.getNode(node.prev);
|
|
1646
1818
|
}
|
|
1647
|
-
if (done) break;
|
|
1648
|
-
if (!node.next) {
|
|
1649
|
-
done = true;
|
|
1650
|
-
break;
|
|
1651
|
-
}
|
|
1652
|
-
node = await this.getNode(node.next);
|
|
1653
|
-
}
|
|
1654
|
-
return new Map(pairs);
|
|
1655
|
-
}
|
|
1656
|
-
async getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1657
|
-
switch (direction) {
|
|
1658
|
-
case -1:
|
|
1659
|
-
return await this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
1660
|
-
case 1:
|
|
1661
|
-
return await this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
1662
|
-
default:
|
|
1663
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
1664
1819
|
}
|
|
1665
1820
|
}
|
|
1666
1821
|
async _createNodeId(isLeaf) {
|
|
@@ -2031,6 +2186,31 @@ var BPTreeAsync = class extends BPTree {
|
|
|
2031
2186
|
}
|
|
2032
2187
|
return node;
|
|
2033
2188
|
}
|
|
2189
|
+
async insertableRightestNodeByPrimary(value) {
|
|
2190
|
+
let node = await this.getNode(this.root.id);
|
|
2191
|
+
while (!node.leaf) {
|
|
2192
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2193
|
+
const nValue = node.values[i];
|
|
2194
|
+
const k = node.keys;
|
|
2195
|
+
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2196
|
+
node = await this.getNode(k[i]);
|
|
2197
|
+
break;
|
|
2198
|
+
}
|
|
2199
|
+
if (i + 1 === node.values.length) {
|
|
2200
|
+
node = await this.getNode(k[i + 1]);
|
|
2201
|
+
break;
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
return node;
|
|
2206
|
+
}
|
|
2207
|
+
async insertableRightestEndNodeByPrimary(value) {
|
|
2208
|
+
const node = await this.insertableRightestNodeByPrimary(value);
|
|
2209
|
+
if (!node.next) {
|
|
2210
|
+
return null;
|
|
2211
|
+
}
|
|
2212
|
+
return await this.getNode(node.next);
|
|
2213
|
+
}
|
|
2034
2214
|
async insertableEndNode(value, direction) {
|
|
2035
2215
|
const insertableNode = await this.insertableNode(value);
|
|
2036
2216
|
let key;
|
|
@@ -2091,58 +2271,114 @@ var BPTreeAsync = class extends BPTree {
|
|
|
2091
2271
|
}
|
|
2092
2272
|
this._nodeDeleteBuffer.clear();
|
|
2093
2273
|
}
|
|
2094
|
-
|
|
2274
|
+
/**
|
|
2275
|
+
* Retrieves the value associated with the given key (PK).
|
|
2276
|
+
* Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
|
|
2277
|
+
*
|
|
2278
|
+
* @param key The key to search for.
|
|
2279
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
2280
|
+
*/
|
|
2281
|
+
async get(key) {
|
|
2095
2282
|
return this.readLock(async () => {
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
filterValues = new Set(pairs.keys());
|
|
2107
|
-
} else {
|
|
2108
|
-
const intersections = /* @__PURE__ */ new Set();
|
|
2109
|
-
for (const key2 of filterValues) {
|
|
2110
|
-
const has = pairs.has(key2);
|
|
2111
|
-
if (has) {
|
|
2112
|
-
intersections.add(key2);
|
|
2283
|
+
let node = await this.leftestNode();
|
|
2284
|
+
while (true) {
|
|
2285
|
+
if (node.values) {
|
|
2286
|
+
const len = node.values.length;
|
|
2287
|
+
for (let i = 0; i < len; i++) {
|
|
2288
|
+
const keys = node.keys[i];
|
|
2289
|
+
for (let j = 0; j < keys.length; j++) {
|
|
2290
|
+
if (keys[j] === key) {
|
|
2291
|
+
return node.values[i];
|
|
2292
|
+
}
|
|
2113
2293
|
}
|
|
2114
2294
|
}
|
|
2115
|
-
filterValues = intersections;
|
|
2116
2295
|
}
|
|
2296
|
+
if (!node.next) break;
|
|
2297
|
+
node = await this.getNode(node.next);
|
|
2117
2298
|
}
|
|
2118
|
-
return
|
|
2299
|
+
return void 0;
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
async *keysStream(condition, filterValues, limit) {
|
|
2303
|
+
const stream = this.whereStream(condition, limit);
|
|
2304
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2305
|
+
for await (const [key] of stream) {
|
|
2306
|
+
if (intersection && !intersection.has(key)) {
|
|
2307
|
+
continue;
|
|
2308
|
+
}
|
|
2309
|
+
yield key;
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
async *whereStream(condition, limit) {
|
|
2313
|
+
let driverKey = null;
|
|
2314
|
+
if ("primaryEqual" in condition) driverKey = "primaryEqual";
|
|
2315
|
+
else if ("equal" in condition) driverKey = "equal";
|
|
2316
|
+
else if ("gt" in condition) driverKey = "gt";
|
|
2317
|
+
else if ("gte" in condition) driverKey = "gte";
|
|
2318
|
+
else if ("lt" in condition) driverKey = "lt";
|
|
2319
|
+
else if ("lte" in condition) driverKey = "lte";
|
|
2320
|
+
else if ("primaryGt" in condition) driverKey = "primaryGt";
|
|
2321
|
+
else if ("primaryGte" in condition) driverKey = "primaryGte";
|
|
2322
|
+
else if ("primaryLt" in condition) driverKey = "primaryLt";
|
|
2323
|
+
else if ("primaryLte" in condition) driverKey = "primaryLte";
|
|
2324
|
+
else if ("like" in condition) driverKey = "like";
|
|
2325
|
+
else if ("notEqual" in condition) driverKey = "notEqual";
|
|
2326
|
+
else if ("primaryNotEqual" in condition) driverKey = "primaryNotEqual";
|
|
2327
|
+
else if ("or" in condition) driverKey = "or";
|
|
2328
|
+
else if ("primaryOr" in condition) driverKey = "primaryOr";
|
|
2329
|
+
if (!driverKey) return;
|
|
2330
|
+
const value = condition[driverKey];
|
|
2331
|
+
const startNode = await this.verifierStartNode[driverKey](value);
|
|
2332
|
+
const endNode = await this.verifierEndNode[driverKey](value);
|
|
2333
|
+
const direction = this.verifierDirection[driverKey];
|
|
2334
|
+
const comparator = this.verifierMap[driverKey];
|
|
2335
|
+
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
2336
|
+
const generator = this.getPairsGenerator(
|
|
2337
|
+
value,
|
|
2338
|
+
startNode,
|
|
2339
|
+
endNode,
|
|
2340
|
+
comparator,
|
|
2341
|
+
direction,
|
|
2342
|
+
earlyTerminate
|
|
2343
|
+
);
|
|
2344
|
+
let count = 0;
|
|
2345
|
+
for await (const pair of generator) {
|
|
2346
|
+
const [k, v] = pair;
|
|
2347
|
+
let isMatch = true;
|
|
2348
|
+
for (const key in condition) {
|
|
2349
|
+
if (key === driverKey) continue;
|
|
2350
|
+
const verify = this.verifierMap[key];
|
|
2351
|
+
const condValue = condition[key];
|
|
2352
|
+
if (!verify(v, condValue)) {
|
|
2353
|
+
isMatch = false;
|
|
2354
|
+
break;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
if (isMatch) {
|
|
2358
|
+
yield pair;
|
|
2359
|
+
count++;
|
|
2360
|
+
if (limit !== void 0 && count >= limit) {
|
|
2361
|
+
break;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
async keys(condition, filterValues) {
|
|
2367
|
+
return this.readLock(async () => {
|
|
2368
|
+
const set = /* @__PURE__ */ new Set();
|
|
2369
|
+
for await (const key of this.keysStream(condition, filterValues)) {
|
|
2370
|
+
set.add(key);
|
|
2371
|
+
}
|
|
2372
|
+
return set;
|
|
2119
2373
|
});
|
|
2120
2374
|
}
|
|
2121
2375
|
async where(condition) {
|
|
2122
2376
|
return this.readLock(async () => {
|
|
2123
|
-
|
|
2124
|
-
for (const
|
|
2125
|
-
|
|
2126
|
-
const value = condition[key];
|
|
2127
|
-
const startNode = await this.verifierStartNode[key](value);
|
|
2128
|
-
const endNode = await this.verifierEndNode[key](value);
|
|
2129
|
-
const direction = this.verifierDirection[key];
|
|
2130
|
-
const comparator = this.verifierMap[key];
|
|
2131
|
-
const earlyTerminate = this.verifierEarlyTerminate[key];
|
|
2132
|
-
const pairs = await this.getPairs(value, startNode, endNode, comparator, direction, earlyTerminate);
|
|
2133
|
-
if (result === null) {
|
|
2134
|
-
result = pairs;
|
|
2135
|
-
} else {
|
|
2136
|
-
const intersection = /* @__PURE__ */ new Map();
|
|
2137
|
-
for (const [k2, v] of pairs) {
|
|
2138
|
-
if (result.has(k2)) {
|
|
2139
|
-
intersection.set(k2, v);
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
result = intersection;
|
|
2143
|
-
}
|
|
2377
|
+
const map = /* @__PURE__ */ new Map();
|
|
2378
|
+
for await (const [key, value] of this.whereStream(condition)) {
|
|
2379
|
+
map.set(key, value);
|
|
2144
2380
|
}
|
|
2145
|
-
return
|
|
2381
|
+
return map;
|
|
2146
2382
|
});
|
|
2147
2383
|
}
|
|
2148
2384
|
async insert(key, value) {
|