serializable-bptree 1.0.4 → 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/dist/cjs/index.js CHANGED
@@ -92,10 +92,56 @@ var BPTree = class {
92
92
  search;
93
93
  order;
94
94
  nodes;
95
+ data;
95
96
  root;
96
97
  _creates;
97
98
  _updates;
98
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
+ };
99
145
  _createNodeId() {
100
146
  const id = this.strategy.id();
101
147
  if (id === 0) {
@@ -103,7 +149,7 @@ var BPTree = class {
103
149
  }
104
150
  return id;
105
151
  }
106
- _createNode(keys, values, leaf = false, parent = 0, next = 0) {
152
+ _createNode(keys, values, leaf = false, parent = 0, next = 0, prev = 0) {
107
153
  const id = this._createNodeId();
108
154
  const node = {
109
155
  id,
@@ -111,7 +157,8 @@ var BPTree = class {
111
157
  values,
112
158
  leaf,
113
159
  parent,
114
- next
160
+ next,
161
+ prev
115
162
  };
116
163
  this.nodes.set(id, node);
117
164
  return node;
@@ -131,14 +178,16 @@ var BPTree = class {
131
178
  this.comparator = comparator;
132
179
  if (head === null) {
133
180
  this.order = strategy.order;
181
+ this.data = {};
134
182
  this.root = this._createNode([], [], true);
135
183
  this._setHeadUpdate(this._headState);
136
184
  this._setCreates(this.root);
137
185
  this._emitHeadUpdates();
138
186
  this._emitCreates();
139
187
  } else {
140
- const { root, order } = head;
188
+ const { root, order, data } = head;
141
189
  this.order = order;
190
+ this.data = data ?? {};
142
191
  this.root = this.getNode(root);
143
192
  }
144
193
  if (this.order < 3) {
@@ -148,9 +197,11 @@ var BPTree = class {
148
197
  get _headState() {
149
198
  const root = this.root.id;
150
199
  const order = this.order;
200
+ const data = this.data;
151
201
  return {
152
202
  root,
153
- order
203
+ order,
204
+ data
154
205
  };
155
206
  }
156
207
  _setHeadUpdate(head) {
@@ -194,7 +245,7 @@ var BPTree = class {
194
245
  }
195
246
  return node;
196
247
  }
197
- _insertableNode(value) {
248
+ insertableNode(value) {
198
249
  let node = this.root;
199
250
  while (!node.leaf) {
200
251
  for (let i = 0, len = node.values.length; i < len; i++) {
@@ -220,7 +271,7 @@ var BPTree = class {
220
271
  * @param value The value to search for.
221
272
  */
222
273
  exists(key, value) {
223
- const node = this._insertableNode(value);
274
+ const node = this.insertableNode(value);
224
275
  for (let i = 0, len = node.values.length; i < len; i++) {
225
276
  const nValue = node.values[i];
226
277
  if (this.comparator.isSame(value, nValue)) {
@@ -306,218 +357,50 @@ var BPTree = class {
306
357
  }
307
358
  }
308
359
  }
309
- _equalCondition(condition) {
310
- return Object.prototype.hasOwnProperty.call(condition, "equal");
311
- }
312
- _notEqualCondition(condition) {
313
- return Object.prototype.hasOwnProperty.call(condition, "notEqual");
314
- }
315
- _onlyGtCondition(condition) {
316
- return Object.prototype.hasOwnProperty.call(condition, "gt") && !Object.prototype.hasOwnProperty.call(condition, "lt");
317
- }
318
- _onlyLtCondition(condition) {
319
- return Object.prototype.hasOwnProperty.call(condition, "lt") && !Object.prototype.hasOwnProperty.call(condition, "gt");
320
- }
321
- _rangeCondition(condition) {
322
- return Object.prototype.hasOwnProperty.call(condition, "gt") && Object.prototype.hasOwnProperty.call(condition, "lt");
323
- }
324
- _getKeysFromValue(value) {
325
- const keys = /* @__PURE__ */ new Set();
326
- const node = this._insertableNode(value);
327
- const [start, end] = this.search.range(node.values, value);
328
- if (start === -1) {
329
- return keys;
330
- }
331
- for (let i = start; i < end; i++) {
332
- const pairKeys = node.keys[i];
333
- for (const key of pairKeys) {
334
- keys.add(key);
335
- }
336
- }
337
- return keys;
338
- }
339
- _getKeysFromNEValue(value) {
340
- const keys = /* @__PURE__ */ new Set();
341
- let node = this.leftestNode();
342
- let done = false;
343
- while (!done) {
344
- for (let i = 0, len = node.values.length; i < len; i++) {
345
- const nValue = node.values[i];
346
- const pairKeys = node.keys[i];
347
- if (this.comparator.isSame(nValue, value) === false) {
348
- for (const key of pairKeys) {
349
- keys.add(key);
350
- }
351
- }
352
- }
353
- if (!node.next) {
354
- done = true;
355
- break;
356
- }
357
- node = this.getNode(node.next);
358
- }
359
- return keys;
360
- }
361
- _getKeysFromRange(gt, lt) {
362
- const keys = /* @__PURE__ */ new Set();
363
- let node = this._insertableNode(gt);
364
- let done = false;
365
- let found = false;
366
- while (!done) {
367
- for (let i = 0, len = node.values.length; i < len; i++) {
368
- const nValue = node.values[i];
369
- const localKeys = node.keys[i];
370
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
371
- found = true;
372
- for (const key of localKeys) {
373
- keys.add(key);
374
- }
375
- } else if (found) {
376
- done = true;
377
- break;
378
- }
379
- }
380
- if (!node.next) {
381
- done = true;
382
- break;
383
- }
384
- node = this.getNode(node.next);
385
- }
386
- return keys;
387
- }
388
- _getKeysFromGt(gt) {
389
- const keys = /* @__PURE__ */ new Set();
390
- let node = this._insertableNode(gt);
391
- let done = false;
392
- let found = false;
393
- while (!done) {
394
- for (let i = 0, len = node.values.length; i < len; i++) {
395
- const nValue = node.values[i];
396
- const localKeys = node.keys[i];
397
- if (this.comparator.isHigher(nValue, gt)) {
398
- found = true;
399
- for (const key of localKeys) {
400
- keys.add(key);
401
- }
402
- } else if (found) {
403
- done = true;
404
- break;
405
- }
406
- }
407
- if (!node.next) {
408
- done = true;
409
- break;
410
- }
411
- node = this.getNode(node.next);
412
- }
413
- return keys;
414
- }
415
- _getKeysFromLt(lt) {
416
- const keys = /* @__PURE__ */ new Set();
417
- let node = this.leftestNode();
418
- let done = false;
419
- let found = false;
420
- while (!done) {
421
- for (let i = 0, len = node.values.length; i < len; i++) {
422
- const nValue = node.values[i];
423
- const localKeys = node.keys[i];
424
- if (this.comparator.isLower(nValue, lt)) {
425
- found = true;
426
- for (const key of localKeys) {
427
- keys.add(key);
428
- }
429
- } else if (found) {
430
- done = true;
431
- break;
432
- }
433
- }
434
- if (!node.next) {
435
- done = true;
436
- break;
437
- }
438
- node = this.getNode(node.next);
439
- }
440
- return keys;
441
- }
442
- _getPairsFromValue(value) {
443
- const node = this._insertableNode(value);
444
- const [start, end] = this.search.range(node.values, value);
445
- if (start === -1) {
446
- return [];
447
- }
448
- const pairs = [];
449
- for (let i = start; i < end; i++) {
450
- const keys = node.keys[i];
451
- for (const key of keys) {
452
- pairs.push({ key, value });
453
- }
454
- }
455
- return pairs;
456
- }
457
- _getPairsFromNEValue(value) {
360
+ _getPairsRightToLeft(value, startNode, fullSearch, comparator) {
458
361
  const pairs = [];
459
- let node = this.leftestNode();
460
- let done = false;
461
- while (!done) {
462
- for (let i = 0, len = node.values.length; i < len; i++) {
463
- const nValue = node.values[i];
464
- const keys = node.keys[i];
465
- if (this.comparator.isSame(nValue, value) === false) {
466
- for (const key of keys) {
467
- pairs.push({ key, value: nValue });
468
- }
469
- }
470
- }
471
- if (!node.next) {
472
- done = true;
473
- break;
474
- }
475
- node = this.getNode(node.next);
476
- }
477
- return pairs;
478
- }
479
- _getPairsFromRange(gt, lt) {
480
- const pairs = [];
481
- let node = this._insertableNode(gt);
362
+ let node = startNode;
482
363
  let done = false;
483
364
  let found = false;
484
365
  while (!done) {
485
- for (let i = 0, len = node.values.length; i < len; i++) {
366
+ let i = node.values.length;
367
+ while (i--) {
486
368
  const nValue = node.values[i];
487
369
  const keys = node.keys[i];
488
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
370
+ if (comparator(nValue, value)) {
489
371
  found = true;
490
- for (const key of keys) {
491
- pairs.push({ key, value: nValue });
372
+ let j = keys.length;
373
+ while (j--) {
374
+ pairs.push({ key: keys[j], value: nValue });
492
375
  }
493
- } else if (found) {
376
+ } else if (found && !fullSearch) {
494
377
  done = true;
495
378
  break;
496
379
  }
497
380
  }
498
- if (!node.next) {
381
+ if (!node.prev) {
499
382
  done = true;
500
383
  break;
501
384
  }
502
- node = this.getNode(node.next);
385
+ node = this.getNode(node.prev);
503
386
  }
504
- return pairs;
387
+ return pairs.reverse();
505
388
  }
506
- _getPairsFromGt(gt) {
389
+ _getPairsLeftToRight(value, startNode, fullSearch, comparator) {
507
390
  const pairs = [];
508
- let node = this._insertableNode(gt);
391
+ let node = startNode;
509
392
  let done = false;
510
393
  let found = false;
511
394
  while (!done) {
512
395
  for (let i = 0, len = node.values.length; i < len; i++) {
513
396
  const nValue = node.values[i];
514
397
  const keys = node.keys[i];
515
- if (this.comparator.isHigher(nValue, gt)) {
398
+ if (comparator(nValue, value)) {
516
399
  found = true;
517
400
  for (const key of keys) {
518
401
  pairs.push({ key, value: nValue });
519
402
  }
520
- } else if (found) {
403
+ } else if (found && !fullSearch) {
521
404
  done = true;
522
405
  break;
523
406
  }
@@ -530,75 +413,62 @@ var BPTree = class {
530
413
  }
531
414
  return pairs;
532
415
  }
533
- _getPairsFromLt(lt) {
534
- const pairs = [];
535
- let node = this.leftestNode();
536
- let done = false;
537
- let found = false;
538
- while (!done) {
539
- for (let i = 0, len = node.values.length; i < len; i++) {
540
- const nValue = node.values[i];
541
- const keys = node.keys[i];
542
- if (this.comparator.isLower(nValue, lt)) {
543
- found = true;
544
- for (const key of keys) {
545
- pairs.push({ key, value: nValue });
546
- }
547
- } else if (found) {
548
- done = true;
549
- break;
550
- }
551
- }
552
- if (!node.next) {
553
- done = true;
554
- break;
555
- }
556
- 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}`);
557
424
  }
558
- return pairs;
559
425
  }
560
426
  /**
561
427
  * It searches for a key within the tree. The result is returned as an array sorted in ascending order based on the value.
562
- * 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.
563
429
  * This method operates much faster than first searching with `where` and then retrieving only the key list.
564
- * @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.
565
431
  */
566
432
  keys(condition) {
567
- if (this._equalCondition(condition)) {
568
- return this._getKeysFromValue(condition.equal);
569
- } else if (this._notEqualCondition(condition)) {
570
- return this._getKeysFromNEValue(condition.notEqual);
571
- } else if (this._rangeCondition(condition)) {
572
- const { gt, lt } = condition;
573
- return this._getKeysFromRange(gt, lt);
574
- } else if (this._onlyGtCondition(condition)) {
575
- return this._getKeysFromGt(condition.gt);
576
- } else if (this._onlyLtCondition(condition)) {
577
- return this._getKeysFromLt(condition.lt);
578
- } else {
579
- 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
+ }
580
447
  }
448
+ return new Set(result ?? []);
581
449
  }
582
450
  /**
583
451
  * It searches for a value within the tree. The result is returned as an array sorted in ascending order based on the value.
584
- * The result includes the key and value attributes, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
585
- * @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.
586
454
  */
587
455
  where(condition) {
588
- if (this._equalCondition(condition)) {
589
- return this._getPairsFromValue(condition.equal);
590
- } else if (this._notEqualCondition(condition)) {
591
- return this._getPairsFromNEValue(condition.notEqual);
592
- } else if (this._rangeCondition(condition)) {
593
- const { gt, lt } = condition;
594
- return this._getPairsFromRange(gt, lt);
595
- } else if (this._onlyGtCondition(condition)) {
596
- return this._getPairsFromGt(condition.gt);
597
- } else if (this._onlyLtCondition(condition)) {
598
- return this._getPairsFromLt(condition.lt);
599
- } else {
600
- 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
+ }
601
470
  }
471
+ return result ?? [];
602
472
  }
603
473
  /**
604
474
  * You enter the key and value as a pair. You can later search for the pair by value.
@@ -607,7 +477,7 @@ var BPTree = class {
607
477
  * @param value The value of the pair.
608
478
  */
609
479
  insert(key, value) {
610
- const before = this._insertableNode(value);
480
+ const before = this.insertableNode(value);
611
481
  this._insertAtLeaf(before, key, value);
612
482
  if (before.values.length === this.order) {
613
483
  const after = this._createNode(
@@ -615,14 +485,21 @@ var BPTree = class {
615
485
  [],
616
486
  true,
617
487
  before.parent,
618
- before.next
488
+ before.next,
489
+ before.id
619
490
  );
620
491
  const mid = Math.ceil(this.order / 2) - 1;
492
+ const beforeNext = before.next;
621
493
  after.values = before.values.slice(mid + 1);
622
494
  after.keys = before.keys.slice(mid + 1);
623
495
  before.values = before.values.slice(0, mid + 1);
624
496
  before.keys = before.keys.slice(0, mid + 1);
625
497
  before.next = after.id;
498
+ if (beforeNext) {
499
+ const node = this.getNode(beforeNext);
500
+ node.prev = after.id;
501
+ this._setUpdates(node);
502
+ }
626
503
  this._insertInParent(before, after.values[0], after);
627
504
  this._setCreates(after);
628
505
  this._setUpdates(before);
@@ -637,7 +514,7 @@ var BPTree = class {
637
514
  * @param value The value of the pair.
638
515
  */
639
516
  delete(key, value) {
640
- const node = this._insertableNode(value);
517
+ const node = this.insertableNode(value);
641
518
  let i = node.values.length;
642
519
  while (i--) {
643
520
  const nValue = node.values[i];
@@ -698,18 +575,18 @@ var BPTree = class {
698
575
  let parentNode = this.getNode(node.parent);
699
576
  let prevNode = null;
700
577
  let nextNode = null;
701
- let prevK = null;
702
- let postK = null;
578
+ let prevValue = null;
579
+ let postValue = null;
703
580
  for (let i = 0, len = parentNode.keys.length; i < len; i++) {
704
581
  const nKey = parentNode.keys[i];
705
582
  if (nKey === node.id) {
706
583
  if (i > 0) {
707
584
  prevNode = this.getNode(parentNode.keys[i - 1]);
708
- prevK = parentNode.values[i - 1];
585
+ prevValue = parentNode.values[i - 1];
709
586
  }
710
587
  if (i < parentNode.keys.length - 1) {
711
588
  nextNode = this.getNode(parentNode.keys[i + 1]);
712
- postK = parentNode.values[i];
589
+ postValue = parentNode.values[i];
713
590
  }
714
591
  }
715
592
  }
@@ -717,19 +594,19 @@ var BPTree = class {
717
594
  let guess;
718
595
  if (prevNode === null) {
719
596
  pointer = nextNode;
720
- guess = postK;
597
+ guess = postValue;
721
598
  } else if (nextNode === null) {
722
599
  isPredecessor = true;
723
600
  pointer = prevNode;
724
- guess = prevK;
601
+ guess = prevValue;
725
602
  } else {
726
603
  if (node.values.length + nextNode.values.length < this.order) {
727
604
  pointer = nextNode;
728
- guess = postK;
605
+ guess = postValue;
729
606
  } else {
730
607
  isPredecessor = true;
731
608
  pointer = prevNode;
732
- guess = prevK;
609
+ guess = prevValue;
733
610
  }
734
611
  }
735
612
  if (node.values.length + pointer.values.length < this.order) {
@@ -743,6 +620,20 @@ var BPTree = class {
743
620
  pointer.values.push(guess);
744
621
  } else {
745
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
+ }
746
637
  }
747
638
  pointer.values.push(...node.values);
748
639
  if (!pointer.leaf) {
@@ -849,6 +740,25 @@ var BPTree = class {
849
740
  }
850
741
  }
851
742
  }
743
+ /**
744
+ * Returns the user-defined data stored in the head of the tree.
745
+ * This value can be set using the `setHeadData` method. If no data has been previously inserted, the default value is returned, and the default value is `{}`.
746
+ * @returns User-defined data stored in the head of the tree.
747
+ */
748
+ getHeadData() {
749
+ return this.data;
750
+ }
751
+ /**
752
+ * Inserts user-defined data into the head of the tree.
753
+ * This feature is useful when you need to store separate, non-volatile information in the tree.
754
+ * For example, you can store information such as the last update time and the number of insertions.
755
+ * @param data User-defined data to be stored in the head of the tree.
756
+ */
757
+ setHeadData(data) {
758
+ this.data = data;
759
+ this._updatedHead = this._headState;
760
+ this._emitHeadUpdates();
761
+ }
852
762
  };
853
763
 
854
764
  // src/SerializeStrategy.ts