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/esm/index.js CHANGED
@@ -61,10 +61,56 @@ var BPTree = class {
61
61
  search;
62
62
  order;
63
63
  nodes;
64
+ data;
64
65
  root;
65
66
  _creates;
66
67
  _updates;
67
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
+ };
68
114
  _createNodeId() {
69
115
  const id = this.strategy.id();
70
116
  if (id === 0) {
@@ -72,7 +118,7 @@ var BPTree = class {
72
118
  }
73
119
  return id;
74
120
  }
75
- _createNode(keys, values, leaf = false, parent = 0, next = 0) {
121
+ _createNode(keys, values, leaf = false, parent = 0, next = 0, prev = 0) {
76
122
  const id = this._createNodeId();
77
123
  const node = {
78
124
  id,
@@ -80,7 +126,8 @@ var BPTree = class {
80
126
  values,
81
127
  leaf,
82
128
  parent,
83
- next
129
+ next,
130
+ prev
84
131
  };
85
132
  this.nodes.set(id, node);
86
133
  return node;
@@ -100,14 +147,16 @@ var BPTree = class {
100
147
  this.comparator = comparator;
101
148
  if (head === null) {
102
149
  this.order = strategy.order;
150
+ this.data = {};
103
151
  this.root = this._createNode([], [], true);
104
152
  this._setHeadUpdate(this._headState);
105
153
  this._setCreates(this.root);
106
154
  this._emitHeadUpdates();
107
155
  this._emitCreates();
108
156
  } else {
109
- const { root, order } = head;
157
+ const { root, order, data } = head;
110
158
  this.order = order;
159
+ this.data = data ?? {};
111
160
  this.root = this.getNode(root);
112
161
  }
113
162
  if (this.order < 3) {
@@ -117,9 +166,11 @@ var BPTree = class {
117
166
  get _headState() {
118
167
  const root = this.root.id;
119
168
  const order = this.order;
169
+ const data = this.data;
120
170
  return {
121
171
  root,
122
- order
172
+ order,
173
+ data
123
174
  };
124
175
  }
125
176
  _setHeadUpdate(head) {
@@ -163,7 +214,7 @@ var BPTree = class {
163
214
  }
164
215
  return node;
165
216
  }
166
- _insertableNode(value) {
217
+ insertableNode(value) {
167
218
  let node = this.root;
168
219
  while (!node.leaf) {
169
220
  for (let i = 0, len = node.values.length; i < len; i++) {
@@ -189,7 +240,7 @@ var BPTree = class {
189
240
  * @param value The value to search for.
190
241
  */
191
242
  exists(key, value) {
192
- const node = this._insertableNode(value);
243
+ const node = this.insertableNode(value);
193
244
  for (let i = 0, len = node.values.length; i < len; i++) {
194
245
  const nValue = node.values[i];
195
246
  if (this.comparator.isSame(value, nValue)) {
@@ -275,218 +326,50 @@ var BPTree = class {
275
326
  }
276
327
  }
277
328
  }
278
- _equalCondition(condition) {
279
- return Object.prototype.hasOwnProperty.call(condition, "equal");
280
- }
281
- _notEqualCondition(condition) {
282
- return Object.prototype.hasOwnProperty.call(condition, "notEqual");
283
- }
284
- _onlyGtCondition(condition) {
285
- return Object.prototype.hasOwnProperty.call(condition, "gt") && !Object.prototype.hasOwnProperty.call(condition, "lt");
286
- }
287
- _onlyLtCondition(condition) {
288
- return Object.prototype.hasOwnProperty.call(condition, "lt") && !Object.prototype.hasOwnProperty.call(condition, "gt");
289
- }
290
- _rangeCondition(condition) {
291
- return Object.prototype.hasOwnProperty.call(condition, "gt") && Object.prototype.hasOwnProperty.call(condition, "lt");
292
- }
293
- _getKeysFromValue(value) {
294
- const keys = /* @__PURE__ */ new Set();
295
- const node = this._insertableNode(value);
296
- const [start, end] = this.search.range(node.values, value);
297
- if (start === -1) {
298
- return keys;
299
- }
300
- for (let i = start; i < end; i++) {
301
- const pairKeys = node.keys[i];
302
- for (const key of pairKeys) {
303
- keys.add(key);
304
- }
305
- }
306
- return keys;
307
- }
308
- _getKeysFromNEValue(value) {
309
- const keys = /* @__PURE__ */ new Set();
310
- let node = this.leftestNode();
311
- let done = false;
312
- while (!done) {
313
- for (let i = 0, len = node.values.length; i < len; i++) {
314
- const nValue = node.values[i];
315
- const pairKeys = node.keys[i];
316
- if (this.comparator.isSame(nValue, value) === false) {
317
- for (const key of pairKeys) {
318
- keys.add(key);
319
- }
320
- }
321
- }
322
- if (!node.next) {
323
- done = true;
324
- break;
325
- }
326
- node = this.getNode(node.next);
327
- }
328
- return keys;
329
- }
330
- _getKeysFromRange(gt, lt) {
331
- const keys = /* @__PURE__ */ new Set();
332
- let node = this._insertableNode(gt);
333
- let done = false;
334
- let found = false;
335
- while (!done) {
336
- for (let i = 0, len = node.values.length; i < len; i++) {
337
- const nValue = node.values[i];
338
- const localKeys = node.keys[i];
339
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
340
- found = true;
341
- for (const key of localKeys) {
342
- keys.add(key);
343
- }
344
- } else if (found) {
345
- done = true;
346
- break;
347
- }
348
- }
349
- if (!node.next) {
350
- done = true;
351
- break;
352
- }
353
- node = this.getNode(node.next);
354
- }
355
- return keys;
356
- }
357
- _getKeysFromGt(gt) {
358
- const keys = /* @__PURE__ */ new Set();
359
- let node = this._insertableNode(gt);
360
- let done = false;
361
- let found = false;
362
- while (!done) {
363
- for (let i = 0, len = node.values.length; i < len; i++) {
364
- const nValue = node.values[i];
365
- const localKeys = node.keys[i];
366
- if (this.comparator.isHigher(nValue, gt)) {
367
- found = true;
368
- for (const key of localKeys) {
369
- keys.add(key);
370
- }
371
- } else if (found) {
372
- done = true;
373
- break;
374
- }
375
- }
376
- if (!node.next) {
377
- done = true;
378
- break;
379
- }
380
- node = this.getNode(node.next);
381
- }
382
- return keys;
383
- }
384
- _getKeysFromLt(lt) {
385
- const keys = /* @__PURE__ */ new Set();
386
- let node = this.leftestNode();
387
- let done = false;
388
- let found = false;
389
- while (!done) {
390
- for (let i = 0, len = node.values.length; i < len; i++) {
391
- const nValue = node.values[i];
392
- const localKeys = node.keys[i];
393
- if (this.comparator.isLower(nValue, lt)) {
394
- found = true;
395
- for (const key of localKeys) {
396
- keys.add(key);
397
- }
398
- } else if (found) {
399
- done = true;
400
- break;
401
- }
402
- }
403
- if (!node.next) {
404
- done = true;
405
- break;
406
- }
407
- node = this.getNode(node.next);
408
- }
409
- return keys;
410
- }
411
- _getPairsFromValue(value) {
412
- const node = this._insertableNode(value);
413
- const [start, end] = this.search.range(node.values, value);
414
- if (start === -1) {
415
- return [];
416
- }
417
- const pairs = [];
418
- for (let i = start; i < end; i++) {
419
- const keys = node.keys[i];
420
- for (const key of keys) {
421
- pairs.push({ key, value });
422
- }
423
- }
424
- return pairs;
425
- }
426
- _getPairsFromNEValue(value) {
329
+ _getPairsRightToLeft(value, startNode, fullSearch, comparator) {
427
330
  const pairs = [];
428
- let node = this.leftestNode();
429
- let done = false;
430
- while (!done) {
431
- for (let i = 0, len = node.values.length; i < len; i++) {
432
- const nValue = node.values[i];
433
- const keys = node.keys[i];
434
- if (this.comparator.isSame(nValue, value) === false) {
435
- for (const key of keys) {
436
- pairs.push({ key, value: nValue });
437
- }
438
- }
439
- }
440
- if (!node.next) {
441
- done = true;
442
- break;
443
- }
444
- node = this.getNode(node.next);
445
- }
446
- return pairs;
447
- }
448
- _getPairsFromRange(gt, lt) {
449
- const pairs = [];
450
- let node = this._insertableNode(gt);
331
+ let node = startNode;
451
332
  let done = false;
452
333
  let found = false;
453
334
  while (!done) {
454
- for (let i = 0, len = node.values.length; i < len; i++) {
335
+ let i = node.values.length;
336
+ while (i--) {
455
337
  const nValue = node.values[i];
456
338
  const keys = node.keys[i];
457
- if (this.comparator.isHigher(nValue, gt) && this.comparator.isLower(nValue, lt)) {
339
+ if (comparator(nValue, value)) {
458
340
  found = true;
459
- for (const key of keys) {
460
- pairs.push({ key, value: nValue });
341
+ let j = keys.length;
342
+ while (j--) {
343
+ pairs.push({ key: keys[j], value: nValue });
461
344
  }
462
- } else if (found) {
345
+ } else if (found && !fullSearch) {
463
346
  done = true;
464
347
  break;
465
348
  }
466
349
  }
467
- if (!node.next) {
350
+ if (!node.prev) {
468
351
  done = true;
469
352
  break;
470
353
  }
471
- node = this.getNode(node.next);
354
+ node = this.getNode(node.prev);
472
355
  }
473
- return pairs;
356
+ return pairs.reverse();
474
357
  }
475
- _getPairsFromGt(gt) {
358
+ _getPairsLeftToRight(value, startNode, fullSearch, comparator) {
476
359
  const pairs = [];
477
- let node = this._insertableNode(gt);
360
+ let node = startNode;
478
361
  let done = false;
479
362
  let found = false;
480
363
  while (!done) {
481
364
  for (let i = 0, len = node.values.length; i < len; i++) {
482
365
  const nValue = node.values[i];
483
366
  const keys = node.keys[i];
484
- if (this.comparator.isHigher(nValue, gt)) {
367
+ if (comparator(nValue, value)) {
485
368
  found = true;
486
369
  for (const key of keys) {
487
370
  pairs.push({ key, value: nValue });
488
371
  }
489
- } else if (found) {
372
+ } else if (found && !fullSearch) {
490
373
  done = true;
491
374
  break;
492
375
  }
@@ -499,75 +382,62 @@ var BPTree = class {
499
382
  }
500
383
  return pairs;
501
384
  }
502
- _getPairsFromLt(lt) {
503
- const pairs = [];
504
- let node = this.leftestNode();
505
- let done = false;
506
- let found = false;
507
- while (!done) {
508
- for (let i = 0, len = node.values.length; i < len; i++) {
509
- const nValue = node.values[i];
510
- const keys = node.keys[i];
511
- if (this.comparator.isLower(nValue, lt)) {
512
- found = true;
513
- for (const key of keys) {
514
- pairs.push({ key, value: nValue });
515
- }
516
- } else if (found) {
517
- done = true;
518
- break;
519
- }
520
- }
521
- if (!node.next) {
522
- done = true;
523
- break;
524
- }
525
- 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}`);
526
393
  }
527
- return pairs;
528
394
  }
529
395
  /**
530
396
  * It searches for a key within the tree. The result is returned as an array sorted in ascending order based on the value.
531
- * 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.
532
398
  * This method operates much faster than first searching with `where` and then retrieving only the key list.
533
- * @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.
534
400
  */
535
401
  keys(condition) {
536
- if (this._equalCondition(condition)) {
537
- return this._getKeysFromValue(condition.equal);
538
- } else if (this._notEqualCondition(condition)) {
539
- return this._getKeysFromNEValue(condition.notEqual);
540
- } else if (this._rangeCondition(condition)) {
541
- const { gt, lt } = condition;
542
- return this._getKeysFromRange(gt, lt);
543
- } else if (this._onlyGtCondition(condition)) {
544
- return this._getKeysFromGt(condition.gt);
545
- } else if (this._onlyLtCondition(condition)) {
546
- return this._getKeysFromLt(condition.lt);
547
- } else {
548
- 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
+ }
549
416
  }
417
+ return new Set(result ?? []);
550
418
  }
551
419
  /**
552
420
  * It searches for a value within the tree. The result is returned as an array sorted in ascending order based on the value.
553
- * The result includes the key and value attributes, and you can use the `gt`, `lt`, `equal`, `notEqual` condition statements.
554
- * @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.
555
423
  */
556
424
  where(condition) {
557
- if (this._equalCondition(condition)) {
558
- return this._getPairsFromValue(condition.equal);
559
- } else if (this._notEqualCondition(condition)) {
560
- return this._getPairsFromNEValue(condition.notEqual);
561
- } else if (this._rangeCondition(condition)) {
562
- const { gt, lt } = condition;
563
- return this._getPairsFromRange(gt, lt);
564
- } else if (this._onlyGtCondition(condition)) {
565
- return this._getPairsFromGt(condition.gt);
566
- } else if (this._onlyLtCondition(condition)) {
567
- return this._getPairsFromLt(condition.lt);
568
- } else {
569
- 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
+ }
570
439
  }
440
+ return result ?? [];
571
441
  }
572
442
  /**
573
443
  * You enter the key and value as a pair. You can later search for the pair by value.
@@ -576,7 +446,7 @@ var BPTree = class {
576
446
  * @param value The value of the pair.
577
447
  */
578
448
  insert(key, value) {
579
- const before = this._insertableNode(value);
449
+ const before = this.insertableNode(value);
580
450
  this._insertAtLeaf(before, key, value);
581
451
  if (before.values.length === this.order) {
582
452
  const after = this._createNode(
@@ -584,14 +454,21 @@ var BPTree = class {
584
454
  [],
585
455
  true,
586
456
  before.parent,
587
- before.next
457
+ before.next,
458
+ before.id
588
459
  );
589
460
  const mid = Math.ceil(this.order / 2) - 1;
461
+ const beforeNext = before.next;
590
462
  after.values = before.values.slice(mid + 1);
591
463
  after.keys = before.keys.slice(mid + 1);
592
464
  before.values = before.values.slice(0, mid + 1);
593
465
  before.keys = before.keys.slice(0, mid + 1);
594
466
  before.next = after.id;
467
+ if (beforeNext) {
468
+ const node = this.getNode(beforeNext);
469
+ node.prev = after.id;
470
+ this._setUpdates(node);
471
+ }
595
472
  this._insertInParent(before, after.values[0], after);
596
473
  this._setCreates(after);
597
474
  this._setUpdates(before);
@@ -606,7 +483,7 @@ var BPTree = class {
606
483
  * @param value The value of the pair.
607
484
  */
608
485
  delete(key, value) {
609
- const node = this._insertableNode(value);
486
+ const node = this.insertableNode(value);
610
487
  let i = node.values.length;
611
488
  while (i--) {
612
489
  const nValue = node.values[i];
@@ -667,18 +544,18 @@ var BPTree = class {
667
544
  let parentNode = this.getNode(node.parent);
668
545
  let prevNode = null;
669
546
  let nextNode = null;
670
- let prevK = null;
671
- let postK = null;
547
+ let prevValue = null;
548
+ let postValue = null;
672
549
  for (let i = 0, len = parentNode.keys.length; i < len; i++) {
673
550
  const nKey = parentNode.keys[i];
674
551
  if (nKey === node.id) {
675
552
  if (i > 0) {
676
553
  prevNode = this.getNode(parentNode.keys[i - 1]);
677
- prevK = parentNode.values[i - 1];
554
+ prevValue = parentNode.values[i - 1];
678
555
  }
679
556
  if (i < parentNode.keys.length - 1) {
680
557
  nextNode = this.getNode(parentNode.keys[i + 1]);
681
- postK = parentNode.values[i];
558
+ postValue = parentNode.values[i];
682
559
  }
683
560
  }
684
561
  }
@@ -686,19 +563,19 @@ var BPTree = class {
686
563
  let guess;
687
564
  if (prevNode === null) {
688
565
  pointer = nextNode;
689
- guess = postK;
566
+ guess = postValue;
690
567
  } else if (nextNode === null) {
691
568
  isPredecessor = true;
692
569
  pointer = prevNode;
693
- guess = prevK;
570
+ guess = prevValue;
694
571
  } else {
695
572
  if (node.values.length + nextNode.values.length < this.order) {
696
573
  pointer = nextNode;
697
- guess = postK;
574
+ guess = postValue;
698
575
  } else {
699
576
  isPredecessor = true;
700
577
  pointer = prevNode;
701
- guess = prevK;
578
+ guess = prevValue;
702
579
  }
703
580
  }
704
581
  if (node.values.length + pointer.values.length < this.order) {
@@ -712,6 +589,20 @@ var BPTree = class {
712
589
  pointer.values.push(guess);
713
590
  } else {
714
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
+ }
715
606
  }
716
607
  pointer.values.push(...node.values);
717
608
  if (!pointer.leaf) {
@@ -818,6 +709,25 @@ var BPTree = class {
818
709
  }
819
710
  }
820
711
  }
712
+ /**
713
+ * Returns the user-defined data stored in the head of the tree.
714
+ * 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 `{}`.
715
+ * @returns User-defined data stored in the head of the tree.
716
+ */
717
+ getHeadData() {
718
+ return this.data;
719
+ }
720
+ /**
721
+ * Inserts user-defined data into the head of the tree.
722
+ * This feature is useful when you need to store separate, non-volatile information in the tree.
723
+ * For example, you can store information such as the last update time and the number of insertions.
724
+ * @param data User-defined data to be stored in the head of the tree.
725
+ */
726
+ setHeadData(data) {
727
+ this.data = data;
728
+ this._updatedHead = this._headState;
729
+ this._emitHeadUpdates();
730
+ }
821
731
  };
822
732
 
823
733
  // src/SerializeStrategy.ts