serializable-bptree 3.4.0-alpha.1 → 4.0.1

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
@@ -6,7 +6,7 @@
6
6
  This is a B+tree that's totally okay with duplicate values. If you need to keep track of the B+ tree's state, don't just leave it in memory - make sure you write it down.
7
7
 
8
8
  ```typescript
9
- import { readFileSync, writeFileSync, existsSync } from 'fs'
9
+ import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'fs'
10
10
  import {
11
11
  BPTreeSync,
12
12
  SerializeStrategySync,
@@ -14,18 +14,22 @@ import {
14
14
  } from 'serializable-bptree'
15
15
 
16
16
  class FileStoreStrategySync extends SerializeStrategySync<K, V> {
17
- id(): number {
18
- return this.autoIncrement('index', 1)
17
+ id(): string {
18
+ return this.autoIncrement('index', 1).toString()
19
19
  }
20
20
 
21
- read(id: number): BPTreeNode<K, V> {
22
- const raw = readFileSync(id.toString(), 'utf8')
21
+ read(id: string): BPTreeNode<K, V> {
22
+ const raw = readFileSync(id, 'utf8')
23
23
  return JSON.parse(raw)
24
24
  }
25
25
 
26
- write(id: number, node: BPTreeNode<K, V>): void {
26
+ write(id: string, node: BPTreeNode<K, V>): void {
27
27
  const stringify = JSON.stringify(node)
28
- writeFileSync(id.toString(), stringify, 'utf8')
28
+ writeFileSync(id, stringify, 'utf8')
29
+ }
30
+
31
+ delete(id: string): void {
32
+ unlinkSync(id)
29
33
  }
30
34
 
31
35
  readHead(): SerializeStrategyHead|null {
@@ -98,7 +102,7 @@ import {
98
102
  ValueComparator,
99
103
  NumericComparator,
100
104
  StringComparator
101
- } from 'https://cdn.jsdelivr.net/npm/serializable-bptree@3.x.x/dist/esm/index.min.js'
105
+ } from 'https://cdn.jsdelivr.net/npm/serializable-bptree@4.x.x/dist/esm/index.min.js'
102
106
  </script>
103
107
  ```
104
108
 
@@ -177,9 +181,10 @@ You need to construct a logic for input/output from the file by inheriting the S
177
181
  import { SerializeStrategySync } from 'serializable-bptree'
178
182
 
179
183
  class MyFileIOStrategySync extends SerializeStrategySync {
180
- id(): number
181
- read(id: number): BPTreeNode<K, V>
182
- write(id: number, node: BPTreeNode<K, V>): void
184
+ id(): string
185
+ read(id: string): BPTreeNode<K, V>
186
+ write(id: string, node: BPTreeNode<K, V>): void
187
+ delete(id: string): void
183
188
  readHead(): SerializeStrategyHead|null
184
189
  writeHead(head: SerializeStrategyHead): void
185
190
  }
@@ -187,49 +192,39 @@ class MyFileIOStrategySync extends SerializeStrategySync {
187
192
 
188
193
  What does this method mean? And why do we need to construct such a method?
189
194
 
190
- #### id(isLeaf: `boolean`): `number`
191
-
192
- 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.
193
-
194
- ```typescript
195
- id(isLeaf: boolean): number {
196
- const current = before + 1
197
- before = current
198
- return current
199
- }
200
- ```
195
+ #### id(isLeaf: `boolean`): `string`
201
196
 
202
- Or, you could use file input/output to save and load the value of the **before** variable.
197
+ 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.
203
198
 
204
199
  Typically, such an **id** value increases sequentially, and it would be beneficial to store such a value separately within the tree. For that purpose, the **setHeadData** and **getHeadData** methods are available. These methods are responsible for storing arbitrary data in the tree's header or retrieving stored data. Below is an example of usage:
205
200
 
206
201
  ```typescript
207
- id(isLeaf: boolean): number {
202
+ id(isLeaf: boolean): string {
208
203
  const current = this.getHeadData('index', 1) as number
209
204
  this.setHeadData('index', current+1)
210
- return current
205
+ return current.toString()
211
206
  }
212
207
  ```
213
208
 
214
- Additionally, there is a more user-friendly usage of this code.
209
+ Additionally, there is a more dev-friendly usage of this code.
215
210
 
216
211
  ```typescript
217
- id(isLeaf: boolean): number {
218
- return this.autoIncrement('index', 1)
212
+ id(isLeaf: boolean): string {
213
+ return this.autoIncrement('index', 1).toString()
219
214
  }
220
215
  ```
221
216
 
222
217
  The **id** method is called before a node is created in the tree. Therefore, it can also be used to allocate space for storing the node.
223
218
 
224
- #### read(id: `number`): `BPTreeNode<K, V>`
219
+ #### read(id: `string`): `BPTreeNode<K, V>`
225
220
 
226
221
  This is a method to load the saved value as a tree instance. If you have previously saved the node as a file, you should use this method to convert it back to JavaScript JSON format and return it.
227
222
 
228
223
  Please refer to the example below:
229
224
 
230
225
  ```typescript
231
- read(id: number): BPTreeNode<K, V> {
232
- const filePath = `./my-store/${id.toString()}`
226
+ read(id: string): BPTreeNode<K, V> {
227
+ const filePath = `./my-store/${id}`
233
228
  const raw = fs.readFileSync(filePath, 'utf8')
234
229
  return JSON.parse(raw)
235
230
  }
@@ -237,7 +232,7 @@ read(id: number): BPTreeNode<K, V> {
237
232
 
238
233
  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.
239
234
 
240
- #### write(id: `number`, node: `BPTreeNode<K, V>`): `void`
235
+ #### write(id: `string`, node: `BPTreeNode<K, V>`): `void`
241
236
 
242
237
  This method is called when there are changes in the internal nodes due to the insert or delete operations of the tree instance. In other words, it's a necessary method for synchronizing the in-memory nodes into a file.
243
238
 
@@ -247,17 +242,17 @@ Please refer to the example below:
247
242
 
248
243
  ```typescript
249
244
  let queue = 0
250
- function writeBack(id: number, node: BPTreeNode<K, V>, timer: number) {
245
+ function writeBack(id: string, node: BPTreeNode<K, V>, timer: number) {
251
246
  clearTimeout(queue)
252
247
  queue = setTimeout(() => {
253
- const filePath = `./my-store/${id.toString()}`
248
+ const filePath = `./my-store/${id}`
254
249
  const stringify = JSON.stringify(node)
255
250
  writeFileSync(filePath, stringify, 'utf8')
256
251
  }, timer)
257
252
  }
258
253
 
259
254
  ...
260
- write(id: number, node: BPTreeNode<K, V>): void {
255
+ write(id: string, node: BPTreeNode<K, V>): void {
261
256
  const writeBackInterval = 10
262
257
  writeBack(id, node, writeBackInterval)
263
258
  }
@@ -265,6 +260,17 @@ write(id: number, node: BPTreeNode<K, V>): void {
265
260
 
266
261
  This kind of delay writing should ideally occur within a few milliseconds. If this is not feasible, consider other approaches.
267
262
 
263
+ #### delete(id: `string`): `void`
264
+
265
+ This method is called when previously created nodes become no longer needed due to deletion or other processes. It can be used to free up space by deleting existing stored nodes.
266
+
267
+ ```typescript
268
+ delete(id: string): void {
269
+ const filePath = `./my-store/${id}`
270
+ fs.unlinkSync(filePath)
271
+ }
272
+ ```
273
+
268
274
  #### readHead(): `SerializeStrategyHead`|`null`
269
275
 
270
276
  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**.
@@ -357,7 +363,7 @@ Support for asynchronous trees has been available since version 3.0.0. Asynchron
357
363
 
358
364
  ```typescript
359
365
  import { existsSync } from 'fs'
360
- import { readFile, writeFile } from 'fs/promises'
366
+ import { readFile, writeFile, unlink } from 'fs/promises'
361
367
  import {
362
368
  BPTreeAsync,
363
369
  SerializeStrategyAsync,
@@ -366,18 +372,22 @@ import {
366
372
  } from 'serializable-bptree'
367
373
 
368
374
  class FileStoreStrategyAsync extends SerializeStrategyAsync<K, V> {
369
- async id(isLeaf: boolean): Promise<number> {
370
- return await this.autoIncrement('index', 1)
375
+ async id(isLeaf: boolean): Promise<string> {
376
+ return await this.autoIncrement('index', 1).toString()
371
377
  }
372
378
 
373
- async read(id: number): Promise<BPTreeNode<K, V>> {
374
- const raw = await readFile(id.toString(), 'utf8')
379
+ async read(id: string): Promise<BPTreeNode<K, V>> {
380
+ const raw = await readFile(id, 'utf8')
375
381
  return JSON.parse(raw)
376
382
  }
377
383
 
378
- async write(id: number, node: BPTreeNode<K, V>): Promise<void> {
384
+ async write(id: string, node: BPTreeNode<K, V>): Promise<void> {
379
385
  const stringify = JSON.stringify(node)
380
- await writeFile(id.toString(), stringify, 'utf8')
386
+ await writeFile(id, stringify, 'utf8')
387
+ }
388
+
389
+ async delete(id: string): Promise<void> {
390
+ await unlink(id)
381
391
  }
382
392
 
383
393
  async readHead(): Promise<SerializeStrategyHead|null> {
@@ -426,6 +426,39 @@ var CacheBranchSync = class _CacheBranchSync extends CacheBranch {
426
426
  }
427
427
  };
428
428
 
429
+ // src/utils/InvertedWeakMap.ts
430
+ var InvertedWeakMap = class {
431
+ _map;
432
+ _registry;
433
+ constructor() {
434
+ this._map = /* @__PURE__ */ new Map();
435
+ this._registry = new FinalizationRegistry((key) => this._map.delete(key));
436
+ }
437
+ clear() {
438
+ return this._map.clear();
439
+ }
440
+ delete(key) {
441
+ return this._map.delete(key);
442
+ }
443
+ get(key) {
444
+ return this._map.get(key)?.deref();
445
+ }
446
+ has(key) {
447
+ return this._map.has(key) && this.get(key) !== void 0;
448
+ }
449
+ set(key, value) {
450
+ this._map.set(key, new WeakRef(value));
451
+ this._registry.register(value, key);
452
+ return this;
453
+ }
454
+ get size() {
455
+ return this._map.size;
456
+ }
457
+ keys() {
458
+ return this._map.keys();
459
+ }
460
+ };
461
+
429
462
  // src/base/BPTree.ts
430
463
  var BPTree = class {
431
464
  _cachedRegexp;
@@ -486,7 +519,7 @@ var BPTree = class {
486
519
  this._nodeCreateBuffer = /* @__PURE__ */ new Map();
487
520
  this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
488
521
  this._nodeDeleteBuffer = /* @__PURE__ */ new Map();
489
- this.nodes = /* @__PURE__ */ new Map();
522
+ this.nodes = new InvertedWeakMap();
490
523
  this.strategy = strategy;
491
524
  this.comparator = comparator;
492
525
  }
@@ -609,12 +642,12 @@ var BPTreeSync = class extends BPTree {
609
642
  }
610
643
  _createNodeId(isLeaf) {
611
644
  const id = this.strategy.id(isLeaf);
612
- if (id === 0) {
613
- throw new Error(`The node's id should never be 0.`);
645
+ if (id === null) {
646
+ throw new Error(`The node's id should never be null.`);
614
647
  }
615
648
  return id;
616
649
  }
617
- _createNode(isLeaf, keys2, values, leaf = false, parent = 0, next = 0, prev = 0) {
650
+ _createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
618
651
  const id = this._createNodeId(isLeaf);
619
652
  const node = {
620
653
  id,
@@ -651,7 +684,7 @@ var BPTreeSync = class extends BPTree {
651
684
  const keys2 = node.keys;
652
685
  this.bufferForNodeDelete(this.root);
653
686
  this.root = this.getNode(keys2[0]);
654
- this.root.parent = 0;
687
+ this.root.parent = null;
655
688
  this.strategy.head.root = this.root.id;
656
689
  this.bufferForNodeUpdate(this.root);
657
690
  return;
@@ -719,7 +752,7 @@ var BPTreeSync = class extends BPTree {
719
752
  this.bufferForNodeUpdate(n);
720
753
  }
721
754
  if (isPredecessor) {
722
- pointer.prev = 0;
755
+ pointer.prev = null;
723
756
  }
724
757
  }
725
758
  pointer.values.push(...node.values);
@@ -1160,12 +1193,12 @@ var BPTreeAsync = class extends BPTree {
1160
1193
  }
1161
1194
  async _createNodeId(isLeaf) {
1162
1195
  const id = await this.strategy.id(isLeaf);
1163
- if (id === 0) {
1164
- throw new Error(`The node's id should never be 0.`);
1196
+ if (id === null) {
1197
+ throw new Error(`The node's id should never be null.`);
1165
1198
  }
1166
1199
  return id;
1167
1200
  }
1168
- async _createNode(isLeaf, keys2, values, leaf = false, parent = 0, next = 0, prev = 0) {
1201
+ async _createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
1169
1202
  const id = await this._createNodeId(isLeaf);
1170
1203
  const node = {
1171
1204
  id,
@@ -1202,7 +1235,7 @@ var BPTreeAsync = class extends BPTree {
1202
1235
  const keys2 = node.keys;
1203
1236
  this.bufferForNodeDelete(this.root);
1204
1237
  this.root = await this.getNode(keys2[0]);
1205
- this.root.parent = 0;
1238
+ this.root.parent = null;
1206
1239
  this.strategy.head.root = this.root.id;
1207
1240
  this.bufferForNodeUpdate(this.root);
1208
1241
  return;
@@ -1270,7 +1303,7 @@ var BPTreeAsync = class extends BPTree {
1270
1303
  this.bufferForNodeUpdate(n);
1271
1304
  }
1272
1305
  if (isPredecessor) {
1273
- pointer.prev = 0;
1306
+ pointer.prev = null;
1274
1307
  }
1275
1308
  }
1276
1309
  pointer.values.push(...node.values);
@@ -1646,7 +1679,7 @@ var SerializeStrategy = class {
1646
1679
  this.order = order;
1647
1680
  this.head = {
1648
1681
  order,
1649
- root: 0,
1682
+ root: null,
1650
1683
  data: {}
1651
1684
  };
1652
1685
  }
@@ -1678,7 +1711,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
1678
1711
  this.node = {};
1679
1712
  }
1680
1713
  id(isLeaf) {
1681
- return this.autoIncrement("index", 1);
1714
+ return this.autoIncrement("index", 1).toString();
1682
1715
  }
1683
1716
  read(id) {
1684
1717
  if (!Object.hasOwn(this.node, id)) {
@@ -1693,7 +1726,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
1693
1726
  delete this.node[id];
1694
1727
  }
1695
1728
  readHead() {
1696
- if (this.head.root === 0) {
1729
+ if (this.head.root === null) {
1697
1730
  return null;
1698
1731
  }
1699
1732
  return this.head;
@@ -1729,7 +1762,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
1729
1762
  this.node = {};
1730
1763
  }
1731
1764
  async id(isLeaf) {
1732
- return await this.autoIncrement("index", 1);
1765
+ return (await this.autoIncrement("index", 1)).toString();
1733
1766
  }
1734
1767
  async read(id) {
1735
1768
  if (!Object.hasOwn(this.node, id)) {
@@ -1744,7 +1777,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
1744
1777
  delete this.node[id];
1745
1778
  }
1746
1779
  async readHead() {
1747
- if (this.head.root === 0) {
1780
+ if (this.head.root === null) {
1748
1781
  return null;
1749
1782
  }
1750
1783
  return this.head;
@@ -392,6 +392,39 @@ var CacheBranchSync = class _CacheBranchSync extends CacheBranch {
392
392
  }
393
393
  };
394
394
 
395
+ // src/utils/InvertedWeakMap.ts
396
+ var InvertedWeakMap = class {
397
+ _map;
398
+ _registry;
399
+ constructor() {
400
+ this._map = /* @__PURE__ */ new Map();
401
+ this._registry = new FinalizationRegistry((key) => this._map.delete(key));
402
+ }
403
+ clear() {
404
+ return this._map.clear();
405
+ }
406
+ delete(key) {
407
+ return this._map.delete(key);
408
+ }
409
+ get(key) {
410
+ return this._map.get(key)?.deref();
411
+ }
412
+ has(key) {
413
+ return this._map.has(key) && this.get(key) !== void 0;
414
+ }
415
+ set(key, value) {
416
+ this._map.set(key, new WeakRef(value));
417
+ this._registry.register(value, key);
418
+ return this;
419
+ }
420
+ get size() {
421
+ return this._map.size;
422
+ }
423
+ keys() {
424
+ return this._map.keys();
425
+ }
426
+ };
427
+
395
428
  // src/base/BPTree.ts
396
429
  var BPTree = class {
397
430
  _cachedRegexp;
@@ -452,7 +485,7 @@ var BPTree = class {
452
485
  this._nodeCreateBuffer = /* @__PURE__ */ new Map();
453
486
  this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
454
487
  this._nodeDeleteBuffer = /* @__PURE__ */ new Map();
455
- this.nodes = /* @__PURE__ */ new Map();
488
+ this.nodes = new InvertedWeakMap();
456
489
  this.strategy = strategy;
457
490
  this.comparator = comparator;
458
491
  }
@@ -575,12 +608,12 @@ var BPTreeSync = class extends BPTree {
575
608
  }
576
609
  _createNodeId(isLeaf) {
577
610
  const id = this.strategy.id(isLeaf);
578
- if (id === 0) {
579
- throw new Error(`The node's id should never be 0.`);
611
+ if (id === null) {
612
+ throw new Error(`The node's id should never be null.`);
580
613
  }
581
614
  return id;
582
615
  }
583
- _createNode(isLeaf, keys2, values, leaf = false, parent = 0, next = 0, prev = 0) {
616
+ _createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
584
617
  const id = this._createNodeId(isLeaf);
585
618
  const node = {
586
619
  id,
@@ -617,7 +650,7 @@ var BPTreeSync = class extends BPTree {
617
650
  const keys2 = node.keys;
618
651
  this.bufferForNodeDelete(this.root);
619
652
  this.root = this.getNode(keys2[0]);
620
- this.root.parent = 0;
653
+ this.root.parent = null;
621
654
  this.strategy.head.root = this.root.id;
622
655
  this.bufferForNodeUpdate(this.root);
623
656
  return;
@@ -685,7 +718,7 @@ var BPTreeSync = class extends BPTree {
685
718
  this.bufferForNodeUpdate(n);
686
719
  }
687
720
  if (isPredecessor) {
688
- pointer.prev = 0;
721
+ pointer.prev = null;
689
722
  }
690
723
  }
691
724
  pointer.values.push(...node.values);
@@ -1126,12 +1159,12 @@ var BPTreeAsync = class extends BPTree {
1126
1159
  }
1127
1160
  async _createNodeId(isLeaf) {
1128
1161
  const id = await this.strategy.id(isLeaf);
1129
- if (id === 0) {
1130
- throw new Error(`The node's id should never be 0.`);
1162
+ if (id === null) {
1163
+ throw new Error(`The node's id should never be null.`);
1131
1164
  }
1132
1165
  return id;
1133
1166
  }
1134
- async _createNode(isLeaf, keys2, values, leaf = false, parent = 0, next = 0, prev = 0) {
1167
+ async _createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
1135
1168
  const id = await this._createNodeId(isLeaf);
1136
1169
  const node = {
1137
1170
  id,
@@ -1168,7 +1201,7 @@ var BPTreeAsync = class extends BPTree {
1168
1201
  const keys2 = node.keys;
1169
1202
  this.bufferForNodeDelete(this.root);
1170
1203
  this.root = await this.getNode(keys2[0]);
1171
- this.root.parent = 0;
1204
+ this.root.parent = null;
1172
1205
  this.strategy.head.root = this.root.id;
1173
1206
  this.bufferForNodeUpdate(this.root);
1174
1207
  return;
@@ -1236,7 +1269,7 @@ var BPTreeAsync = class extends BPTree {
1236
1269
  this.bufferForNodeUpdate(n);
1237
1270
  }
1238
1271
  if (isPredecessor) {
1239
- pointer.prev = 0;
1272
+ pointer.prev = null;
1240
1273
  }
1241
1274
  }
1242
1275
  pointer.values.push(...node.values);
@@ -1612,7 +1645,7 @@ var SerializeStrategy = class {
1612
1645
  this.order = order;
1613
1646
  this.head = {
1614
1647
  order,
1615
- root: 0,
1648
+ root: null,
1616
1649
  data: {}
1617
1650
  };
1618
1651
  }
@@ -1644,7 +1677,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
1644
1677
  this.node = {};
1645
1678
  }
1646
1679
  id(isLeaf) {
1647
- return this.autoIncrement("index", 1);
1680
+ return this.autoIncrement("index", 1).toString();
1648
1681
  }
1649
1682
  read(id) {
1650
1683
  if (!Object.hasOwn(this.node, id)) {
@@ -1659,7 +1692,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
1659
1692
  delete this.node[id];
1660
1693
  }
1661
1694
  readHead() {
1662
- if (this.head.root === 0) {
1695
+ if (this.head.root === null) {
1663
1696
  return null;
1664
1697
  }
1665
1698
  return this.head;
@@ -1695,7 +1728,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
1695
1728
  this.node = {};
1696
1729
  }
1697
1730
  async id(isLeaf) {
1698
- return await this.autoIncrement("index", 1);
1731
+ return (await this.autoIncrement("index", 1)).toString();
1699
1732
  }
1700
1733
  async read(id) {
1701
1734
  if (!Object.hasOwn(this.node, id)) {
@@ -1710,7 +1743,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
1710
1743
  delete this.node[id];
1711
1744
  }
1712
1745
  async readHead() {
1713
- if (this.head.root === 0) {
1746
+ if (this.head.root === null) {
1714
1747
  return null;
1715
1748
  }
1716
1749
  return this.head;
@@ -8,12 +8,12 @@ export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
8
8
  protected _getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>[]>;
9
9
  protected _getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>[]>;
10
10
  protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): Promise<BPTreePair<K, V>[]>;
11
- protected _createNodeId(isLeaf: boolean): Promise<number>;
12
- protected _createNode(isLeaf: boolean, keys: number[] | K[][], values: V[], leaf?: boolean, parent?: number, next?: number, prev?: number): Promise<BPTreeUnknownNode<K, V>>;
11
+ protected _createNodeId(isLeaf: boolean): Promise<string>;
12
+ protected _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): Promise<BPTreeUnknownNode<K, V>>;
13
13
  protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): Promise<void>;
14
14
  protected _insertInParent(node: BPTreeUnknownNode<K, V>, value: V, pointer: BPTreeUnknownNode<K, V>): Promise<void>;
15
15
  init(): Promise<void>;
16
- protected getNode(id: number): Promise<BPTreeUnknownNode<K, V>>;
16
+ protected getNode(id: string): Promise<BPTreeUnknownNode<K, V>>;
17
17
  protected insertableNode(value: V): Promise<BPTreeLeafNode<K, V>>;
18
18
  protected leftestNode(): Promise<BPTreeLeafNode<K, V>>;
19
19
  protected commitHeadBuffer(): Promise<void>;
@@ -8,12 +8,12 @@ export declare class BPTreeSync<K, V> extends BPTree<K, V> {
8
8
  protected _getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>[];
9
9
  protected _getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>[];
10
10
  protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): BPTreePair<K, V>[];
11
- protected _createNodeId(isLeaf: boolean): number;
12
- protected _createNode(isLeaf: boolean, keys: number[] | K[][], values: V[], leaf?: boolean, parent?: number, next?: number, prev?: number): BPTreeUnknownNode<K, V>;
11
+ protected _createNodeId(isLeaf: boolean): string;
12
+ protected _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): BPTreeUnknownNode<K, V>;
13
13
  protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): void;
14
14
  protected _insertInParent(node: BPTreeUnknownNode<K, V>, value: V, pointer: BPTreeUnknownNode<K, V>): void;
15
15
  init(): void;
16
- protected getNode(id: number): BPTreeUnknownNode<K, V>;
16
+ protected getNode(id: string): BPTreeUnknownNode<K, V>;
17
17
  protected insertableNode(value: V): BPTreeLeafNode<K, V>;
18
18
  protected leftestNode(): BPTreeLeafNode<K, V>;
19
19
  protected commitHeadBuffer(): void;
@@ -2,10 +2,10 @@ import { BPTreeNode } from './base/BPTree';
2
2
  import { SerializeStrategy, SerializeStrategyHead } from './base/SerializeStrategy';
3
3
  import { Json } from './utils/types';
4
4
  export declare abstract class SerializeStrategyAsync<K, V> extends SerializeStrategy<K, V> {
5
- abstract id(isLeaf: boolean): Promise<number>;
6
- abstract read(id: number): Promise<BPTreeNode<K, V>>;
7
- abstract write(id: number, node: BPTreeNode<K, V>): Promise<void>;
8
- abstract delete(id: number): Promise<void>;
5
+ abstract id(isLeaf: boolean): Promise<string>;
6
+ abstract read(id: string): Promise<BPTreeNode<K, V>>;
7
+ abstract write(id: string, node: BPTreeNode<K, V>): Promise<void>;
8
+ abstract delete(id: string): Promise<void>;
9
9
  abstract readHead(): Promise<SerializeStrategyHead | null>;
10
10
  abstract writeHead(head: SerializeStrategyHead): Promise<void>;
11
11
  getHeadData(key: string, defaultValue: Json): Promise<Json>;
@@ -13,12 +13,12 @@ export declare abstract class SerializeStrategyAsync<K, V> extends SerializeStra
13
13
  autoIncrement(key: string, defaultValue: number): Promise<number>;
14
14
  }
15
15
  export declare class InMemoryStoreStrategyAsync<K, V> extends SerializeStrategyAsync<K, V> {
16
- protected readonly node: Record<number, BPTreeNode<K, V>>;
16
+ protected readonly node: Record<string, BPTreeNode<K, V>>;
17
17
  constructor(order: number);
18
- id(isLeaf: boolean): Promise<number>;
19
- read(id: number): Promise<BPTreeNode<K, V>>;
20
- write(id: number, node: BPTreeNode<K, V>): Promise<void>;
21
- delete(id: number): Promise<void>;
18
+ id(isLeaf: boolean): Promise<string>;
19
+ read(id: string): Promise<BPTreeNode<K, V>>;
20
+ write(id: string, node: BPTreeNode<K, V>): Promise<void>;
21
+ delete(id: string): Promise<void>;
22
22
  readHead(): Promise<SerializeStrategyHead | null>;
23
23
  writeHead(head: SerializeStrategyHead): Promise<void>;
24
24
  }
@@ -2,10 +2,10 @@ import { BPTreeNode } from './base/BPTree';
2
2
  import { SerializeStrategy, SerializeStrategyHead } from './base/SerializeStrategy';
3
3
  import { Json } from './utils/types';
4
4
  export declare abstract class SerializeStrategySync<K, V> extends SerializeStrategy<K, V> {
5
- abstract id(isLeaf: boolean): number;
6
- abstract read(id: number): BPTreeNode<K, V>;
7
- abstract write(id: number, node: BPTreeNode<K, V>): void;
8
- abstract delete(id: number): void;
5
+ abstract id(isLeaf: boolean): string;
6
+ abstract read(id: string): BPTreeNode<K, V>;
7
+ abstract write(id: string, node: BPTreeNode<K, V>): void;
8
+ abstract delete(id: string): void;
9
9
  abstract readHead(): SerializeStrategyHead | null;
10
10
  abstract writeHead(head: SerializeStrategyHead): void;
11
11
  getHeadData(key: string, defaultValue: Json): Json;
@@ -13,12 +13,12 @@ export declare abstract class SerializeStrategySync<K, V> extends SerializeStrat
13
13
  autoIncrement(key: string, defaultValue: number): number;
14
14
  }
15
15
  export declare class InMemoryStoreStrategySync<K, V> extends SerializeStrategySync<K, V> {
16
- protected readonly node: Record<number, BPTreeNode<K, V>>;
16
+ protected readonly node: Record<string, BPTreeNode<K, V>>;
17
17
  constructor(order: number);
18
- id(isLeaf: boolean): number;
19
- read(id: number): BPTreeNode<K, V>;
20
- write(id: number, node: BPTreeNode<K, V>): void;
21
- delete(id: number): void;
18
+ id(isLeaf: boolean): string;
19
+ read(id: string): BPTreeNode<K, V>;
20
+ write(id: string, node: BPTreeNode<K, V>): void;
21
+ delete(id: string): void;
22
22
  readHead(): SerializeStrategyHead | null;
23
23
  writeHead(head: SerializeStrategyHead): void;
24
24
  }
@@ -1,9 +1,10 @@
1
1
  import { ValueComparator } from './ValueComparator';
2
2
  import { SerializableData, SerializeStrategy } from './SerializeStrategy';
3
+ import { InvertedWeakMap } from '../utils/InvertedWeakMap';
3
4
  type Sync<T> = T;
4
5
  type Async<T> = Promise<T>;
5
6
  type Deferred<T> = Sync<T> | Async<T>;
6
- export type BPTreeNodeKey<K> = number | K;
7
+ export type BPTreeNodeKey<K> = string | K;
7
8
  export type BPTreeCondition<V> = Partial<{
8
9
  /** Searches for pairs greater than the given value. */
9
10
  gt: Partial<V>;
@@ -26,17 +27,17 @@ export type BPTreePair<K, V> = {
26
27
  };
27
28
  export type BPTreeUnknownNode<K, V> = BPTreeInternalNode<K, V> | BPTreeLeafNode<K, V>;
28
29
  export interface BPTreeNode<K, V> {
29
- id: number;
30
- keys: number[] | K[][];
30
+ id: string;
31
+ keys: string[] | K[][];
31
32
  values: V[];
32
33
  leaf: boolean;
33
- parent: number;
34
- next: number;
35
- prev: number;
34
+ parent: string | null;
35
+ next: string | null;
36
+ prev: string | null;
36
37
  }
37
38
  export interface BPTreeInternalNode<K, V> extends BPTreeNode<K, V> {
38
39
  leaf: false;
39
- keys: number[];
40
+ keys: string[];
40
41
  }
41
42
  export interface BPTreeLeafNode<K, V> extends BPTreeNode<K, V> {
42
43
  leaf: true;
@@ -46,12 +47,12 @@ export declare abstract class BPTree<K, V> {
46
47
  private readonly _cachedRegexp;
47
48
  protected readonly strategy: SerializeStrategy<K, V>;
48
49
  protected readonly comparator: ValueComparator<V>;
49
- protected readonly nodes: Map<number, BPTreeUnknownNode<K, V>>;
50
+ protected readonly nodes: InvertedWeakMap<string, BPTreeUnknownNode<K, V>>;
50
51
  protected order: number;
51
52
  protected root: BPTreeUnknownNode<K, V>;
52
- protected readonly _nodeCreateBuffer: Map<number, BPTreeUnknownNode<K, V>>;
53
- protected readonly _nodeUpdateBuffer: Map<number, BPTreeUnknownNode<K, V>>;
54
- protected readonly _nodeDeleteBuffer: Map<number, BPTreeUnknownNode<K, V>>;
53
+ protected readonly _nodeCreateBuffer: Map<string, BPTreeUnknownNode<K, V>>;
54
+ protected readonly _nodeUpdateBuffer: Map<string, BPTreeUnknownNode<K, V>>;
55
+ protected readonly _nodeDeleteBuffer: Map<string, BPTreeUnknownNode<K, V>>;
55
56
  protected readonly verifierMap: Record<keyof BPTreeCondition<V>, (nodeValue: V, value: V) => boolean>;
56
57
  protected readonly verifierStartNode: Record<keyof BPTreeCondition<V>, (value: V) => Deferred<BPTreeLeafNode<K, V>>>;
57
58
  protected readonly verifierDirection: Record<keyof BPTreeCondition<V>, -1 | 1>;
@@ -60,11 +61,11 @@ export declare abstract class BPTree<K, V> {
60
61
  protected abstract _getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>[]>;
61
62
  protected abstract _getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>[]>;
62
63
  protected abstract getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: -1 | 1): Deferred<BPTreePair<K, V>[]>;
63
- protected abstract _createNodeId(isLeaf: boolean): Deferred<number>;
64
- protected abstract _createNode(isLeaf: boolean, keys: number[] | K[][], values: V[], leaf?: boolean, parent?: number, next?: number, prev?: number): Deferred<BPTreeUnknownNode<K, V>>;
64
+ protected abstract _createNodeId(isLeaf: boolean): Deferred<string>;
65
+ protected abstract _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): Deferred<BPTreeUnknownNode<K, V>>;
65
66
  protected abstract _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): Deferred<void>;
66
67
  protected abstract _insertInParent(node: BPTreeUnknownNode<K, V>, value: V, pointer: BPTreeUnknownNode<K, V>): Deferred<void>;
67
- protected abstract getNode(id: number): Deferred<BPTreeUnknownNode<K, V>>;
68
+ protected abstract getNode(id: string): Deferred<BPTreeUnknownNode<K, V>>;
68
69
  protected abstract insertableNode(value: V): Deferred<BPTreeLeafNode<K, V>>;
69
70
  protected abstract leftestNode(): Deferred<BPTreeLeafNode<K, V>>;
70
71
  protected abstract commitHeadBuffer(): Deferred<void>;
@@ -2,7 +2,7 @@ import { BPTreeNode } from './BPTree';
2
2
  import type { Json } from '../utils/types';
3
3
  export type SerializableData = Record<string, Json>;
4
4
  export interface SerializeStrategyHead {
5
- root: number;
5
+ root: string | null;
6
6
  order: number;
7
7
  data: SerializableData;
8
8
  }
@@ -14,29 +14,28 @@ export declare abstract class SerializeStrategy<K, V> {
14
14
  * The rule for generating node IDs is set.
15
15
  * When a new node is created within the tree, the value returned by this method becomes the node's ID.
16
16
  *
17
- * **WARNING!** The return value should never be `0`.
18
17
  * @param isLeaf This is a flag that indicates whether the node is a leaf node or not.
19
18
  */
20
- abstract id(isLeaf: boolean): number | Promise<number>;
19
+ abstract id(isLeaf: boolean): string | Promise<string>;
21
20
  /**
22
21
  * Read the stored node from the ID.
23
22
  * The JSON object of the read node should be returned.
24
23
  * @param id This is the ID of the node to be read.
25
24
  */
26
- abstract read(id: number): BPTreeNode<K, V> | Promise<BPTreeNode<K, V>>;
25
+ abstract read(id: string): BPTreeNode<K, V> | Promise<BPTreeNode<K, V>>;
27
26
  /**
28
27
  * It is called when a node is created or updated and needs to be stored.
29
28
  * The node ID and the node JSON object are passed as parameters. Use this to store the data.
30
29
  * @param id This is the ID of the node to be stored.
31
30
  * @param node This is the JSON object of the node to be stored.
32
31
  */
33
- abstract write(id: number, node: BPTreeNode<K, V>): void | Promise<void>;
32
+ abstract write(id: string, node: BPTreeNode<K, V>): void | Promise<void>;
34
33
  /**
35
34
  * This method is called when previously created nodes become no longer needed due to deletion or other processes.
36
35
  * It can be used to free up space by deleting existing stored nodes.
37
36
  * @param id This is the ID of the node to be deleted.
38
37
  */
39
- abstract delete(id: number): void | Promise<void>;
38
+ abstract delete(id: string): void | Promise<void>;
40
39
  /**
41
40
  * It is called when the `init` method of the tree instance is called.
42
41
  * This method should return the information needed to initialize the tree. This information refers to the values stored in the `writeHead` method.
@@ -53,7 +52,7 @@ export declare abstract class SerializeStrategy<K, V> {
53
52
  abstract writeHead(head: SerializeStrategyHead): void | Promise<void>;
54
53
  /**
55
54
  * Retrieves the data stored in the tree.
56
- * If there are no values stored in the tree, it returns the `defaultValue`.
55
+ * If no value is stored in the tree, it stores a `defaultValue` and then returns that value.
57
56
  * @param key The key of the data stored in the tree.
58
57
  */
59
58
  abstract getHeadData(key: string, defaultValue: Json): Json | Promise<Json>;
@@ -0,0 +1,12 @@
1
+ export declare class InvertedWeakMap<K extends string | number | symbol, V extends WeakKey> {
2
+ private readonly _map;
3
+ private readonly _registry;
4
+ constructor();
5
+ clear(): void;
6
+ delete(key: K): boolean;
7
+ get(key: K): V | undefined;
8
+ has(key: K): boolean;
9
+ set(key: K, value: V): this;
10
+ get size(): number;
11
+ keys(): IterableIterator<K>;
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "3.4.0-alpha.1",
3
+ "version": "4.0.1",
4
4
  "description": "Store the B+tree flexibly, not only in-memory.",
5
5
  "main": "dist/cjs/index.cjs",
6
6
  "module": "dist/esm/index.mjs",