serializable-bptree 3.0.0 → 3.1.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 +35 -1
- package/dist/cjs/index.js +71 -49
- package/dist/esm/index.js +71 -49
- package/dist/typings/BPTreeAsync.d.ts +5 -21
- package/dist/typings/BPTreeSync.d.ts +5 -21
- package/dist/typings/base/BPTree.d.ts +10 -10
- package/dist/typings/base/ValueComparator.d.ts +56 -0
- package/dist/typings/index.d.ts +1 -1
- package/dist/typings/utils/CacheStorage.d.ts +3 -0
- package/package.json +1 -1
- package/dist/typings/ValueComparator.d.ts +0 -18
package/README.md
CHANGED
|
@@ -129,11 +129,45 @@ class AgeComparator extends ValueComparator<MyObject> {
|
|
|
129
129
|
asc(a: MyObject, b: MyObject): number {
|
|
130
130
|
return a.age - b.age
|
|
131
131
|
}
|
|
132
|
+
|
|
133
|
+
match(value: MyObject): string {
|
|
134
|
+
return value.age
|
|
135
|
+
}
|
|
132
136
|
}
|
|
133
137
|
```
|
|
134
138
|
|
|
139
|
+
#### asc
|
|
140
|
+
|
|
135
141
|
The **asc** method should return values in ascending order. If the return value is negative, it means that the parameter **a** is smaller than **b**. If the return value is positive, it means that **a** is greater than **b**. If the return value is **0**, it indicates that **a** and **b** are of the same size.
|
|
136
142
|
|
|
143
|
+
#### match
|
|
144
|
+
|
|
145
|
+
The `match` method is used for the **LIKE** operator. This method specifies which value to test against a regular expression. For example, if you have a tree with values of the structure `{ country: string, capital: number }`, and you want to perform a **LIKE** operation based on the **capital** value, the method should return **value.capital**. In this case, you **CANNOT** perform a **LIKE** operation based on the **country** attribute. The returned value must be a string.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
interface MyObject {
|
|
149
|
+
country: string
|
|
150
|
+
capital: string
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
class CompositeComparator extends ValueComparator<MyObject> {
|
|
154
|
+
...
|
|
155
|
+
match(value: MyObject): string {
|
|
156
|
+
return value.capital
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
For a tree with simple structure, without complex nesting, returning the value directly would be sufficient.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
class StringComparator extends ValueComparator<string> {
|
|
165
|
+
match(value: string): string {
|
|
166
|
+
return value
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
137
171
|
### Serialize strategy
|
|
138
172
|
|
|
139
173
|
A B+tree instance is made up of numerous nodes. You would want to store this value when such nodes are created or updated. Let's assume you want to save it to a file.
|
|
@@ -371,7 +405,7 @@ The implementation method for asynchronous operations is not significantly diffe
|
|
|
371
405
|
|
|
372
406
|
The serializable-bptree minimizes file I/O by storing loaded nodes in-memory. This approach works well in situations where there is a 1:1 relationship between the remote storage and the client. However, in a 1:n scenario, where multiple clients read from and write to a single remote storage, data inconsistency between the remote storage and the clients can occur.
|
|
373
407
|
|
|
374
|
-
To solve this
|
|
408
|
+
To solve this problem, it's necessary to update the cached nodes. The forceUpdate method was created for this purpose. It fetches the node data cached in the tree instance again. To use this feature, when you save data to the remote storage, you must send a signal to all clients connected to that remote storage indicating that the node has been updated. Clients must receive this signal and configure logic to call the **forceUpdate** method; however, this goes beyond the scope of the library, so you must implement it yourself.
|
|
375
409
|
|
|
376
410
|
### Concurrency Issue in Asynchronous Trees
|
|
377
411
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -32,8 +32,48 @@ __export(src_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(src_exports);
|
|
34
34
|
|
|
35
|
+
// src/base/ValueComparator.ts
|
|
36
|
+
var ValueComparator = class {
|
|
37
|
+
isLower(value, than) {
|
|
38
|
+
return this.asc(value, than) < 0;
|
|
39
|
+
}
|
|
40
|
+
isSame(value, than) {
|
|
41
|
+
return this.asc(value, than) === 0;
|
|
42
|
+
}
|
|
43
|
+
isHigher(value, than) {
|
|
44
|
+
return this.asc(value, than) > 0;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var NumericComparator = class extends ValueComparator {
|
|
48
|
+
asc(a, b) {
|
|
49
|
+
return a - b;
|
|
50
|
+
}
|
|
51
|
+
match(value) {
|
|
52
|
+
return value.toString();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var StringComparator = class extends ValueComparator {
|
|
56
|
+
asc(a, b) {
|
|
57
|
+
return a.localeCompare(b);
|
|
58
|
+
}
|
|
59
|
+
match(value) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/utils/CacheStorage.ts
|
|
65
|
+
var CacheStorage = class extends Map {
|
|
66
|
+
ensure(key, generator) {
|
|
67
|
+
if (!this.has(key)) {
|
|
68
|
+
this.set(key, generator());
|
|
69
|
+
}
|
|
70
|
+
return this.get(key);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
35
74
|
// src/base/BPTree.ts
|
|
36
75
|
var BPTree = class {
|
|
76
|
+
_regexpCache;
|
|
37
77
|
strategy;
|
|
38
78
|
comparator;
|
|
39
79
|
nodes;
|
|
@@ -51,11 +91,13 @@ var BPTree = class {
|
|
|
51
91
|
equal: (nv, v) => this.comparator.isSame(nv, v),
|
|
52
92
|
notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
|
|
53
93
|
like: (nv, v) => {
|
|
54
|
-
const nodeValue =
|
|
55
|
-
const value =
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
94
|
+
const nodeValue = this.comparator.match(nv);
|
|
95
|
+
const value = this.comparator.match(v);
|
|
96
|
+
const regexp = this._regexpCache.ensure(value, () => {
|
|
97
|
+
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
98
|
+
return new RegExp(`^${pattern}$`, "i");
|
|
99
|
+
});
|
|
100
|
+
return regexp.test(nodeValue);
|
|
59
101
|
}
|
|
60
102
|
};
|
|
61
103
|
verifierStartNode = {
|
|
@@ -76,7 +118,7 @@ var BPTree = class {
|
|
|
76
118
|
notEqual: 1,
|
|
77
119
|
like: 1
|
|
78
120
|
};
|
|
79
|
-
|
|
121
|
+
verifierFullScan = {
|
|
80
122
|
gt: false,
|
|
81
123
|
gte: false,
|
|
82
124
|
lt: false,
|
|
@@ -96,6 +138,7 @@ var BPTree = class {
|
|
|
96
138
|
};
|
|
97
139
|
}
|
|
98
140
|
constructor(strategy, comparator) {
|
|
141
|
+
this._regexpCache = new CacheStorage();
|
|
99
142
|
this._headBuffer = null;
|
|
100
143
|
this._nodeCreateBuffer = /* @__PURE__ */ new Map();
|
|
101
144
|
this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
|
|
@@ -594,9 +637,9 @@ var BPTreeSync = class extends BPTree {
|
|
|
594
637
|
const value = condition[key];
|
|
595
638
|
const startNode = this.verifierStartNode[key](value);
|
|
596
639
|
const direction = this.verifierDirection[key];
|
|
597
|
-
const
|
|
640
|
+
const fullScan = this.verifierFullScan[key];
|
|
598
641
|
const comparator = this.verifierMap[key];
|
|
599
|
-
const pairs = this.getPairs(value, startNode,
|
|
642
|
+
const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
600
643
|
if (result === null) {
|
|
601
644
|
result = pairs.map((pair) => pair.key);
|
|
602
645
|
} else {
|
|
@@ -612,9 +655,9 @@ var BPTreeSync = class extends BPTree {
|
|
|
612
655
|
const value = condition[key];
|
|
613
656
|
const startNode = this.verifierStartNode[key](value);
|
|
614
657
|
const direction = this.verifierDirection[key];
|
|
615
|
-
const
|
|
658
|
+
const fullScan = this.verifierFullScan[key];
|
|
616
659
|
const comparator = this.verifierMap[key];
|
|
617
|
-
const pairs = this.getPairs(value, startNode,
|
|
660
|
+
const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
618
661
|
if (result === null) {
|
|
619
662
|
result = pairs;
|
|
620
663
|
} else {
|
|
@@ -700,13 +743,14 @@ var BPTreeSync = class extends BPTree {
|
|
|
700
743
|
this.bufferForHeadUpdate(this.headState);
|
|
701
744
|
this.commitHeadBuffer();
|
|
702
745
|
}
|
|
703
|
-
forceUpdate(
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
746
|
+
forceUpdate() {
|
|
747
|
+
const keys = [...this.nodes.keys()];
|
|
748
|
+
this.nodes.clear();
|
|
749
|
+
this.init();
|
|
750
|
+
for (const key of keys) {
|
|
751
|
+
this.getNode(key);
|
|
708
752
|
}
|
|
709
|
-
return
|
|
753
|
+
return keys.length;
|
|
710
754
|
}
|
|
711
755
|
};
|
|
712
756
|
|
|
@@ -1128,9 +1172,9 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1128
1172
|
const value = condition[key];
|
|
1129
1173
|
const startNode = await this.verifierStartNode[key](value);
|
|
1130
1174
|
const direction = this.verifierDirection[key];
|
|
1131
|
-
const
|
|
1175
|
+
const fullScan = this.verifierFullScan[key];
|
|
1132
1176
|
const comparator = this.verifierMap[key];
|
|
1133
|
-
const pairs = await this.getPairs(value, startNode,
|
|
1177
|
+
const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
1134
1178
|
if (result === null) {
|
|
1135
1179
|
result = pairs.map((pair) => pair.key);
|
|
1136
1180
|
} else {
|
|
@@ -1146,9 +1190,9 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1146
1190
|
const value = condition[key];
|
|
1147
1191
|
const startNode = await this.verifierStartNode[key](value);
|
|
1148
1192
|
const direction = this.verifierDirection[key];
|
|
1149
|
-
const
|
|
1193
|
+
const fullScan = this.verifierFullScan[key];
|
|
1150
1194
|
const comparator = this.verifierMap[key];
|
|
1151
|
-
const pairs = await this.getPairs(value, startNode,
|
|
1195
|
+
const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
1152
1196
|
if (result === null) {
|
|
1153
1197
|
result = pairs;
|
|
1154
1198
|
} else {
|
|
@@ -1234,13 +1278,14 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1234
1278
|
this.bufferForHeadUpdate(this.headState);
|
|
1235
1279
|
await this.commitHeadBuffer();
|
|
1236
1280
|
}
|
|
1237
|
-
async forceUpdate(
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1281
|
+
async forceUpdate() {
|
|
1282
|
+
const keys = [...this.nodes.keys()];
|
|
1283
|
+
this.nodes.clear();
|
|
1284
|
+
await this.init();
|
|
1285
|
+
for (const key of keys) {
|
|
1286
|
+
await this.getNode(key);
|
|
1242
1287
|
}
|
|
1243
|
-
return
|
|
1288
|
+
return keys.length;
|
|
1244
1289
|
}
|
|
1245
1290
|
};
|
|
1246
1291
|
|
|
@@ -1315,26 +1360,3 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
|
|
|
1315
1360
|
this.data.head = head;
|
|
1316
1361
|
}
|
|
1317
1362
|
};
|
|
1318
|
-
|
|
1319
|
-
// src/ValueComparator.ts
|
|
1320
|
-
var ValueComparator = class {
|
|
1321
|
-
isLower(value, than) {
|
|
1322
|
-
return this.asc(value, than) < 0;
|
|
1323
|
-
}
|
|
1324
|
-
isSame(value, than) {
|
|
1325
|
-
return this.asc(value, than) === 0;
|
|
1326
|
-
}
|
|
1327
|
-
isHigher(value, than) {
|
|
1328
|
-
return this.asc(value, than) > 0;
|
|
1329
|
-
}
|
|
1330
|
-
};
|
|
1331
|
-
var NumericComparator = class extends ValueComparator {
|
|
1332
|
-
asc(a, b) {
|
|
1333
|
-
return a - b;
|
|
1334
|
-
}
|
|
1335
|
-
};
|
|
1336
|
-
var StringComparator = class extends ValueComparator {
|
|
1337
|
-
asc(a, b) {
|
|
1338
|
-
return a.localeCompare(b);
|
|
1339
|
-
}
|
|
1340
|
-
};
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
|
+
// src/base/ValueComparator.ts
|
|
2
|
+
var ValueComparator = class {
|
|
3
|
+
isLower(value, than) {
|
|
4
|
+
return this.asc(value, than) < 0;
|
|
5
|
+
}
|
|
6
|
+
isSame(value, than) {
|
|
7
|
+
return this.asc(value, than) === 0;
|
|
8
|
+
}
|
|
9
|
+
isHigher(value, than) {
|
|
10
|
+
return this.asc(value, than) > 0;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var NumericComparator = class extends ValueComparator {
|
|
14
|
+
asc(a, b) {
|
|
15
|
+
return a - b;
|
|
16
|
+
}
|
|
17
|
+
match(value) {
|
|
18
|
+
return value.toString();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var StringComparator = class extends ValueComparator {
|
|
22
|
+
asc(a, b) {
|
|
23
|
+
return a.localeCompare(b);
|
|
24
|
+
}
|
|
25
|
+
match(value) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// src/utils/CacheStorage.ts
|
|
31
|
+
var CacheStorage = class extends Map {
|
|
32
|
+
ensure(key, generator) {
|
|
33
|
+
if (!this.has(key)) {
|
|
34
|
+
this.set(key, generator());
|
|
35
|
+
}
|
|
36
|
+
return this.get(key);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
1
40
|
// src/base/BPTree.ts
|
|
2
41
|
var BPTree = class {
|
|
42
|
+
_regexpCache;
|
|
3
43
|
strategy;
|
|
4
44
|
comparator;
|
|
5
45
|
nodes;
|
|
@@ -17,11 +57,13 @@ var BPTree = class {
|
|
|
17
57
|
equal: (nv, v) => this.comparator.isSame(nv, v),
|
|
18
58
|
notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
|
|
19
59
|
like: (nv, v) => {
|
|
20
|
-
const nodeValue =
|
|
21
|
-
const value =
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
60
|
+
const nodeValue = this.comparator.match(nv);
|
|
61
|
+
const value = this.comparator.match(v);
|
|
62
|
+
const regexp = this._regexpCache.ensure(value, () => {
|
|
63
|
+
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
64
|
+
return new RegExp(`^${pattern}$`, "i");
|
|
65
|
+
});
|
|
66
|
+
return regexp.test(nodeValue);
|
|
25
67
|
}
|
|
26
68
|
};
|
|
27
69
|
verifierStartNode = {
|
|
@@ -42,7 +84,7 @@ var BPTree = class {
|
|
|
42
84
|
notEqual: 1,
|
|
43
85
|
like: 1
|
|
44
86
|
};
|
|
45
|
-
|
|
87
|
+
verifierFullScan = {
|
|
46
88
|
gt: false,
|
|
47
89
|
gte: false,
|
|
48
90
|
lt: false,
|
|
@@ -62,6 +104,7 @@ var BPTree = class {
|
|
|
62
104
|
};
|
|
63
105
|
}
|
|
64
106
|
constructor(strategy, comparator) {
|
|
107
|
+
this._regexpCache = new CacheStorage();
|
|
65
108
|
this._headBuffer = null;
|
|
66
109
|
this._nodeCreateBuffer = /* @__PURE__ */ new Map();
|
|
67
110
|
this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
|
|
@@ -560,9 +603,9 @@ var BPTreeSync = class extends BPTree {
|
|
|
560
603
|
const value = condition[key];
|
|
561
604
|
const startNode = this.verifierStartNode[key](value);
|
|
562
605
|
const direction = this.verifierDirection[key];
|
|
563
|
-
const
|
|
606
|
+
const fullScan = this.verifierFullScan[key];
|
|
564
607
|
const comparator = this.verifierMap[key];
|
|
565
|
-
const pairs = this.getPairs(value, startNode,
|
|
608
|
+
const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
566
609
|
if (result === null) {
|
|
567
610
|
result = pairs.map((pair) => pair.key);
|
|
568
611
|
} else {
|
|
@@ -578,9 +621,9 @@ var BPTreeSync = class extends BPTree {
|
|
|
578
621
|
const value = condition[key];
|
|
579
622
|
const startNode = this.verifierStartNode[key](value);
|
|
580
623
|
const direction = this.verifierDirection[key];
|
|
581
|
-
const
|
|
624
|
+
const fullScan = this.verifierFullScan[key];
|
|
582
625
|
const comparator = this.verifierMap[key];
|
|
583
|
-
const pairs = this.getPairs(value, startNode,
|
|
626
|
+
const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
584
627
|
if (result === null) {
|
|
585
628
|
result = pairs;
|
|
586
629
|
} else {
|
|
@@ -666,13 +709,14 @@ var BPTreeSync = class extends BPTree {
|
|
|
666
709
|
this.bufferForHeadUpdate(this.headState);
|
|
667
710
|
this.commitHeadBuffer();
|
|
668
711
|
}
|
|
669
|
-
forceUpdate(
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
712
|
+
forceUpdate() {
|
|
713
|
+
const keys = [...this.nodes.keys()];
|
|
714
|
+
this.nodes.clear();
|
|
715
|
+
this.init();
|
|
716
|
+
for (const key of keys) {
|
|
717
|
+
this.getNode(key);
|
|
674
718
|
}
|
|
675
|
-
return
|
|
719
|
+
return keys.length;
|
|
676
720
|
}
|
|
677
721
|
};
|
|
678
722
|
|
|
@@ -1094,9 +1138,9 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1094
1138
|
const value = condition[key];
|
|
1095
1139
|
const startNode = await this.verifierStartNode[key](value);
|
|
1096
1140
|
const direction = this.verifierDirection[key];
|
|
1097
|
-
const
|
|
1141
|
+
const fullScan = this.verifierFullScan[key];
|
|
1098
1142
|
const comparator = this.verifierMap[key];
|
|
1099
|
-
const pairs = await this.getPairs(value, startNode,
|
|
1143
|
+
const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
1100
1144
|
if (result === null) {
|
|
1101
1145
|
result = pairs.map((pair) => pair.key);
|
|
1102
1146
|
} else {
|
|
@@ -1112,9 +1156,9 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1112
1156
|
const value = condition[key];
|
|
1113
1157
|
const startNode = await this.verifierStartNode[key](value);
|
|
1114
1158
|
const direction = this.verifierDirection[key];
|
|
1115
|
-
const
|
|
1159
|
+
const fullScan = this.verifierFullScan[key];
|
|
1116
1160
|
const comparator = this.verifierMap[key];
|
|
1117
|
-
const pairs = await this.getPairs(value, startNode,
|
|
1161
|
+
const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
|
|
1118
1162
|
if (result === null) {
|
|
1119
1163
|
result = pairs;
|
|
1120
1164
|
} else {
|
|
@@ -1200,13 +1244,14 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1200
1244
|
this.bufferForHeadUpdate(this.headState);
|
|
1201
1245
|
await this.commitHeadBuffer();
|
|
1202
1246
|
}
|
|
1203
|
-
async forceUpdate(
|
|
1204
|
-
const
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1247
|
+
async forceUpdate() {
|
|
1248
|
+
const keys = [...this.nodes.keys()];
|
|
1249
|
+
this.nodes.clear();
|
|
1250
|
+
await this.init();
|
|
1251
|
+
for (const key of keys) {
|
|
1252
|
+
await this.getNode(key);
|
|
1208
1253
|
}
|
|
1209
|
-
return
|
|
1254
|
+
return keys.length;
|
|
1210
1255
|
}
|
|
1211
1256
|
};
|
|
1212
1257
|
|
|
@@ -1281,29 +1326,6 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
|
|
|
1281
1326
|
this.data.head = head;
|
|
1282
1327
|
}
|
|
1283
1328
|
};
|
|
1284
|
-
|
|
1285
|
-
// src/ValueComparator.ts
|
|
1286
|
-
var ValueComparator = class {
|
|
1287
|
-
isLower(value, than) {
|
|
1288
|
-
return this.asc(value, than) < 0;
|
|
1289
|
-
}
|
|
1290
|
-
isSame(value, than) {
|
|
1291
|
-
return this.asc(value, than) === 0;
|
|
1292
|
-
}
|
|
1293
|
-
isHigher(value, than) {
|
|
1294
|
-
return this.asc(value, than) > 0;
|
|
1295
|
-
}
|
|
1296
|
-
};
|
|
1297
|
-
var NumericComparator = class extends ValueComparator {
|
|
1298
|
-
asc(a, b) {
|
|
1299
|
-
return a - b;
|
|
1300
|
-
}
|
|
1301
|
-
};
|
|
1302
|
-
var StringComparator = class extends ValueComparator {
|
|
1303
|
-
asc(a, b) {
|
|
1304
|
-
return a.localeCompare(b);
|
|
1305
|
-
}
|
|
1306
|
-
};
|
|
1307
1329
|
export {
|
|
1308
1330
|
BPTreeAsync,
|
|
1309
1331
|
BPTreeSync,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Json } from './utils/types';
|
|
2
|
-
import { BPTree, BPTreeLeafNode, BPTreePair, BPTreeNodeKey, BPTreeUnknownNode } from './base/BPTree';
|
|
2
|
+
import { BPTree, BPTreeCondition, BPTreeLeafNode, BPTreePair, BPTreeNodeKey, BPTreeUnknownNode } from './base/BPTree';
|
|
3
3
|
import { SerializeStrategyAsync } from './SerializeStrategyAsync';
|
|
4
|
-
import { ValueComparator } from './ValueComparator';
|
|
4
|
+
import { ValueComparator } from './base/ValueComparator';
|
|
5
5
|
export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
|
|
6
6
|
protected readonly strategy: SerializeStrategyAsync<K, V>;
|
|
7
7
|
constructor(strategy: SerializeStrategyAsync<K, V>, comparator: ValueComparator<V>);
|
|
@@ -19,27 +19,11 @@ export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
|
|
|
19
19
|
protected commitHeadBuffer(): Promise<void>;
|
|
20
20
|
protected commitNodeCreateBuffer(): Promise<void>;
|
|
21
21
|
protected commitNodeUpdateBuffer(): Promise<void>;
|
|
22
|
-
keys(condition:
|
|
23
|
-
|
|
24
|
-
lt: V;
|
|
25
|
-
gte: V;
|
|
26
|
-
lte: V;
|
|
27
|
-
equal: V;
|
|
28
|
-
notEqual: V;
|
|
29
|
-
like: V;
|
|
30
|
-
}>): Promise<Set<K>>;
|
|
31
|
-
where(condition: Partial<{
|
|
32
|
-
gt: V;
|
|
33
|
-
lt: V;
|
|
34
|
-
gte: V;
|
|
35
|
-
lte: V;
|
|
36
|
-
equal: V;
|
|
37
|
-
notEqual: V;
|
|
38
|
-
like: V;
|
|
39
|
-
}>): Promise<BPTreePair<K, V>[]>;
|
|
22
|
+
keys(condition: BPTreeCondition<V>): Promise<Set<K>>;
|
|
23
|
+
where(condition: BPTreeCondition<V>): Promise<BPTreePair<K, V>[]>;
|
|
40
24
|
insert(key: K, value: V): Promise<void>;
|
|
41
25
|
delete(key: K, value: V): Promise<void>;
|
|
42
26
|
exists(key: K, value: V): Promise<boolean>;
|
|
43
27
|
setHeadData(data: Record<string, Json>): Promise<void>;
|
|
44
|
-
forceUpdate(
|
|
28
|
+
forceUpdate(): Promise<number>;
|
|
45
29
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Json } from './utils/types';
|
|
2
|
-
import { BPTree, BPTreeLeafNode, BPTreePair, BPTreeNodeKey, BPTreeUnknownNode } from './base/BPTree';
|
|
2
|
+
import { BPTree, BPTreeCondition, BPTreeLeafNode, BPTreePair, BPTreeNodeKey, BPTreeUnknownNode } from './base/BPTree';
|
|
3
3
|
import { SerializeStrategySync } from './SerializeStrategySync';
|
|
4
|
-
import { ValueComparator } from './ValueComparator';
|
|
4
|
+
import { ValueComparator } from './base/ValueComparator';
|
|
5
5
|
export declare class BPTreeSync<K, V> extends BPTree<K, V> {
|
|
6
6
|
protected readonly strategy: SerializeStrategySync<K, V>;
|
|
7
7
|
constructor(strategy: SerializeStrategySync<K, V>, comparator: ValueComparator<V>);
|
|
@@ -20,27 +20,11 @@ export declare class BPTreeSync<K, V> extends BPTree<K, V> {
|
|
|
20
20
|
protected commitHeadBuffer(): void;
|
|
21
21
|
protected commitNodeCreateBuffer(): void;
|
|
22
22
|
protected commitNodeUpdateBuffer(): void;
|
|
23
|
-
keys(condition:
|
|
24
|
-
|
|
25
|
-
lt: V;
|
|
26
|
-
gte: V;
|
|
27
|
-
lte: V;
|
|
28
|
-
equal: V;
|
|
29
|
-
notEqual: V;
|
|
30
|
-
like: V;
|
|
31
|
-
}>): Set<K>;
|
|
32
|
-
where(condition: Partial<{
|
|
33
|
-
gt: V;
|
|
34
|
-
lt: V;
|
|
35
|
-
gte: V;
|
|
36
|
-
lte: V;
|
|
37
|
-
equal: V;
|
|
38
|
-
notEqual: V;
|
|
39
|
-
like: V;
|
|
40
|
-
}>): BPTreePair<K, V>[];
|
|
23
|
+
keys(condition: BPTreeCondition<V>): Set<K>;
|
|
24
|
+
where(condition: BPTreeCondition<V>): BPTreePair<K, V>[];
|
|
41
25
|
insert(key: K, value: V): void;
|
|
42
26
|
delete(key: K, value: V): void;
|
|
43
27
|
exists(key: K, value: V): boolean;
|
|
44
28
|
setHeadData(data: Record<string, Json>): void;
|
|
45
|
-
forceUpdate(
|
|
29
|
+
forceUpdate(): number;
|
|
46
30
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Json } from '../utils/types';
|
|
2
|
-
import { ValueComparator } from '
|
|
2
|
+
import { ValueComparator } from './ValueComparator';
|
|
3
3
|
import { SerializeStrategy, SerializeStrategyHead } from './SerializeStrategy';
|
|
4
4
|
type Sync<T> = T;
|
|
5
5
|
type Async<T> = Promise<T>;
|
|
@@ -7,19 +7,19 @@ type Deferred<T> = Sync<T> | Async<T>;
|
|
|
7
7
|
export type BPTreeNodeKey<K> = number | K;
|
|
8
8
|
export type BPTreeCondition<V> = Partial<{
|
|
9
9
|
/** Searches for pairs greater than the given value. */
|
|
10
|
-
gt: V
|
|
10
|
+
gt: Partial<V>;
|
|
11
11
|
/** Searches for pairs less than the given value. */
|
|
12
|
-
lt: V
|
|
12
|
+
lt: Partial<V>;
|
|
13
13
|
/** Searches for pairs greater than or equal to the given value. */
|
|
14
|
-
gte: V
|
|
14
|
+
gte: Partial<V>;
|
|
15
15
|
/** Searches for pairs less than or equal to the given value. */
|
|
16
|
-
lte: V
|
|
16
|
+
lte: Partial<V>;
|
|
17
17
|
/** "Searches for pairs equal to the given value. */
|
|
18
|
-
equal: V
|
|
18
|
+
equal: Partial<V>;
|
|
19
19
|
/** Searches for pairs not equal to the given value. */
|
|
20
|
-
notEqual: V
|
|
20
|
+
notEqual: Partial<V>;
|
|
21
21
|
/** Searches for values matching the given pattern. '%' matches zero or more characters, and '_' matches exactly one character. */
|
|
22
|
-
like: V
|
|
22
|
+
like: Partial<V>;
|
|
23
23
|
}>;
|
|
24
24
|
export type BPTreePair<K, V> = {
|
|
25
25
|
key: K;
|
|
@@ -44,6 +44,7 @@ export interface BPTreeLeafNode<K, V> extends BPTreeNode<K, V> {
|
|
|
44
44
|
keys: K[][];
|
|
45
45
|
}
|
|
46
46
|
export declare abstract class BPTree<K, V> {
|
|
47
|
+
private readonly _regexpCache;
|
|
47
48
|
protected readonly strategy: SerializeStrategy<K, V>;
|
|
48
49
|
protected readonly comparator: ValueComparator<V>;
|
|
49
50
|
protected readonly nodes: Map<number, BPTreeUnknownNode<K, V>>;
|
|
@@ -56,7 +57,7 @@ export declare abstract class BPTree<K, V> {
|
|
|
56
57
|
protected readonly verifierMap: Record<keyof BPTreeCondition<V>, (nodeValue: V, value: V) => boolean>;
|
|
57
58
|
protected readonly verifierStartNode: Record<keyof BPTreeCondition<V>, (value: V) => Deferred<BPTreeLeafNode<K, V>>>;
|
|
58
59
|
protected readonly verifierDirection: Record<keyof BPTreeCondition<V>, -1 | 1>;
|
|
59
|
-
protected readonly
|
|
60
|
+
protected readonly verifierFullScan: Record<keyof BPTreeCondition<V>, boolean>;
|
|
60
61
|
protected get headState(): SerializeStrategyHead;
|
|
61
62
|
protected constructor(strategy: SerializeStrategy<K, V>, comparator: ValueComparator<V>);
|
|
62
63
|
protected abstract _getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullSearch: boolean, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>[]>;
|
|
@@ -120,7 +121,6 @@ export declare abstract class BPTree<K, V> {
|
|
|
120
121
|
/**
|
|
121
122
|
* This method deletes nodes cached in-memory and caches new nodes from the stored nodes.
|
|
122
123
|
* Typically, there's no need to use this method, but it can be used to synchronize data in scenarios where the remote storage and the client are in a 1:n relationship.
|
|
123
|
-
* @param nodeId The node ID to update. If no parameters are passed, it updates all currently cached nodes.
|
|
124
124
|
* @returns The return value is the total number of nodes updated.
|
|
125
125
|
*/
|
|
126
126
|
abstract forceUpdate(nodeId: number): Deferred<number>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export declare abstract class ValueComparator<V> {
|
|
2
|
+
/**
|
|
3
|
+
* Implement an algorithm that sorts values in ascending order.
|
|
4
|
+
* If it returns a negative number, a is less than b. If it returns 0, the two values are equal. If it returns a positive number, a is greater than b.
|
|
5
|
+
* @param a Value a.
|
|
6
|
+
* @param b Value b.
|
|
7
|
+
*/
|
|
8
|
+
abstract asc(a: V, b: V): number;
|
|
9
|
+
/**
|
|
10
|
+
* The `match` method is used for the **LIKE** operator.
|
|
11
|
+
* This method specifies which value to test against a regular expression.
|
|
12
|
+
*
|
|
13
|
+
* For example, if you have a tree with values of the structure `{ country: string, capital: number }`,
|
|
14
|
+
* and you want to perform a **LIKE** operation based on the **capital** value, the method should return **value.capital**.
|
|
15
|
+
* In this case, you **CANNOT** perform a **LIKE** operation based on the **country** attribute.
|
|
16
|
+
* The returned value must be a string.
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* interface MyObject {
|
|
20
|
+
* country: string
|
|
21
|
+
* capital: string
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* class CompositeComparator extends ValueComparator<MyObject> {
|
|
25
|
+
* match(value: MyObject): string {
|
|
26
|
+
* return value.capital
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* For a tree with simple structure, without complex nesting, returning the value directly would be sufficient.
|
|
32
|
+
*
|
|
33
|
+
* ```
|
|
34
|
+
* class StringComparator extends ValueComparator<string> {
|
|
35
|
+
* match(value: string): string {
|
|
36
|
+
* return value
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @param value The inserted value.
|
|
42
|
+
* @returns The value to test against a regular expression.
|
|
43
|
+
*/
|
|
44
|
+
abstract match(value: V): string;
|
|
45
|
+
isLower(value: V, than: V): boolean;
|
|
46
|
+
isSame(value: V, than: V): boolean;
|
|
47
|
+
isHigher(value: V, than: V): boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare class NumericComparator extends ValueComparator<number> {
|
|
50
|
+
asc(a: number, b: number): number;
|
|
51
|
+
match(value: number): string;
|
|
52
|
+
}
|
|
53
|
+
export declare class StringComparator extends ValueComparator<string> {
|
|
54
|
+
asc(a: string, b: string): number;
|
|
55
|
+
match(value: string): string;
|
|
56
|
+
}
|
package/dist/typings/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { BPTreeNode } from './base/BPTree';
|
|
2
2
|
export type { SerializeStrategyHead } from './base/SerializeStrategy';
|
|
3
|
+
export { ValueComparator, NumericComparator, StringComparator } from './base/ValueComparator';
|
|
3
4
|
export { BPTreeSync } from './BPTreeSync';
|
|
4
5
|
export { BPTreeAsync } from './BPTreeAsync';
|
|
5
6
|
export { SerializeStrategySync, InMemoryStoreStrategySync } from './SerializeStrategySync';
|
|
6
7
|
export { SerializeStrategyAsync, InMemoryStoreStrategyAsync } from './SerializeStrategyAsync';
|
|
7
|
-
export { ValueComparator, NumericComparator, StringComparator } from './ValueComparator';
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export declare abstract class ValueComparator<V> {
|
|
2
|
-
/**
|
|
3
|
-
* Implement an algorithm that sorts values in ascending order.
|
|
4
|
-
* If it returns a negative number, a is less than b. If it returns 0, the two values are equal. If it returns a positive number, a is greater than b.
|
|
5
|
-
* @param a Value a.
|
|
6
|
-
* @param b Value b.
|
|
7
|
-
*/
|
|
8
|
-
abstract asc(a: V, b: V): number;
|
|
9
|
-
isLower(value: V, than: V): boolean;
|
|
10
|
-
isSame(value: V, than: V): boolean;
|
|
11
|
-
isHigher(value: V, than: V): boolean;
|
|
12
|
-
}
|
|
13
|
-
export declare class NumericComparator extends ValueComparator<number> {
|
|
14
|
-
asc(a: number, b: number): number;
|
|
15
|
-
}
|
|
16
|
-
export declare class StringComparator extends ValueComparator<string> {
|
|
17
|
-
asc(a: string, b: string): number;
|
|
18
|
-
}
|