serializable-bptree 1.1.0 → 2.0.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
@@ -59,7 +59,7 @@ tree.where({ gt: 0, lt: 4 }) // [{ key: 'a', value: 1 }, { key: 'c', value: 3 }]
59
59
 
60
60
  ## Why use a `serializable-bptree`?
61
61
 
62
- Firstly, in most cases, there is no need to use a B+tree in JavaScript. This is because there is a great alternative, the Map object. Nonetheless, if you need to retrieve values in a sorted order, a B+tree can be a good solution. These cases are often related to databases, and you may want to store this state not just in memory, but on a remote server or in a file. In this case, `serializable-bptree` can help you.
62
+ Firstly, in most cases, there is no need to use a B+tree in JavaScript. This is because there is a great alternative, the Map object. Nonetheless, if you need to retrieve values in a sorted order, a B+tree can be a good solution. These cases are often related to databases, and you may want to store this state not just in memory, but on a remote server or in a file. In this case, **serializable-bptree** can help you.
63
63
 
64
64
  ## How to use
65
65
 
@@ -77,7 +77,7 @@ import { BPTree } from 'serializable-bptree'
77
77
 
78
78
  ```html
79
79
  <script type="module">
80
- import { BPTree } from 'https://cdn.jsdelivr.net/npm/serializable-bptree@1.x.x/dist/esm/index.min.js'
80
+ import { BPTree, ValueComparator, NumericComparator, StringComparator, InMemoryStoreStrategy } from 'https://cdn.jsdelivr.net/npm/serializable-bptree@1.x.x/dist/esm/index.min.js'
81
81
  </script>
82
82
  ```
83
83
 
@@ -85,15 +85,15 @@ import { BPTree } from 'serializable-bptree'
85
85
 
86
86
  ### Value comparator
87
87
 
88
- B+tree needs to keep values in sorted order. Therefore, a process to compare the sizes of values is needed, and that role is played by the `ValueComparator`.
88
+ B+tree needs to keep values in sorted order. Therefore, a process to compare the sizes of values is needed, and that role is played by the **ValueComparator**.
89
89
 
90
- Commonly used numerical and string comparisons are natively supported by the `serializable-bptree` library. Use it as follows:
90
+ Commonly used numerical and string comparisons are natively supported by the **serializable-bptree** library. Use it as follows:
91
91
 
92
92
  ```typescript
93
93
  import { NumericComparator, StringComparator } from 'serializable-bptree'
94
94
  ```
95
95
 
96
- However, you may want to sort complex objects other than numbers and strings. For example, if you want to sort by the `age` property order of an object, you need to create a new class that inherits from the `ValueComparator` class. Use it as follows:
96
+ However, you may want to sort complex objects other than numbers and strings. For example, if you want to sort by the **age** property order of an object, you need to create a new class that inherits from the **ValueComparator** class. Use it as follows:
97
97
 
98
98
  ```typescript
99
99
  import { ValueComparator } from 'serializable-bptree'
@@ -103,13 +103,15 @@ interface MyObject {
103
103
  name: string
104
104
  }
105
105
 
106
- class AgeComparator {
106
+ class AgeComparator extends ValueComparator<MyObject> {
107
107
  asc(a: MyObject, b: MyObject): number {
108
108
  return a.age - b.age
109
109
  }
110
110
  }
111
111
  ```
112
112
 
113
+ 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.
114
+
113
115
  ### Serialize strategy
114
116
 
115
117
  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.
@@ -132,7 +134,7 @@ What does this method mean? And why do we need to construct such a method?
132
134
 
133
135
  #### id(): `number`
134
136
 
135
- When a node is created in the B+tree, the node needs a unique value to represent itself. This is the `node.id` attribute, and you can specify this attribute yourself. For example, it could be implemented like this.
137
+ When a node is created in the B+tree, the node needs a unique value to represent itself. This is the **node.id** attribute, and you can specify this attribute yourself. For example, it could be implemented like this.
136
138
 
137
139
  ```typescript
138
140
  id(): number {
@@ -142,7 +144,9 @@ id(): number {
142
144
  }
143
145
  ```
144
146
 
145
- Or, you could use file input/output to save and load the value of the `before` variable.
147
+ Or, you could use file input/output to save and load the value of the **before** variable.
148
+
149
+ This method is called before a node is created in the tree. Therefore, it can also be used to allocate space for storing the node.
146
150
 
147
151
  #### read(id: `number`): `BPTreeNode<K, V>`
148
152
 
@@ -158,7 +162,7 @@ read(id: number): BPTreeNode<K, V> {
158
162
  }
159
163
  ```
160
164
 
161
- This method is called only once when loading a node from a tree instance.
165
+ This method is called only once when loading a node from a tree instance. The loaded node is loaded into memory, and subsequently, when the tree references the node, it operates based on the values in memory **without** re-invoking this method.
162
166
 
163
167
  #### write(id: `number`, node: `BPTreeNode<K, V>`): `void`
164
168
 
@@ -181,7 +185,7 @@ function writeBack(id: number, node: BPTreeNode<K, V>, timer: number) {
181
185
 
182
186
  ...
183
187
  write(id: number, node: BPTreeNode<K, V>): void {
184
- const writeBackInterval = 100
188
+ const writeBackInterval = 10
185
189
  writeBack(id, node, writeBackInterval)
186
190
  }
187
191
  ```
@@ -190,32 +194,32 @@ This kind of delay writing should ideally occur within a few milliseconds. If th
190
194
 
191
195
  #### readHead(): `SerializeStrategyHead`|`null`
192
196
 
193
- This method is called only once when the tree is created. It's a method to restore the saved tree information. If it is the initial creation and there is no stored root node, it should return `null`.
197
+ This method is called only once when the tree is created. It's a method to restore the saved tree information. If it is the initial creation and there is no stored root node, it should return **null**.
194
198
 
195
- This method should return the value stored in the `writeHead` method.
199
+ This method should return the value stored in the **writeHead** method.
196
200
 
197
201
  #### writeHead(head: `SerializeStrategyHead`): `void`
198
202
 
199
- This method is called whenever the head information of the tree changes, typically when the root node changes.
203
+ This method is called whenever the head information of the tree changes, typically when the root node changes. This method also works when the tree's **setHeadData** method is called. This is because the method attempts to store head data in the root node.
200
204
 
201
- As a parameter, it receives the header information of the tree. This value should be serialized and stored. Later, the `readHead` method should convert this serialized value into a json format and return it.
205
+ As a parameter, it receives the header information of the tree. This value should be serialized and stored. Later, the **readHead** method should convert this serialized value into a json format and return it.
202
206
 
203
207
  ### The Default `ValueComparator` and `SerializeStrategy`
204
208
 
205
- To utilize `serializable-bptree`, you need to implement certain functions. However, a few basic helper classes are provided by default.
209
+ To utilize **serializable-bptree**, you need to implement certain functions. However, a few basic helper classes are provided by default.
206
210
 
207
211
  #### ValueComparator
208
212
 
209
213
  * `NumericComparator`
210
214
  * `StringComparator`
211
215
 
212
- If the values being inserted into the tree are numeric, please use the `NumericComparator` class.
216
+ If the values being inserted into the tree are numeric, please use the **NumericComparator** class.
213
217
 
214
218
  ```typescript
215
219
  import { NumericComparator } from 'serializable-bptree'
216
220
  ```
217
221
 
218
- If the values being inserted into the tree can be strings, you can use the `StringComparator` class in this case.
222
+ If the values being inserted into the tree can be strings, you can use the **StringComparator** class in this case.
219
223
 
220
224
  ```typescript
221
225
  import { StringComparator } from 'serializable-bptree'
@@ -225,7 +229,7 @@ import { StringComparator } from 'serializable-bptree'
225
229
 
226
230
  * `InMemoryStoreStrategy`
227
231
 
228
- As of now, the only class supported by default is the `InMemoryStoreStrategy`. This class is suitable for use when you prefer to operate the tree solely in-memory, similar to a typical B+ tree.
232
+ As of now, the only class supported by default is the **InMemoryStoreStrategy**. This class is suitable for use when you prefer to operate the tree solely in-memory, similar to a typical B+ tree.
229
233
 
230
234
  ```typescript
231
235
  import { InMemoryStoreStrategy } from 'serializable-bptree'
package/dist/cjs/index.js CHANGED
@@ -97,6 +97,51 @@ var BPTree = class {
97
97
  _creates;
98
98
  _updates;
99
99
  _updatedHead;
100
+ _verifierMap = {
101
+ gt: (nv, v) => this.comparator.isHigher(nv, v),
102
+ gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
103
+ lt: (nv, v) => this.comparator.isLower(nv, v),
104
+ lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
105
+ equal: (nv, v) => this.comparator.isSame(nv, v),
106
+ notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
107
+ like: (nv, v) => {
108
+ const nodeValue = nv.toString();
109
+ const value = v.toString();
110
+ const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
111
+ const regex = new RegExp(`^${pattern}$`, "i");
112
+ return regex.test(nodeValue);
113
+ }
114
+ };
115
+ _verifierStartNode = {
116
+ gt: (v) => this.insertableNode(v),
117
+ gte: (v) => this.insertableNode(v),
118
+ // todo
119
+ lt: (v) => this.insertableNode(v),
120
+ lte: (v) => this.insertableNode(v),
121
+ // todo
122
+ equal: (v) => this.insertableNode(v),
123
+ notEqual: (v) => this.leftestNode(),
124
+ like: (v) => this.leftestNode()
125
+ // todo
126
+ };
127
+ _verifierDirection = {
128
+ gt: 1,
129
+ gte: 1,
130
+ lt: -1,
131
+ lte: -1,
132
+ equal: 1,
133
+ notEqual: 1,
134
+ like: 1
135
+ };
136
+ _verifierFullSearch = {
137
+ gt: false,
138
+ gte: false,
139
+ lt: false,
140
+ lte: false,
141
+ equal: false,
142
+ notEqual: true,
143
+ like: true
144
+ };
100
145
  _createNodeId() {
101
146
  const id = this.strategy.id();
102
147
  if (id === 0) {
@@ -104,7 +149,7 @@ var BPTree = class {
104
149
  }
105
150
  return id;
106
151
  }
107
- _createNode(keys, values, leaf = false, parent = 0, next = 0) {
152
+ _createNode(keys, values, leaf = false, parent = 0, next = 0, prev = 0) {
108
153
  const id = this._createNodeId();
109
154
  const node = {
110
155
  id,
@@ -112,7 +157,8 @@ var BPTree = class {
112
157
  values,
113
158
  leaf,
114
159
  parent,
115
- next
160
+ next,
161
+ prev
116
162
  };
117
163
  this.nodes.set(id, node);
118
164
  return node;
@@ -199,7 +245,7 @@ var BPTree = class {
199
245
  }
200
246
  return node;
201
247
  }
202
- _insertableNode(value) {
248
+ insertableNode(value) {
203
249
  let node = this.root;
204
250
  while (!node.leaf) {
205
251
  for (let i = 0, len = node.values.length; i < len; i++) {
@@ -225,7 +271,7 @@ var BPTree = class {
225
271
  * @param value The value to search for.
226
272
  */
227
273
  exists(key, value) {
228
- const node = this._insertableNode(value);
274
+ const node = this.insertableNode(value);
229
275
  for (let i = 0, len = node.values.length; i < len; i++) {
230
276
  const nValue = node.values[i];
231
277
  if (this.comparator.isSame(value, nValue)) {
@@ -311,218 +357,50 @@ var BPTree = class {
311
357
  }
312
358
  }
313
359
  }
314
- _equalCondition(condition) {
315
- return Object.prototype.hasOwnProperty.call(condition, "equal");
316
- }
317
- _notEqualCondition(condition) {
318
- return Object.prototype.hasOwnProperty.call(condition, "notEqual");
319
- }
320
- _onlyGtCondition(condition) {
321
- return Object.prototype.hasOwnProperty.call(condition, "gt") && !Object.prototype.hasOwnProperty.call(condition, "lt");
322
- }
323
- _onlyLtCondition(condition) {
324
- return Object.prototype.hasOwnProperty.call(condition, "lt") && !Object.prototype.hasOwnProperty.call(condition, "gt");
325
- }
326
- _rangeCondition(condition) {
327
- return Object.prototype.hasOwnProperty.call(condition, "gt") && Object.prototype.hasOwnProperty.call(condition, "lt");
328
- }
329
- _getKeysFromValue(value) {
330
- const keys = /* @__PURE__ */ new Set();
331
- const node = this._insertableNode(value);
332
- const [start, end] = this.search.range(node.values, value);
333
- if (start === -1) {
334
- return keys;
335
- }
336
- for (let i = start; i < end; i++) {
337
- const pairKeys = node.keys[i];
338
- for (const key of pairKeys) {
339
- keys.add(key);
340
- }
341
- }
342
- return keys;
343
- }
344
- _getKeysFromNEValue(value) {
345
- const keys = /* @__PURE__ */ new Set();
346
- let node = this.leftestNode();
347
- let done = false;
348
- while (!done) {
349
- for (let i = 0, len = node.values.length; i < len; i++) {
350
- const nValue = node.values[i];
351
- const pairKeys = node.keys[i];
352
- if (this.comparator.isSame(nValue, value) === false) {
353
- for (const key of pairKeys) {
354
- keys.add(key);
355
- }
356
- }
357
- }
358
- if (!node.next) {
359
- done = true;
360
- break;
361
- }
362
- node = this.getNode(node.next);
363
- }
364
- return keys;
365
- }
366
- _getKeysFromRange(gt, lt) {
367
- const keys = /* @__PURE__ */ new Set();
368
- let node = this._insertableNode(gt);
369
- let done = false;
370
- let found = false;
371
- while (!done) {
372
- for (let i = 0, len = node.values.length; i < len; i++) {
373
- const nValue = node.values[i];
374
- const localKeys = node.keys[i];
375
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
376
- found = true;
377
- for (const key of localKeys) {
378
- keys.add(key);
379
- }
380
- } else if (found) {
381
- done = true;
382
- break;
383
- }
384
- }
385
- if (!node.next) {
386
- done = true;
387
- break;
388
- }
389
- node = this.getNode(node.next);
390
- }
391
- return keys;
392
- }
393
- _getKeysFromGt(gt) {
394
- const keys = /* @__PURE__ */ new Set();
395
- let node = this._insertableNode(gt);
396
- let done = false;
397
- let found = false;
398
- while (!done) {
399
- for (let i = 0, len = node.values.length; i < len; i++) {
400
- const nValue = node.values[i];
401
- const localKeys = node.keys[i];
402
- if (this.comparator.isHigher(nValue, gt)) {
403
- found = true;
404
- for (const key of localKeys) {
405
- keys.add(key);
406
- }
407
- } else if (found) {
408
- done = true;
409
- break;
410
- }
411
- }
412
- if (!node.next) {
413
- done = true;
414
- break;
415
- }
416
- node = this.getNode(node.next);
417
- }
418
- return keys;
419
- }
420
- _getKeysFromLt(lt) {
421
- const keys = /* @__PURE__ */ new Set();
422
- let node = this.leftestNode();
423
- let done = false;
424
- let found = false;
425
- while (!done) {
426
- for (let i = 0, len = node.values.length; i < len; i++) {
427
- const nValue = node.values[i];
428
- const localKeys = node.keys[i];
429
- if (this.comparator.isLower(nValue, lt)) {
430
- found = true;
431
- for (const key of localKeys) {
432
- keys.add(key);
433
- }
434
- } else if (found) {
435
- done = true;
436
- break;
437
- }
438
- }
439
- if (!node.next) {
440
- done = true;
441
- break;
442
- }
443
- node = this.getNode(node.next);
444
- }
445
- return keys;
446
- }
447
- _getPairsFromValue(value) {
448
- const node = this._insertableNode(value);
449
- const [start, end] = this.search.range(node.values, value);
450
- if (start === -1) {
451
- return [];
452
- }
453
- const pairs = [];
454
- for (let i = start; i < end; i++) {
455
- const keys = node.keys[i];
456
- for (const key of keys) {
457
- pairs.push({ key, value });
458
- }
459
- }
460
- return pairs;
461
- }
462
- _getPairsFromNEValue(value) {
360
+ _getPairsRightToLeft(value, startNode, fullSearch, comparator) {
463
361
  const pairs = [];
464
- let node = this.leftestNode();
465
- let done = false;
466
- while (!done) {
467
- for (let i = 0, len = node.values.length; i < len; i++) {
468
- const nValue = node.values[i];
469
- const keys = node.keys[i];
470
- if (this.comparator.isSame(nValue, value) === false) {
471
- for (const key of keys) {
472
- pairs.push({ key, value: nValue });
473
- }
474
- }
475
- }
476
- if (!node.next) {
477
- done = true;
478
- break;
479
- }
480
- node = this.getNode(node.next);
481
- }
482
- return pairs;
483
- }
484
- _getPairsFromRange(gt, lt) {
485
- const pairs = [];
486
- let node = this._insertableNode(gt);
362
+ let node = startNode;
487
363
  let done = false;
488
364
  let found = false;
489
365
  while (!done) {
490
- for (let i = 0, len = node.values.length; i < len; i++) {
366
+ let i = node.values.length;
367
+ while (i--) {
491
368
  const nValue = node.values[i];
492
369
  const keys = node.keys[i];
493
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
370
+ if (comparator(nValue, value)) {
494
371
  found = true;
495
- for (const key of keys) {
496
- pairs.push({ key, value: nValue });
372
+ let j = keys.length;
373
+ while (j--) {
374
+ pairs.push({ key: keys[j], value: nValue });
497
375
  }
498
- } else if (found) {
376
+ } else if (found && !fullSearch) {
499
377
  done = true;
500
378
  break;
501
379
  }
502
380
  }
503
- if (!node.next) {
381
+ if (!node.prev) {
504
382
  done = true;
505
383
  break;
506
384
  }
507
- node = this.getNode(node.next);
385
+ node = this.getNode(node.prev);
508
386
  }
509
- return pairs;
387
+ return pairs.reverse();
510
388
  }
511
- _getPairsFromGt(gt) {
389
+ _getPairsLeftToRight(value, startNode, fullSearch, comparator) {
512
390
  const pairs = [];
513
- let node = this._insertableNode(gt);
391
+ let node = startNode;
514
392
  let done = false;
515
393
  let found = false;
516
394
  while (!done) {
517
395
  for (let i = 0, len = node.values.length; i < len; i++) {
518
396
  const nValue = node.values[i];
519
397
  const keys = node.keys[i];
520
- if (this.comparator.isHigher(nValue, gt)) {
398
+ if (comparator(nValue, value)) {
521
399
  found = true;
522
400
  for (const key of keys) {
523
401
  pairs.push({ key, value: nValue });
524
402
  }
525
- } else if (found) {
403
+ } else if (found && !fullSearch) {
526
404
  done = true;
527
405
  break;
528
406
  }
@@ -535,75 +413,62 @@ var BPTree = class {
535
413
  }
536
414
  return pairs;
537
415
  }
538
- _getPairsFromLt(lt) {
539
- const pairs = [];
540
- let node = this.leftestNode();
541
- let done = false;
542
- let found = false;
543
- while (!done) {
544
- for (let i = 0, len = node.values.length; i < len; i++) {
545
- const nValue = node.values[i];
546
- const keys = node.keys[i];
547
- if (this.comparator.isLower(nValue, lt)) {
548
- found = true;
549
- for (const key of keys) {
550
- pairs.push({ key, value: nValue });
551
- }
552
- } else if (found) {
553
- done = true;
554
- break;
555
- }
556
- }
557
- if (!node.next) {
558
- done = true;
559
- break;
560
- }
561
- node = this.getNode(node.next);
416
+ getPairs(value, startNode, fullSearch, comparator, direction) {
417
+ switch (direction) {
418
+ case -1:
419
+ return this._getPairsRightToLeft(value, startNode, fullSearch, comparator);
420
+ case 1:
421
+ return this._getPairsLeftToRight(value, startNode, fullSearch, comparator);
422
+ default:
423
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
562
424
  }
563
- return pairs;
564
425
  }
565
426
  /**
566
427
  * It searches for a key within the tree. The result is returned as an array sorted in ascending order based on the value.
567
- * The result is key set instance, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
428
+ * The result is key set instance, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
568
429
  * This method operates much faster than first searching with `where` and then retrieving only the key list.
569
- * @param condition You can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
430
+ * @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
570
431
  */
571
432
  keys(condition) {
572
- if (this._equalCondition(condition)) {
573
- return this._getKeysFromValue(condition.equal);
574
- } else if (this._notEqualCondition(condition)) {
575
- return this._getKeysFromNEValue(condition.notEqual);
576
- } else if (this._rangeCondition(condition)) {
577
- const { gt, lt } = condition;
578
- return this._getKeysFromRange(gt, lt);
579
- } else if (this._onlyGtCondition(condition)) {
580
- return this._getKeysFromGt(condition.gt);
581
- } else if (this._onlyLtCondition(condition)) {
582
- return this._getKeysFromLt(condition.lt);
583
- } else {
584
- throw new Error(`The 'condition' parameter is invalid.`);
433
+ let result = null;
434
+ for (const k in condition) {
435
+ const key = k;
436
+ const value = condition[key];
437
+ const startNode = this._verifierStartNode[key](value);
438
+ const direction = this._verifierDirection[key];
439
+ const fullSearch = this._verifierFullSearch[key];
440
+ const comparator = this._verifierMap[key];
441
+ const pairs = this.getPairs(value, startNode, fullSearch, comparator, direction);
442
+ if (result === null) {
443
+ result = pairs.map((pair) => pair.key);
444
+ } else {
445
+ result = result.filter((key2) => pairs.find((p) => p.key === key2));
446
+ }
585
447
  }
448
+ return new Set(result ?? []);
586
449
  }
587
450
  /**
588
451
  * It searches for a value within the tree. The result is returned as an array sorted in ascending order based on the value.
589
- * The result includes the key and value attributes, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
590
- * @param condition You can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
452
+ * The result includes the key and value attributes, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
453
+ * @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
591
454
  */
592
455
  where(condition) {
593
- if (this._equalCondition(condition)) {
594
- return this._getPairsFromValue(condition.equal);
595
- } else if (this._notEqualCondition(condition)) {
596
- return this._getPairsFromNEValue(condition.notEqual);
597
- } else if (this._rangeCondition(condition)) {
598
- const { gt, lt } = condition;
599
- return this._getPairsFromRange(gt, lt);
600
- } else if (this._onlyGtCondition(condition)) {
601
- return this._getPairsFromGt(condition.gt);
602
- } else if (this._onlyLtCondition(condition)) {
603
- return this._getPairsFromLt(condition.lt);
604
- } else {
605
- throw new Error(`The 'condition' parameter is invalid.`);
456
+ let result = null;
457
+ for (const k in condition) {
458
+ const key = k;
459
+ const value = condition[key];
460
+ const startNode = this._verifierStartNode[key](value);
461
+ const direction = this._verifierDirection[key];
462
+ const fullSearch = this._verifierFullSearch[key];
463
+ const comparator = this._verifierMap[key];
464
+ const pairs = this.getPairs(value, startNode, fullSearch, comparator, direction);
465
+ if (result === null) {
466
+ result = pairs;
467
+ } else {
468
+ result = result.filter((pair) => pairs.find((p) => p.key === pair.key));
469
+ }
606
470
  }
471
+ return result ?? [];
607
472
  }
608
473
  /**
609
474
  * You enter the key and value as a pair. You can later search for the pair by value.
@@ -612,7 +477,7 @@ var BPTree = class {
612
477
  * @param value The value of the pair.
613
478
  */
614
479
  insert(key, value) {
615
- const before = this._insertableNode(value);
480
+ const before = this.insertableNode(value);
616
481
  this._insertAtLeaf(before, key, value);
617
482
  if (before.values.length === this.order) {
618
483
  const after = this._createNode(
@@ -620,14 +485,21 @@ var BPTree = class {
620
485
  [],
621
486
  true,
622
487
  before.parent,
623
- before.next
488
+ before.next,
489
+ before.id
624
490
  );
625
491
  const mid = Math.ceil(this.order / 2) - 1;
492
+ const beforeNext = before.next;
626
493
  after.values = before.values.slice(mid + 1);
627
494
  after.keys = before.keys.slice(mid + 1);
628
495
  before.values = before.values.slice(0, mid + 1);
629
496
  before.keys = before.keys.slice(0, mid + 1);
630
497
  before.next = after.id;
498
+ if (beforeNext) {
499
+ const node = this.getNode(beforeNext);
500
+ node.prev = after.id;
501
+ this._setUpdates(node);
502
+ }
631
503
  this._insertInParent(before, after.values[0], after);
632
504
  this._setCreates(after);
633
505
  this._setUpdates(before);
@@ -642,7 +514,7 @@ var BPTree = class {
642
514
  * @param value The value of the pair.
643
515
  */
644
516
  delete(key, value) {
645
- const node = this._insertableNode(value);
517
+ const node = this.insertableNode(value);
646
518
  let i = node.values.length;
647
519
  while (i--) {
648
520
  const nValue = node.values[i];
@@ -703,18 +575,18 @@ var BPTree = class {
703
575
  let parentNode = this.getNode(node.parent);
704
576
  let prevNode = null;
705
577
  let nextNode = null;
706
- let prevK = null;
707
- let postK = null;
578
+ let prevValue = null;
579
+ let postValue = null;
708
580
  for (let i = 0, len = parentNode.keys.length; i < len; i++) {
709
581
  const nKey = parentNode.keys[i];
710
582
  if (nKey === node.id) {
711
583
  if (i > 0) {
712
584
  prevNode = this.getNode(parentNode.keys[i - 1]);
713
- prevK = parentNode.values[i - 1];
585
+ prevValue = parentNode.values[i - 1];
714
586
  }
715
587
  if (i < parentNode.keys.length - 1) {
716
588
  nextNode = this.getNode(parentNode.keys[i + 1]);
717
- postK = parentNode.values[i];
589
+ postValue = parentNode.values[i];
718
590
  }
719
591
  }
720
592
  }
@@ -722,19 +594,19 @@ var BPTree = class {
722
594
  let guess;
723
595
  if (prevNode === null) {
724
596
  pointer = nextNode;
725
- guess = postK;
597
+ guess = postValue;
726
598
  } else if (nextNode === null) {
727
599
  isPredecessor = true;
728
600
  pointer = prevNode;
729
- guess = prevK;
601
+ guess = prevValue;
730
602
  } else {
731
603
  if (node.values.length + nextNode.values.length < this.order) {
732
604
  pointer = nextNode;
733
- guess = postK;
605
+ guess = postValue;
734
606
  } else {
735
607
  isPredecessor = true;
736
608
  pointer = prevNode;
737
- guess = prevK;
609
+ guess = prevValue;
738
610
  }
739
611
  }
740
612
  if (node.values.length + pointer.values.length < this.order) {
@@ -748,6 +620,20 @@ var BPTree = class {
748
620
  pointer.values.push(guess);
749
621
  } else {
750
622
  pointer.next = node.next;
623
+ pointer.prev = node.id;
624
+ if (pointer.next) {
625
+ const n = this.getNode(node.next);
626
+ n.prev = pointer.id;
627
+ this._setUpdates(n);
628
+ }
629
+ if (pointer.prev) {
630
+ const n = this.getNode(node.id);
631
+ n.next = pointer.id;
632
+ this._setUpdates(n);
633
+ }
634
+ if (isPredecessor) {
635
+ pointer.prev = 0;
636
+ }
751
637
  }
752
638
  pointer.values.push(...node.values);
753
639
  if (!pointer.leaf) {
package/dist/esm/index.js CHANGED
@@ -66,6 +66,51 @@ var BPTree = class {
66
66
  _creates;
67
67
  _updates;
68
68
  _updatedHead;
69
+ _verifierMap = {
70
+ gt: (nv, v) => this.comparator.isHigher(nv, v),
71
+ gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
72
+ lt: (nv, v) => this.comparator.isLower(nv, v),
73
+ lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
74
+ equal: (nv, v) => this.comparator.isSame(nv, v),
75
+ notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
76
+ like: (nv, v) => {
77
+ const nodeValue = nv.toString();
78
+ const value = v.toString();
79
+ const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
80
+ const regex = new RegExp(`^${pattern}$`, "i");
81
+ return regex.test(nodeValue);
82
+ }
83
+ };
84
+ _verifierStartNode = {
85
+ gt: (v) => this.insertableNode(v),
86
+ gte: (v) => this.insertableNode(v),
87
+ // todo
88
+ lt: (v) => this.insertableNode(v),
89
+ lte: (v) => this.insertableNode(v),
90
+ // todo
91
+ equal: (v) => this.insertableNode(v),
92
+ notEqual: (v) => this.leftestNode(),
93
+ like: (v) => this.leftestNode()
94
+ // todo
95
+ };
96
+ _verifierDirection = {
97
+ gt: 1,
98
+ gte: 1,
99
+ lt: -1,
100
+ lte: -1,
101
+ equal: 1,
102
+ notEqual: 1,
103
+ like: 1
104
+ };
105
+ _verifierFullSearch = {
106
+ gt: false,
107
+ gte: false,
108
+ lt: false,
109
+ lte: false,
110
+ equal: false,
111
+ notEqual: true,
112
+ like: true
113
+ };
69
114
  _createNodeId() {
70
115
  const id = this.strategy.id();
71
116
  if (id === 0) {
@@ -73,7 +118,7 @@ var BPTree = class {
73
118
  }
74
119
  return id;
75
120
  }
76
- _createNode(keys, values, leaf = false, parent = 0, next = 0) {
121
+ _createNode(keys, values, leaf = false, parent = 0, next = 0, prev = 0) {
77
122
  const id = this._createNodeId();
78
123
  const node = {
79
124
  id,
@@ -81,7 +126,8 @@ var BPTree = class {
81
126
  values,
82
127
  leaf,
83
128
  parent,
84
- next
129
+ next,
130
+ prev
85
131
  };
86
132
  this.nodes.set(id, node);
87
133
  return node;
@@ -168,7 +214,7 @@ var BPTree = class {
168
214
  }
169
215
  return node;
170
216
  }
171
- _insertableNode(value) {
217
+ insertableNode(value) {
172
218
  let node = this.root;
173
219
  while (!node.leaf) {
174
220
  for (let i = 0, len = node.values.length; i < len; i++) {
@@ -194,7 +240,7 @@ var BPTree = class {
194
240
  * @param value The value to search for.
195
241
  */
196
242
  exists(key, value) {
197
- const node = this._insertableNode(value);
243
+ const node = this.insertableNode(value);
198
244
  for (let i = 0, len = node.values.length; i < len; i++) {
199
245
  const nValue = node.values[i];
200
246
  if (this.comparator.isSame(value, nValue)) {
@@ -280,218 +326,50 @@ var BPTree = class {
280
326
  }
281
327
  }
282
328
  }
283
- _equalCondition(condition) {
284
- return Object.prototype.hasOwnProperty.call(condition, "equal");
285
- }
286
- _notEqualCondition(condition) {
287
- return Object.prototype.hasOwnProperty.call(condition, "notEqual");
288
- }
289
- _onlyGtCondition(condition) {
290
- return Object.prototype.hasOwnProperty.call(condition, "gt") && !Object.prototype.hasOwnProperty.call(condition, "lt");
291
- }
292
- _onlyLtCondition(condition) {
293
- return Object.prototype.hasOwnProperty.call(condition, "lt") && !Object.prototype.hasOwnProperty.call(condition, "gt");
294
- }
295
- _rangeCondition(condition) {
296
- return Object.prototype.hasOwnProperty.call(condition, "gt") && Object.prototype.hasOwnProperty.call(condition, "lt");
297
- }
298
- _getKeysFromValue(value) {
299
- const keys = /* @__PURE__ */ new Set();
300
- const node = this._insertableNode(value);
301
- const [start, end] = this.search.range(node.values, value);
302
- if (start === -1) {
303
- return keys;
304
- }
305
- for (let i = start; i < end; i++) {
306
- const pairKeys = node.keys[i];
307
- for (const key of pairKeys) {
308
- keys.add(key);
309
- }
310
- }
311
- return keys;
312
- }
313
- _getKeysFromNEValue(value) {
314
- const keys = /* @__PURE__ */ new Set();
315
- let node = this.leftestNode();
316
- let done = false;
317
- while (!done) {
318
- for (let i = 0, len = node.values.length; i < len; i++) {
319
- const nValue = node.values[i];
320
- const pairKeys = node.keys[i];
321
- if (this.comparator.isSame(nValue, value) === false) {
322
- for (const key of pairKeys) {
323
- keys.add(key);
324
- }
325
- }
326
- }
327
- if (!node.next) {
328
- done = true;
329
- break;
330
- }
331
- node = this.getNode(node.next);
332
- }
333
- return keys;
334
- }
335
- _getKeysFromRange(gt, lt) {
336
- const keys = /* @__PURE__ */ new Set();
337
- let node = this._insertableNode(gt);
338
- let done = false;
339
- let found = false;
340
- while (!done) {
341
- for (let i = 0, len = node.values.length; i < len; i++) {
342
- const nValue = node.values[i];
343
- const localKeys = node.keys[i];
344
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
345
- found = true;
346
- for (const key of localKeys) {
347
- keys.add(key);
348
- }
349
- } else if (found) {
350
- done = true;
351
- break;
352
- }
353
- }
354
- if (!node.next) {
355
- done = true;
356
- break;
357
- }
358
- node = this.getNode(node.next);
359
- }
360
- return keys;
361
- }
362
- _getKeysFromGt(gt) {
363
- const keys = /* @__PURE__ */ new Set();
364
- let node = this._insertableNode(gt);
365
- let done = false;
366
- let found = false;
367
- while (!done) {
368
- for (let i = 0, len = node.values.length; i < len; i++) {
369
- const nValue = node.values[i];
370
- const localKeys = node.keys[i];
371
- if (this.comparator.isHigher(nValue, gt)) {
372
- found = true;
373
- for (const key of localKeys) {
374
- keys.add(key);
375
- }
376
- } else if (found) {
377
- done = true;
378
- break;
379
- }
380
- }
381
- if (!node.next) {
382
- done = true;
383
- break;
384
- }
385
- node = this.getNode(node.next);
386
- }
387
- return keys;
388
- }
389
- _getKeysFromLt(lt) {
390
- const keys = /* @__PURE__ */ new Set();
391
- let node = this.leftestNode();
392
- let done = false;
393
- let found = false;
394
- while (!done) {
395
- for (let i = 0, len = node.values.length; i < len; i++) {
396
- const nValue = node.values[i];
397
- const localKeys = node.keys[i];
398
- if (this.comparator.isLower(nValue, lt)) {
399
- found = true;
400
- for (const key of localKeys) {
401
- keys.add(key);
402
- }
403
- } else if (found) {
404
- done = true;
405
- break;
406
- }
407
- }
408
- if (!node.next) {
409
- done = true;
410
- break;
411
- }
412
- node = this.getNode(node.next);
413
- }
414
- return keys;
415
- }
416
- _getPairsFromValue(value) {
417
- const node = this._insertableNode(value);
418
- const [start, end] = this.search.range(node.values, value);
419
- if (start === -1) {
420
- return [];
421
- }
422
- const pairs = [];
423
- for (let i = start; i < end; i++) {
424
- const keys = node.keys[i];
425
- for (const key of keys) {
426
- pairs.push({ key, value });
427
- }
428
- }
429
- return pairs;
430
- }
431
- _getPairsFromNEValue(value) {
329
+ _getPairsRightToLeft(value, startNode, fullSearch, comparator) {
432
330
  const pairs = [];
433
- let node = this.leftestNode();
434
- let done = false;
435
- while (!done) {
436
- for (let i = 0, len = node.values.length; i < len; i++) {
437
- const nValue = node.values[i];
438
- const keys = node.keys[i];
439
- if (this.comparator.isSame(nValue, value) === false) {
440
- for (const key of keys) {
441
- pairs.push({ key, value: nValue });
442
- }
443
- }
444
- }
445
- if (!node.next) {
446
- done = true;
447
- break;
448
- }
449
- node = this.getNode(node.next);
450
- }
451
- return pairs;
452
- }
453
- _getPairsFromRange(gt, lt) {
454
- const pairs = [];
455
- let node = this._insertableNode(gt);
331
+ let node = startNode;
456
332
  let done = false;
457
333
  let found = false;
458
334
  while (!done) {
459
- for (let i = 0, len = node.values.length; i < len; i++) {
335
+ let i = node.values.length;
336
+ while (i--) {
460
337
  const nValue = node.values[i];
461
338
  const keys = node.keys[i];
462
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
339
+ if (comparator(nValue, value)) {
463
340
  found = true;
464
- for (const key of keys) {
465
- pairs.push({ key, value: nValue });
341
+ let j = keys.length;
342
+ while (j--) {
343
+ pairs.push({ key: keys[j], value: nValue });
466
344
  }
467
- } else if (found) {
345
+ } else if (found && !fullSearch) {
468
346
  done = true;
469
347
  break;
470
348
  }
471
349
  }
472
- if (!node.next) {
350
+ if (!node.prev) {
473
351
  done = true;
474
352
  break;
475
353
  }
476
- node = this.getNode(node.next);
354
+ node = this.getNode(node.prev);
477
355
  }
478
- return pairs;
356
+ return pairs.reverse();
479
357
  }
480
- _getPairsFromGt(gt) {
358
+ _getPairsLeftToRight(value, startNode, fullSearch, comparator) {
481
359
  const pairs = [];
482
- let node = this._insertableNode(gt);
360
+ let node = startNode;
483
361
  let done = false;
484
362
  let found = false;
485
363
  while (!done) {
486
364
  for (let i = 0, len = node.values.length; i < len; i++) {
487
365
  const nValue = node.values[i];
488
366
  const keys = node.keys[i];
489
- if (this.comparator.isHigher(nValue, gt)) {
367
+ if (comparator(nValue, value)) {
490
368
  found = true;
491
369
  for (const key of keys) {
492
370
  pairs.push({ key, value: nValue });
493
371
  }
494
- } else if (found) {
372
+ } else if (found && !fullSearch) {
495
373
  done = true;
496
374
  break;
497
375
  }
@@ -504,75 +382,62 @@ var BPTree = class {
504
382
  }
505
383
  return pairs;
506
384
  }
507
- _getPairsFromLt(lt) {
508
- const pairs = [];
509
- let node = this.leftestNode();
510
- let done = false;
511
- let found = false;
512
- while (!done) {
513
- for (let i = 0, len = node.values.length; i < len; i++) {
514
- const nValue = node.values[i];
515
- const keys = node.keys[i];
516
- if (this.comparator.isLower(nValue, lt)) {
517
- found = true;
518
- for (const key of keys) {
519
- pairs.push({ key, value: nValue });
520
- }
521
- } else if (found) {
522
- done = true;
523
- break;
524
- }
525
- }
526
- if (!node.next) {
527
- done = true;
528
- break;
529
- }
530
- node = this.getNode(node.next);
385
+ getPairs(value, startNode, fullSearch, comparator, direction) {
386
+ switch (direction) {
387
+ case -1:
388
+ return this._getPairsRightToLeft(value, startNode, fullSearch, comparator);
389
+ case 1:
390
+ return this._getPairsLeftToRight(value, startNode, fullSearch, comparator);
391
+ default:
392
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
531
393
  }
532
- return pairs;
533
394
  }
534
395
  /**
535
396
  * It searches for a key within the tree. The result is returned as an array sorted in ascending order based on the value.
536
- * The result is key set instance, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
397
+ * The result is key set instance, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
537
398
  * This method operates much faster than first searching with `where` and then retrieving only the key list.
538
- * @param condition You can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
399
+ * @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
539
400
  */
540
401
  keys(condition) {
541
- if (this._equalCondition(condition)) {
542
- return this._getKeysFromValue(condition.equal);
543
- } else if (this._notEqualCondition(condition)) {
544
- return this._getKeysFromNEValue(condition.notEqual);
545
- } else if (this._rangeCondition(condition)) {
546
- const { gt, lt } = condition;
547
- return this._getKeysFromRange(gt, lt);
548
- } else if (this._onlyGtCondition(condition)) {
549
- return this._getKeysFromGt(condition.gt);
550
- } else if (this._onlyLtCondition(condition)) {
551
- return this._getKeysFromLt(condition.lt);
552
- } else {
553
- throw new Error(`The 'condition' parameter is invalid.`);
402
+ let result = null;
403
+ for (const k in condition) {
404
+ const key = k;
405
+ const value = condition[key];
406
+ const startNode = this._verifierStartNode[key](value);
407
+ const direction = this._verifierDirection[key];
408
+ const fullSearch = this._verifierFullSearch[key];
409
+ const comparator = this._verifierMap[key];
410
+ const pairs = this.getPairs(value, startNode, fullSearch, comparator, direction);
411
+ if (result === null) {
412
+ result = pairs.map((pair) => pair.key);
413
+ } else {
414
+ result = result.filter((key2) => pairs.find((p) => p.key === key2));
415
+ }
554
416
  }
417
+ return new Set(result ?? []);
555
418
  }
556
419
  /**
557
420
  * It searches for a value within the tree. The result is returned as an array sorted in ascending order based on the value.
558
- * The result includes the key and value attributes, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
559
- * @param condition You can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
421
+ * The result includes the key and value attributes, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
422
+ * @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
560
423
  */
561
424
  where(condition) {
562
- if (this._equalCondition(condition)) {
563
- return this._getPairsFromValue(condition.equal);
564
- } else if (this._notEqualCondition(condition)) {
565
- return this._getPairsFromNEValue(condition.notEqual);
566
- } else if (this._rangeCondition(condition)) {
567
- const { gt, lt } = condition;
568
- return this._getPairsFromRange(gt, lt);
569
- } else if (this._onlyGtCondition(condition)) {
570
- return this._getPairsFromGt(condition.gt);
571
- } else if (this._onlyLtCondition(condition)) {
572
- return this._getPairsFromLt(condition.lt);
573
- } else {
574
- throw new Error(`The 'condition' parameter is invalid.`);
425
+ let result = null;
426
+ for (const k in condition) {
427
+ const key = k;
428
+ const value = condition[key];
429
+ const startNode = this._verifierStartNode[key](value);
430
+ const direction = this._verifierDirection[key];
431
+ const fullSearch = this._verifierFullSearch[key];
432
+ const comparator = this._verifierMap[key];
433
+ const pairs = this.getPairs(value, startNode, fullSearch, comparator, direction);
434
+ if (result === null) {
435
+ result = pairs;
436
+ } else {
437
+ result = result.filter((pair) => pairs.find((p) => p.key === pair.key));
438
+ }
575
439
  }
440
+ return result ?? [];
576
441
  }
577
442
  /**
578
443
  * You enter the key and value as a pair. You can later search for the pair by value.
@@ -581,7 +446,7 @@ var BPTree = class {
581
446
  * @param value The value of the pair.
582
447
  */
583
448
  insert(key, value) {
584
- const before = this._insertableNode(value);
449
+ const before = this.insertableNode(value);
585
450
  this._insertAtLeaf(before, key, value);
586
451
  if (before.values.length === this.order) {
587
452
  const after = this._createNode(
@@ -589,14 +454,21 @@ var BPTree = class {
589
454
  [],
590
455
  true,
591
456
  before.parent,
592
- before.next
457
+ before.next,
458
+ before.id
593
459
  );
594
460
  const mid = Math.ceil(this.order / 2) - 1;
461
+ const beforeNext = before.next;
595
462
  after.values = before.values.slice(mid + 1);
596
463
  after.keys = before.keys.slice(mid + 1);
597
464
  before.values = before.values.slice(0, mid + 1);
598
465
  before.keys = before.keys.slice(0, mid + 1);
599
466
  before.next = after.id;
467
+ if (beforeNext) {
468
+ const node = this.getNode(beforeNext);
469
+ node.prev = after.id;
470
+ this._setUpdates(node);
471
+ }
600
472
  this._insertInParent(before, after.values[0], after);
601
473
  this._setCreates(after);
602
474
  this._setUpdates(before);
@@ -611,7 +483,7 @@ var BPTree = class {
611
483
  * @param value The value of the pair.
612
484
  */
613
485
  delete(key, value) {
614
- const node = this._insertableNode(value);
486
+ const node = this.insertableNode(value);
615
487
  let i = node.values.length;
616
488
  while (i--) {
617
489
  const nValue = node.values[i];
@@ -672,18 +544,18 @@ var BPTree = class {
672
544
  let parentNode = this.getNode(node.parent);
673
545
  let prevNode = null;
674
546
  let nextNode = null;
675
- let prevK = null;
676
- let postK = null;
547
+ let prevValue = null;
548
+ let postValue = null;
677
549
  for (let i = 0, len = parentNode.keys.length; i < len; i++) {
678
550
  const nKey = parentNode.keys[i];
679
551
  if (nKey === node.id) {
680
552
  if (i > 0) {
681
553
  prevNode = this.getNode(parentNode.keys[i - 1]);
682
- prevK = parentNode.values[i - 1];
554
+ prevValue = parentNode.values[i - 1];
683
555
  }
684
556
  if (i < parentNode.keys.length - 1) {
685
557
  nextNode = this.getNode(parentNode.keys[i + 1]);
686
- postK = parentNode.values[i];
558
+ postValue = parentNode.values[i];
687
559
  }
688
560
  }
689
561
  }
@@ -691,19 +563,19 @@ var BPTree = class {
691
563
  let guess;
692
564
  if (prevNode === null) {
693
565
  pointer = nextNode;
694
- guess = postK;
566
+ guess = postValue;
695
567
  } else if (nextNode === null) {
696
568
  isPredecessor = true;
697
569
  pointer = prevNode;
698
- guess = prevK;
570
+ guess = prevValue;
699
571
  } else {
700
572
  if (node.values.length + nextNode.values.length < this.order) {
701
573
  pointer = nextNode;
702
- guess = postK;
574
+ guess = postValue;
703
575
  } else {
704
576
  isPredecessor = true;
705
577
  pointer = prevNode;
706
- guess = prevK;
578
+ guess = prevValue;
707
579
  }
708
580
  }
709
581
  if (node.values.length + pointer.values.length < this.order) {
@@ -717,6 +589,20 @@ var BPTree = class {
717
589
  pointer.values.push(guess);
718
590
  } else {
719
591
  pointer.next = node.next;
592
+ pointer.prev = node.id;
593
+ if (pointer.next) {
594
+ const n = this.getNode(node.next);
595
+ n.prev = pointer.id;
596
+ this._setUpdates(n);
597
+ }
598
+ if (pointer.prev) {
599
+ const n = this.getNode(node.id);
600
+ n.next = pointer.id;
601
+ this._setUpdates(n);
602
+ }
603
+ if (isPredecessor) {
604
+ pointer.prev = 0;
605
+ }
720
606
  }
721
607
  pointer.values.push(...node.values);
722
608
  if (!pointer.leaf) {
@@ -2,14 +2,22 @@ import type { Json } from './utils/types';
2
2
  import { BinarySearch } from './utils/BinarySearch';
3
3
  import { ValueComparator } from './ValueComparator';
4
4
  import { SerializeStrategy } from './SerializeStrategy';
5
- type BPTreeCondition<V> = {
6
- gt?: V;
7
- lt?: V;
8
- } | {
5
+ type BPTreeCondition<V> = Partial<{
6
+ /** Searches for pairs greater than the given value. */
7
+ gt: V;
8
+ /** Searches for pairs less than the given value. */
9
+ lt: V;
10
+ /** Searches for pairs greater than or equal to the given value. */
11
+ gte: V;
12
+ /** Searches for pairs less than or equal to the given value. */
13
+ lte: V;
14
+ /** "Searches for pairs equal to the given value. */
9
15
  equal: V;
10
- } | {
16
+ /** Searches for pairs not equal to the given value. */
11
17
  notEqual: V;
12
- };
18
+ /** Searches for values matching the given pattern. '%' matches zero or more characters, and '_' matches exactly one character. */
19
+ like: V;
20
+ }>;
13
21
  type BPTreePair<K, V> = {
14
22
  key: K;
15
23
  value: V;
@@ -22,6 +30,7 @@ export interface BPTreeNode<K, V> {
22
30
  leaf: boolean;
23
31
  parent: number;
24
32
  next: number;
33
+ prev: number;
25
34
  }
26
35
  export interface BPTreeInternalNode<K, V> extends BPTreeNode<K, V> {
27
36
  leaf: false;
@@ -42,6 +51,10 @@ export declare class BPTree<K, V> {
42
51
  private readonly _creates;
43
52
  private readonly _updates;
44
53
  private _updatedHead;
54
+ private readonly _verifierMap;
55
+ private readonly _verifierStartNode;
56
+ private readonly _verifierDirection;
57
+ private readonly _verifierFullSearch;
45
58
  private _createNodeId;
46
59
  private _createNode;
47
60
  /**
@@ -58,7 +71,7 @@ export declare class BPTree<K, V> {
58
71
  private _emitUpdates;
59
72
  protected getNode(id: number): BPTreeUnknownNode<K, V>;
60
73
  protected leftestNode(): BPTreeLeafNode<K, V>;
61
- private _insertableNode;
74
+ protected insertableNode(value: V): BPTreeLeafNode<K, V>;
62
75
  /**
63
76
  * It returns whether there is a value in the tree.
64
77
  * @param key The key value to search for.
@@ -67,32 +80,20 @@ export declare class BPTree<K, V> {
67
80
  exists(key: K, value: V): boolean;
68
81
  private _insertAtLeaf;
69
82
  private _insertInParent;
70
- private _equalCondition;
71
- private _notEqualCondition;
72
- private _onlyGtCondition;
73
- private _onlyLtCondition;
74
- private _rangeCondition;
75
- private _getKeysFromValue;
76
- private _getKeysFromNEValue;
77
- private _getKeysFromRange;
78
- private _getKeysFromGt;
79
- private _getKeysFromLt;
80
- private _getPairsFromValue;
81
- private _getPairsFromNEValue;
82
- private _getPairsFromRange;
83
- private _getPairsFromGt;
84
- private _getPairsFromLt;
83
+ private _getPairsRightToLeft;
84
+ private _getPairsLeftToRight;
85
+ protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullSearch: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: -1 | 1): BPTreePair<K, V>[];
85
86
  /**
86
87
  * It searches for a key within the tree. The result is returned as an array sorted in ascending order based on the value.
87
- * The result is key set instance, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
88
+ * The result is key set instance, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
88
89
  * This method operates much faster than first searching with `where` and then retrieving only the key list.
89
- * @param condition You can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
90
+ * @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
90
91
  */
91
92
  keys(condition: BPTreeCondition<V>): Set<K>;
92
93
  /**
93
94
  * It searches for a value within the tree. The result is returned as an array sorted in ascending order based on the value.
94
- * The result includes the key and value attributes, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
95
- * @param condition You can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
95
+ * The result includes the key and value attributes, and you can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
96
+ * @param condition You can use the `gt`, `lt`, `gte`, `lte`, `equal`, `notEqual`, `like` condition statements.
96
97
  */
97
98
  where(condition: BPTreeCondition<V>): BPTreePair<K, V>[];
98
99
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "Store the B+tree flexibly, not only in-memory.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -17,6 +17,7 @@
17
17
  "serializable-bptree",
18
18
  "b-plus-tree",
19
19
  "serialize",
20
+ "serialization",
20
21
  "store",
21
22
  "btree",
22
23
  "bptree",