serializable-bptree 8.3.0 → 8.3.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.
@@ -1519,83 +1519,217 @@ var BPTreeTransaction = class _BPTreeTransaction {
1519
1519
  return regexp.test(nodeValue);
1520
1520
  }
1521
1521
  };
1522
- verifierStartNode = {
1523
- gt: (v) => this.insertableNodeByPrimary(v),
1524
- gte: (v) => this.insertableNodeByPrimary(v),
1525
- lt: (v) => this.insertableNodeByPrimary(v),
1526
- lte: (v) => this.insertableRightestNodeByPrimary(v),
1527
- equal: (v) => this.insertableNodeByPrimary(v),
1528
- notEqual: (v) => this.leftestNode(),
1529
- or: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
1530
- primaryGt: (v) => this.insertableNodeByPrimary(v),
1531
- primaryGte: (v) => this.insertableNodeByPrimary(v),
1532
- primaryLt: (v) => this.insertableNodeByPrimary(v),
1533
- primaryLte: (v) => this.insertableRightestNodeByPrimary(v),
1534
- primaryEqual: (v) => this.insertableNodeByPrimary(v),
1535
- primaryNotEqual: (v) => this.leftestNode(),
1536
- primaryOr: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
1537
- like: (v) => this.leftestNode()
1538
- };
1539
- verifierEndNode = {
1540
- gt: (v) => null,
1541
- gte: (v) => null,
1542
- lt: (v) => null,
1543
- lte: (v) => null,
1544
- equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
1545
- notEqual: (v) => null,
1546
- or: (v) => this.insertableEndNode(
1547
- this.highestValue(this.ensureValues(v)),
1548
- this.verifierDirection.or
1549
- ),
1550
- primaryGt: (v) => null,
1551
- primaryGte: (v) => null,
1552
- primaryLt: (v) => null,
1553
- primaryLte: (v) => null,
1554
- primaryEqual: (v) => this.insertableRightestEndNodeByPrimary(v),
1555
- primaryNotEqual: (v) => null,
1556
- primaryOr: (v) => this.insertableRightestEndNodeByPrimary(
1557
- this.highestPrimaryValue(this.ensureValues(v))
1558
- ),
1559
- like: (v) => null
1560
- };
1561
- verifierDirection = {
1562
- gt: 1,
1563
- gte: 1,
1564
- lt: -1,
1565
- lte: -1,
1566
- equal: 1,
1567
- notEqual: 1,
1568
- or: 1,
1569
- primaryGt: 1,
1570
- primaryGte: 1,
1571
- primaryLt: -1,
1572
- primaryLte: -1,
1573
- primaryEqual: 1,
1574
- primaryNotEqual: 1,
1575
- primaryOr: 1,
1576
- like: 1
1577
- };
1578
- /**
1579
- * Determines whether early termination is allowed for each condition.
1580
- * When true, the search will stop once a match is found and then a non-match is encountered.
1581
- * Only applicable for conditions that guarantee contiguous matches in a sorted B+Tree.
1582
- */
1583
- verifierEarlyTerminate = {
1584
- gt: false,
1585
- gte: false,
1586
- lt: false,
1587
- lte: false,
1588
- equal: true,
1589
- notEqual: false,
1590
- or: false,
1591
- primaryGt: false,
1592
- primaryGte: false,
1593
- primaryLt: false,
1594
- primaryLte: false,
1595
- primaryEqual: true,
1596
- primaryNotEqual: false,
1597
- primaryOr: false,
1598
- like: false
1522
+ searchConfigs = {
1523
+ gt: {
1524
+ asc: {
1525
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1526
+ end: () => null,
1527
+ direction: 1,
1528
+ earlyTerminate: false
1529
+ },
1530
+ desc: {
1531
+ start: (tx) => tx.rightestNode(),
1532
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1533
+ direction: -1,
1534
+ earlyTerminate: true
1535
+ }
1536
+ },
1537
+ gte: {
1538
+ asc: {
1539
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1540
+ end: () => null,
1541
+ direction: 1,
1542
+ earlyTerminate: false
1543
+ },
1544
+ desc: {
1545
+ start: (tx) => tx.rightestNode(),
1546
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1547
+ direction: -1,
1548
+ earlyTerminate: true
1549
+ }
1550
+ },
1551
+ lt: {
1552
+ asc: {
1553
+ start: (tx) => tx.leftestNode(),
1554
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1555
+ direction: 1,
1556
+ earlyTerminate: true
1557
+ },
1558
+ desc: {
1559
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1560
+ end: () => null,
1561
+ direction: -1,
1562
+ earlyTerminate: false
1563
+ }
1564
+ },
1565
+ lte: {
1566
+ asc: {
1567
+ start: (tx) => tx.leftestNode(),
1568
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1569
+ direction: 1,
1570
+ earlyTerminate: true
1571
+ },
1572
+ desc: {
1573
+ start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
1574
+ end: () => null,
1575
+ direction: -1,
1576
+ earlyTerminate: false
1577
+ }
1578
+ },
1579
+ equal: {
1580
+ asc: {
1581
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1582
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1583
+ direction: 1,
1584
+ earlyTerminate: true
1585
+ },
1586
+ desc: {
1587
+ start: (tx, v) => tx.insertableEndNode(v[0], 1),
1588
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1589
+ direction: -1,
1590
+ earlyTerminate: true
1591
+ }
1592
+ },
1593
+ notEqual: {
1594
+ asc: {
1595
+ start: (tx) => tx.leftestNode(),
1596
+ end: () => null,
1597
+ direction: 1,
1598
+ earlyTerminate: false
1599
+ },
1600
+ desc: {
1601
+ start: (tx) => tx.rightestNode(),
1602
+ end: () => null,
1603
+ direction: -1,
1604
+ earlyTerminate: false
1605
+ }
1606
+ },
1607
+ or: {
1608
+ asc: {
1609
+ start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestValue(v)),
1610
+ end: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
1611
+ direction: 1,
1612
+ earlyTerminate: false
1613
+ },
1614
+ desc: {
1615
+ start: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
1616
+ end: (tx, v) => tx.insertableEndNode(tx.lowestValue(v), -1),
1617
+ direction: -1,
1618
+ earlyTerminate: false
1619
+ }
1620
+ },
1621
+ primaryGt: {
1622
+ asc: {
1623
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1624
+ end: () => null,
1625
+ direction: 1,
1626
+ earlyTerminate: false
1627
+ },
1628
+ desc: {
1629
+ start: (tx) => tx.rightestNode(),
1630
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1631
+ direction: -1,
1632
+ earlyTerminate: true
1633
+ }
1634
+ },
1635
+ primaryGte: {
1636
+ asc: {
1637
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1638
+ end: () => null,
1639
+ direction: 1,
1640
+ earlyTerminate: false
1641
+ },
1642
+ desc: {
1643
+ start: (tx) => tx.rightestNode(),
1644
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1645
+ direction: -1,
1646
+ earlyTerminate: true
1647
+ }
1648
+ },
1649
+ primaryLt: {
1650
+ asc: {
1651
+ start: (tx) => tx.leftestNode(),
1652
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1653
+ direction: 1,
1654
+ earlyTerminate: true
1655
+ },
1656
+ desc: {
1657
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1658
+ end: () => null,
1659
+ direction: -1,
1660
+ earlyTerminate: false
1661
+ }
1662
+ },
1663
+ primaryLte: {
1664
+ asc: {
1665
+ start: (tx) => tx.leftestNode(),
1666
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1667
+ direction: 1,
1668
+ earlyTerminate: true
1669
+ },
1670
+ desc: {
1671
+ start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
1672
+ end: () => null,
1673
+ direction: -1,
1674
+ earlyTerminate: false
1675
+ }
1676
+ },
1677
+ primaryEqual: {
1678
+ asc: {
1679
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1680
+ end: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
1681
+ direction: 1,
1682
+ earlyTerminate: true
1683
+ },
1684
+ desc: {
1685
+ start: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
1686
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1687
+ direction: -1,
1688
+ earlyTerminate: true
1689
+ }
1690
+ },
1691
+ primaryNotEqual: {
1692
+ asc: {
1693
+ start: (tx) => tx.leftestNode(),
1694
+ end: () => null,
1695
+ direction: 1,
1696
+ earlyTerminate: false
1697
+ },
1698
+ desc: {
1699
+ start: (tx) => tx.rightestNode(),
1700
+ end: () => null,
1701
+ direction: -1,
1702
+ earlyTerminate: false
1703
+ }
1704
+ },
1705
+ primaryOr: {
1706
+ asc: {
1707
+ start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestPrimaryValue(v)),
1708
+ end: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
1709
+ direction: 1,
1710
+ earlyTerminate: false
1711
+ },
1712
+ desc: {
1713
+ start: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
1714
+ end: (tx, v) => tx.insertableEndNode(tx.lowestPrimaryValue(v), -1),
1715
+ direction: -1,
1716
+ earlyTerminate: false
1717
+ }
1718
+ },
1719
+ like: {
1720
+ asc: {
1721
+ start: (tx) => tx.leftestNode(),
1722
+ end: () => null,
1723
+ direction: 1,
1724
+ earlyTerminate: false
1725
+ },
1726
+ desc: {
1727
+ start: (tx) => tx.rightestNode(),
1728
+ end: () => null,
1729
+ direction: -1,
1730
+ earlyTerminate: false
1731
+ }
1732
+ }
1599
1733
  };
1600
1734
  /**
1601
1735
  * Priority map for condition types.
@@ -1696,6 +1830,39 @@ var BPTreeTransaction = class _BPTreeTransaction {
1696
1830
  }
1697
1831
  return true;
1698
1832
  }
1833
+ /**
1834
+ * Inserts a key-value pair into an already-cloned leaf node in-place.
1835
+ * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
1836
+ * Used by batchInsert to batch multiple insertions with a single clone/update.
1837
+ * @returns true if the leaf was modified, false if the key already exists.
1838
+ */
1839
+ _insertValueIntoLeaf(leaf, key, value) {
1840
+ if (leaf.values.length) {
1841
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
1842
+ const nValue = leaf.values[i];
1843
+ if (this.comparator.isSame(value, nValue)) {
1844
+ if (leaf.keys[i].includes(key)) {
1845
+ return false;
1846
+ }
1847
+ leaf.keys[i].push(key);
1848
+ return true;
1849
+ } else if (this.comparator.isLower(value, nValue)) {
1850
+ leaf.values.splice(i, 0, value);
1851
+ leaf.keys.splice(i, 0, [key]);
1852
+ return true;
1853
+ } else if (i + 1 === leaf.values.length) {
1854
+ leaf.values.push(value);
1855
+ leaf.keys.push([key]);
1856
+ return true;
1857
+ }
1858
+ }
1859
+ } else {
1860
+ leaf.values = [value];
1861
+ leaf.keys = [[key]];
1862
+ return true;
1863
+ }
1864
+ return false;
1865
+ }
1699
1866
  _cloneNode(node) {
1700
1867
  return JSON.parse(JSON.stringify(node));
1701
1868
  }
@@ -2175,16 +2342,20 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2175
2342
  const driverKey = this.getDriverKey(condition);
2176
2343
  if (!driverKey) return;
2177
2344
  const value = condition[driverKey];
2178
- let startNode = this.verifierStartNode[driverKey](value);
2179
- let endNode = this.verifierEndNode[driverKey](value);
2180
- let direction = this.verifierDirection[driverKey];
2345
+ const v = this.ensureValues(value);
2346
+ const config = this.searchConfigs[driverKey][order];
2347
+ let startNode = config.start(this, v);
2348
+ let endNode = config.end(this, v);
2349
+ const direction = config.direction;
2350
+ const earlyTerminate = config.earlyTerminate;
2351
+ if (order === "desc" && !startNode) {
2352
+ startNode = this.rightestNode();
2353
+ }
2354
+ if (order === "asc" && !startNode) {
2355
+ startNode = this.leftestNode();
2356
+ }
2357
+ if (!startNode) return;
2181
2358
  const comparator = this.verifierMap[driverKey];
2182
- const earlyTerminate = this.verifierEarlyTerminate[driverKey];
2183
- if (order === "desc") {
2184
- startNode = endNode ?? this.rightestNode();
2185
- endNode = null;
2186
- direction *= -1;
2187
- }
2188
2359
  const generator = this.getPairsGenerator(
2189
2360
  value,
2190
2361
  startNode,
@@ -2196,7 +2367,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2196
2367
  let count = 0;
2197
2368
  const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2198
2369
  for (const pair of generator) {
2199
- const [k, v] = pair;
2370
+ const [k, v2] = pair;
2200
2371
  if (intersection && !intersection.has(k)) {
2201
2372
  continue;
2202
2373
  }
@@ -2205,7 +2376,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2205
2376
  if (key === driverKey) continue;
2206
2377
  const verify = this.verifierMap[key];
2207
2378
  const condValue = condition[key];
2208
- if (!verify(v, condValue)) {
2379
+ if (!verify(v2, condValue)) {
2209
2380
  isMatch = false;
2210
2381
  break;
2211
2382
  }
@@ -2259,29 +2430,46 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2259
2430
  batchInsert(entries) {
2260
2431
  if (entries.length === 0) return;
2261
2432
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2433
+ let currentLeaf = null;
2434
+ let modified = false;
2262
2435
  for (const [key, value] of sorted) {
2263
- let before = this.insertableNode(value);
2264
- before = this._insertAtLeaf(before, key, value);
2265
- if (before.values.length === this.order) {
2436
+ const targetLeaf = this.insertableNode(value);
2437
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2438
+ } else {
2439
+ if (currentLeaf !== null && modified) {
2440
+ this._updateNode(currentLeaf);
2441
+ }
2442
+ currentLeaf = this._cloneNode(targetLeaf);
2443
+ modified = false;
2444
+ }
2445
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2446
+ modified = modified || changed;
2447
+ if (currentLeaf.values.length === this.order) {
2448
+ this._updateNode(currentLeaf);
2266
2449
  let after = this._createNode(
2267
2450
  true,
2268
2451
  [],
2269
2452
  [],
2270
- before.parent,
2453
+ currentLeaf.parent,
2271
2454
  null,
2272
2455
  null
2273
2456
  );
2274
2457
  const mid = Math.ceil(this.order / 2) - 1;
2275
2458
  after = this._cloneNode(after);
2276
- after.values = before.values.slice(mid + 1);
2277
- after.keys = before.keys.slice(mid + 1);
2278
- before.values = before.values.slice(0, mid + 1);
2279
- before.keys = before.keys.slice(0, mid + 1);
2280
- this._updateNode(before);
2459
+ after.values = currentLeaf.values.slice(mid + 1);
2460
+ after.keys = currentLeaf.keys.slice(mid + 1);
2461
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
2462
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
2463
+ this._updateNode(currentLeaf);
2281
2464
  this._updateNode(after);
2282
- this._insertInParent(before, after.values[0], after);
2465
+ this._insertInParent(currentLeaf, after.values[0], after);
2466
+ currentLeaf = null;
2467
+ modified = false;
2283
2468
  }
2284
2469
  }
2470
+ if (currentLeaf !== null && modified) {
2471
+ this._updateNode(currentLeaf);
2472
+ }
2285
2473
  }
2286
2474
  _deleteEntry(node, key) {
2287
2475
  if (!node.leaf) {
@@ -3296,16 +3484,20 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3296
3484
  const driverKey = this.getDriverKey(condition);
3297
3485
  if (!driverKey) return;
3298
3486
  const value = condition[driverKey];
3299
- let startNode = await this.verifierStartNode[driverKey](value);
3300
- let endNode = await this.verifierEndNode[driverKey](value);
3301
- let direction = this.verifierDirection[driverKey];
3487
+ const v = this.ensureValues(value);
3488
+ const config = this.searchConfigs[driverKey][order];
3489
+ let startNode = await config.start(this, v);
3490
+ let endNode = await config.end(this, v);
3491
+ const direction = config.direction;
3492
+ const earlyTerminate = config.earlyTerminate;
3493
+ if (order === "desc" && !startNode) {
3494
+ startNode = await this.rightestNode();
3495
+ }
3496
+ if (order === "asc" && !startNode) {
3497
+ startNode = await this.leftestNode();
3498
+ }
3499
+ if (!startNode) return;
3302
3500
  const comparator = this.verifierMap[driverKey];
3303
- const earlyTerminate = this.verifierEarlyTerminate[driverKey];
3304
- if (order === "desc") {
3305
- startNode = endNode ?? await this.rightestNode();
3306
- endNode = null;
3307
- direction *= -1;
3308
- }
3309
3501
  const generator = this.getPairsGenerator(
3310
3502
  value,
3311
3503
  startNode,
@@ -3317,7 +3509,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3317
3509
  let count = 0;
3318
3510
  const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3319
3511
  for await (const pair of generator) {
3320
- const [k, v] = pair;
3512
+ const [k, v2] = pair;
3321
3513
  if (intersection && !intersection.has(k)) {
3322
3514
  continue;
3323
3515
  }
@@ -3326,7 +3518,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3326
3518
  if (key === driverKey) continue;
3327
3519
  const verify = this.verifierMap[key];
3328
3520
  const condValue = condition[key];
3329
- if (!verify(v, condValue)) {
3521
+ if (!verify(v2, condValue)) {
3330
3522
  isMatch = false;
3331
3523
  break;
3332
3524
  }
@@ -3383,29 +3575,46 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3383
3575
  if (entries.length === 0) return;
3384
3576
  return this.writeLock(0, async () => {
3385
3577
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3578
+ let currentLeaf = null;
3579
+ let modified = false;
3386
3580
  for (const [key, value] of sorted) {
3387
- let before = await this.insertableNode(value);
3388
- before = await this._insertAtLeaf(before, key, value);
3389
- if (before.values.length === this.order) {
3581
+ const targetLeaf = await this.insertableNode(value);
3582
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3583
+ } else {
3584
+ if (currentLeaf !== null && modified) {
3585
+ await this._updateNode(currentLeaf);
3586
+ }
3587
+ currentLeaf = this._cloneNode(targetLeaf);
3588
+ modified = false;
3589
+ }
3590
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3591
+ modified = modified || changed;
3592
+ if (currentLeaf.values.length === this.order) {
3593
+ await this._updateNode(currentLeaf);
3390
3594
  let after = await this._createNode(
3391
3595
  true,
3392
3596
  [],
3393
3597
  [],
3394
- before.parent,
3598
+ currentLeaf.parent,
3395
3599
  null,
3396
3600
  null
3397
3601
  );
3398
3602
  const mid = Math.ceil(this.order / 2) - 1;
3399
3603
  after = this._cloneNode(after);
3400
- after.values = before.values.slice(mid + 1);
3401
- after.keys = before.keys.slice(mid + 1);
3402
- before.values = before.values.slice(0, mid + 1);
3403
- before.keys = before.keys.slice(0, mid + 1);
3404
- await this._updateNode(before);
3604
+ after.values = currentLeaf.values.slice(mid + 1);
3605
+ after.keys = currentLeaf.keys.slice(mid + 1);
3606
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
3607
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
3608
+ await this._updateNode(currentLeaf);
3405
3609
  await this._updateNode(after);
3406
- await this._insertInParent(before, after.values[0], after);
3610
+ await this._insertInParent(currentLeaf, after.values[0], after);
3611
+ currentLeaf = null;
3612
+ modified = false;
3407
3613
  }
3408
3614
  }
3615
+ if (currentLeaf !== null && modified) {
3616
+ await this._updateNode(currentLeaf);
3617
+ }
3409
3618
  });
3410
3619
  }
3411
3620
  async _deleteEntry(node, key) {
@@ -1483,83 +1483,217 @@ var BPTreeTransaction = class _BPTreeTransaction {
1483
1483
  return regexp.test(nodeValue);
1484
1484
  }
1485
1485
  };
1486
- verifierStartNode = {
1487
- gt: (v) => this.insertableNodeByPrimary(v),
1488
- gte: (v) => this.insertableNodeByPrimary(v),
1489
- lt: (v) => this.insertableNodeByPrimary(v),
1490
- lte: (v) => this.insertableRightestNodeByPrimary(v),
1491
- equal: (v) => this.insertableNodeByPrimary(v),
1492
- notEqual: (v) => this.leftestNode(),
1493
- or: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
1494
- primaryGt: (v) => this.insertableNodeByPrimary(v),
1495
- primaryGte: (v) => this.insertableNodeByPrimary(v),
1496
- primaryLt: (v) => this.insertableNodeByPrimary(v),
1497
- primaryLte: (v) => this.insertableRightestNodeByPrimary(v),
1498
- primaryEqual: (v) => this.insertableNodeByPrimary(v),
1499
- primaryNotEqual: (v) => this.leftestNode(),
1500
- primaryOr: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
1501
- like: (v) => this.leftestNode()
1502
- };
1503
- verifierEndNode = {
1504
- gt: (v) => null,
1505
- gte: (v) => null,
1506
- lt: (v) => null,
1507
- lte: (v) => null,
1508
- equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
1509
- notEqual: (v) => null,
1510
- or: (v) => this.insertableEndNode(
1511
- this.highestValue(this.ensureValues(v)),
1512
- this.verifierDirection.or
1513
- ),
1514
- primaryGt: (v) => null,
1515
- primaryGte: (v) => null,
1516
- primaryLt: (v) => null,
1517
- primaryLte: (v) => null,
1518
- primaryEqual: (v) => this.insertableRightestEndNodeByPrimary(v),
1519
- primaryNotEqual: (v) => null,
1520
- primaryOr: (v) => this.insertableRightestEndNodeByPrimary(
1521
- this.highestPrimaryValue(this.ensureValues(v))
1522
- ),
1523
- like: (v) => null
1524
- };
1525
- verifierDirection = {
1526
- gt: 1,
1527
- gte: 1,
1528
- lt: -1,
1529
- lte: -1,
1530
- equal: 1,
1531
- notEqual: 1,
1532
- or: 1,
1533
- primaryGt: 1,
1534
- primaryGte: 1,
1535
- primaryLt: -1,
1536
- primaryLte: -1,
1537
- primaryEqual: 1,
1538
- primaryNotEqual: 1,
1539
- primaryOr: 1,
1540
- like: 1
1541
- };
1542
- /**
1543
- * Determines whether early termination is allowed for each condition.
1544
- * When true, the search will stop once a match is found and then a non-match is encountered.
1545
- * Only applicable for conditions that guarantee contiguous matches in a sorted B+Tree.
1546
- */
1547
- verifierEarlyTerminate = {
1548
- gt: false,
1549
- gte: false,
1550
- lt: false,
1551
- lte: false,
1552
- equal: true,
1553
- notEqual: false,
1554
- or: false,
1555
- primaryGt: false,
1556
- primaryGte: false,
1557
- primaryLt: false,
1558
- primaryLte: false,
1559
- primaryEqual: true,
1560
- primaryNotEqual: false,
1561
- primaryOr: false,
1562
- like: false
1486
+ searchConfigs = {
1487
+ gt: {
1488
+ asc: {
1489
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1490
+ end: () => null,
1491
+ direction: 1,
1492
+ earlyTerminate: false
1493
+ },
1494
+ desc: {
1495
+ start: (tx) => tx.rightestNode(),
1496
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1497
+ direction: -1,
1498
+ earlyTerminate: true
1499
+ }
1500
+ },
1501
+ gte: {
1502
+ asc: {
1503
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1504
+ end: () => null,
1505
+ direction: 1,
1506
+ earlyTerminate: false
1507
+ },
1508
+ desc: {
1509
+ start: (tx) => tx.rightestNode(),
1510
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1511
+ direction: -1,
1512
+ earlyTerminate: true
1513
+ }
1514
+ },
1515
+ lt: {
1516
+ asc: {
1517
+ start: (tx) => tx.leftestNode(),
1518
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1519
+ direction: 1,
1520
+ earlyTerminate: true
1521
+ },
1522
+ desc: {
1523
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1524
+ end: () => null,
1525
+ direction: -1,
1526
+ earlyTerminate: false
1527
+ }
1528
+ },
1529
+ lte: {
1530
+ asc: {
1531
+ start: (tx) => tx.leftestNode(),
1532
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1533
+ direction: 1,
1534
+ earlyTerminate: true
1535
+ },
1536
+ desc: {
1537
+ start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
1538
+ end: () => null,
1539
+ direction: -1,
1540
+ earlyTerminate: false
1541
+ }
1542
+ },
1543
+ equal: {
1544
+ asc: {
1545
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1546
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1547
+ direction: 1,
1548
+ earlyTerminate: true
1549
+ },
1550
+ desc: {
1551
+ start: (tx, v) => tx.insertableEndNode(v[0], 1),
1552
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1553
+ direction: -1,
1554
+ earlyTerminate: true
1555
+ }
1556
+ },
1557
+ notEqual: {
1558
+ asc: {
1559
+ start: (tx) => tx.leftestNode(),
1560
+ end: () => null,
1561
+ direction: 1,
1562
+ earlyTerminate: false
1563
+ },
1564
+ desc: {
1565
+ start: (tx) => tx.rightestNode(),
1566
+ end: () => null,
1567
+ direction: -1,
1568
+ earlyTerminate: false
1569
+ }
1570
+ },
1571
+ or: {
1572
+ asc: {
1573
+ start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestValue(v)),
1574
+ end: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
1575
+ direction: 1,
1576
+ earlyTerminate: false
1577
+ },
1578
+ desc: {
1579
+ start: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
1580
+ end: (tx, v) => tx.insertableEndNode(tx.lowestValue(v), -1),
1581
+ direction: -1,
1582
+ earlyTerminate: false
1583
+ }
1584
+ },
1585
+ primaryGt: {
1586
+ asc: {
1587
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1588
+ end: () => null,
1589
+ direction: 1,
1590
+ earlyTerminate: false
1591
+ },
1592
+ desc: {
1593
+ start: (tx) => tx.rightestNode(),
1594
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1595
+ direction: -1,
1596
+ earlyTerminate: true
1597
+ }
1598
+ },
1599
+ primaryGte: {
1600
+ asc: {
1601
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1602
+ end: () => null,
1603
+ direction: 1,
1604
+ earlyTerminate: false
1605
+ },
1606
+ desc: {
1607
+ start: (tx) => tx.rightestNode(),
1608
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1609
+ direction: -1,
1610
+ earlyTerminate: true
1611
+ }
1612
+ },
1613
+ primaryLt: {
1614
+ asc: {
1615
+ start: (tx) => tx.leftestNode(),
1616
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1617
+ direction: 1,
1618
+ earlyTerminate: true
1619
+ },
1620
+ desc: {
1621
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1622
+ end: () => null,
1623
+ direction: -1,
1624
+ earlyTerminate: false
1625
+ }
1626
+ },
1627
+ primaryLte: {
1628
+ asc: {
1629
+ start: (tx) => tx.leftestNode(),
1630
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1631
+ direction: 1,
1632
+ earlyTerminate: true
1633
+ },
1634
+ desc: {
1635
+ start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
1636
+ end: () => null,
1637
+ direction: -1,
1638
+ earlyTerminate: false
1639
+ }
1640
+ },
1641
+ primaryEqual: {
1642
+ asc: {
1643
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1644
+ end: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
1645
+ direction: 1,
1646
+ earlyTerminate: true
1647
+ },
1648
+ desc: {
1649
+ start: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
1650
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1651
+ direction: -1,
1652
+ earlyTerminate: true
1653
+ }
1654
+ },
1655
+ primaryNotEqual: {
1656
+ asc: {
1657
+ start: (tx) => tx.leftestNode(),
1658
+ end: () => null,
1659
+ direction: 1,
1660
+ earlyTerminate: false
1661
+ },
1662
+ desc: {
1663
+ start: (tx) => tx.rightestNode(),
1664
+ end: () => null,
1665
+ direction: -1,
1666
+ earlyTerminate: false
1667
+ }
1668
+ },
1669
+ primaryOr: {
1670
+ asc: {
1671
+ start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestPrimaryValue(v)),
1672
+ end: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
1673
+ direction: 1,
1674
+ earlyTerminate: false
1675
+ },
1676
+ desc: {
1677
+ start: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
1678
+ end: (tx, v) => tx.insertableEndNode(tx.lowestPrimaryValue(v), -1),
1679
+ direction: -1,
1680
+ earlyTerminate: false
1681
+ }
1682
+ },
1683
+ like: {
1684
+ asc: {
1685
+ start: (tx) => tx.leftestNode(),
1686
+ end: () => null,
1687
+ direction: 1,
1688
+ earlyTerminate: false
1689
+ },
1690
+ desc: {
1691
+ start: (tx) => tx.rightestNode(),
1692
+ end: () => null,
1693
+ direction: -1,
1694
+ earlyTerminate: false
1695
+ }
1696
+ }
1563
1697
  };
1564
1698
  /**
1565
1699
  * Priority map for condition types.
@@ -1660,6 +1794,39 @@ var BPTreeTransaction = class _BPTreeTransaction {
1660
1794
  }
1661
1795
  return true;
1662
1796
  }
1797
+ /**
1798
+ * Inserts a key-value pair into an already-cloned leaf node in-place.
1799
+ * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
1800
+ * Used by batchInsert to batch multiple insertions with a single clone/update.
1801
+ * @returns true if the leaf was modified, false if the key already exists.
1802
+ */
1803
+ _insertValueIntoLeaf(leaf, key, value) {
1804
+ if (leaf.values.length) {
1805
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
1806
+ const nValue = leaf.values[i];
1807
+ if (this.comparator.isSame(value, nValue)) {
1808
+ if (leaf.keys[i].includes(key)) {
1809
+ return false;
1810
+ }
1811
+ leaf.keys[i].push(key);
1812
+ return true;
1813
+ } else if (this.comparator.isLower(value, nValue)) {
1814
+ leaf.values.splice(i, 0, value);
1815
+ leaf.keys.splice(i, 0, [key]);
1816
+ return true;
1817
+ } else if (i + 1 === leaf.values.length) {
1818
+ leaf.values.push(value);
1819
+ leaf.keys.push([key]);
1820
+ return true;
1821
+ }
1822
+ }
1823
+ } else {
1824
+ leaf.values = [value];
1825
+ leaf.keys = [[key]];
1826
+ return true;
1827
+ }
1828
+ return false;
1829
+ }
1663
1830
  _cloneNode(node) {
1664
1831
  return JSON.parse(JSON.stringify(node));
1665
1832
  }
@@ -2139,16 +2306,20 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2139
2306
  const driverKey = this.getDriverKey(condition);
2140
2307
  if (!driverKey) return;
2141
2308
  const value = condition[driverKey];
2142
- let startNode = this.verifierStartNode[driverKey](value);
2143
- let endNode = this.verifierEndNode[driverKey](value);
2144
- let direction = this.verifierDirection[driverKey];
2309
+ const v = this.ensureValues(value);
2310
+ const config = this.searchConfigs[driverKey][order];
2311
+ let startNode = config.start(this, v);
2312
+ let endNode = config.end(this, v);
2313
+ const direction = config.direction;
2314
+ const earlyTerminate = config.earlyTerminate;
2315
+ if (order === "desc" && !startNode) {
2316
+ startNode = this.rightestNode();
2317
+ }
2318
+ if (order === "asc" && !startNode) {
2319
+ startNode = this.leftestNode();
2320
+ }
2321
+ if (!startNode) return;
2145
2322
  const comparator = this.verifierMap[driverKey];
2146
- const earlyTerminate = this.verifierEarlyTerminate[driverKey];
2147
- if (order === "desc") {
2148
- startNode = endNode ?? this.rightestNode();
2149
- endNode = null;
2150
- direction *= -1;
2151
- }
2152
2323
  const generator = this.getPairsGenerator(
2153
2324
  value,
2154
2325
  startNode,
@@ -2160,7 +2331,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2160
2331
  let count = 0;
2161
2332
  const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2162
2333
  for (const pair of generator) {
2163
- const [k, v] = pair;
2334
+ const [k, v2] = pair;
2164
2335
  if (intersection && !intersection.has(k)) {
2165
2336
  continue;
2166
2337
  }
@@ -2169,7 +2340,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2169
2340
  if (key === driverKey) continue;
2170
2341
  const verify = this.verifierMap[key];
2171
2342
  const condValue = condition[key];
2172
- if (!verify(v, condValue)) {
2343
+ if (!verify(v2, condValue)) {
2173
2344
  isMatch = false;
2174
2345
  break;
2175
2346
  }
@@ -2223,29 +2394,46 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2223
2394
  batchInsert(entries) {
2224
2395
  if (entries.length === 0) return;
2225
2396
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2397
+ let currentLeaf = null;
2398
+ let modified = false;
2226
2399
  for (const [key, value] of sorted) {
2227
- let before = this.insertableNode(value);
2228
- before = this._insertAtLeaf(before, key, value);
2229
- if (before.values.length === this.order) {
2400
+ const targetLeaf = this.insertableNode(value);
2401
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2402
+ } else {
2403
+ if (currentLeaf !== null && modified) {
2404
+ this._updateNode(currentLeaf);
2405
+ }
2406
+ currentLeaf = this._cloneNode(targetLeaf);
2407
+ modified = false;
2408
+ }
2409
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2410
+ modified = modified || changed;
2411
+ if (currentLeaf.values.length === this.order) {
2412
+ this._updateNode(currentLeaf);
2230
2413
  let after = this._createNode(
2231
2414
  true,
2232
2415
  [],
2233
2416
  [],
2234
- before.parent,
2417
+ currentLeaf.parent,
2235
2418
  null,
2236
2419
  null
2237
2420
  );
2238
2421
  const mid = Math.ceil(this.order / 2) - 1;
2239
2422
  after = this._cloneNode(after);
2240
- after.values = before.values.slice(mid + 1);
2241
- after.keys = before.keys.slice(mid + 1);
2242
- before.values = before.values.slice(0, mid + 1);
2243
- before.keys = before.keys.slice(0, mid + 1);
2244
- this._updateNode(before);
2423
+ after.values = currentLeaf.values.slice(mid + 1);
2424
+ after.keys = currentLeaf.keys.slice(mid + 1);
2425
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
2426
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
2427
+ this._updateNode(currentLeaf);
2245
2428
  this._updateNode(after);
2246
- this._insertInParent(before, after.values[0], after);
2429
+ this._insertInParent(currentLeaf, after.values[0], after);
2430
+ currentLeaf = null;
2431
+ modified = false;
2247
2432
  }
2248
2433
  }
2434
+ if (currentLeaf !== null && modified) {
2435
+ this._updateNode(currentLeaf);
2436
+ }
2249
2437
  }
2250
2438
  _deleteEntry(node, key) {
2251
2439
  if (!node.leaf) {
@@ -3260,16 +3448,20 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3260
3448
  const driverKey = this.getDriverKey(condition);
3261
3449
  if (!driverKey) return;
3262
3450
  const value = condition[driverKey];
3263
- let startNode = await this.verifierStartNode[driverKey](value);
3264
- let endNode = await this.verifierEndNode[driverKey](value);
3265
- let direction = this.verifierDirection[driverKey];
3451
+ const v = this.ensureValues(value);
3452
+ const config = this.searchConfigs[driverKey][order];
3453
+ let startNode = await config.start(this, v);
3454
+ let endNode = await config.end(this, v);
3455
+ const direction = config.direction;
3456
+ const earlyTerminate = config.earlyTerminate;
3457
+ if (order === "desc" && !startNode) {
3458
+ startNode = await this.rightestNode();
3459
+ }
3460
+ if (order === "asc" && !startNode) {
3461
+ startNode = await this.leftestNode();
3462
+ }
3463
+ if (!startNode) return;
3266
3464
  const comparator = this.verifierMap[driverKey];
3267
- const earlyTerminate = this.verifierEarlyTerminate[driverKey];
3268
- if (order === "desc") {
3269
- startNode = endNode ?? await this.rightestNode();
3270
- endNode = null;
3271
- direction *= -1;
3272
- }
3273
3465
  const generator = this.getPairsGenerator(
3274
3466
  value,
3275
3467
  startNode,
@@ -3281,7 +3473,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3281
3473
  let count = 0;
3282
3474
  const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3283
3475
  for await (const pair of generator) {
3284
- const [k, v] = pair;
3476
+ const [k, v2] = pair;
3285
3477
  if (intersection && !intersection.has(k)) {
3286
3478
  continue;
3287
3479
  }
@@ -3290,7 +3482,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3290
3482
  if (key === driverKey) continue;
3291
3483
  const verify = this.verifierMap[key];
3292
3484
  const condValue = condition[key];
3293
- if (!verify(v, condValue)) {
3485
+ if (!verify(v2, condValue)) {
3294
3486
  isMatch = false;
3295
3487
  break;
3296
3488
  }
@@ -3347,29 +3539,46 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3347
3539
  if (entries.length === 0) return;
3348
3540
  return this.writeLock(0, async () => {
3349
3541
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3542
+ let currentLeaf = null;
3543
+ let modified = false;
3350
3544
  for (const [key, value] of sorted) {
3351
- let before = await this.insertableNode(value);
3352
- before = await this._insertAtLeaf(before, key, value);
3353
- if (before.values.length === this.order) {
3545
+ const targetLeaf = await this.insertableNode(value);
3546
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3547
+ } else {
3548
+ if (currentLeaf !== null && modified) {
3549
+ await this._updateNode(currentLeaf);
3550
+ }
3551
+ currentLeaf = this._cloneNode(targetLeaf);
3552
+ modified = false;
3553
+ }
3554
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3555
+ modified = modified || changed;
3556
+ if (currentLeaf.values.length === this.order) {
3557
+ await this._updateNode(currentLeaf);
3354
3558
  let after = await this._createNode(
3355
3559
  true,
3356
3560
  [],
3357
3561
  [],
3358
- before.parent,
3562
+ currentLeaf.parent,
3359
3563
  null,
3360
3564
  null
3361
3565
  );
3362
3566
  const mid = Math.ceil(this.order / 2) - 1;
3363
3567
  after = this._cloneNode(after);
3364
- after.values = before.values.slice(mid + 1);
3365
- after.keys = before.keys.slice(mid + 1);
3366
- before.values = before.values.slice(0, mid + 1);
3367
- before.keys = before.keys.slice(0, mid + 1);
3368
- await this._updateNode(before);
3568
+ after.values = currentLeaf.values.slice(mid + 1);
3569
+ after.keys = currentLeaf.keys.slice(mid + 1);
3570
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
3571
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
3572
+ await this._updateNode(currentLeaf);
3369
3573
  await this._updateNode(after);
3370
- await this._insertInParent(before, after.values[0], after);
3574
+ await this._insertInParent(currentLeaf, after.values[0], after);
3575
+ currentLeaf = null;
3576
+ modified = false;
3371
3577
  }
3372
3578
  }
3579
+ if (currentLeaf !== null && modified) {
3580
+ await this._updateNode(currentLeaf);
3581
+ }
3373
3582
  });
3374
3583
  }
3375
3584
  async _deleteEntry(node, key) {
@@ -17,15 +17,12 @@ export declare abstract class BPTreeTransaction<K, V> {
17
17
  protected isInitialized: boolean;
18
18
  protected isDestroyed: boolean;
19
19
  protected readonly verifierMap: Record<keyof BPTreeCondition<V>, (nodeValue: V, value: V | V[]) => boolean>;
20
- protected readonly verifierStartNode: Record<keyof BPTreeCondition<V>, (value: V) => Deferred<BPTreeLeafNode<K, V>>>;
21
- protected readonly verifierEndNode: Record<keyof BPTreeCondition<V>, (value: V) => Deferred<BPTreeLeafNode<K, V> | null>>;
22
- protected readonly verifierDirection: Record<keyof BPTreeCondition<V>, -1 | 1>;
23
- /**
24
- * Determines whether early termination is allowed for each condition.
25
- * When true, the search will stop once a match is found and then a non-match is encountered.
26
- * Only applicable for conditions that guarantee contiguous matches in a sorted B+Tree.
27
- */
28
- protected readonly verifierEarlyTerminate: Record<keyof BPTreeCondition<V>, boolean>;
20
+ protected readonly searchConfigs: Record<keyof BPTreeCondition<V>, Record<'asc' | 'desc', {
21
+ start: (tx: BPTreeTransaction<K, V>, v: V[]) => Deferred<BPTreeLeafNode<K, V> | null>;
22
+ end: (tx: BPTreeTransaction<K, V>, v: V[]) => Deferred<BPTreeLeafNode<K, V> | null>;
23
+ direction: 1 | -1;
24
+ earlyTerminate: boolean;
25
+ }>>;
29
26
  /**
30
27
  * Priority map for condition types.
31
28
  * Higher value = higher selectivity (fewer expected results).
@@ -80,6 +77,13 @@ export declare abstract class BPTreeTransaction<K, V> {
80
77
  * @returns Returns true if the value satisfies the condition.
81
78
  */
82
79
  verify(nodeValue: V, condition: BPTreeCondition<V>): boolean;
80
+ /**
81
+ * Inserts a key-value pair into an already-cloned leaf node in-place.
82
+ * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
83
+ * Used by batchInsert to batch multiple insertions with a single clone/update.
84
+ * @returns true if the leaf was modified, false if the key already exists.
85
+ */
86
+ protected _insertValueIntoLeaf(leaf: BPTreeLeafNode<K, V>, key: K, value: V): boolean;
83
87
  protected _cloneNode<T extends BPTreeUnknownNode<K, V>>(node: T): T;
84
88
  /**
85
89
  * Selects the best driver key from a condition object.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "8.3.0",
3
+ "version": "8.3.2",
4
4
  "description": "Store the B+tree flexibly, not only in-memory.",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "main": "./dist/cjs/index.cjs",