serializable-bptree 5.1.0 → 5.1.2

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
@@ -64,6 +64,8 @@ tree.where({ gt: 1 }) // Map([{ key: 'c', value: 3 }])
64
64
  tree.where({ lt: 2 }) // Map([{ key: 'a', value: 1 }])
65
65
  tree.where({ gt: 0, lt: 4 }) // Map([{ key: 'a', value: 1 }, { key: 'c', value: 3 }])
66
66
  tree.where({ or: [3, 1] }) // Map([{ key: 'a', value: 1 }, { key: 'c', value: 3 }])
67
+
68
+ tree.clear()
67
69
  ```
68
70
 
69
71
  ## Why use a `serializable-bptree`?
@@ -461,6 +463,8 @@ await tree.where({ equal: 1 }) // Map([{ key: 'a', value: 1 }])
461
463
  await tree.where({ gt: 1 }) // Map([{ key: 'c', value: 3 }])
462
464
  await tree.where({ lt: 2 }) // Map([{ key: 'a', value: 1 }])
463
465
  await tree.where({ gt: 0, lt: 4 }) // Map([{ key: 'a', value: 1 }, { key: 'c', value: 3 }])
466
+
467
+ tree.clear()
464
468
  ```
465
469
 
466
470
  The implementation method for asynchronous operations is not significantly different. The **-Async** suffix is used instead of the **-Sync** suffix in the **BPTree** and **SerializeStrategy** classes. The only difference is that the methods become asynchronous. The **ValueComparator** class and similar value comparators do not use asynchronous operations.
@@ -61,16 +61,167 @@ var StringComparator = class extends ValueComparator {
61
61
  }
62
62
  };
63
63
 
64
- // src/utils/InvertedWeakMap.ts
64
+ // node_modules/cache-entanglement/dist/esm/index.mjs
65
+ var __create = Object.create;
66
+ var __defProp2 = Object.defineProperty;
67
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
68
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
69
+ var __getProtoOf = Object.getPrototypeOf;
70
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
71
+ var __commonJS = (cb, mod) => function __require() {
72
+ return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
73
+ };
74
+ var __copyProps2 = (to, from, except, desc) => {
75
+ if (from && typeof from === "object" || typeof from === "function") {
76
+ for (let key of __getOwnPropNames2(from))
77
+ if (!__hasOwnProp2.call(to, key) && key !== except)
78
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
79
+ }
80
+ return to;
81
+ };
82
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps2(
83
+ // If the importer is in node compatibility mode or this is not an ESM
84
+ // file that has been converted to a CommonJS file using a Babel-
85
+ // compatible transform (i.e. "__esModule" has not been set), then set
86
+ // "default" to the CommonJS "module.exports" for node compatibility.
87
+ isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
88
+ mod
89
+ ));
90
+ var require_ms = __commonJS({
91
+ "node_modules/ms/index.js"(exports, module2) {
92
+ var s = 1e3;
93
+ var m = s * 60;
94
+ var h = m * 60;
95
+ var d = h * 24;
96
+ var w = d * 7;
97
+ var y = d * 365.25;
98
+ module2.exports = function(val, options) {
99
+ options = options || {};
100
+ var type = typeof val;
101
+ if (type === "string" && val.length > 0) {
102
+ return parse(val);
103
+ } else if (type === "number" && isFinite(val)) {
104
+ return options.long ? fmtLong(val) : fmtShort(val);
105
+ }
106
+ throw new Error(
107
+ "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
108
+ );
109
+ };
110
+ function parse(str) {
111
+ str = String(str);
112
+ if (str.length > 100) {
113
+ return;
114
+ }
115
+ var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
116
+ str
117
+ );
118
+ if (!match) {
119
+ return;
120
+ }
121
+ var n = parseFloat(match[1]);
122
+ var type = (match[2] || "ms").toLowerCase();
123
+ switch (type) {
124
+ case "years":
125
+ case "year":
126
+ case "yrs":
127
+ case "yr":
128
+ case "y":
129
+ return n * y;
130
+ case "weeks":
131
+ case "week":
132
+ case "w":
133
+ return n * w;
134
+ case "days":
135
+ case "day":
136
+ case "d":
137
+ return n * d;
138
+ case "hours":
139
+ case "hour":
140
+ case "hrs":
141
+ case "hr":
142
+ case "h":
143
+ return n * h;
144
+ case "minutes":
145
+ case "minute":
146
+ case "mins":
147
+ case "min":
148
+ case "m":
149
+ return n * m;
150
+ case "seconds":
151
+ case "second":
152
+ case "secs":
153
+ case "sec":
154
+ case "s":
155
+ return n * s;
156
+ case "milliseconds":
157
+ case "millisecond":
158
+ case "msecs":
159
+ case "msec":
160
+ case "ms":
161
+ return n;
162
+ default:
163
+ return void 0;
164
+ }
165
+ }
166
+ function fmtShort(ms2) {
167
+ var msAbs = Math.abs(ms2);
168
+ if (msAbs >= d) {
169
+ return Math.round(ms2 / d) + "d";
170
+ }
171
+ if (msAbs >= h) {
172
+ return Math.round(ms2 / h) + "h";
173
+ }
174
+ if (msAbs >= m) {
175
+ return Math.round(ms2 / m) + "m";
176
+ }
177
+ if (msAbs >= s) {
178
+ return Math.round(ms2 / s) + "s";
179
+ }
180
+ return ms2 + "ms";
181
+ }
182
+ function fmtLong(ms2) {
183
+ var msAbs = Math.abs(ms2);
184
+ if (msAbs >= d) {
185
+ return plural(ms2, msAbs, d, "day");
186
+ }
187
+ if (msAbs >= h) {
188
+ return plural(ms2, msAbs, h, "hour");
189
+ }
190
+ if (msAbs >= m) {
191
+ return plural(ms2, msAbs, m, "minute");
192
+ }
193
+ if (msAbs >= s) {
194
+ return plural(ms2, msAbs, s, "second");
195
+ }
196
+ return ms2 + " ms";
197
+ }
198
+ function plural(ms2, msAbs, n, name) {
199
+ var isPlural = msAbs >= n * 1.5;
200
+ return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
201
+ }
202
+ }
203
+ });
204
+ var import_ms = __toESM(require_ms());
65
205
  var InvertedWeakMap = class {
66
206
  _map;
207
+ _keepAlive;
208
+ _timeouts;
67
209
  _registry;
68
- constructor() {
210
+ _lifespan;
211
+ constructor(option) {
212
+ const { lifespan } = option;
213
+ this._lifespan = lifespan;
69
214
  this._map = /* @__PURE__ */ new Map();
70
- this._registry = new FinalizationRegistry((key) => this._map.delete(key));
215
+ this._keepAlive = /* @__PURE__ */ new Map();
216
+ this._timeouts = /* @__PURE__ */ new Map();
217
+ this._registry = new FinalizationRegistry((key) => {
218
+ this._stopExpire(key, true);
219
+ this._map.delete(key);
220
+ });
71
221
  }
72
222
  clear() {
73
- return this._map.clear();
223
+ this._keepAlive.clear();
224
+ this._map.clear();
74
225
  }
75
226
  delete(key) {
76
227
  const ref = this._map.get(key);
@@ -80,6 +231,8 @@ var InvertedWeakMap = class {
80
231
  this._registry.unregister(raw);
81
232
  }
82
233
  }
234
+ this._stopExpire(key, true);
235
+ this._keepAlive.delete(key);
83
236
  return this._map.delete(key);
84
237
  }
85
238
  get(key) {
@@ -91,8 +244,39 @@ var InvertedWeakMap = class {
91
244
  set(key, value) {
92
245
  this._map.set(key, new WeakRef(value));
93
246
  this._registry.register(value, key);
247
+ if (this._lifespan > 0) {
248
+ this._stopExpire(key, true);
249
+ this._startExpire(key, value);
250
+ }
94
251
  return this;
95
252
  }
253
+ extendExpire(key) {
254
+ if (!(this._lifespan > 0)) {
255
+ return;
256
+ }
257
+ if (!this._keepAlive.has(key)) {
258
+ return;
259
+ }
260
+ this._stopExpire(key, false);
261
+ this._startExpire(key, this._keepAlive.get(key));
262
+ }
263
+ _startExpire(key, value) {
264
+ this._keepAlive.set(key, value);
265
+ this._timeouts.set(key, setTimeout(() => {
266
+ this._keepAlive.delete(key);
267
+ }, this._lifespan));
268
+ }
269
+ _stopExpire(key, removeKeepAlive) {
270
+ if (!this._timeouts.has(key)) {
271
+ return;
272
+ }
273
+ const timeout = this._timeouts.get(key);
274
+ this._timeouts.delete(key);
275
+ clearTimeout(timeout);
276
+ if (removeKeepAlive) {
277
+ this._keepAlive.delete(key);
278
+ }
279
+ }
96
280
  get size() {
97
281
  return this._map.size;
98
282
  }
@@ -100,13 +284,252 @@ var InvertedWeakMap = class {
100
284
  return this._map.keys();
101
285
  }
102
286
  };
287
+ var CacheEntanglement = class {
288
+ creation;
289
+ beforeUpdateHook;
290
+ lifespan;
291
+ dependencies;
292
+ caches;
293
+ assignments;
294
+ parameters;
295
+ dependencyKeys;
296
+ constructor(creation, option) {
297
+ option = option ?? {};
298
+ const {
299
+ dependencies,
300
+ lifespan,
301
+ beforeUpdateHook
302
+ } = option;
303
+ this.creation = creation;
304
+ this.beforeUpdateHook = beforeUpdateHook ?? (() => {
305
+ });
306
+ this.lifespan = this._normalizeMs(lifespan ?? 0);
307
+ this.assignments = [];
308
+ this.caches = new InvertedWeakMap({ lifespan: this.lifespan });
309
+ this.dependencies = dependencies ?? {};
310
+ this.dependencyKeys = Object.keys(this.dependencies);
311
+ this.parameters = {};
312
+ for (const name in this.dependencies) {
313
+ const dependency = this.dependencies[name];
314
+ if (!dependency.assignments.includes(this)) {
315
+ dependency.assignments.push(this);
316
+ }
317
+ }
318
+ }
319
+ _normalizeMs(time) {
320
+ if (typeof time === "string") {
321
+ return (0, import_ms.default)(time);
322
+ }
323
+ return time;
324
+ }
325
+ dependencyKey(key) {
326
+ const tokens = key.split("/");
327
+ tokens.pop();
328
+ return tokens.join("/");
329
+ }
330
+ /**
331
+ * Returns all keys stored in the instance.
332
+ */
333
+ keys() {
334
+ return this.caches.keys();
335
+ }
336
+ /**
337
+ * Deletes all cache values stored in the instance.
338
+ */
339
+ clear() {
340
+ for (const key of this.keys()) {
341
+ this.delete(key);
342
+ }
343
+ }
344
+ /**
345
+ * Checks if there is a cache value stored in the key within the instance.
346
+ * @param key The key to search.
347
+ */
348
+ exists(key) {
349
+ return this.caches.has(key);
350
+ }
351
+ /**
352
+ * Returns the cache value stored in the key within the instance. If the cached value is not present, an error is thrown.
353
+ * @param key The key to search.
354
+ */
355
+ get(key) {
356
+ if (!this.caches.has(key)) {
357
+ throw new Error(`Cache value not found: ${key}`);
358
+ }
359
+ return this.caches.get(key);
360
+ }
361
+ };
362
+ var CacheData = class _CacheData {
363
+ static StructuredClone = globalThis.structuredClone.bind(globalThis);
364
+ _value;
365
+ constructor(value) {
366
+ this._value = value;
367
+ }
368
+ /**
369
+ * This is cached data.
370
+ * It was generated at the time of caching, so there is a risk of modification if it's an object due to shallow copying.
371
+ * Therefore, if it's not a primitive type, please avoid using this value directly and use the `clone` method to use a copied version of the data.
372
+ */
373
+ get raw() {
374
+ return this._value;
375
+ }
376
+ /**
377
+ * The method returns a copied value of the cached data.
378
+ * You can pass a function as a parameter to copy the value. This parameter function should return the copied value.
379
+ *
380
+ * If no parameter is passed, it defaults to using `structuredClone` function to copy the value.
381
+ * If you prefer shallow copying instead of deep copying,
382
+ * you can use the default options `array-shallow-copy`, `object-shallow-copy` and `deep-copy`,
383
+ * which are replaced with functions to shallow copy arrays and objects, respectively. This is a syntactic sugar.
384
+ * @param strategy The function that returns the copied value.
385
+ * If you want to perform a shallow copy, simply pass the strings `array-shallow-copy` or `object-shallow-copy` for easy use.
386
+ * The `array-shallow-copy` strategy performs a shallow copy of an array.
387
+ * The `object-shallow-copy` strategy performs a shallow copy of an object.
388
+ * The `deep-copy` strategy performs a deep copy of the value using `structuredClone`.
389
+ * The default is `deep-copy`.
390
+ */
391
+ clone(strategy = "deep-copy") {
392
+ if (strategy && typeof strategy !== "string") {
393
+ return strategy(this.raw);
394
+ }
395
+ switch (strategy) {
396
+ case "array-shallow-copy":
397
+ return [].concat(this.raw);
398
+ case "object-shallow-copy":
399
+ return Object.assign({}, this.raw);
400
+ case "deep-copy":
401
+ default:
402
+ return _CacheData.StructuredClone(this.raw);
403
+ }
404
+ }
405
+ };
406
+ var CacheEntanglementSync = class extends CacheEntanglement {
407
+ constructor(creation, option) {
408
+ super(creation, option);
409
+ }
410
+ resolve(key, ...parameter) {
411
+ const resolved = {};
412
+ const dependencyKey = this.dependencyKey(key);
413
+ this.beforeUpdateHook(key, dependencyKey, ...parameter);
414
+ for (let i = 0, len = this.dependencyKeys.length; i < len; i++) {
415
+ const name = this.dependencyKeys[i];
416
+ const dependency = this.dependencies[name];
417
+ if (!dependency.caches.has(key) && !dependency.caches.has(dependencyKey)) {
418
+ throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
419
+ cause: {
420
+ from: this
421
+ }
422
+ });
423
+ }
424
+ const dependencyValue = dependency.caches.get(key) ?? dependency.caches.get(dependencyKey);
425
+ resolved[name] = dependencyValue;
426
+ }
427
+ this.parameters[key] = parameter;
428
+ const value = new CacheData(this.creation(key, resolved, ...parameter));
429
+ this.caches.set(key, value);
430
+ return value;
431
+ }
432
+ cache(key, ...parameter) {
433
+ if (!this.caches.has(key)) {
434
+ this.resolve(key, ...parameter);
435
+ } else {
436
+ this.caches.extendExpire(key);
437
+ }
438
+ return this.caches.get(key);
439
+ }
440
+ update(key, ...parameter) {
441
+ this.resolve(key, ...parameter);
442
+ for (let i = 0, len = this.assignments.length; i < len; i++) {
443
+ const t = this.assignments[i];
444
+ const instance = t;
445
+ for (const cacheKey of instance.caches.keys()) {
446
+ if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
447
+ instance.update(cacheKey, ...instance.parameters[cacheKey]);
448
+ }
449
+ }
450
+ }
451
+ return this.caches.get(key);
452
+ }
453
+ delete(key) {
454
+ this.caches.delete(key);
455
+ for (let i = 0, len = this.assignments.length; i < len; i++) {
456
+ const t = this.assignments[i];
457
+ const instance = t;
458
+ for (const cacheKey of instance.caches.keys()) {
459
+ if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
460
+ instance.delete(cacheKey);
461
+ }
462
+ }
463
+ }
464
+ }
465
+ };
466
+ var CacheEntanglementAsync = class extends CacheEntanglement {
467
+ constructor(creation, option) {
468
+ super(creation, option);
469
+ }
470
+ async resolve(key, ...parameter) {
471
+ const resolved = {};
472
+ const dependencyKey = this.dependencyKey(key);
473
+ await this.beforeUpdateHook(key, dependencyKey, ...parameter);
474
+ for (let i = 0, len = this.dependencyKeys.length; i < len; i++) {
475
+ const name = this.dependencyKeys[i];
476
+ const dependency = this.dependencies[name];
477
+ if (!dependency.caches.has(key) && !dependency.caches.has(dependencyKey)) {
478
+ throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
479
+ cause: {
480
+ from: this
481
+ }
482
+ });
483
+ }
484
+ const dependencyValue = dependency.caches.get(key) ?? dependency.caches.get(dependencyKey);
485
+ resolved[name] = dependencyValue;
486
+ }
487
+ this.parameters[key] = parameter;
488
+ const value = new CacheData(await this.creation(key, resolved, ...parameter));
489
+ this.caches.set(key, value);
490
+ return value;
491
+ }
492
+ async cache(key, ...parameter) {
493
+ if (!this.caches.has(key)) {
494
+ await this.resolve(key, ...parameter);
495
+ } else {
496
+ this.caches.extendExpire(key);
497
+ }
498
+ return this.caches.get(key);
499
+ }
500
+ async update(key, ...parameter) {
501
+ await this.resolve(key, ...parameter);
502
+ for (let i = 0, len = this.assignments.length; i < len; i++) {
503
+ const t = this.assignments[i];
504
+ const instance = t;
505
+ for (const cacheKey of instance.caches.keys()) {
506
+ if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
507
+ await instance.update(cacheKey, ...instance.parameters[cacheKey]);
508
+ }
509
+ }
510
+ }
511
+ return this.caches.get(key);
512
+ }
513
+ async delete(key) {
514
+ this.caches.delete(key);
515
+ for (let i = 0, len = this.assignments.length; i < len; i++) {
516
+ const t = this.assignments[i];
517
+ const instance = t;
518
+ for (const cacheKey of instance.caches.keys()) {
519
+ if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
520
+ await instance.delete(cacheKey);
521
+ }
522
+ }
523
+ }
524
+ }
525
+ };
103
526
 
104
527
  // src/base/BPTree.ts
105
528
  var BPTree = class {
106
529
  _cachedRegexp;
107
530
  strategy;
108
531
  comparator;
109
- nodes;
532
+ option;
110
533
  order;
111
534
  root;
112
535
  _strategyDirty;
@@ -124,12 +547,8 @@ var BPTree = class {
124
547
  like: (nv, v) => {
125
548
  const nodeValue = this.comparator.match(nv);
126
549
  const value = this.comparator.match(v);
127
- if (!this._cachedRegexp.has(value)) {
128
- const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
129
- const regexp2 = new RegExp(`^${pattern}$`, "i");
130
- this._cachedRegexp.set(value, regexp2);
131
- }
132
- const regexp = this._cachedRegexp.get(value);
550
+ const cache = this._cachedRegexp.cache(value);
551
+ const regexp = cache.raw;
133
552
  return regexp.test(nodeValue);
134
553
  }
135
554
  };
@@ -166,15 +585,24 @@ var BPTree = class {
166
585
  or: 1,
167
586
  like: 1
168
587
  };
169
- constructor(strategy, comparator) {
588
+ constructor(strategy, comparator, option) {
589
+ this.strategy = strategy;
590
+ this.comparator = comparator;
591
+ this.option = option ?? {};
170
592
  this._strategyDirty = false;
171
- this._cachedRegexp = new InvertedWeakMap();
172
593
  this._nodeCreateBuffer = /* @__PURE__ */ new Map();
173
594
  this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
174
595
  this._nodeDeleteBuffer = /* @__PURE__ */ new Map();
175
- this.nodes = new InvertedWeakMap();
176
- this.strategy = strategy;
177
- this.comparator = comparator;
596
+ this._cachedRegexp = this._createCachedRegexp();
597
+ }
598
+ _createCachedRegexp() {
599
+ return new CacheEntanglementSync((key) => {
600
+ const pattern = key.replace(/%/g, ".*").replace(/_/g, ".");
601
+ const regexp = new RegExp(`^${pattern}$`, "i");
602
+ return regexp;
603
+ }, {
604
+ lifespan: this.option.lifespan ?? "3m"
605
+ });
178
606
  }
179
607
  ensureValues(v) {
180
608
  if (!Array.isArray(v)) {
@@ -248,12 +676,28 @@ var BPTree = class {
248
676
  getHeadData() {
249
677
  return this.strategy.head.data;
250
678
  }
679
+ /**
680
+ * Clears all cached nodes.
681
+ * This method is useful for freeing up memory when the tree is no longer needed.
682
+ */
683
+ clear() {
684
+ this._cachedRegexp.clear();
685
+ this.nodes.clear();
686
+ }
251
687
  };
252
688
 
253
689
  // src/BPTreeSync.ts
254
690
  var BPTreeSync = class extends BPTree {
255
- constructor(strategy, comparator) {
256
- super(strategy, comparator);
691
+ constructor(strategy, comparator, option) {
692
+ super(strategy, comparator, option);
693
+ this.nodes = this._createCachedNode();
694
+ }
695
+ _createCachedNode() {
696
+ return new CacheEntanglementSync((key) => {
697
+ return this.strategy.read(key);
698
+ }, {
699
+ lifespan: this.option.lifespan ?? "3m"
700
+ });
257
701
  }
258
702
  getPairsRightToLeft(value, startNode, endNode, comparator) {
259
703
  const pairs = [];
@@ -338,7 +782,7 @@ var BPTreeSync = class extends BPTree {
338
782
  next,
339
783
  prev
340
784
  };
341
- this.nodes.set(id, node);
785
+ this._nodeCreateBuffer.set(id, node);
342
786
  return node;
343
787
  }
344
788
  _deleteEntry(node, key, value) {
@@ -552,7 +996,6 @@ var BPTreeSync = class extends BPTree {
552
996
  this.strategy.head.root = root.id;
553
997
  node.parent = root.id;
554
998
  pointer.parent = root.id;
555
- this.bufferForNodeCreate(root);
556
999
  this.bufferForNodeUpdate(node);
557
1000
  this.bufferForNodeUpdate(pointer);
558
1001
  return;
@@ -588,7 +1031,6 @@ var BPTreeSync = class extends BPTree {
588
1031
  this.bufferForNodeUpdate(node2);
589
1032
  }
590
1033
  this._insertInParent(parentNode, midValue, parentPointer);
591
- this.bufferForNodeCreate(parentPointer);
592
1034
  this.bufferForNodeUpdate(parentNode);
593
1035
  }
594
1036
  }
@@ -600,7 +1042,6 @@ var BPTreeSync = class extends BPTree {
600
1042
  this.order = this.strategy.order;
601
1043
  this.root = this._createNode(true, [], [], true);
602
1044
  this.strategy.head.root = this.root.id;
603
- this.bufferForNodeCreate(this.root);
604
1045
  this.commitHeadBuffer();
605
1046
  this.commitNodeCreateBuffer();
606
1047
  } else {
@@ -614,10 +1055,11 @@ var BPTreeSync = class extends BPTree {
614
1055
  }
615
1056
  }
616
1057
  getNode(id) {
617
- if (!this.nodes.has(id)) {
618
- this.nodes.set(id, this.strategy.read(id));
1058
+ if (this._nodeCreateBuffer.has(id)) {
1059
+ return this._nodeCreateBuffer.get(id);
619
1060
  }
620
- return this.nodes.get(id);
1061
+ const cache = this.nodes.cache(id);
1062
+ return cache.raw;
621
1063
  }
622
1064
  insertableNode(value) {
623
1065
  let node = this.root;
@@ -773,7 +1215,6 @@ var BPTreeSync = class extends BPTree {
773
1215
  this.bufferForNodeUpdate(node);
774
1216
  }
775
1217
  this._insertInParent(before, after.values[0], after);
776
- this.bufferForNodeCreate(after);
777
1218
  this.bufferForNodeUpdate(before);
778
1219
  }
779
1220
  this.commitHeadBuffer();
@@ -839,8 +1280,16 @@ var BPTreeSync = class extends BPTree {
839
1280
 
840
1281
  // src/BPTreeAsync.ts
841
1282
  var BPTreeAsync = class extends BPTree {
842
- constructor(strategy, comparator) {
843
- super(strategy, comparator);
1283
+ constructor(strategy, comparator, option) {
1284
+ super(strategy, comparator, option);
1285
+ this.nodes = this._createCachedNode();
1286
+ }
1287
+ _createCachedNode() {
1288
+ return new CacheEntanglementAsync(async (key) => {
1289
+ return await this.strategy.read(key);
1290
+ }, {
1291
+ lifespan: this.option.lifespan ?? "3m"
1292
+ });
844
1293
  }
845
1294
  async getPairsRightToLeft(value, startNode, endNode, comparator) {
846
1295
  const pairs = [];
@@ -925,7 +1374,7 @@ var BPTreeAsync = class extends BPTree {
925
1374
  next,
926
1375
  prev
927
1376
  };
928
- this.nodes.set(id, node);
1377
+ this._nodeCreateBuffer.set(id, node);
929
1378
  return node;
930
1379
  }
931
1380
  async _deleteEntry(node, key, value) {
@@ -1139,7 +1588,6 @@ var BPTreeAsync = class extends BPTree {
1139
1588
  this.strategy.head.root = root.id;
1140
1589
  node.parent = root.id;
1141
1590
  pointer.parent = root.id;
1142
- this.bufferForNodeCreate(root);
1143
1591
  this.bufferForNodeUpdate(node);
1144
1592
  this.bufferForNodeUpdate(pointer);
1145
1593
  return;
@@ -1175,7 +1623,6 @@ var BPTreeAsync = class extends BPTree {
1175
1623
  this.bufferForNodeUpdate(node2);
1176
1624
  }
1177
1625
  await this._insertInParent(parentNode, midValue, parentPointer);
1178
- this.bufferForNodeCreate(parentPointer);
1179
1626
  this.bufferForNodeUpdate(parentNode);
1180
1627
  }
1181
1628
  }
@@ -1187,7 +1634,6 @@ var BPTreeAsync = class extends BPTree {
1187
1634
  this.order = this.strategy.order;
1188
1635
  this.root = await this._createNode(true, [], [], true);
1189
1636
  this.strategy.head.root = this.root.id;
1190
- this.bufferForNodeCreate(this.root);
1191
1637
  await this.commitHeadBuffer();
1192
1638
  await this.commitNodeCreateBuffer();
1193
1639
  } else {
@@ -1201,10 +1647,11 @@ var BPTreeAsync = class extends BPTree {
1201
1647
  }
1202
1648
  }
1203
1649
  async getNode(id) {
1204
- if (!this.nodes.has(id)) {
1205
- this.nodes.set(id, await this.strategy.read(id));
1650
+ if (this._nodeCreateBuffer.has(id)) {
1651
+ return this._nodeCreateBuffer.get(id);
1206
1652
  }
1207
- return this.nodes.get(id);
1653
+ const cache = await this.nodes.cache(id);
1654
+ return cache.raw;
1208
1655
  }
1209
1656
  async insertableNode(value) {
1210
1657
  let node = this.root;
@@ -1360,7 +1807,6 @@ var BPTreeAsync = class extends BPTree {
1360
1807
  this.bufferForNodeUpdate(node);
1361
1808
  }
1362
1809
  await this._insertInParent(before, after.values[0], after);
1363
- this.bufferForNodeCreate(after);
1364
1810
  this.bufferForNodeUpdate(before);
1365
1811
  }
1366
1812
  await this.commitHeadBuffer();