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/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;
|
|
@@ -449,9 +449,15 @@ var BPTree = class {
|
|
|
449
449
|
lt: (nv, v) => this.comparator.isLower(nv, v),
|
|
450
450
|
lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
|
|
451
451
|
equal: (nv, v) => this.comparator.isSame(nv, v),
|
|
452
|
-
primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
|
|
453
452
|
notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
|
|
454
453
|
or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
|
|
454
|
+
primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
|
|
455
|
+
primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
456
|
+
primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
|
|
457
|
+
primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
458
|
+
primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
|
|
459
|
+
primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
|
|
460
|
+
primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
|
|
455
461
|
like: (nv, v) => {
|
|
456
462
|
const nodeValue = this.comparator.match(nv);
|
|
457
463
|
const value = this.comparator.match(v);
|
|
@@ -466,9 +472,15 @@ var BPTree = class {
|
|
|
466
472
|
lt: (v) => this.insertableNode(v),
|
|
467
473
|
lte: (v) => this.insertableNode(v),
|
|
468
474
|
equal: (v) => this.insertableNode(v),
|
|
469
|
-
primaryEqual: (v) => this.insertableNodeByPrimary(v),
|
|
470
475
|
notEqual: (v) => this.leftestNode(),
|
|
471
476
|
or: (v) => this.insertableNode(this.lowestValue(this.ensureValues(v))),
|
|
477
|
+
primaryGt: (v) => this.insertableNodeByPrimary(v),
|
|
478
|
+
primaryGte: (v) => this.insertableNodeByPrimary(v),
|
|
479
|
+
primaryLt: (v) => this.insertableNodeByPrimary(v),
|
|
480
|
+
primaryLte: (v) => this.insertableRightestNodeByPrimary(v),
|
|
481
|
+
primaryEqual: (v) => this.insertableNodeByPrimary(v),
|
|
482
|
+
primaryNotEqual: (v) => this.leftestNode(),
|
|
483
|
+
primaryOr: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
|
|
472
484
|
like: (v) => this.leftestNode()
|
|
473
485
|
};
|
|
474
486
|
verifierEndNode = {
|
|
@@ -477,12 +489,20 @@ var BPTree = class {
|
|
|
477
489
|
lt: (v) => null,
|
|
478
490
|
lte: (v) => null,
|
|
479
491
|
equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
|
|
480
|
-
primaryEqual: (v) => null,
|
|
481
492
|
notEqual: (v) => null,
|
|
482
493
|
or: (v) => this.insertableEndNode(
|
|
483
494
|
this.highestValue(this.ensureValues(v)),
|
|
484
495
|
this.verifierDirection.or
|
|
485
496
|
),
|
|
497
|
+
primaryGt: (v) => null,
|
|
498
|
+
primaryGte: (v) => null,
|
|
499
|
+
primaryLt: (v) => null,
|
|
500
|
+
primaryLte: (v) => null,
|
|
501
|
+
primaryEqual: (v) => null,
|
|
502
|
+
primaryNotEqual: (v) => null,
|
|
503
|
+
primaryOr: (v) => this.insertableRightestEndNodeByPrimary(
|
|
504
|
+
this.highestPrimaryValue(this.ensureValues(v))
|
|
505
|
+
),
|
|
486
506
|
like: (v) => null
|
|
487
507
|
};
|
|
488
508
|
verifierDirection = {
|
|
@@ -491,9 +511,15 @@ var BPTree = class {
|
|
|
491
511
|
lt: -1,
|
|
492
512
|
lte: -1,
|
|
493
513
|
equal: 1,
|
|
494
|
-
primaryEqual: 1,
|
|
495
514
|
notEqual: 1,
|
|
496
515
|
or: 1,
|
|
516
|
+
primaryGt: 1,
|
|
517
|
+
primaryGte: 1,
|
|
518
|
+
primaryLt: -1,
|
|
519
|
+
primaryLte: -1,
|
|
520
|
+
primaryEqual: 1,
|
|
521
|
+
primaryNotEqual: 1,
|
|
522
|
+
primaryOr: 1,
|
|
497
523
|
like: 1
|
|
498
524
|
};
|
|
499
525
|
/**
|
|
@@ -507,11 +533,93 @@ var BPTree = class {
|
|
|
507
533
|
lt: false,
|
|
508
534
|
lte: false,
|
|
509
535
|
equal: true,
|
|
510
|
-
primaryEqual: true,
|
|
511
536
|
notEqual: false,
|
|
512
537
|
or: false,
|
|
538
|
+
primaryGt: false,
|
|
539
|
+
primaryGte: false,
|
|
540
|
+
primaryLt: false,
|
|
541
|
+
primaryLte: false,
|
|
542
|
+
primaryEqual: true,
|
|
543
|
+
primaryNotEqual: false,
|
|
544
|
+
primaryOr: false,
|
|
513
545
|
like: false
|
|
514
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
|
+
}
|
|
515
623
|
constructor(strategy, comparator, option) {
|
|
516
624
|
this.strategy = strategy;
|
|
517
625
|
this.comparator = comparator;
|
|
@@ -545,6 +653,14 @@ var BPTree = class {
|
|
|
545
653
|
const i = v.length - 1;
|
|
546
654
|
return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
|
|
547
655
|
}
|
|
656
|
+
lowestPrimaryValue(v) {
|
|
657
|
+
const i = 0;
|
|
658
|
+
return [...v].sort((a, b) => this.comparator.primaryAsc(a, b))[i];
|
|
659
|
+
}
|
|
660
|
+
highestPrimaryValue(v) {
|
|
661
|
+
const i = v.length - 1;
|
|
662
|
+
return [...v].sort((a, b) => this.comparator.primaryAsc(a, b))[i];
|
|
663
|
+
}
|
|
548
664
|
_insertAtLeaf(node, key, value) {
|
|
549
665
|
if (node.values.length) {
|
|
550
666
|
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
@@ -624,8 +740,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
624
740
|
capacity: this.option.capacity ?? 1e3
|
|
625
741
|
});
|
|
626
742
|
}
|
|
627
|
-
|
|
628
|
-
const pairs = [];
|
|
743
|
+
*getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
629
744
|
let node = startNode;
|
|
630
745
|
let done = false;
|
|
631
746
|
let hasMatched = false;
|
|
@@ -634,71 +749,52 @@ var BPTreeSync = class extends BPTree {
|
|
|
634
749
|
done = true;
|
|
635
750
|
break;
|
|
636
751
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
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;
|
|
646
781
|
}
|
|
647
|
-
} else if (earlyTerminate && hasMatched) {
|
|
648
|
-
done = true;
|
|
649
|
-
break;
|
|
650
782
|
}
|
|
651
783
|
}
|
|
652
784
|
if (done) break;
|
|
653
|
-
if (
|
|
654
|
-
|
|
655
|
-
break;
|
|
656
|
-
}
|
|
657
|
-
node = this.getNode(node.prev);
|
|
658
|
-
}
|
|
659
|
-
return new Map(pairs.reverse());
|
|
660
|
-
}
|
|
661
|
-
getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
662
|
-
const pairs = [];
|
|
663
|
-
let node = startNode;
|
|
664
|
-
let done = false;
|
|
665
|
-
let hasMatched = false;
|
|
666
|
-
while (!done) {
|
|
667
|
-
if (endNode && node.id === endNode.id) {
|
|
668
|
-
done = true;
|
|
669
|
-
break;
|
|
670
|
-
}
|
|
671
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
672
|
-
const nValue = node.values[i];
|
|
673
|
-
const keys = node.keys[i];
|
|
674
|
-
if (comparator(nValue, value)) {
|
|
675
|
-
hasMatched = true;
|
|
676
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
677
|
-
const key = keys[j];
|
|
678
|
-
pairs.push([key, nValue]);
|
|
679
|
-
}
|
|
680
|
-
} else if (earlyTerminate && hasMatched) {
|
|
785
|
+
if (direction === 1) {
|
|
786
|
+
if (!node.next) {
|
|
681
787
|
done = true;
|
|
682
788
|
break;
|
|
683
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);
|
|
684
797
|
}
|
|
685
|
-
if (done) break;
|
|
686
|
-
if (!node.next) {
|
|
687
|
-
done = true;
|
|
688
|
-
break;
|
|
689
|
-
}
|
|
690
|
-
node = this.getNode(node.next);
|
|
691
|
-
}
|
|
692
|
-
return new Map(pairs);
|
|
693
|
-
}
|
|
694
|
-
getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
695
|
-
switch (direction) {
|
|
696
|
-
case -1:
|
|
697
|
-
return this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
698
|
-
case 1:
|
|
699
|
-
return this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
700
|
-
default:
|
|
701
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
702
798
|
}
|
|
703
799
|
}
|
|
704
800
|
_createNodeId(isLeaf) {
|
|
@@ -1069,6 +1165,31 @@ var BPTreeSync = class extends BPTree {
|
|
|
1069
1165
|
}
|
|
1070
1166
|
return node;
|
|
1071
1167
|
}
|
|
1168
|
+
insertableRightestNodeByPrimary(value) {
|
|
1169
|
+
let node = this.getNode(this.root.id);
|
|
1170
|
+
while (!node.leaf) {
|
|
1171
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
1172
|
+
const nValue = node.values[i];
|
|
1173
|
+
const k = node.keys;
|
|
1174
|
+
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
1175
|
+
node = this.getNode(k[i]);
|
|
1176
|
+
break;
|
|
1177
|
+
}
|
|
1178
|
+
if (i + 1 === node.values.length) {
|
|
1179
|
+
node = this.getNode(k[i + 1]);
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
return node;
|
|
1185
|
+
}
|
|
1186
|
+
insertableRightestEndNodeByPrimary(value) {
|
|
1187
|
+
const node = this.insertableRightestNodeByPrimary(value);
|
|
1188
|
+
if (!node.next) {
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
return this.getNode(node.next);
|
|
1192
|
+
}
|
|
1072
1193
|
insertableEndNode(value, direction) {
|
|
1073
1194
|
const insertableNode = this.insertableNode(value);
|
|
1074
1195
|
let key;
|
|
@@ -1129,55 +1250,109 @@ var BPTreeSync = class extends BPTree {
|
|
|
1129
1250
|
}
|
|
1130
1251
|
this._nodeDeleteBuffer.clear();
|
|
1131
1252
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
if (
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
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
|
+
}
|
|
1150
1271
|
}
|
|
1151
1272
|
}
|
|
1152
|
-
filterValues = intersections;
|
|
1153
1273
|
}
|
|
1274
|
+
if (!node.next) break;
|
|
1275
|
+
node = this.getNode(node.next);
|
|
1154
1276
|
}
|
|
1155
|
-
return
|
|
1277
|
+
return void 0;
|
|
1156
1278
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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;
|
|
1176
1332
|
}
|
|
1177
|
-
result = intersection;
|
|
1178
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);
|
|
1347
|
+
}
|
|
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);
|
|
1179
1354
|
}
|
|
1180
|
-
return
|
|
1355
|
+
return map;
|
|
1181
1356
|
}
|
|
1182
1357
|
insert(key, value) {
|
|
1183
1358
|
const before = this.insertableNode(value);
|
|
@@ -1552,8 +1727,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1552
1727
|
this.lock.writeUnlock(lockId);
|
|
1553
1728
|
});
|
|
1554
1729
|
}
|
|
1555
|
-
async
|
|
1556
|
-
const pairs = [];
|
|
1730
|
+
async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1557
1731
|
let node = startNode;
|
|
1558
1732
|
let done = false;
|
|
1559
1733
|
let hasMatched = false;
|
|
@@ -1562,71 +1736,52 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1562
1736
|
done = true;
|
|
1563
1737
|
break;
|
|
1564
1738
|
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
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;
|
|
1574
1768
|
}
|
|
1575
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1576
|
-
done = true;
|
|
1577
|
-
break;
|
|
1578
1769
|
}
|
|
1579
1770
|
}
|
|
1580
1771
|
if (done) break;
|
|
1581
|
-
if (
|
|
1582
|
-
|
|
1583
|
-
break;
|
|
1584
|
-
}
|
|
1585
|
-
node = await this.getNode(node.prev);
|
|
1586
|
-
}
|
|
1587
|
-
return new Map(pairs.reverse());
|
|
1588
|
-
}
|
|
1589
|
-
async getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
1590
|
-
const pairs = [];
|
|
1591
|
-
let node = startNode;
|
|
1592
|
-
let done = false;
|
|
1593
|
-
let hasMatched = false;
|
|
1594
|
-
while (!done) {
|
|
1595
|
-
if (endNode && node.id === endNode.id) {
|
|
1596
|
-
done = true;
|
|
1597
|
-
break;
|
|
1598
|
-
}
|
|
1599
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
1600
|
-
const nValue = node.values[i];
|
|
1601
|
-
const keys = node.keys[i];
|
|
1602
|
-
if (comparator(nValue, value)) {
|
|
1603
|
-
hasMatched = true;
|
|
1604
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
1605
|
-
const key = keys[j];
|
|
1606
|
-
pairs.push([key, nValue]);
|
|
1607
|
-
}
|
|
1608
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1772
|
+
if (direction === 1) {
|
|
1773
|
+
if (!node.next) {
|
|
1609
1774
|
done = true;
|
|
1610
1775
|
break;
|
|
1611
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);
|
|
1612
1784
|
}
|
|
1613
|
-
if (done) break;
|
|
1614
|
-
if (!node.next) {
|
|
1615
|
-
done = true;
|
|
1616
|
-
break;
|
|
1617
|
-
}
|
|
1618
|
-
node = await this.getNode(node.next);
|
|
1619
|
-
}
|
|
1620
|
-
return new Map(pairs);
|
|
1621
|
-
}
|
|
1622
|
-
async getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1623
|
-
switch (direction) {
|
|
1624
|
-
case -1:
|
|
1625
|
-
return await this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
1626
|
-
case 1:
|
|
1627
|
-
return await this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
1628
|
-
default:
|
|
1629
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
1630
1785
|
}
|
|
1631
1786
|
}
|
|
1632
1787
|
async _createNodeId(isLeaf) {
|
|
@@ -1997,6 +2152,31 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1997
2152
|
}
|
|
1998
2153
|
return node;
|
|
1999
2154
|
}
|
|
2155
|
+
async insertableRightestNodeByPrimary(value) {
|
|
2156
|
+
let node = await this.getNode(this.root.id);
|
|
2157
|
+
while (!node.leaf) {
|
|
2158
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2159
|
+
const nValue = node.values[i];
|
|
2160
|
+
const k = node.keys;
|
|
2161
|
+
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2162
|
+
node = await this.getNode(k[i]);
|
|
2163
|
+
break;
|
|
2164
|
+
}
|
|
2165
|
+
if (i + 1 === node.values.length) {
|
|
2166
|
+
node = await this.getNode(k[i + 1]);
|
|
2167
|
+
break;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
return node;
|
|
2172
|
+
}
|
|
2173
|
+
async insertableRightestEndNodeByPrimary(value) {
|
|
2174
|
+
const node = await this.insertableRightestNodeByPrimary(value);
|
|
2175
|
+
if (!node.next) {
|
|
2176
|
+
return null;
|
|
2177
|
+
}
|
|
2178
|
+
return await this.getNode(node.next);
|
|
2179
|
+
}
|
|
2000
2180
|
async insertableEndNode(value, direction) {
|
|
2001
2181
|
const insertableNode = await this.insertableNode(value);
|
|
2002
2182
|
let key;
|
|
@@ -2057,58 +2237,114 @@ var BPTreeAsync = class extends BPTree {
|
|
|
2057
2237
|
}
|
|
2058
2238
|
this._nodeDeleteBuffer.clear();
|
|
2059
2239
|
}
|
|
2060
|
-
|
|
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) {
|
|
2061
2248
|
return this.readLock(async () => {
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
filterValues = new Set(pairs.keys());
|
|
2073
|
-
} else {
|
|
2074
|
-
const intersections = /* @__PURE__ */ new Set();
|
|
2075
|
-
for (const key2 of filterValues) {
|
|
2076
|
-
const has = pairs.has(key2);
|
|
2077
|
-
if (has) {
|
|
2078
|
-
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
|
+
}
|
|
2079
2259
|
}
|
|
2080
2260
|
}
|
|
2081
|
-
filterValues = intersections;
|
|
2082
2261
|
}
|
|
2262
|
+
if (!node.next) break;
|
|
2263
|
+
node = await this.getNode(node.next);
|
|
2083
2264
|
}
|
|
2084
|
-
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;
|
|
2085
2339
|
});
|
|
2086
2340
|
}
|
|
2087
2341
|
async where(condition) {
|
|
2088
2342
|
return this.readLock(async () => {
|
|
2089
|
-
|
|
2090
|
-
for (const
|
|
2091
|
-
|
|
2092
|
-
const value = condition[key];
|
|
2093
|
-
const startNode = await this.verifierStartNode[key](value);
|
|
2094
|
-
const endNode = await this.verifierEndNode[key](value);
|
|
2095
|
-
const direction = this.verifierDirection[key];
|
|
2096
|
-
const comparator = this.verifierMap[key];
|
|
2097
|
-
const earlyTerminate = this.verifierEarlyTerminate[key];
|
|
2098
|
-
const pairs = await this.getPairs(value, startNode, endNode, comparator, direction, earlyTerminate);
|
|
2099
|
-
if (result === null) {
|
|
2100
|
-
result = pairs;
|
|
2101
|
-
} else {
|
|
2102
|
-
const intersection = /* @__PURE__ */ new Map();
|
|
2103
|
-
for (const [k2, v] of pairs) {
|
|
2104
|
-
if (result.has(k2)) {
|
|
2105
|
-
intersection.set(k2, v);
|
|
2106
|
-
}
|
|
2107
|
-
}
|
|
2108
|
-
result = intersection;
|
|
2109
|
-
}
|
|
2343
|
+
const map = /* @__PURE__ */ new Map();
|
|
2344
|
+
for await (const [key, value] of this.whereStream(condition)) {
|
|
2345
|
+
map.set(key, value);
|
|
2110
2346
|
}
|
|
2111
|
-
return
|
|
2347
|
+
return map;
|
|
2112
2348
|
});
|
|
2113
2349
|
}
|
|
2114
2350
|
async insert(key, value) {
|