dataply 0.0.11 → 0.0.13
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/dist/cjs/index.js +443 -207
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -490,7 +490,7 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
|
490
490
|
return this.caches.get(key);
|
|
491
491
|
}
|
|
492
492
|
};
|
|
493
|
-
var BPTree = class {
|
|
493
|
+
var BPTree = class _BPTree {
|
|
494
494
|
_cachedRegexp;
|
|
495
495
|
strategy;
|
|
496
496
|
comparator;
|
|
@@ -507,9 +507,15 @@ var BPTree = class {
|
|
|
507
507
|
lt: (nv, v) => this.comparator.isLower(nv, v),
|
|
508
508
|
lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
|
|
509
509
|
equal: (nv, v) => this.comparator.isSame(nv, v),
|
|
510
|
-
primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
|
|
511
510
|
notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
|
|
512
511
|
or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
|
|
512
|
+
primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
|
|
513
|
+
primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
514
|
+
primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
|
|
515
|
+
primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
516
|
+
primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
|
|
517
|
+
primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
|
|
518
|
+
primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
|
|
513
519
|
like: (nv, v) => {
|
|
514
520
|
const nodeValue = this.comparator.match(nv);
|
|
515
521
|
const value = this.comparator.match(v);
|
|
@@ -524,9 +530,15 @@ var BPTree = class {
|
|
|
524
530
|
lt: (v) => this.insertableNode(v),
|
|
525
531
|
lte: (v) => this.insertableNode(v),
|
|
526
532
|
equal: (v) => this.insertableNode(v),
|
|
527
|
-
primaryEqual: (v) => this.insertableNodeByPrimary(v),
|
|
528
533
|
notEqual: (v) => this.leftestNode(),
|
|
529
534
|
or: (v) => this.insertableNode(this.lowestValue(this.ensureValues(v))),
|
|
535
|
+
primaryGt: (v) => this.insertableNodeByPrimary(v),
|
|
536
|
+
primaryGte: (v) => this.insertableNodeByPrimary(v),
|
|
537
|
+
primaryLt: (v) => this.insertableNodeByPrimary(v),
|
|
538
|
+
primaryLte: (v) => this.insertableRightestNodeByPrimary(v),
|
|
539
|
+
primaryEqual: (v) => this.insertableNodeByPrimary(v),
|
|
540
|
+
primaryNotEqual: (v) => this.leftestNode(),
|
|
541
|
+
primaryOr: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
|
|
530
542
|
like: (v) => this.leftestNode()
|
|
531
543
|
};
|
|
532
544
|
verifierEndNode = {
|
|
@@ -535,12 +547,20 @@ var BPTree = class {
|
|
|
535
547
|
lt: (v) => null,
|
|
536
548
|
lte: (v) => null,
|
|
537
549
|
equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
|
|
538
|
-
primaryEqual: (v) => null,
|
|
539
550
|
notEqual: (v) => null,
|
|
540
551
|
or: (v) => this.insertableEndNode(
|
|
541
552
|
this.highestValue(this.ensureValues(v)),
|
|
542
553
|
this.verifierDirection.or
|
|
543
554
|
),
|
|
555
|
+
primaryGt: (v) => null,
|
|
556
|
+
primaryGte: (v) => null,
|
|
557
|
+
primaryLt: (v) => null,
|
|
558
|
+
primaryLte: (v) => null,
|
|
559
|
+
primaryEqual: (v) => null,
|
|
560
|
+
primaryNotEqual: (v) => null,
|
|
561
|
+
primaryOr: (v) => this.insertableRightestEndNodeByPrimary(
|
|
562
|
+
this.highestPrimaryValue(this.ensureValues(v))
|
|
563
|
+
),
|
|
544
564
|
like: (v) => null
|
|
545
565
|
};
|
|
546
566
|
verifierDirection = {
|
|
@@ -549,9 +569,15 @@ var BPTree = class {
|
|
|
549
569
|
lt: -1,
|
|
550
570
|
lte: -1,
|
|
551
571
|
equal: 1,
|
|
552
|
-
primaryEqual: 1,
|
|
553
572
|
notEqual: 1,
|
|
554
573
|
or: 1,
|
|
574
|
+
primaryGt: 1,
|
|
575
|
+
primaryGte: 1,
|
|
576
|
+
primaryLt: -1,
|
|
577
|
+
primaryLte: -1,
|
|
578
|
+
primaryEqual: 1,
|
|
579
|
+
primaryNotEqual: 1,
|
|
580
|
+
primaryOr: 1,
|
|
555
581
|
like: 1
|
|
556
582
|
};
|
|
557
583
|
/**
|
|
@@ -565,11 +591,93 @@ var BPTree = class {
|
|
|
565
591
|
lt: false,
|
|
566
592
|
lte: false,
|
|
567
593
|
equal: true,
|
|
568
|
-
primaryEqual: true,
|
|
569
594
|
notEqual: false,
|
|
570
595
|
or: false,
|
|
596
|
+
primaryGt: false,
|
|
597
|
+
primaryGte: false,
|
|
598
|
+
primaryLt: false,
|
|
599
|
+
primaryLte: false,
|
|
600
|
+
primaryEqual: true,
|
|
601
|
+
primaryNotEqual: false,
|
|
602
|
+
primaryOr: false,
|
|
571
603
|
like: false
|
|
572
604
|
};
|
|
605
|
+
/**
|
|
606
|
+
* Priority map for condition types.
|
|
607
|
+
* Higher value = higher selectivity (fewer expected results).
|
|
608
|
+
* Used by `chooseDriver` to select the most selective index.
|
|
609
|
+
*/
|
|
610
|
+
static conditionPriority = {
|
|
611
|
+
equal: 100,
|
|
612
|
+
primaryEqual: 100,
|
|
613
|
+
or: 80,
|
|
614
|
+
primaryOr: 80,
|
|
615
|
+
gt: 50,
|
|
616
|
+
gte: 50,
|
|
617
|
+
lt: 50,
|
|
618
|
+
lte: 50,
|
|
619
|
+
primaryGt: 50,
|
|
620
|
+
primaryGte: 50,
|
|
621
|
+
primaryLt: 50,
|
|
622
|
+
primaryLte: 50,
|
|
623
|
+
like: 30,
|
|
624
|
+
notEqual: 10,
|
|
625
|
+
primaryNotEqual: 10
|
|
626
|
+
};
|
|
627
|
+
/**
|
|
628
|
+
* Selects the best driver tree from multiple tree/condition pairs.
|
|
629
|
+
* Uses rule-based optimization to choose the tree with highest estimated selectivity.
|
|
630
|
+
*
|
|
631
|
+
* @param candidates Array of { tree, condition } pairs to evaluate
|
|
632
|
+
* @returns The candidate with highest priority condition, or null if empty
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* ```typescript
|
|
636
|
+
* const driver = BPTreeSync.chooseDriver([
|
|
637
|
+
* { tree: idxId, condition: { equal: 100 } },
|
|
638
|
+
* { tree: idxAge, condition: { gt: 20 } }
|
|
639
|
+
* ])
|
|
640
|
+
* // Returns { tree: idxId, condition: { equal: 100 } } because 'equal' has higher priority
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
643
|
+
static ChooseDriver(candidates) {
|
|
644
|
+
if (candidates.length === 0) return null;
|
|
645
|
+
if (candidates.length === 1) return candidates[0];
|
|
646
|
+
let best = candidates[0];
|
|
647
|
+
let bestScore = 0;
|
|
648
|
+
for (const candidate of candidates) {
|
|
649
|
+
let score = 0;
|
|
650
|
+
for (const key in candidate.condition) {
|
|
651
|
+
const condKey = key;
|
|
652
|
+
const priority = _BPTree.conditionPriority[condKey] ?? 0;
|
|
653
|
+
if (priority > score) {
|
|
654
|
+
score = priority;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (score > bestScore) {
|
|
658
|
+
bestScore = score;
|
|
659
|
+
best = candidate;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return best;
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Verified if the value satisfies the condition.
|
|
666
|
+
*
|
|
667
|
+
* @param nodeValue The value to verify.
|
|
668
|
+
* @param condition The condition to verify against.
|
|
669
|
+
* @returns Returns true if the value satisfies the condition.
|
|
670
|
+
*/
|
|
671
|
+
verify(nodeValue, condition) {
|
|
672
|
+
for (const key in condition) {
|
|
673
|
+
const verify = this.verifierMap[key];
|
|
674
|
+
const condValue = condition[key];
|
|
675
|
+
if (!verify(nodeValue, condValue)) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
573
681
|
constructor(strategy, comparator, option) {
|
|
574
682
|
this.strategy = strategy;
|
|
575
683
|
this.comparator = comparator;
|
|
@@ -603,6 +711,14 @@ var BPTree = class {
|
|
|
603
711
|
const i = v.length - 1;
|
|
604
712
|
return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
|
|
605
713
|
}
|
|
714
|
+
lowestPrimaryValue(v) {
|
|
715
|
+
const i = 0;
|
|
716
|
+
return [...v].sort((a, b) => this.comparator.primaryAsc(a, b))[i];
|
|
717
|
+
}
|
|
718
|
+
highestPrimaryValue(v) {
|
|
719
|
+
const i = v.length - 1;
|
|
720
|
+
return [...v].sort((a, b) => this.comparator.primaryAsc(a, b))[i];
|
|
721
|
+
}
|
|
606
722
|
_insertAtLeaf(node, key, value) {
|
|
607
723
|
if (node.values.length) {
|
|
608
724
|
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
@@ -680,8 +796,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
680
796
|
capacity: this.option.capacity ?? 1e3
|
|
681
797
|
});
|
|
682
798
|
}
|
|
683
|
-
|
|
684
|
-
const pairs = [];
|
|
799
|
+
*getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
685
800
|
let node = startNode;
|
|
686
801
|
let done = false;
|
|
687
802
|
let hasMatched = false;
|
|
@@ -690,71 +805,52 @@ var BPTreeSync = class extends BPTree {
|
|
|
690
805
|
done = true;
|
|
691
806
|
break;
|
|
692
807
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
808
|
+
const len = node.values.length;
|
|
809
|
+
if (direction === 1) {
|
|
810
|
+
for (let i = 0; i < len; i++) {
|
|
811
|
+
const nValue = node.values[i];
|
|
812
|
+
const keys = node.keys[i];
|
|
813
|
+
if (comparator(nValue, value)) {
|
|
814
|
+
hasMatched = true;
|
|
815
|
+
for (let j = 0; j < keys.length; j++) {
|
|
816
|
+
yield [keys[j], nValue];
|
|
817
|
+
}
|
|
818
|
+
} else if (earlyTerminate && hasMatched) {
|
|
819
|
+
done = true;
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
} else {
|
|
824
|
+
let i = len;
|
|
825
|
+
while (i--) {
|
|
826
|
+
const nValue = node.values[i];
|
|
827
|
+
const keys = node.keys[i];
|
|
828
|
+
if (comparator(nValue, value)) {
|
|
829
|
+
hasMatched = true;
|
|
830
|
+
let j = keys.length;
|
|
831
|
+
while (j--) {
|
|
832
|
+
yield [keys[j], nValue];
|
|
833
|
+
}
|
|
834
|
+
} else if (earlyTerminate && hasMatched) {
|
|
835
|
+
done = true;
|
|
836
|
+
break;
|
|
702
837
|
}
|
|
703
|
-
} else if (earlyTerminate && hasMatched) {
|
|
704
|
-
done = true;
|
|
705
|
-
break;
|
|
706
838
|
}
|
|
707
839
|
}
|
|
708
840
|
if (done) break;
|
|
709
|
-
if (
|
|
710
|
-
|
|
711
|
-
break;
|
|
712
|
-
}
|
|
713
|
-
node = this.getNode(node.prev);
|
|
714
|
-
}
|
|
715
|
-
return new Map(pairs.reverse());
|
|
716
|
-
}
|
|
717
|
-
getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
718
|
-
const pairs = [];
|
|
719
|
-
let node = startNode;
|
|
720
|
-
let done = false;
|
|
721
|
-
let hasMatched = false;
|
|
722
|
-
while (!done) {
|
|
723
|
-
if (endNode && node.id === endNode.id) {
|
|
724
|
-
done = true;
|
|
725
|
-
break;
|
|
726
|
-
}
|
|
727
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
728
|
-
const nValue = node.values[i];
|
|
729
|
-
const keys = node.keys[i];
|
|
730
|
-
if (comparator(nValue, value)) {
|
|
731
|
-
hasMatched = true;
|
|
732
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
733
|
-
const key = keys[j];
|
|
734
|
-
pairs.push([key, nValue]);
|
|
735
|
-
}
|
|
736
|
-
} else if (earlyTerminate && hasMatched) {
|
|
841
|
+
if (direction === 1) {
|
|
842
|
+
if (!node.next) {
|
|
737
843
|
done = true;
|
|
738
844
|
break;
|
|
739
845
|
}
|
|
846
|
+
node = this.getNode(node.next);
|
|
847
|
+
} else {
|
|
848
|
+
if (!node.prev) {
|
|
849
|
+
done = true;
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
852
|
+
node = this.getNode(node.prev);
|
|
740
853
|
}
|
|
741
|
-
if (done) break;
|
|
742
|
-
if (!node.next) {
|
|
743
|
-
done = true;
|
|
744
|
-
break;
|
|
745
|
-
}
|
|
746
|
-
node = this.getNode(node.next);
|
|
747
|
-
}
|
|
748
|
-
return new Map(pairs);
|
|
749
|
-
}
|
|
750
|
-
getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
751
|
-
switch (direction) {
|
|
752
|
-
case -1:
|
|
753
|
-
return this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
754
|
-
case 1:
|
|
755
|
-
return this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
756
|
-
default:
|
|
757
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
758
854
|
}
|
|
759
855
|
}
|
|
760
856
|
_createNodeId(isLeaf) {
|
|
@@ -1125,6 +1221,31 @@ var BPTreeSync = class extends BPTree {
|
|
|
1125
1221
|
}
|
|
1126
1222
|
return node;
|
|
1127
1223
|
}
|
|
1224
|
+
insertableRightestNodeByPrimary(value) {
|
|
1225
|
+
let node = this.getNode(this.root.id);
|
|
1226
|
+
while (!node.leaf) {
|
|
1227
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
1228
|
+
const nValue = node.values[i];
|
|
1229
|
+
const k = node.keys;
|
|
1230
|
+
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
1231
|
+
node = this.getNode(k[i]);
|
|
1232
|
+
break;
|
|
1233
|
+
}
|
|
1234
|
+
if (i + 1 === node.values.length) {
|
|
1235
|
+
node = this.getNode(k[i + 1]);
|
|
1236
|
+
break;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
return node;
|
|
1241
|
+
}
|
|
1242
|
+
insertableRightestEndNodeByPrimary(value) {
|
|
1243
|
+
const node = this.insertableRightestNodeByPrimary(value);
|
|
1244
|
+
if (!node.next) {
|
|
1245
|
+
return null;
|
|
1246
|
+
}
|
|
1247
|
+
return this.getNode(node.next);
|
|
1248
|
+
}
|
|
1128
1249
|
insertableEndNode(value, direction) {
|
|
1129
1250
|
const insertableNode = this.insertableNode(value);
|
|
1130
1251
|
let key;
|
|
@@ -1185,55 +1306,109 @@ var BPTreeSync = class extends BPTree {
|
|
|
1185
1306
|
}
|
|
1186
1307
|
this._nodeDeleteBuffer.clear();
|
|
1187
1308
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
if (
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1309
|
+
/**
|
|
1310
|
+
* Retrieves the value associated with the given key (PK).
|
|
1311
|
+
* Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
|
|
1312
|
+
*
|
|
1313
|
+
* @param key The key to search for.
|
|
1314
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
1315
|
+
*/
|
|
1316
|
+
get(key) {
|
|
1317
|
+
let node = this.leftestNode();
|
|
1318
|
+
while (true) {
|
|
1319
|
+
if (node.values) {
|
|
1320
|
+
const len = node.values.length;
|
|
1321
|
+
for (let i = 0; i < len; i++) {
|
|
1322
|
+
const keys = node.keys[i];
|
|
1323
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1324
|
+
if (keys[j] === key) {
|
|
1325
|
+
return node.values[i];
|
|
1326
|
+
}
|
|
1206
1327
|
}
|
|
1207
1328
|
}
|
|
1208
|
-
filterValues = intersections;
|
|
1209
1329
|
}
|
|
1330
|
+
if (!node.next) break;
|
|
1331
|
+
node = this.getNode(node.next);
|
|
1210
1332
|
}
|
|
1211
|
-
return
|
|
1333
|
+
return void 0;
|
|
1212
1334
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1335
|
+
*keysStream(condition, filterValues, limit) {
|
|
1336
|
+
const stream = this.whereStream(condition, limit);
|
|
1337
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
1338
|
+
for (const [key] of stream) {
|
|
1339
|
+
if (intersection && !intersection.has(key)) {
|
|
1340
|
+
continue;
|
|
1341
|
+
}
|
|
1342
|
+
yield key;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
*whereStream(condition, limit) {
|
|
1346
|
+
let driverKey = null;
|
|
1347
|
+
if ("primaryEqual" in condition) driverKey = "primaryEqual";
|
|
1348
|
+
else if ("equal" in condition) driverKey = "equal";
|
|
1349
|
+
else if ("gt" in condition) driverKey = "gt";
|
|
1350
|
+
else if ("gte" in condition) driverKey = "gte";
|
|
1351
|
+
else if ("lt" in condition) driverKey = "lt";
|
|
1352
|
+
else if ("lte" in condition) driverKey = "lte";
|
|
1353
|
+
else if ("primaryGt" in condition) driverKey = "primaryGt";
|
|
1354
|
+
else if ("primaryGte" in condition) driverKey = "primaryGte";
|
|
1355
|
+
else if ("primaryLt" in condition) driverKey = "primaryLt";
|
|
1356
|
+
else if ("primaryLte" in condition) driverKey = "primaryLte";
|
|
1357
|
+
else if ("like" in condition) driverKey = "like";
|
|
1358
|
+
else if ("notEqual" in condition) driverKey = "notEqual";
|
|
1359
|
+
else if ("primaryNotEqual" in condition) driverKey = "primaryNotEqual";
|
|
1360
|
+
else if ("or" in condition) driverKey = "or";
|
|
1361
|
+
else if ("primaryOr" in condition) driverKey = "primaryOr";
|
|
1362
|
+
if (!driverKey) return;
|
|
1363
|
+
const value = condition[driverKey];
|
|
1364
|
+
const startNode = this.verifierStartNode[driverKey](value);
|
|
1365
|
+
const endNode = this.verifierEndNode[driverKey](value);
|
|
1366
|
+
const direction = this.verifierDirection[driverKey];
|
|
1367
|
+
const comparator = this.verifierMap[driverKey];
|
|
1368
|
+
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
1369
|
+
const generator = this.getPairsGenerator(
|
|
1370
|
+
value,
|
|
1371
|
+
startNode,
|
|
1372
|
+
endNode,
|
|
1373
|
+
comparator,
|
|
1374
|
+
direction,
|
|
1375
|
+
earlyTerminate
|
|
1376
|
+
);
|
|
1377
|
+
let count = 0;
|
|
1378
|
+
for (const pair of generator) {
|
|
1379
|
+
const [k, v] = pair;
|
|
1380
|
+
let isMatch = true;
|
|
1381
|
+
for (const key in condition) {
|
|
1382
|
+
if (key === driverKey) continue;
|
|
1383
|
+
const verify = this.verifierMap[key];
|
|
1384
|
+
const condValue = condition[key];
|
|
1385
|
+
if (!verify(v, condValue)) {
|
|
1386
|
+
isMatch = false;
|
|
1387
|
+
break;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
if (isMatch) {
|
|
1391
|
+
yield pair;
|
|
1392
|
+
count++;
|
|
1393
|
+
if (limit !== void 0 && count >= limit) {
|
|
1394
|
+
break;
|
|
1232
1395
|
}
|
|
1233
|
-
result = intersection;
|
|
1234
1396
|
}
|
|
1235
1397
|
}
|
|
1236
|
-
|
|
1398
|
+
}
|
|
1399
|
+
keys(condition, filterValues) {
|
|
1400
|
+
const set = /* @__PURE__ */ new Set();
|
|
1401
|
+
for (const key of this.keysStream(condition, filterValues)) {
|
|
1402
|
+
set.add(key);
|
|
1403
|
+
}
|
|
1404
|
+
return set;
|
|
1405
|
+
}
|
|
1406
|
+
where(condition) {
|
|
1407
|
+
const map = /* @__PURE__ */ new Map();
|
|
1408
|
+
for (const [key, value] of this.whereStream(condition)) {
|
|
1409
|
+
map.set(key, value);
|
|
1410
|
+
}
|
|
1411
|
+
return map;
|
|
1237
1412
|
}
|
|
1238
1413
|
insert(key, value) {
|
|
1239
1414
|
const before = this.insertableNode(value);
|
|
@@ -1604,8 +1779,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1604
1779
|
this.lock.writeUnlock(lockId);
|
|
1605
1780
|
});
|
|
1606
1781
|
}
|
|
1607
|
-
async
|
|
1608
|
-
const pairs = [];
|
|
1782
|
+
async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1609
1783
|
let node = startNode;
|
|
1610
1784
|
let done = false;
|
|
1611
1785
|
let hasMatched = false;
|
|
@@ -1614,71 +1788,52 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1614
1788
|
done = true;
|
|
1615
1789
|
break;
|
|
1616
1790
|
}
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1791
|
+
const len = node.values.length;
|
|
1792
|
+
if (direction === 1) {
|
|
1793
|
+
for (let i = 0; i < len; i++) {
|
|
1794
|
+
const nValue = node.values[i];
|
|
1795
|
+
const keys = node.keys[i];
|
|
1796
|
+
if (comparator(nValue, value)) {
|
|
1797
|
+
hasMatched = true;
|
|
1798
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1799
|
+
yield [keys[j], nValue];
|
|
1800
|
+
}
|
|
1801
|
+
} else if (earlyTerminate && hasMatched) {
|
|
1802
|
+
done = true;
|
|
1803
|
+
break;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
} else {
|
|
1807
|
+
let i = len;
|
|
1808
|
+
while (i--) {
|
|
1809
|
+
const nValue = node.values[i];
|
|
1810
|
+
const keys = node.keys[i];
|
|
1811
|
+
if (comparator(nValue, value)) {
|
|
1812
|
+
hasMatched = true;
|
|
1813
|
+
let j = keys.length;
|
|
1814
|
+
while (j--) {
|
|
1815
|
+
yield [keys[j], nValue];
|
|
1816
|
+
}
|
|
1817
|
+
} else if (earlyTerminate && hasMatched) {
|
|
1818
|
+
done = true;
|
|
1819
|
+
break;
|
|
1626
1820
|
}
|
|
1627
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1628
|
-
done = true;
|
|
1629
|
-
break;
|
|
1630
1821
|
}
|
|
1631
1822
|
}
|
|
1632
1823
|
if (done) break;
|
|
1633
|
-
if (
|
|
1634
|
-
|
|
1635
|
-
break;
|
|
1636
|
-
}
|
|
1637
|
-
node = await this.getNode(node.prev);
|
|
1638
|
-
}
|
|
1639
|
-
return new Map(pairs.reverse());
|
|
1640
|
-
}
|
|
1641
|
-
async getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate) {
|
|
1642
|
-
const pairs = [];
|
|
1643
|
-
let node = startNode;
|
|
1644
|
-
let done = false;
|
|
1645
|
-
let hasMatched = false;
|
|
1646
|
-
while (!done) {
|
|
1647
|
-
if (endNode && node.id === endNode.id) {
|
|
1648
|
-
done = true;
|
|
1649
|
-
break;
|
|
1650
|
-
}
|
|
1651
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
1652
|
-
const nValue = node.values[i];
|
|
1653
|
-
const keys = node.keys[i];
|
|
1654
|
-
if (comparator(nValue, value)) {
|
|
1655
|
-
hasMatched = true;
|
|
1656
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
1657
|
-
const key = keys[j];
|
|
1658
|
-
pairs.push([key, nValue]);
|
|
1659
|
-
}
|
|
1660
|
-
} else if (earlyTerminate && hasMatched) {
|
|
1824
|
+
if (direction === 1) {
|
|
1825
|
+
if (!node.next) {
|
|
1661
1826
|
done = true;
|
|
1662
1827
|
break;
|
|
1663
1828
|
}
|
|
1829
|
+
node = await this.getNode(node.next);
|
|
1830
|
+
} else {
|
|
1831
|
+
if (!node.prev) {
|
|
1832
|
+
done = true;
|
|
1833
|
+
break;
|
|
1834
|
+
}
|
|
1835
|
+
node = await this.getNode(node.prev);
|
|
1664
1836
|
}
|
|
1665
|
-
if (done) break;
|
|
1666
|
-
if (!node.next) {
|
|
1667
|
-
done = true;
|
|
1668
|
-
break;
|
|
1669
|
-
}
|
|
1670
|
-
node = await this.getNode(node.next);
|
|
1671
|
-
}
|
|
1672
|
-
return new Map(pairs);
|
|
1673
|
-
}
|
|
1674
|
-
async getPairs(value, startNode, endNode, comparator, direction, earlyTerminate) {
|
|
1675
|
-
switch (direction) {
|
|
1676
|
-
case -1:
|
|
1677
|
-
return await this.getPairsRightToLeft(value, startNode, endNode, comparator, earlyTerminate);
|
|
1678
|
-
case 1:
|
|
1679
|
-
return await this.getPairsLeftToRight(value, startNode, endNode, comparator, earlyTerminate);
|
|
1680
|
-
default:
|
|
1681
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
1682
1837
|
}
|
|
1683
1838
|
}
|
|
1684
1839
|
async _createNodeId(isLeaf) {
|
|
@@ -2049,6 +2204,31 @@ var BPTreeAsync = class extends BPTree {
|
|
|
2049
2204
|
}
|
|
2050
2205
|
return node;
|
|
2051
2206
|
}
|
|
2207
|
+
async insertableRightestNodeByPrimary(value) {
|
|
2208
|
+
let node = await this.getNode(this.root.id);
|
|
2209
|
+
while (!node.leaf) {
|
|
2210
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2211
|
+
const nValue = node.values[i];
|
|
2212
|
+
const k = node.keys;
|
|
2213
|
+
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2214
|
+
node = await this.getNode(k[i]);
|
|
2215
|
+
break;
|
|
2216
|
+
}
|
|
2217
|
+
if (i + 1 === node.values.length) {
|
|
2218
|
+
node = await this.getNode(k[i + 1]);
|
|
2219
|
+
break;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
return node;
|
|
2224
|
+
}
|
|
2225
|
+
async insertableRightestEndNodeByPrimary(value) {
|
|
2226
|
+
const node = await this.insertableRightestNodeByPrimary(value);
|
|
2227
|
+
if (!node.next) {
|
|
2228
|
+
return null;
|
|
2229
|
+
}
|
|
2230
|
+
return await this.getNode(node.next);
|
|
2231
|
+
}
|
|
2052
2232
|
async insertableEndNode(value, direction) {
|
|
2053
2233
|
const insertableNode = await this.insertableNode(value);
|
|
2054
2234
|
let key;
|
|
@@ -2109,58 +2289,114 @@ var BPTreeAsync = class extends BPTree {
|
|
|
2109
2289
|
}
|
|
2110
2290
|
this._nodeDeleteBuffer.clear();
|
|
2111
2291
|
}
|
|
2112
|
-
|
|
2292
|
+
/**
|
|
2293
|
+
* Retrieves the value associated with the given key (PK).
|
|
2294
|
+
* Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
|
|
2295
|
+
*
|
|
2296
|
+
* @param key The key to search for.
|
|
2297
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
2298
|
+
*/
|
|
2299
|
+
async get(key) {
|
|
2113
2300
|
return this.readLock(async () => {
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
filterValues = new Set(pairs.keys());
|
|
2125
|
-
} else {
|
|
2126
|
-
const intersections = /* @__PURE__ */ new Set();
|
|
2127
|
-
for (const key2 of filterValues) {
|
|
2128
|
-
const has = pairs.has(key2);
|
|
2129
|
-
if (has) {
|
|
2130
|
-
intersections.add(key2);
|
|
2301
|
+
let node = await this.leftestNode();
|
|
2302
|
+
while (true) {
|
|
2303
|
+
if (node.values) {
|
|
2304
|
+
const len = node.values.length;
|
|
2305
|
+
for (let i = 0; i < len; i++) {
|
|
2306
|
+
const keys = node.keys[i];
|
|
2307
|
+
for (let j = 0; j < keys.length; j++) {
|
|
2308
|
+
if (keys[j] === key) {
|
|
2309
|
+
return node.values[i];
|
|
2310
|
+
}
|
|
2131
2311
|
}
|
|
2132
2312
|
}
|
|
2133
|
-
filterValues = intersections;
|
|
2134
2313
|
}
|
|
2314
|
+
if (!node.next) break;
|
|
2315
|
+
node = await this.getNode(node.next);
|
|
2135
2316
|
}
|
|
2136
|
-
return
|
|
2317
|
+
return void 0;
|
|
2318
|
+
});
|
|
2319
|
+
}
|
|
2320
|
+
async *keysStream(condition, filterValues, limit) {
|
|
2321
|
+
const stream = this.whereStream(condition, limit);
|
|
2322
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2323
|
+
for await (const [key] of stream) {
|
|
2324
|
+
if (intersection && !intersection.has(key)) {
|
|
2325
|
+
continue;
|
|
2326
|
+
}
|
|
2327
|
+
yield key;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
async *whereStream(condition, limit) {
|
|
2331
|
+
let driverKey = null;
|
|
2332
|
+
if ("primaryEqual" in condition) driverKey = "primaryEqual";
|
|
2333
|
+
else if ("equal" in condition) driverKey = "equal";
|
|
2334
|
+
else if ("gt" in condition) driverKey = "gt";
|
|
2335
|
+
else if ("gte" in condition) driverKey = "gte";
|
|
2336
|
+
else if ("lt" in condition) driverKey = "lt";
|
|
2337
|
+
else if ("lte" in condition) driverKey = "lte";
|
|
2338
|
+
else if ("primaryGt" in condition) driverKey = "primaryGt";
|
|
2339
|
+
else if ("primaryGte" in condition) driverKey = "primaryGte";
|
|
2340
|
+
else if ("primaryLt" in condition) driverKey = "primaryLt";
|
|
2341
|
+
else if ("primaryLte" in condition) driverKey = "primaryLte";
|
|
2342
|
+
else if ("like" in condition) driverKey = "like";
|
|
2343
|
+
else if ("notEqual" in condition) driverKey = "notEqual";
|
|
2344
|
+
else if ("primaryNotEqual" in condition) driverKey = "primaryNotEqual";
|
|
2345
|
+
else if ("or" in condition) driverKey = "or";
|
|
2346
|
+
else if ("primaryOr" in condition) driverKey = "primaryOr";
|
|
2347
|
+
if (!driverKey) return;
|
|
2348
|
+
const value = condition[driverKey];
|
|
2349
|
+
const startNode = await this.verifierStartNode[driverKey](value);
|
|
2350
|
+
const endNode = await this.verifierEndNode[driverKey](value);
|
|
2351
|
+
const direction = this.verifierDirection[driverKey];
|
|
2352
|
+
const comparator = this.verifierMap[driverKey];
|
|
2353
|
+
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
2354
|
+
const generator = this.getPairsGenerator(
|
|
2355
|
+
value,
|
|
2356
|
+
startNode,
|
|
2357
|
+
endNode,
|
|
2358
|
+
comparator,
|
|
2359
|
+
direction,
|
|
2360
|
+
earlyTerminate
|
|
2361
|
+
);
|
|
2362
|
+
let count = 0;
|
|
2363
|
+
for await (const pair of generator) {
|
|
2364
|
+
const [k, v] = pair;
|
|
2365
|
+
let isMatch = true;
|
|
2366
|
+
for (const key in condition) {
|
|
2367
|
+
if (key === driverKey) continue;
|
|
2368
|
+
const verify = this.verifierMap[key];
|
|
2369
|
+
const condValue = condition[key];
|
|
2370
|
+
if (!verify(v, condValue)) {
|
|
2371
|
+
isMatch = false;
|
|
2372
|
+
break;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
if (isMatch) {
|
|
2376
|
+
yield pair;
|
|
2377
|
+
count++;
|
|
2378
|
+
if (limit !== void 0 && count >= limit) {
|
|
2379
|
+
break;
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
async keys(condition, filterValues) {
|
|
2385
|
+
return this.readLock(async () => {
|
|
2386
|
+
const set = /* @__PURE__ */ new Set();
|
|
2387
|
+
for await (const key of this.keysStream(condition, filterValues)) {
|
|
2388
|
+
set.add(key);
|
|
2389
|
+
}
|
|
2390
|
+
return set;
|
|
2137
2391
|
});
|
|
2138
2392
|
}
|
|
2139
2393
|
async where(condition) {
|
|
2140
2394
|
return this.readLock(async () => {
|
|
2141
|
-
|
|
2142
|
-
for (const
|
|
2143
|
-
|
|
2144
|
-
const value = condition[key];
|
|
2145
|
-
const startNode = await this.verifierStartNode[key](value);
|
|
2146
|
-
const endNode = await this.verifierEndNode[key](value);
|
|
2147
|
-
const direction = this.verifierDirection[key];
|
|
2148
|
-
const comparator = this.verifierMap[key];
|
|
2149
|
-
const earlyTerminate = this.verifierEarlyTerminate[key];
|
|
2150
|
-
const pairs = await this.getPairs(value, startNode, endNode, comparator, direction, earlyTerminate);
|
|
2151
|
-
if (result === null) {
|
|
2152
|
-
result = pairs;
|
|
2153
|
-
} else {
|
|
2154
|
-
const intersection = /* @__PURE__ */ new Map();
|
|
2155
|
-
for (const [k2, v] of pairs) {
|
|
2156
|
-
if (result.has(k2)) {
|
|
2157
|
-
intersection.set(k2, v);
|
|
2158
|
-
}
|
|
2159
|
-
}
|
|
2160
|
-
result = intersection;
|
|
2161
|
-
}
|
|
2395
|
+
const map = /* @__PURE__ */ new Map();
|
|
2396
|
+
for await (const [key, value] of this.whereStream(condition)) {
|
|
2397
|
+
map.set(key, value);
|
|
2162
2398
|
}
|
|
2163
|
-
return
|
|
2399
|
+
return map;
|
|
2164
2400
|
});
|
|
2165
2401
|
}
|
|
2166
2402
|
async insert(key, value) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dataply",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "A lightweight storage engine for Node.js with support for MVCC, WAL.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "izure <admin@izure.org>",
|
|
@@ -47,6 +47,6 @@
|
|
|
47
47
|
"cache-entanglement": "^1.7.1",
|
|
48
48
|
"hookall": "^2.2.0",
|
|
49
49
|
"ryoiki": "^1.2.0",
|
|
50
|
-
"serializable-bptree": "^6.
|
|
50
|
+
"serializable-bptree": "^6.2.0"
|
|
51
51
|
}
|
|
52
52
|
}
|