serializable-bptree 5.0.5 → 5.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 CHANGED
@@ -63,6 +63,7 @@ tree.where({ equal: 1 }) // Map([{ key: 'a', value: 1 }])
63
63
  tree.where({ gt: 1 }) // Map([{ key: 'c', value: 3 }])
64
64
  tree.where({ lt: 2 }) // Map([{ key: 'a', value: 1 }])
65
65
  tree.where({ gt: 0, lt: 4 }) // Map([{ key: 'a', value: 1 }, { key: 'c', value: 3 }])
66
+ tree.where({ or: [3, 1] }) // Map([{ key: 'a', value: 1 }, { key: 'c', value: 3 }])
66
67
  ```
67
68
 
68
69
  ## Why use a `serializable-bptree`?
@@ -320,32 +321,64 @@ import {
320
321
 
321
322
  ## Data Query Condition Clause
322
323
 
323
- This library supports various conditional clauses. Currently, it supports **gte**, **gt**, **lte**, **lt**, **equal**, **notEqual**, and **like** conditions. Each condition is as follows:
324
+ This library supports various conditional clauses. Currently, it supports **gte**, **gt**, **lte**, **lt**, **equal**, **notEqual**, **or**, and **like** conditions. Each condition is as follows:
324
325
 
325
326
  ### `gte`
326
327
 
327
328
  Queries values that are greater than or equal to the given value.
328
329
 
330
+ ```typescript
331
+ tree.where({ gte: 1 })
332
+ ```
333
+
329
334
  ### `gt`
330
335
 
331
336
  Queries values that are greater than the given value.
332
337
 
338
+ ```typescript
339
+ tree.where({ gt: 1 })
340
+ ```
341
+
333
342
  ### `lte`
334
343
 
335
344
  Queries values that are less than or equal to the given value.
336
345
 
346
+ ```typescript
347
+ tree.where({ lte: 5 })
348
+ ```
349
+
337
350
  ### `lt`
338
351
 
339
352
  Queries values that are less than the given value.
340
353
 
354
+ ```typescript
355
+ tree.where({ lt: 5 })
356
+ ```
357
+
341
358
  ### `equal`
342
359
 
343
360
  Queries values that match the given value.
344
361
 
362
+ ```typescript
363
+ tree.where({ equal: 3 })
364
+ ```
365
+
345
366
  ### `notEqual`
346
367
 
347
368
  Queries values that do not match the given value.
348
369
 
370
+ ```typescript
371
+ tree.where({ notEqual: 3 })
372
+ ```
373
+
374
+ ### `or`
375
+
376
+ Queries values that satisfy at least one of the given conditions. It accepts an array of conditions, and if any of these conditions are met, the data is included in the result.
377
+
378
+ ```typescript
379
+ tree.where({ or: [1, 2, 3] })
380
+ ```
381
+
349
382
  ### `like`
350
383
 
351
384
  Queries values that contain the given value in a manner similar to regular expressions. Special characters such as % and _ can be used.
@@ -357,6 +390,13 @@ Using **p_t**, it can match any string where the underscore is replaced by any c
357
390
 
358
391
  You can obtain matching data by combining these condition clauses. If there are multiple conditions, an **AND** operation is used to retrieve only the data that satisfies all conditions.
359
392
 
393
+ ```typescript
394
+ tree.where({ like: 'hello%' })
395
+ tree.where({ like: 'he__o%' })
396
+ tree.where({ like: '%world!' })
397
+ tree.where({ like: '%lo, wor%' })
398
+ ```
399
+
360
400
  ## Using Asynchronously
361
401
 
362
402
  Support for asynchronous trees has been available since version 3.0.0. Asynchronous is useful for operations with delays, such as file input/output and remote storage. Here is an example of how to use it:
@@ -120,6 +120,7 @@ var BPTree = class {
120
120
  lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
121
121
  equal: (nv, v) => this.comparator.isSame(nv, v),
122
122
  notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
123
+ or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
123
124
  like: (nv, v) => {
124
125
  const nodeValue = this.comparator.match(nv);
125
126
  const value = this.comparator.match(v);
@@ -139,8 +140,22 @@ var BPTree = class {
139
140
  lte: (v) => this.insertableNode(v),
140
141
  equal: (v) => this.insertableNode(v),
141
142
  notEqual: (v) => this.leftestNode(),
143
+ or: (v) => this.insertableNode(this.lowestValue(this.ensureValues(v))),
142
144
  like: (v) => this.leftestNode()
143
145
  };
146
+ verifierEndNode = {
147
+ gt: (v) => null,
148
+ gte: (v) => null,
149
+ lt: (v) => null,
150
+ lte: (v) => null,
151
+ equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
152
+ notEqual: (v) => null,
153
+ or: (v) => this.insertableEndNode(
154
+ this.highestValue(this.ensureValues(v)),
155
+ this.verifierDirection.or
156
+ ),
157
+ like: (v) => null
158
+ };
144
159
  verifierDirection = {
145
160
  gt: 1,
146
161
  gte: 1,
@@ -148,17 +163,9 @@ var BPTree = class {
148
163
  lte: -1,
149
164
  equal: 1,
150
165
  notEqual: 1,
166
+ or: 1,
151
167
  like: 1
152
168
  };
153
- verifierFullScan = {
154
- gt: false,
155
- gte: false,
156
- lt: false,
157
- lte: false,
158
- equal: false,
159
- notEqual: true,
160
- like: true
161
- };
162
169
  constructor(strategy, comparator) {
163
170
  this._strategyDirty = false;
164
171
  this._cachedRegexp = new InvertedWeakMap();
@@ -169,12 +176,31 @@ var BPTree = class {
169
176
  this.strategy = strategy;
170
177
  this.comparator = comparator;
171
178
  }
179
+ ensureValues(v) {
180
+ if (!Array.isArray(v)) {
181
+ v = [v];
182
+ }
183
+ return v;
184
+ }
185
+ lowestValue(v) {
186
+ const i = 0;
187
+ return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
188
+ }
189
+ highestValue(v) {
190
+ const i = v.length - 1;
191
+ return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
192
+ }
172
193
  _insertAtLeaf(node, key, value) {
173
194
  if (node.values.length) {
174
195
  for (let i = 0, len = node.values.length; i < len; i++) {
175
196
  const nValue = node.values[i];
176
197
  if (this.comparator.isSame(value, nValue)) {
177
198
  const keys = node.keys[i];
199
+ if (keys.includes(key)) {
200
+ throw new Error("The key already exists.", {
201
+ cause: { key, value }
202
+ });
203
+ }
178
204
  keys.push(key);
179
205
  this.bufferForNodeUpdate(node);
180
206
  break;
@@ -229,25 +255,24 @@ var BPTreeSync = class extends BPTree {
229
255
  constructor(strategy, comparator) {
230
256
  super(strategy, comparator);
231
257
  }
232
- getPairsRightToLeft(value, startNode, fullScan, comparator) {
258
+ getPairsRightToLeft(value, startNode, endNode, comparator) {
233
259
  const pairs = [];
234
260
  let node = startNode;
235
261
  let done = false;
236
- let found = false;
237
262
  while (!done) {
263
+ if (endNode && node.id === endNode.id) {
264
+ done = true;
265
+ break;
266
+ }
238
267
  let i = node.values.length;
239
268
  while (i--) {
240
269
  const nValue = node.values[i];
241
270
  const keys = node.keys[i];
242
271
  if (comparator(nValue, value)) {
243
- found = true;
244
272
  let j = keys.length;
245
273
  while (j--) {
246
274
  pairs.push([keys[j], nValue]);
247
275
  }
248
- } else if (found && !fullScan) {
249
- done = true;
250
- break;
251
276
  }
252
277
  }
253
278
  if (!node.prev) {
@@ -258,24 +283,23 @@ var BPTreeSync = class extends BPTree {
258
283
  }
259
284
  return new Map(pairs.reverse());
260
285
  }
261
- getPairsLeftToRight(value, startNode, fullScan, comparator) {
286
+ getPairsLeftToRight(value, startNode, endNode, comparator) {
262
287
  const pairs = [];
263
288
  let node = startNode;
264
289
  let done = false;
265
- let found = false;
266
290
  while (!done) {
291
+ if (endNode && node.id === endNode.id) {
292
+ done = true;
293
+ break;
294
+ }
267
295
  for (let i = 0, len = node.values.length; i < len; i++) {
268
296
  const nValue = node.values[i];
269
297
  const keys = node.keys[i];
270
298
  if (comparator(nValue, value)) {
271
- found = true;
272
299
  for (let j = 0, len2 = keys.length; j < len2; j++) {
273
300
  const key = keys[j];
274
301
  pairs.push([key, nValue]);
275
302
  }
276
- } else if (found && !fullScan) {
277
- done = true;
278
- break;
279
303
  }
280
304
  }
281
305
  if (!node.next) {
@@ -286,12 +310,12 @@ var BPTreeSync = class extends BPTree {
286
310
  }
287
311
  return new Map(pairs);
288
312
  }
289
- getPairs(value, startNode, fullScan, comparator, direction) {
313
+ getPairs(value, startNode, endNode, comparator, direction) {
290
314
  switch (direction) {
291
315
  case -1:
292
- return this.getPairsRightToLeft(value, startNode, fullScan, comparator);
316
+ return this.getPairsRightToLeft(value, startNode, endNode, comparator);
293
317
  case 1:
294
- return this.getPairsLeftToRight(value, startNode, fullScan, comparator);
318
+ return this.getPairsLeftToRight(value, startNode, endNode, comparator);
295
319
  default:
296
320
  throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
297
321
  }
@@ -615,6 +639,25 @@ var BPTreeSync = class extends BPTree {
615
639
  }
616
640
  return node;
617
641
  }
642
+ insertableEndNode(value, direction) {
643
+ const insertableNode = this.insertableNode(value);
644
+ let key;
645
+ switch (direction) {
646
+ case -1:
647
+ key = "prev";
648
+ break;
649
+ case 1:
650
+ key = "next";
651
+ break;
652
+ default:
653
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
654
+ }
655
+ const guessNode = insertableNode[key];
656
+ if (!guessNode) {
657
+ return null;
658
+ }
659
+ return this.getNode(guessNode);
660
+ }
618
661
  leftestNode() {
619
662
  let node = this.root;
620
663
  while (!node.leaf) {
@@ -623,6 +666,14 @@ var BPTreeSync = class extends BPTree {
623
666
  }
624
667
  return node;
625
668
  }
669
+ rightestNode() {
670
+ let node = this.root;
671
+ while (!node.leaf) {
672
+ const keys = node.keys;
673
+ node = this.getNode(keys[keys.length - 1]);
674
+ }
675
+ return node;
676
+ }
626
677
  commitHeadBuffer() {
627
678
  if (!this._strategyDirty) {
628
679
  return;
@@ -653,10 +704,10 @@ var BPTreeSync = class extends BPTree {
653
704
  const key = k;
654
705
  const value = condition[key];
655
706
  const startNode = this.verifierStartNode[key](value);
707
+ const endNode = this.verifierEndNode[key](value);
656
708
  const direction = this.verifierDirection[key];
657
- const fullScan = this.verifierFullScan[key];
658
709
  const comparator = this.verifierMap[key];
659
- const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
710
+ const pairs = this.getPairs(value, startNode, endNode, comparator, direction);
660
711
  if (!filterValues) {
661
712
  filterValues = new Set(pairs.keys());
662
713
  } else {
@@ -678,10 +729,10 @@ var BPTreeSync = class extends BPTree {
678
729
  const key = k;
679
730
  const value = condition[key];
680
731
  const startNode = this.verifierStartNode[key](value);
732
+ const endNode = this.verifierEndNode[key](value);
681
733
  const direction = this.verifierDirection[key];
682
- const fullScan = this.verifierFullScan[key];
683
734
  const comparator = this.verifierMap[key];
684
- const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
735
+ const pairs = this.getPairs(value, startNode, endNode, comparator, direction);
685
736
  if (result === null) {
686
737
  result = pairs;
687
738
  } else {
@@ -791,25 +842,24 @@ var BPTreeAsync = class extends BPTree {
791
842
  constructor(strategy, comparator) {
792
843
  super(strategy, comparator);
793
844
  }
794
- async getPairsRightToLeft(value, startNode, fullScan, comparator) {
845
+ async getPairsRightToLeft(value, startNode, endNode, comparator) {
795
846
  const pairs = [];
796
847
  let node = startNode;
797
848
  let done = false;
798
- let found = false;
799
849
  while (!done) {
850
+ if (endNode && node.id === endNode.id) {
851
+ done = true;
852
+ break;
853
+ }
800
854
  let i = node.values.length;
801
855
  while (i--) {
802
856
  const nValue = node.values[i];
803
857
  const keys = node.keys[i];
804
858
  if (comparator(nValue, value)) {
805
- found = true;
806
859
  let j = keys.length;
807
860
  while (j--) {
808
861
  pairs.push([keys[j], nValue]);
809
862
  }
810
- } else if (found && !fullScan) {
811
- done = true;
812
- break;
813
863
  }
814
864
  }
815
865
  if (!node.prev) {
@@ -820,24 +870,23 @@ var BPTreeAsync = class extends BPTree {
820
870
  }
821
871
  return new Map(pairs.reverse());
822
872
  }
823
- async getPairsLeftToRight(value, startNode, fullScan, comparator) {
873
+ async getPairsLeftToRight(value, startNode, endNode, comparator) {
824
874
  const pairs = [];
825
875
  let node = startNode;
826
876
  let done = false;
827
- let found = false;
828
877
  while (!done) {
878
+ if (endNode && node.id === endNode.id) {
879
+ done = true;
880
+ break;
881
+ }
829
882
  for (let i = 0, len = node.values.length; i < len; i++) {
830
883
  const nValue = node.values[i];
831
884
  const keys = node.keys[i];
832
885
  if (comparator(nValue, value)) {
833
- found = true;
834
886
  for (let j = 0, len2 = keys.length; j < len2; j++) {
835
887
  const key = keys[j];
836
888
  pairs.push([key, nValue]);
837
889
  }
838
- } else if (found && !fullScan) {
839
- done = true;
840
- break;
841
890
  }
842
891
  }
843
892
  if (!node.next) {
@@ -848,12 +897,12 @@ var BPTreeAsync = class extends BPTree {
848
897
  }
849
898
  return new Map(pairs);
850
899
  }
851
- async getPairs(value, startNode, fullScan, comparator, direction) {
900
+ async getPairs(value, startNode, endNode, comparator, direction) {
852
901
  switch (direction) {
853
902
  case -1:
854
- return await this.getPairsRightToLeft(value, startNode, fullScan, comparator);
903
+ return await this.getPairsRightToLeft(value, startNode, endNode, comparator);
855
904
  case 1:
856
- return await this.getPairsLeftToRight(value, startNode, fullScan, comparator);
905
+ return await this.getPairsLeftToRight(value, startNode, endNode, comparator);
857
906
  default:
858
907
  throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
859
908
  }
@@ -1177,6 +1226,25 @@ var BPTreeAsync = class extends BPTree {
1177
1226
  }
1178
1227
  return node;
1179
1228
  }
1229
+ async insertableEndNode(value, direction) {
1230
+ const insertableNode = await this.insertableNode(value);
1231
+ let key;
1232
+ switch (direction) {
1233
+ case -1:
1234
+ key = "prev";
1235
+ break;
1236
+ case 1:
1237
+ key = "next";
1238
+ break;
1239
+ default:
1240
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
1241
+ }
1242
+ const guessNode = insertableNode[key];
1243
+ if (!guessNode) {
1244
+ return null;
1245
+ }
1246
+ return await this.getNode(guessNode);
1247
+ }
1180
1248
  async leftestNode() {
1181
1249
  let node = this.root;
1182
1250
  while (!node.leaf) {
@@ -1185,6 +1253,14 @@ var BPTreeAsync = class extends BPTree {
1185
1253
  }
1186
1254
  return node;
1187
1255
  }
1256
+ async rightestNode() {
1257
+ let node = this.root;
1258
+ while (!node.leaf) {
1259
+ const keys = node.keys;
1260
+ node = await this.getNode(keys[keys.length - 1]);
1261
+ }
1262
+ return node;
1263
+ }
1188
1264
  async commitHeadBuffer() {
1189
1265
  if (!this._strategyDirty) {
1190
1266
  return;
@@ -1215,10 +1291,10 @@ var BPTreeAsync = class extends BPTree {
1215
1291
  const key = k;
1216
1292
  const value = condition[key];
1217
1293
  const startNode = await this.verifierStartNode[key](value);
1294
+ const endNode = await this.verifierEndNode[key](value);
1218
1295
  const direction = this.verifierDirection[key];
1219
- const fullScan = this.verifierFullScan[key];
1220
1296
  const comparator = this.verifierMap[key];
1221
- const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
1297
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1222
1298
  if (!filterValues) {
1223
1299
  filterValues = new Set(pairs.keys());
1224
1300
  } else {
@@ -1240,10 +1316,10 @@ var BPTreeAsync = class extends BPTree {
1240
1316
  const key = k;
1241
1317
  const value = condition[key];
1242
1318
  const startNode = await this.verifierStartNode[key](value);
1319
+ const endNode = await this.verifierEndNode[key](value);
1243
1320
  const direction = this.verifierDirection[key];
1244
- const fullScan = this.verifierFullScan[key];
1245
1321
  const comparator = this.verifierMap[key];
1246
- const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
1322
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1247
1323
  if (result === null) {
1248
1324
  result = pairs;
1249
1325
  } else {
@@ -86,6 +86,7 @@ var BPTree = class {
86
86
  lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
87
87
  equal: (nv, v) => this.comparator.isSame(nv, v),
88
88
  notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
89
+ or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
89
90
  like: (nv, v) => {
90
91
  const nodeValue = this.comparator.match(nv);
91
92
  const value = this.comparator.match(v);
@@ -105,8 +106,22 @@ var BPTree = class {
105
106
  lte: (v) => this.insertableNode(v),
106
107
  equal: (v) => this.insertableNode(v),
107
108
  notEqual: (v) => this.leftestNode(),
109
+ or: (v) => this.insertableNode(this.lowestValue(this.ensureValues(v))),
108
110
  like: (v) => this.leftestNode()
109
111
  };
112
+ verifierEndNode = {
113
+ gt: (v) => null,
114
+ gte: (v) => null,
115
+ lt: (v) => null,
116
+ lte: (v) => null,
117
+ equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
118
+ notEqual: (v) => null,
119
+ or: (v) => this.insertableEndNode(
120
+ this.highestValue(this.ensureValues(v)),
121
+ this.verifierDirection.or
122
+ ),
123
+ like: (v) => null
124
+ };
110
125
  verifierDirection = {
111
126
  gt: 1,
112
127
  gte: 1,
@@ -114,17 +129,9 @@ var BPTree = class {
114
129
  lte: -1,
115
130
  equal: 1,
116
131
  notEqual: 1,
132
+ or: 1,
117
133
  like: 1
118
134
  };
119
- verifierFullScan = {
120
- gt: false,
121
- gte: false,
122
- lt: false,
123
- lte: false,
124
- equal: false,
125
- notEqual: true,
126
- like: true
127
- };
128
135
  constructor(strategy, comparator) {
129
136
  this._strategyDirty = false;
130
137
  this._cachedRegexp = new InvertedWeakMap();
@@ -135,12 +142,31 @@ var BPTree = class {
135
142
  this.strategy = strategy;
136
143
  this.comparator = comparator;
137
144
  }
145
+ ensureValues(v) {
146
+ if (!Array.isArray(v)) {
147
+ v = [v];
148
+ }
149
+ return v;
150
+ }
151
+ lowestValue(v) {
152
+ const i = 0;
153
+ return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
154
+ }
155
+ highestValue(v) {
156
+ const i = v.length - 1;
157
+ return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
158
+ }
138
159
  _insertAtLeaf(node, key, value) {
139
160
  if (node.values.length) {
140
161
  for (let i = 0, len = node.values.length; i < len; i++) {
141
162
  const nValue = node.values[i];
142
163
  if (this.comparator.isSame(value, nValue)) {
143
164
  const keys = node.keys[i];
165
+ if (keys.includes(key)) {
166
+ throw new Error("The key already exists.", {
167
+ cause: { key, value }
168
+ });
169
+ }
144
170
  keys.push(key);
145
171
  this.bufferForNodeUpdate(node);
146
172
  break;
@@ -195,25 +221,24 @@ var BPTreeSync = class extends BPTree {
195
221
  constructor(strategy, comparator) {
196
222
  super(strategy, comparator);
197
223
  }
198
- getPairsRightToLeft(value, startNode, fullScan, comparator) {
224
+ getPairsRightToLeft(value, startNode, endNode, comparator) {
199
225
  const pairs = [];
200
226
  let node = startNode;
201
227
  let done = false;
202
- let found = false;
203
228
  while (!done) {
229
+ if (endNode && node.id === endNode.id) {
230
+ done = true;
231
+ break;
232
+ }
204
233
  let i = node.values.length;
205
234
  while (i--) {
206
235
  const nValue = node.values[i];
207
236
  const keys = node.keys[i];
208
237
  if (comparator(nValue, value)) {
209
- found = true;
210
238
  let j = keys.length;
211
239
  while (j--) {
212
240
  pairs.push([keys[j], nValue]);
213
241
  }
214
- } else if (found && !fullScan) {
215
- done = true;
216
- break;
217
242
  }
218
243
  }
219
244
  if (!node.prev) {
@@ -224,24 +249,23 @@ var BPTreeSync = class extends BPTree {
224
249
  }
225
250
  return new Map(pairs.reverse());
226
251
  }
227
- getPairsLeftToRight(value, startNode, fullScan, comparator) {
252
+ getPairsLeftToRight(value, startNode, endNode, comparator) {
228
253
  const pairs = [];
229
254
  let node = startNode;
230
255
  let done = false;
231
- let found = false;
232
256
  while (!done) {
257
+ if (endNode && node.id === endNode.id) {
258
+ done = true;
259
+ break;
260
+ }
233
261
  for (let i = 0, len = node.values.length; i < len; i++) {
234
262
  const nValue = node.values[i];
235
263
  const keys = node.keys[i];
236
264
  if (comparator(nValue, value)) {
237
- found = true;
238
265
  for (let j = 0, len2 = keys.length; j < len2; j++) {
239
266
  const key = keys[j];
240
267
  pairs.push([key, nValue]);
241
268
  }
242
- } else if (found && !fullScan) {
243
- done = true;
244
- break;
245
269
  }
246
270
  }
247
271
  if (!node.next) {
@@ -252,12 +276,12 @@ var BPTreeSync = class extends BPTree {
252
276
  }
253
277
  return new Map(pairs);
254
278
  }
255
- getPairs(value, startNode, fullScan, comparator, direction) {
279
+ getPairs(value, startNode, endNode, comparator, direction) {
256
280
  switch (direction) {
257
281
  case -1:
258
- return this.getPairsRightToLeft(value, startNode, fullScan, comparator);
282
+ return this.getPairsRightToLeft(value, startNode, endNode, comparator);
259
283
  case 1:
260
- return this.getPairsLeftToRight(value, startNode, fullScan, comparator);
284
+ return this.getPairsLeftToRight(value, startNode, endNode, comparator);
261
285
  default:
262
286
  throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
263
287
  }
@@ -581,6 +605,25 @@ var BPTreeSync = class extends BPTree {
581
605
  }
582
606
  return node;
583
607
  }
608
+ insertableEndNode(value, direction) {
609
+ const insertableNode = this.insertableNode(value);
610
+ let key;
611
+ switch (direction) {
612
+ case -1:
613
+ key = "prev";
614
+ break;
615
+ case 1:
616
+ key = "next";
617
+ break;
618
+ default:
619
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
620
+ }
621
+ const guessNode = insertableNode[key];
622
+ if (!guessNode) {
623
+ return null;
624
+ }
625
+ return this.getNode(guessNode);
626
+ }
584
627
  leftestNode() {
585
628
  let node = this.root;
586
629
  while (!node.leaf) {
@@ -589,6 +632,14 @@ var BPTreeSync = class extends BPTree {
589
632
  }
590
633
  return node;
591
634
  }
635
+ rightestNode() {
636
+ let node = this.root;
637
+ while (!node.leaf) {
638
+ const keys = node.keys;
639
+ node = this.getNode(keys[keys.length - 1]);
640
+ }
641
+ return node;
642
+ }
592
643
  commitHeadBuffer() {
593
644
  if (!this._strategyDirty) {
594
645
  return;
@@ -619,10 +670,10 @@ var BPTreeSync = class extends BPTree {
619
670
  const key = k;
620
671
  const value = condition[key];
621
672
  const startNode = this.verifierStartNode[key](value);
673
+ const endNode = this.verifierEndNode[key](value);
622
674
  const direction = this.verifierDirection[key];
623
- const fullScan = this.verifierFullScan[key];
624
675
  const comparator = this.verifierMap[key];
625
- const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
676
+ const pairs = this.getPairs(value, startNode, endNode, comparator, direction);
626
677
  if (!filterValues) {
627
678
  filterValues = new Set(pairs.keys());
628
679
  } else {
@@ -644,10 +695,10 @@ var BPTreeSync = class extends BPTree {
644
695
  const key = k;
645
696
  const value = condition[key];
646
697
  const startNode = this.verifierStartNode[key](value);
698
+ const endNode = this.verifierEndNode[key](value);
647
699
  const direction = this.verifierDirection[key];
648
- const fullScan = this.verifierFullScan[key];
649
700
  const comparator = this.verifierMap[key];
650
- const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
701
+ const pairs = this.getPairs(value, startNode, endNode, comparator, direction);
651
702
  if (result === null) {
652
703
  result = pairs;
653
704
  } else {
@@ -757,25 +808,24 @@ var BPTreeAsync = class extends BPTree {
757
808
  constructor(strategy, comparator) {
758
809
  super(strategy, comparator);
759
810
  }
760
- async getPairsRightToLeft(value, startNode, fullScan, comparator) {
811
+ async getPairsRightToLeft(value, startNode, endNode, comparator) {
761
812
  const pairs = [];
762
813
  let node = startNode;
763
814
  let done = false;
764
- let found = false;
765
815
  while (!done) {
816
+ if (endNode && node.id === endNode.id) {
817
+ done = true;
818
+ break;
819
+ }
766
820
  let i = node.values.length;
767
821
  while (i--) {
768
822
  const nValue = node.values[i];
769
823
  const keys = node.keys[i];
770
824
  if (comparator(nValue, value)) {
771
- found = true;
772
825
  let j = keys.length;
773
826
  while (j--) {
774
827
  pairs.push([keys[j], nValue]);
775
828
  }
776
- } else if (found && !fullScan) {
777
- done = true;
778
- break;
779
829
  }
780
830
  }
781
831
  if (!node.prev) {
@@ -786,24 +836,23 @@ var BPTreeAsync = class extends BPTree {
786
836
  }
787
837
  return new Map(pairs.reverse());
788
838
  }
789
- async getPairsLeftToRight(value, startNode, fullScan, comparator) {
839
+ async getPairsLeftToRight(value, startNode, endNode, comparator) {
790
840
  const pairs = [];
791
841
  let node = startNode;
792
842
  let done = false;
793
- let found = false;
794
843
  while (!done) {
844
+ if (endNode && node.id === endNode.id) {
845
+ done = true;
846
+ break;
847
+ }
795
848
  for (let i = 0, len = node.values.length; i < len; i++) {
796
849
  const nValue = node.values[i];
797
850
  const keys = node.keys[i];
798
851
  if (comparator(nValue, value)) {
799
- found = true;
800
852
  for (let j = 0, len2 = keys.length; j < len2; j++) {
801
853
  const key = keys[j];
802
854
  pairs.push([key, nValue]);
803
855
  }
804
- } else if (found && !fullScan) {
805
- done = true;
806
- break;
807
856
  }
808
857
  }
809
858
  if (!node.next) {
@@ -814,12 +863,12 @@ var BPTreeAsync = class extends BPTree {
814
863
  }
815
864
  return new Map(pairs);
816
865
  }
817
- async getPairs(value, startNode, fullScan, comparator, direction) {
866
+ async getPairs(value, startNode, endNode, comparator, direction) {
818
867
  switch (direction) {
819
868
  case -1:
820
- return await this.getPairsRightToLeft(value, startNode, fullScan, comparator);
869
+ return await this.getPairsRightToLeft(value, startNode, endNode, comparator);
821
870
  case 1:
822
- return await this.getPairsLeftToRight(value, startNode, fullScan, comparator);
871
+ return await this.getPairsLeftToRight(value, startNode, endNode, comparator);
823
872
  default:
824
873
  throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
825
874
  }
@@ -1143,6 +1192,25 @@ var BPTreeAsync = class extends BPTree {
1143
1192
  }
1144
1193
  return node;
1145
1194
  }
1195
+ async insertableEndNode(value, direction) {
1196
+ const insertableNode = await this.insertableNode(value);
1197
+ let key;
1198
+ switch (direction) {
1199
+ case -1:
1200
+ key = "prev";
1201
+ break;
1202
+ case 1:
1203
+ key = "next";
1204
+ break;
1205
+ default:
1206
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
1207
+ }
1208
+ const guessNode = insertableNode[key];
1209
+ if (!guessNode) {
1210
+ return null;
1211
+ }
1212
+ return await this.getNode(guessNode);
1213
+ }
1146
1214
  async leftestNode() {
1147
1215
  let node = this.root;
1148
1216
  while (!node.leaf) {
@@ -1151,6 +1219,14 @@ var BPTreeAsync = class extends BPTree {
1151
1219
  }
1152
1220
  return node;
1153
1221
  }
1222
+ async rightestNode() {
1223
+ let node = this.root;
1224
+ while (!node.leaf) {
1225
+ const keys = node.keys;
1226
+ node = await this.getNode(keys[keys.length - 1]);
1227
+ }
1228
+ return node;
1229
+ }
1154
1230
  async commitHeadBuffer() {
1155
1231
  if (!this._strategyDirty) {
1156
1232
  return;
@@ -1181,10 +1257,10 @@ var BPTreeAsync = class extends BPTree {
1181
1257
  const key = k;
1182
1258
  const value = condition[key];
1183
1259
  const startNode = await this.verifierStartNode[key](value);
1260
+ const endNode = await this.verifierEndNode[key](value);
1184
1261
  const direction = this.verifierDirection[key];
1185
- const fullScan = this.verifierFullScan[key];
1186
1262
  const comparator = this.verifierMap[key];
1187
- const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
1263
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1188
1264
  if (!filterValues) {
1189
1265
  filterValues = new Set(pairs.keys());
1190
1266
  } else {
@@ -1206,10 +1282,10 @@ var BPTreeAsync = class extends BPTree {
1206
1282
  const key = k;
1207
1283
  const value = condition[key];
1208
1284
  const startNode = await this.verifierStartNode[key](value);
1285
+ const endNode = await this.verifierEndNode[key](value);
1209
1286
  const direction = this.verifierDirection[key];
1210
- const fullScan = this.verifierFullScan[key];
1211
1287
  const comparator = this.verifierMap[key];
1212
- const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
1288
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1213
1289
  if (result === null) {
1214
1290
  result = pairs;
1215
1291
  } else {
@@ -5,9 +5,9 @@ import { SerializableData } from './base/SerializeStrategy';
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>);
8
- protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
9
- protected getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
10
- protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): Promise<BPTreePair<K, V>>;
8
+ protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
9
+ protected getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
10
+ protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): Promise<BPTreePair<K, V>>;
11
11
  protected _createNodeId(isLeaf: boolean): Promise<string>;
12
12
  protected _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): Promise<BPTreeUnknownNode<K, V>>;
13
13
  protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): Promise<void>;
@@ -15,7 +15,9 @@ export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
15
15
  init(): Promise<void>;
16
16
  protected getNode(id: string): Promise<BPTreeUnknownNode<K, V>>;
17
17
  protected insertableNode(value: V): Promise<BPTreeLeafNode<K, V>>;
18
+ protected insertableEndNode(value: V, direction: 1 | -1): Promise<BPTreeLeafNode<K, V> | null>;
18
19
  protected leftestNode(): Promise<BPTreeLeafNode<K, V>>;
20
+ protected rightestNode(): Promise<BPTreeLeafNode<K, V>>;
19
21
  protected commitHeadBuffer(): Promise<void>;
20
22
  protected commitNodeCreateBuffer(): Promise<void>;
21
23
  protected commitNodeUpdateBuffer(): Promise<void>;
@@ -5,9 +5,9 @@ import { SerializableData } from './base/SerializeStrategy';
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>);
8
- protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>;
9
- protected getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>;
10
- protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): BPTreePair<K, V>;
8
+ protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>;
9
+ protected getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>;
10
+ protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): BPTreePair<K, V>;
11
11
  protected _createNodeId(isLeaf: boolean): string;
12
12
  protected _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): BPTreeUnknownNode<K, V>;
13
13
  protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): void;
@@ -15,7 +15,9 @@ export declare class BPTreeSync<K, V> extends BPTree<K, V> {
15
15
  init(): void;
16
16
  protected getNode(id: string): BPTreeUnknownNode<K, V>;
17
17
  protected insertableNode(value: V): BPTreeLeafNode<K, V>;
18
+ protected insertableEndNode(value: V, direction: 1 | -1): BPTreeLeafNode<K, V> | null;
18
19
  protected leftestNode(): BPTreeLeafNode<K, V>;
20
+ protected rightestNode(): BPTreeLeafNode<K, V>;
19
21
  protected commitHeadBuffer(): void;
20
22
  protected commitNodeCreateBuffer(): void;
21
23
  protected commitNodeUpdateBuffer(): void;
@@ -18,6 +18,8 @@ export type BPTreeCondition<V> = Partial<{
18
18
  equal: Partial<V>;
19
19
  /** Searches for pairs not equal to the given value. */
20
20
  notEqual: Partial<V>;
21
+ /** Searches for pairs that satisfy at least one of the conditions. */
22
+ or: Partial<V>[];
21
23
  /** Searches for values matching the given pattern. '%' matches zero or more characters, and '_' matches exactly one character. */
22
24
  like: Partial<V>;
23
25
  }>;
@@ -51,21 +53,23 @@ export declare abstract class BPTree<K, V> {
51
53
  protected readonly _nodeCreateBuffer: Map<string, BPTreeUnknownNode<K, V>>;
52
54
  protected readonly _nodeUpdateBuffer: Map<string, BPTreeUnknownNode<K, V>>;
53
55
  protected readonly _nodeDeleteBuffer: Map<string, BPTreeUnknownNode<K, V>>;
54
- protected readonly verifierMap: Record<keyof BPTreeCondition<V>, (nodeValue: V, value: V) => boolean>;
56
+ protected readonly verifierMap: Record<keyof BPTreeCondition<V>, (nodeValue: V, value: V | V[]) => boolean>;
55
57
  protected readonly verifierStartNode: Record<keyof BPTreeCondition<V>, (value: V) => Deferred<BPTreeLeafNode<K, V>>>;
58
+ protected readonly verifierEndNode: Record<keyof BPTreeCondition<V>, (value: V) => Deferred<BPTreeLeafNode<K, V> | null>>;
56
59
  protected readonly verifierDirection: Record<keyof BPTreeCondition<V>, -1 | 1>;
57
- protected readonly verifierFullScan: Record<keyof BPTreeCondition<V>, boolean>;
58
60
  protected constructor(strategy: SerializeStrategy<K, V>, comparator: ValueComparator<V>);
59
- protected abstract getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>>;
60
- protected abstract getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>>;
61
- protected abstract getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: -1 | 1): Deferred<BPTreePair<K, V>>;
61
+ protected abstract getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>>;
62
+ protected abstract getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>>;
63
+ protected abstract getPairs(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean, direction: -1 | 1): Deferred<BPTreePair<K, V>>;
62
64
  protected abstract _createNodeId(isLeaf: boolean): Deferred<string>;
63
65
  protected abstract _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): Deferred<BPTreeUnknownNode<K, V>>;
64
66
  protected abstract _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): Deferred<void>;
65
67
  protected abstract _insertInParent(node: BPTreeUnknownNode<K, V>, value: V, pointer: BPTreeUnknownNode<K, V>): Deferred<void>;
66
68
  protected abstract getNode(id: string): Deferred<BPTreeUnknownNode<K, V>>;
67
69
  protected abstract insertableNode(value: V): Deferred<BPTreeLeafNode<K, V>>;
70
+ protected abstract insertableEndNode(value: V, direction: 1 | -1): Deferred<BPTreeLeafNode<K, V> | null>;
68
71
  protected abstract leftestNode(): Deferred<BPTreeLeafNode<K, V>>;
72
+ protected abstract rightestNode(): Deferred<BPTreeLeafNode<K, V>>;
69
73
  protected abstract commitHeadBuffer(): Deferred<void>;
70
74
  protected abstract commitNodeCreateBuffer(): Deferred<void>;
71
75
  protected abstract commitNodeUpdateBuffer(): Deferred<void>;
@@ -123,6 +127,9 @@ export declare abstract class BPTree<K, V> {
123
127
  * @returns The return value is the total number of nodes updated.
124
128
  */
125
129
  abstract forceUpdate(): Deferred<number>;
130
+ protected ensureValues(v: V | V[]): V[];
131
+ protected lowestValue(v: V[]): V;
132
+ protected highestValue(v: V[]): V;
126
133
  protected _insertAtLeaf(node: BPTreeLeafNode<K, V>, key: K, value: V): void;
127
134
  protected bufferForNodeCreate(node: BPTreeUnknownNode<K, V>): void;
128
135
  protected bufferForNodeUpdate(node: BPTreeUnknownNode<K, V>): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "5.0.5",
3
+ "version": "5.1.0",
4
4
  "description": "Store the B+tree flexibly, not only in-memory.",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "main": "./dist/cjs/index.cjs",
@@ -37,9 +37,9 @@
37
37
  "license": "MIT",
38
38
  "devDependencies": {
39
39
  "@types/jest": "^29.5.14",
40
- "esbuild": "^0.24.0",
40
+ "esbuild": "^0.25.4",
41
41
  "jest": "^29.7.0",
42
- "ts-jest": "^29.2.5",
43
- "typescript": "^5.6.3"
42
+ "ts-jest": "^29.3.3",
43
+ "typescript": "^5.8.3"
44
44
  }
45
45
  }