serializable-bptree 8.4.1 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,8 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  BPTreeAsync: () => BPTreeAsync,
24
24
  BPTreeAsyncTransaction: () => BPTreeAsyncTransaction,
25
+ BPTreePureAsync: () => BPTreePureAsync,
26
+ BPTreePureSync: () => BPTreePureSync,
25
27
  BPTreeSync: () => BPTreeSync,
26
28
  BPTreeSyncTransaction: () => BPTreeSyncTransaction,
27
29
  InMemoryStoreStrategyAsync: () => InMemoryStoreStrategyAsync,
@@ -228,6 +230,7 @@ var MVCCTransaction = class {
228
230
  // 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
229
231
  bufferHistory = /* @__PURE__ */ new Map();
230
232
  // Nested Transaction Properties
233
+ activeDescendantCount = 0;
231
234
  parent;
232
235
  localVersion;
233
236
  // Local version for Nested Conflict Detection
@@ -304,6 +307,7 @@ var MVCCTransaction = class {
304
307
  return this.deleteBuffer.has(key);
305
308
  }
306
309
  _recordHistory(key) {
310
+ if (this.activeDescendantCount === 0) return;
307
311
  const existsInWriteBuffer = this.writeBuffer.has(key);
308
312
  const existsInDeleteBuffer = this.deleteBuffer.has(key);
309
313
  const currentVer = this.keyVersions.get(key);
@@ -416,6 +420,9 @@ var MVCCTransaction = class {
416
420
  this._cleanupAll();
417
421
  this.committed = true;
418
422
  if (this.root !== this) {
423
+ if (this.parent) {
424
+ this.parent._updateActiveDescendantCount(-1);
425
+ }
419
426
  this.root.activeTransactions.delete(this);
420
427
  }
421
428
  return {
@@ -503,6 +510,16 @@ var MVCCTransaction = class {
503
510
  }
504
511
  }
505
512
  }
513
+ /**
514
+ * Updates the descendant count for this transaction and its ancestors.
515
+ * @param delta The amount to change the count by.
516
+ */
517
+ _updateActiveDescendantCount(delta) {
518
+ this.activeDescendantCount += delta;
519
+ if (this.parent) {
520
+ this.parent._updateActiveDescendantCount(delta);
521
+ }
522
+ }
506
523
  };
507
524
  var SyncMVCCStrategy = class extends MVCCStrategy {
508
525
  };
@@ -547,7 +564,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
547
564
  if (this.committed) throw new Error("Transaction already committed");
548
565
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
549
566
  const child = new _SyncMVCCTransaction(void 0, void 0, this, childVersion);
550
- this.root.activeTransactions.add(child);
567
+ this._updateActiveDescendantCount(1);
568
+ const rootAny = this.root;
569
+ rootAny.activeTransactions.add(child);
551
570
  return child;
552
571
  }
553
572
  read(key) {
@@ -665,6 +684,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
665
684
  };
666
685
  }
667
686
  this._cleanupAll();
687
+ this.parent._updateActiveDescendantCount(-1);
668
688
  this.committed = true;
669
689
  } else {
670
690
  if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
@@ -1209,7 +1229,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1209
1229
  if (this.committed) throw new Error("Transaction already committed");
1210
1230
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
1211
1231
  const child = new _AsyncMVCCTransaction(void 0, void 0, this, childVersion);
1212
- this.root.activeTransactions.add(child);
1232
+ this._updateActiveDescendantCount(1);
1233
+ const rootAny = this.root;
1234
+ rootAny.activeTransactions.add(child);
1213
1235
  return child;
1214
1236
  }
1215
1237
  async read(key) {
@@ -1327,6 +1349,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1327
1349
  };
1328
1350
  }
1329
1351
  this._cleanupAll();
1352
+ this.parent._updateActiveDescendantCount(-1);
1330
1353
  this.committed = true;
1331
1354
  } else {
1332
1355
  if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
@@ -1566,86 +1589,120 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1566
1589
  }
1567
1590
  };
1568
1591
 
1569
- // src/base/BPTreeTransaction.ts
1570
- var BPTreeTransaction = class _BPTreeTransaction {
1571
- _cachedRegexp = /* @__PURE__ */ new Map();
1572
- nodes = /* @__PURE__ */ new Map();
1573
- deletedNodeBuffer = /* @__PURE__ */ new Map();
1574
- rootTx;
1575
- mvccRoot;
1576
- mvcc;
1577
- strategy;
1578
- comparator;
1579
- option;
1580
- order;
1581
- rootId;
1582
- isInitialized = false;
1583
- isDestroyed = false;
1584
- verifierMap = {
1585
- gt: (nv, v) => this.comparator.isHigher(nv, v),
1586
- gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
1587
- lt: (nv, v) => this.comparator.isLower(nv, v),
1588
- lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
1589
- equal: (nv, v) => this.comparator.isSame(nv, v),
1590
- notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
1591
- or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
1592
- primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
1593
- primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
1594
- primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
1595
- primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
1596
- primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
1597
- primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
1598
- primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
1592
+ // src/base/BPTreeAlgorithmSync.ts
1593
+ function cloneNode(node) {
1594
+ return JSON.parse(JSON.stringify(node));
1595
+ }
1596
+ function binarySearchValues(values, target, comparator, usePrimary = false, upperBound = false) {
1597
+ let low = 0;
1598
+ let high = values.length;
1599
+ let found = false;
1600
+ while (low < high) {
1601
+ const mid = low + high >>> 1;
1602
+ const cmp = usePrimary ? comparator.primaryAsc(target, values[mid]) : comparator.asc(target, values[mid]);
1603
+ if (cmp === 0) {
1604
+ found = true;
1605
+ if (upperBound) low = mid + 1;
1606
+ else high = mid;
1607
+ } else if (cmp < 0) {
1608
+ high = mid;
1609
+ } else {
1610
+ low = mid + 1;
1611
+ }
1612
+ }
1613
+ return { index: low, found };
1614
+ }
1615
+ function insertValueIntoLeaf(leaf, key, value, comparator) {
1616
+ if (leaf.values.length) {
1617
+ const { index, found } = binarySearchValues(leaf.values, value, comparator);
1618
+ if (found) {
1619
+ if (leaf.keys[index].includes(key)) {
1620
+ return false;
1621
+ }
1622
+ leaf.keys[index].push(key);
1623
+ return true;
1624
+ }
1625
+ leaf.values.splice(index, 0, value);
1626
+ leaf.keys.splice(index, 0, [key]);
1627
+ return true;
1628
+ } else {
1629
+ leaf.values = [value];
1630
+ leaf.keys = [[key]];
1631
+ return true;
1632
+ }
1633
+ }
1634
+ function createVerifierMap(comparator, cachedRegexp, ensureValues) {
1635
+ return {
1636
+ gt: (nv, v) => comparator.isHigher(nv, v),
1637
+ gte: (nv, v) => comparator.isHigher(nv, v) || comparator.isSame(nv, v),
1638
+ lt: (nv, v) => comparator.isLower(nv, v),
1639
+ lte: (nv, v) => comparator.isLower(nv, v) || comparator.isSame(nv, v),
1640
+ equal: (nv, v) => comparator.isSame(nv, v),
1641
+ notEqual: (nv, v) => comparator.isSame(nv, v) === false,
1642
+ or: (nv, v) => ensureValues(v).some((v2) => comparator.isSame(nv, v2)),
1643
+ primaryGt: (nv, v) => comparator.isPrimaryHigher(nv, v),
1644
+ primaryGte: (nv, v) => comparator.isPrimaryHigher(nv, v) || comparator.isPrimarySame(nv, v),
1645
+ primaryLt: (nv, v) => comparator.isPrimaryLower(nv, v),
1646
+ primaryLte: (nv, v) => comparator.isPrimaryLower(nv, v) || comparator.isPrimarySame(nv, v),
1647
+ primaryEqual: (nv, v) => comparator.isPrimarySame(nv, v),
1648
+ primaryNotEqual: (nv, v) => comparator.isPrimarySame(nv, v) === false,
1649
+ primaryOr: (nv, v) => ensureValues(v).some((v2) => comparator.isPrimarySame(nv, v2)),
1599
1650
  like: (nv, v) => {
1600
- const nodeValue = this.comparator.match(nv);
1651
+ const nodeValue = comparator.match(nv);
1601
1652
  const value = v;
1602
- if (!this._cachedRegexp.has(value)) {
1653
+ if (!cachedRegexp.has(value)) {
1603
1654
  const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
1604
1655
  const regexp2 = new RegExp(`^${pattern}$`, "i");
1605
- this._cachedRegexp.set(value, regexp2);
1656
+ cachedRegexp.set(value, regexp2);
1606
1657
  }
1607
- const regexp = this._cachedRegexp.get(value);
1658
+ const regexp = cachedRegexp.get(value);
1608
1659
  return regexp.test(nodeValue);
1609
1660
  }
1610
1661
  };
1611
- searchConfigs = {
1662
+ }
1663
+ function createSearchConfigs(comparator, ensureValues) {
1664
+ const lowest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[0];
1665
+ const highest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[v.length - 1];
1666
+ const lowestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[0];
1667
+ const highestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[v.length - 1];
1668
+ return {
1612
1669
  gt: {
1613
1670
  asc: {
1614
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1671
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1615
1672
  end: () => null,
1616
1673
  direction: 1,
1617
1674
  earlyTerminate: false
1618
1675
  },
1619
1676
  desc: {
1620
- start: (tx) => tx.rightestNode(),
1621
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
1677
+ start: (r, ops) => rightestNode(ops, r),
1678
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
1622
1679
  direction: -1,
1623
1680
  earlyTerminate: true
1624
1681
  }
1625
1682
  },
1626
1683
  gte: {
1627
1684
  asc: {
1628
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1685
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1629
1686
  end: () => null,
1630
1687
  direction: 1,
1631
1688
  earlyTerminate: false
1632
1689
  },
1633
1690
  desc: {
1634
- start: (tx) => tx.rightestNode(),
1635
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
1691
+ start: (r, ops) => rightestNode(ops, r),
1692
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
1636
1693
  direction: -1,
1637
1694
  earlyTerminate: true
1638
1695
  }
1639
1696
  },
1640
1697
  lt: {
1641
1698
  asc: {
1642
- start: (tx) => tx.leftestNode(),
1643
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1699
+ start: (r, ops) => leftestNode(ops, r),
1700
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
1644
1701
  direction: 1,
1645
1702
  earlyTerminate: true
1646
1703
  },
1647
1704
  desc: {
1648
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1705
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1649
1706
  end: () => null,
1650
1707
  direction: -1,
1651
1708
  earlyTerminate: false
@@ -1653,13 +1710,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
1653
1710
  },
1654
1711
  lte: {
1655
1712
  asc: {
1656
- start: (tx) => tx.leftestNode(),
1657
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1713
+ start: (r, ops) => leftestNode(ops, r),
1714
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
1658
1715
  direction: 1,
1659
1716
  earlyTerminate: true
1660
1717
  },
1661
1718
  desc: {
1662
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1719
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1663
1720
  end: () => null,
1664
1721
  direction: -1,
1665
1722
  earlyTerminate: false
@@ -1667,27 +1724,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
1667
1724
  },
1668
1725
  equal: {
1669
1726
  asc: {
1670
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1671
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1727
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1728
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
1672
1729
  direction: 1,
1673
1730
  earlyTerminate: true
1674
1731
  },
1675
1732
  desc: {
1676
- start: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1677
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
1733
+ start: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
1734
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
1678
1735
  direction: -1,
1679
1736
  earlyTerminate: true
1680
1737
  }
1681
1738
  },
1682
1739
  notEqual: {
1683
1740
  asc: {
1684
- start: (tx) => tx.leftestNode(),
1741
+ start: (r, ops) => leftestNode(ops, r),
1685
1742
  end: () => null,
1686
1743
  direction: 1,
1687
1744
  earlyTerminate: false
1688
1745
  },
1689
1746
  desc: {
1690
- start: (tx) => tx.rightestNode(),
1747
+ start: (r, ops) => rightestNode(ops, r),
1691
1748
  end: () => null,
1692
1749
  direction: -1,
1693
1750
  earlyTerminate: false
@@ -1695,55 +1752,55 @@ var BPTreeTransaction = class _BPTreeTransaction {
1695
1752
  },
1696
1753
  or: {
1697
1754
  asc: {
1698
- start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestValue(v)),
1699
- end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
1755
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, lowest(ensureValues(v)), comparator),
1756
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, highest(ensureValues(v)), 1, comparator),
1700
1757
  direction: 1,
1701
1758
  earlyTerminate: false
1702
1759
  },
1703
1760
  desc: {
1704
- start: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
1705
- end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestValue(v), -1),
1761
+ start: (r, ops, v) => findOuterBoundaryLeaf(ops, r, highest(ensureValues(v)), 1, comparator),
1762
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, lowest(ensureValues(v)), -1, comparator),
1706
1763
  direction: -1,
1707
1764
  earlyTerminate: false
1708
1765
  }
1709
1766
  },
1710
1767
  primaryGt: {
1711
1768
  asc: {
1712
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1769
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1713
1770
  end: () => null,
1714
1771
  direction: 1,
1715
1772
  earlyTerminate: false
1716
1773
  },
1717
1774
  desc: {
1718
- start: (tx) => tx.rightestNode(),
1719
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
1775
+ start: (r, ops) => rightestNode(ops, r),
1776
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
1720
1777
  direction: -1,
1721
1778
  earlyTerminate: true
1722
1779
  }
1723
1780
  },
1724
1781
  primaryGte: {
1725
1782
  asc: {
1726
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1783
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1727
1784
  end: () => null,
1728
1785
  direction: 1,
1729
1786
  earlyTerminate: false
1730
1787
  },
1731
1788
  desc: {
1732
- start: (tx) => tx.rightestNode(),
1733
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
1789
+ start: (r, ops) => rightestNode(ops, r),
1790
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
1734
1791
  direction: -1,
1735
1792
  earlyTerminate: true
1736
1793
  }
1737
1794
  },
1738
1795
  primaryLt: {
1739
1796
  asc: {
1740
- start: (tx) => tx.leftestNode(),
1741
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1797
+ start: (r, ops) => leftestNode(ops, r),
1798
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
1742
1799
  direction: 1,
1743
1800
  earlyTerminate: true
1744
1801
  },
1745
1802
  desc: {
1746
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1803
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1747
1804
  end: () => null,
1748
1805
  direction: -1,
1749
1806
  earlyTerminate: false
@@ -1751,13 +1808,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
1751
1808
  },
1752
1809
  primaryLte: {
1753
1810
  asc: {
1754
- start: (tx) => tx.leftestNode(),
1755
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1811
+ start: (r, ops) => leftestNode(ops, r),
1812
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
1756
1813
  direction: 1,
1757
1814
  earlyTerminate: true
1758
1815
  },
1759
1816
  desc: {
1760
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1817
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1761
1818
  end: () => null,
1762
1819
  direction: -1,
1763
1820
  earlyTerminate: false
@@ -1765,27 +1822,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
1765
1822
  },
1766
1823
  primaryEqual: {
1767
1824
  asc: {
1768
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1769
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1825
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1826
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
1770
1827
  direction: 1,
1771
1828
  earlyTerminate: true
1772
1829
  },
1773
1830
  desc: {
1774
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1775
- end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
1831
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1832
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
1776
1833
  direction: -1,
1777
1834
  earlyTerminate: true
1778
1835
  }
1779
1836
  },
1780
1837
  primaryNotEqual: {
1781
1838
  asc: {
1782
- start: (tx) => tx.leftestNode(),
1839
+ start: (r, ops) => leftestNode(ops, r),
1783
1840
  end: () => null,
1784
1841
  direction: 1,
1785
1842
  earlyTerminate: false
1786
1843
  },
1787
1844
  desc: {
1788
- start: (tx) => tx.rightestNode(),
1845
+ start: (r, ops) => rightestNode(ops, r),
1789
1846
  end: () => null,
1790
1847
  direction: -1,
1791
1848
  earlyTerminate: false
@@ -1793,176 +1850,1186 @@ var BPTreeTransaction = class _BPTreeTransaction {
1793
1850
  },
1794
1851
  primaryOr: {
1795
1852
  asc: {
1796
- start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestPrimaryValue(v)),
1797
- end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestPrimaryValue(v), 1),
1853
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, lowestPrimary(ensureValues(v)), comparator),
1854
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, highestPrimary(ensureValues(v)), 1, comparator),
1798
1855
  direction: 1,
1799
1856
  earlyTerminate: false
1800
1857
  },
1801
1858
  desc: {
1802
- start: (tx, v) => tx.findUpperBoundLeaf(tx.highestPrimaryValue(v)),
1803
- end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestPrimaryValue(v), -1),
1859
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, highestPrimary(ensureValues(v)), comparator),
1860
+ end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, lowestPrimary(ensureValues(v)), -1, comparator),
1804
1861
  direction: -1,
1805
1862
  earlyTerminate: false
1806
1863
  }
1807
1864
  },
1808
1865
  like: {
1809
1866
  asc: {
1810
- start: (tx) => tx.leftestNode(),
1867
+ start: (r, ops) => leftestNode(ops, r),
1811
1868
  end: () => null,
1812
1869
  direction: 1,
1813
1870
  earlyTerminate: false
1814
1871
  },
1815
1872
  desc: {
1816
- start: (tx) => tx.rightestNode(),
1873
+ start: (r, ops) => rightestNode(ops, r),
1817
1874
  end: () => null,
1818
1875
  direction: -1,
1819
1876
  earlyTerminate: false
1820
1877
  }
1821
1878
  }
1822
1879
  };
1823
- /**
1824
- * Priority map for condition types.
1825
- * Higher value = higher selectivity (fewer expected results).
1826
- * Used by `chooseDriver` to select the most selective index.
1827
- */
1828
- static conditionPriority = {
1829
- equal: 100,
1830
- primaryEqual: 100,
1831
- or: 80,
1832
- primaryOr: 80,
1833
- gt: 50,
1834
- gte: 50,
1835
- lt: 50,
1836
- lte: 50,
1837
- primaryGt: 50,
1838
- primaryGte: 50,
1839
- primaryLt: 50,
1840
- primaryLte: 50,
1841
- like: 30,
1842
- notEqual: 10,
1843
- primaryNotEqual: 10
1844
- };
1845
- /**
1846
- * Selects the best driver tree from multiple tree/condition pairs.
1847
- * Uses rule-based optimization to choose the tree with highest estimated selectivity.
1848
- *
1849
- * @param candidates Array of { tree, condition } pairs to evaluate
1850
- * @returns The candidate with highest priority condition, or null if empty
1851
- *
1852
- * @example
1853
- * ```typescript
1854
- * const driver = BPTreeSync.chooseDriver([
1855
- * { tree: idxId, condition: { equal: 100 } },
1856
- * { tree: idxAge, condition: { gt: 20 } }
1857
- * ])
1858
- * // Returns { tree: idxId, condition: { equal: 100 } } because 'equal' has higher priority
1859
- * ```
1860
- */
1861
- static ChooseDriver(candidates) {
1862
- if (candidates.length === 0) return null;
1863
- if (candidates.length === 1) return candidates[0];
1864
- let best = candidates[0];
1865
- let bestScore = 0;
1866
- for (const candidate of candidates) {
1867
- let score = 0;
1868
- for (const key in candidate.condition) {
1869
- const condKey = key;
1870
- const priority = _BPTreeTransaction.conditionPriority[condKey] ?? 0;
1871
- if (priority > score) {
1872
- score = priority;
1873
- }
1874
- }
1875
- if (score > bestScore) {
1876
- bestScore = score;
1877
- best = candidate;
1878
- }
1880
+ }
1881
+ var _lowerBoundKeys = [
1882
+ "primaryEqual",
1883
+ "equal",
1884
+ "primaryGt",
1885
+ "gt",
1886
+ "primaryGte",
1887
+ "gte",
1888
+ "primaryOr",
1889
+ "or"
1890
+ ];
1891
+ var _upperBoundKeys = [
1892
+ "primaryEqual",
1893
+ "equal",
1894
+ "primaryLt",
1895
+ "lt",
1896
+ "primaryLte",
1897
+ "lte",
1898
+ "primaryOr",
1899
+ "or"
1900
+ ];
1901
+ var _multiValueKeys = [
1902
+ "or",
1903
+ "primaryOr"
1904
+ ];
1905
+ function resolveStartEndConfigs(condition, order, comparator, ensureValues) {
1906
+ const direction = order === "asc" ? 1 : -1;
1907
+ const startCandidates = order === "asc" ? _lowerBoundKeys : _upperBoundKeys;
1908
+ const endCandidates = order === "asc" ? _upperBoundKeys : _lowerBoundKeys;
1909
+ let startKey = null;
1910
+ let endKey = null;
1911
+ let startValues = [];
1912
+ let endValues = [];
1913
+ for (let i = 0, len = startCandidates.length; i < len; i++) {
1914
+ const key = startCandidates[i];
1915
+ if (key in condition) {
1916
+ startKey = key;
1917
+ startValues = _multiValueKeys.includes(key) ? ensureValues(condition[key]) : [condition[key]];
1918
+ break;
1879
1919
  }
1880
- return best;
1881
1920
  }
1882
- /**
1883
- * Checks for conflicts between multiple transactions.
1884
- *
1885
- * @param transactions Array of BPTreeTransaction instances to check
1886
- * @returns An array of keys that are in conflict. Empty array if no conflicts.
1887
- */
1888
- static CheckConflicts(transactions) {
1889
- return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
1921
+ for (let i = 0, len = endCandidates.length; i < len; i++) {
1922
+ const key = endCandidates[i];
1923
+ if (key in condition) {
1924
+ endKey = key;
1925
+ endValues = _multiValueKeys.includes(key) ? ensureValues(condition[key]) : [condition[key]];
1926
+ break;
1927
+ }
1890
1928
  }
1891
- /**
1892
- * Returns the ID of the root node.
1893
- * @returns The root node ID.
1894
- */
1895
- getRootId() {
1896
- return this.rootId;
1929
+ return { startKey, endKey, startValues, endValues, direction };
1930
+ }
1931
+ function verify(nodeValue, condition, verifierMap) {
1932
+ for (const key in condition) {
1933
+ const verifyFn = verifierMap[key];
1934
+ const condValue = condition[key];
1935
+ if (!verifyFn(nodeValue, condValue)) {
1936
+ return false;
1937
+ }
1897
1938
  }
1898
- /**
1899
- * Returns the order of the B+Tree.
1900
- * @returns The order of the tree.
1901
- */
1902
- getOrder() {
1903
- return this.order;
1939
+ return true;
1940
+ }
1941
+ function locateLeaf(ops, rootId, value, comparator) {
1942
+ let node = ops.getNode(rootId);
1943
+ while (!node.leaf) {
1944
+ const { index } = binarySearchValues(node.values, value, comparator, false, true);
1945
+ node = ops.getNode(node.keys[index]);
1946
+ }
1947
+ return node;
1948
+ }
1949
+ function findLowerBoundLeaf(ops, rootId, value, comparator) {
1950
+ let node = ops.getNode(rootId);
1951
+ while (!node.leaf) {
1952
+ const { index } = binarySearchValues(node.values, value, comparator, true, false);
1953
+ node = ops.getNode(node.keys[index]);
1954
+ }
1955
+ return node;
1956
+ }
1957
+ function findUpperBoundLeaf(ops, rootId, value, comparator) {
1958
+ let node = ops.getNode(rootId);
1959
+ while (!node.leaf) {
1960
+ const { index } = binarySearchValues(node.values, value, comparator, true, true);
1961
+ node = ops.getNode(node.keys[index]);
1962
+ }
1963
+ return node;
1964
+ }
1965
+ function findOuterBoundaryLeaf(ops, rootId, value, direction, comparator) {
1966
+ const insertableNode = direction === -1 ? findLowerBoundLeaf(ops, rootId, value, comparator) : findUpperBoundLeaf(ops, rootId, value, comparator);
1967
+ let key;
1968
+ switch (direction) {
1969
+ case -1:
1970
+ key = "prev";
1971
+ break;
1972
+ case 1:
1973
+ key = "next";
1974
+ break;
1975
+ default:
1976
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
1904
1977
  }
1905
- /**
1906
- * Verified if the value satisfies the condition.
1907
- *
1908
- * @param nodeValue The value to verify.
1909
- * @param condition The condition to verify against.
1910
- * @returns Returns true if the value satisfies the condition.
1911
- */
1912
- verify(nodeValue, condition) {
1913
- for (const key in condition) {
1914
- const verify = this.verifierMap[key];
1915
- const condValue = condition[key];
1916
- if (!verify(nodeValue, condValue)) {
1917
- return false;
1918
- }
1919
- }
1920
- return true;
1978
+ const guessNode = insertableNode[key];
1979
+ if (!guessNode) {
1980
+ return null;
1921
1981
  }
1922
- /**
1923
- * Inserts a key-value pair into an already-cloned leaf node in-place.
1924
- * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
1925
- * Used by batchInsert to batch multiple insertions with a single clone/update.
1926
- * @returns true if the leaf was modified, false if the key already exists.
1927
- */
1928
- _insertValueIntoLeaf(leaf, key, value) {
1929
- if (leaf.values.length) {
1930
- const { index, found } = this._binarySearchValues(leaf.values, value);
1931
- if (found) {
1932
- if (leaf.keys[index].includes(key)) {
1933
- return false;
1982
+ return ops.getNode(guessNode);
1983
+ }
1984
+ function leftestNode(ops, rootId) {
1985
+ let node = ops.getNode(rootId);
1986
+ while (!node.leaf) {
1987
+ const keys = node.keys;
1988
+ node = ops.getNode(keys[0]);
1989
+ }
1990
+ return node;
1991
+ }
1992
+ function rightestNode(ops, rootId) {
1993
+ let node = ops.getNode(rootId);
1994
+ while (!node.leaf) {
1995
+ const keys = node.keys;
1996
+ node = ops.getNode(keys[keys.length - 1]);
1997
+ }
1998
+ return node;
1999
+ }
2000
+ function* getPairsGenerator(ops, startNode, endNode, direction) {
2001
+ let node = startNode;
2002
+ while (true) {
2003
+ if (endNode && node.id === endNode.id) {
2004
+ break;
2005
+ }
2006
+ const len = node.values.length;
2007
+ if (direction === 1) {
2008
+ for (let i = 0; i < len; i++) {
2009
+ const nValue = node.values[i];
2010
+ const keys = node.keys[i];
2011
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
2012
+ yield [keys[j], nValue];
1934
2013
  }
1935
- leaf.keys[index].push(key);
1936
- return true;
1937
2014
  }
1938
- leaf.values.splice(index, 0, value);
1939
- leaf.keys.splice(index, 0, [key]);
1940
- return true;
1941
2015
  } else {
1942
- leaf.values = [value];
1943
- leaf.keys = [[key]];
1944
- return true;
2016
+ let i = len;
2017
+ while (i--) {
2018
+ const nValue = node.values[i];
2019
+ const keys = node.keys[i];
2020
+ let j = keys.length;
2021
+ while (j--) {
2022
+ yield [keys[j], nValue];
2023
+ }
2024
+ }
1945
2025
  }
2026
+ if (direction === 1) {
2027
+ if (!node.next) break;
2028
+ node = ops.getNode(node.next);
2029
+ } else {
2030
+ if (!node.prev) break;
2031
+ node = ops.getNode(node.prev);
2032
+ }
2033
+ }
2034
+ }
2035
+ function insertAtLeaf(ops, node, key, value, comparator) {
2036
+ let leaf = node;
2037
+ if (leaf.values.length) {
2038
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
2039
+ const nValue = leaf.values[i];
2040
+ if (comparator.isSame(value, nValue)) {
2041
+ const keys = leaf.keys[i];
2042
+ if (keys.includes(key)) {
2043
+ break;
2044
+ }
2045
+ leaf = cloneNode(leaf);
2046
+ leaf.keys[i].push(key);
2047
+ ops.updateNode(leaf);
2048
+ return leaf;
2049
+ } else if (comparator.isLower(value, nValue)) {
2050
+ leaf = cloneNode(leaf);
2051
+ leaf.values.splice(i, 0, value);
2052
+ leaf.keys.splice(i, 0, [key]);
2053
+ ops.updateNode(leaf);
2054
+ return leaf;
2055
+ } else if (i + 1 === leaf.values.length) {
2056
+ leaf = cloneNode(leaf);
2057
+ leaf.values.push(value);
2058
+ leaf.keys.push([key]);
2059
+ ops.updateNode(leaf);
2060
+ return leaf;
2061
+ }
2062
+ }
2063
+ } else {
2064
+ leaf = cloneNode(leaf);
2065
+ leaf.values = [value];
2066
+ leaf.keys = [[key]];
2067
+ ops.updateNode(leaf);
2068
+ return leaf;
1946
2069
  }
1947
- _cloneNode(node) {
1948
- return JSON.parse(JSON.stringify(node));
2070
+ return leaf;
2071
+ }
2072
+ function insertInParent(ops, ctx, node, value, newSiblingNode) {
2073
+ if (ctx.rootId === node.id) {
2074
+ node = cloneNode(node);
2075
+ newSiblingNode = cloneNode(newSiblingNode);
2076
+ const root = ops.createNode(false, [node.id, newSiblingNode.id], [value]);
2077
+ ctx.rootId = root.id;
2078
+ node.parent = root.id;
2079
+ newSiblingNode.parent = root.id;
2080
+ if (newSiblingNode.leaf) {
2081
+ ;
2082
+ node.next = newSiblingNode.id;
2083
+ newSiblingNode.prev = node.id;
2084
+ }
2085
+ ops.writeHead({
2086
+ root: root.id,
2087
+ order: ctx.order,
2088
+ data: ctx.headData()
2089
+ });
2090
+ ops.updateNode(node);
2091
+ ops.updateNode(newSiblingNode);
2092
+ return;
2093
+ }
2094
+ const parentNode = cloneNode(ops.getNode(node.parent));
2095
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2096
+ if (nodeIndex === -1) {
2097
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2098
+ }
2099
+ parentNode.values.splice(nodeIndex, 0, value);
2100
+ parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
2101
+ newSiblingNode = cloneNode(newSiblingNode);
2102
+ newSiblingNode.parent = parentNode.id;
2103
+ if (newSiblingNode.leaf) {
2104
+ const leftSibling = cloneNode(node);
2105
+ const oldNextId = leftSibling.next;
2106
+ newSiblingNode.prev = leftSibling.id;
2107
+ newSiblingNode.next = oldNextId;
2108
+ leftSibling.next = newSiblingNode.id;
2109
+ ops.updateNode(leftSibling);
2110
+ if (oldNextId) {
2111
+ const oldNext = cloneNode(ops.getNode(oldNextId));
2112
+ oldNext.prev = newSiblingNode.id;
2113
+ ops.updateNode(oldNext);
2114
+ }
2115
+ }
2116
+ ops.updateNode(parentNode);
2117
+ ops.updateNode(newSiblingNode);
2118
+ if (parentNode.keys.length > ctx.order) {
2119
+ const newSiblingNodeRecursive = ops.createNode(false, [], []);
2120
+ newSiblingNodeRecursive.parent = parentNode.parent;
2121
+ const mid = Math.ceil(ctx.order / 2) - 1;
2122
+ newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
2123
+ newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
2124
+ const midValue = parentNode.values[mid];
2125
+ parentNode.values = parentNode.values.slice(0, mid);
2126
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
2127
+ for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
2128
+ const k = newSiblingNodeRecursive.keys[i];
2129
+ const n = cloneNode(ops.getNode(k));
2130
+ n.parent = newSiblingNodeRecursive.id;
2131
+ ops.updateNode(n);
2132
+ }
2133
+ ops.updateNode(parentNode);
2134
+ insertInParent(ops, ctx, parentNode, midValue, newSiblingNodeRecursive);
2135
+ }
2136
+ }
2137
+ function insertOp(ops, ctx, key, value, comparator) {
2138
+ let before = locateLeaf(ops, ctx.rootId, value, comparator);
2139
+ before = insertAtLeaf(ops, before, key, value, comparator);
2140
+ if (before.values.length === ctx.order) {
2141
+ let after = ops.createNode(
2142
+ true,
2143
+ [],
2144
+ [],
2145
+ before.parent,
2146
+ null,
2147
+ null
2148
+ );
2149
+ const mid = Math.ceil(ctx.order / 2) - 1;
2150
+ after = cloneNode(after);
2151
+ after.values = before.values.slice(mid + 1);
2152
+ after.keys = before.keys.slice(mid + 1);
2153
+ before.values = before.values.slice(0, mid + 1);
2154
+ before.keys = before.keys.slice(0, mid + 1);
2155
+ ops.updateNode(before);
2156
+ ops.updateNode(after);
2157
+ insertInParent(ops, ctx, before, after.values[0], after);
2158
+ }
2159
+ }
2160
+ function deleteEntry(ops, ctx, node, key, comparator) {
2161
+ if (!node.leaf) {
2162
+ let keyIndex = -1;
2163
+ for (let i = 0, len = node.keys.length; i < len; i++) {
2164
+ if (node.keys[i] === key) {
2165
+ keyIndex = i;
2166
+ break;
2167
+ }
2168
+ }
2169
+ if (keyIndex !== -1) {
2170
+ node = cloneNode(node);
2171
+ node.keys.splice(keyIndex, 1);
2172
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2173
+ node.values.splice(valueIndex, 1);
2174
+ ops.updateNode(node);
2175
+ }
1949
2176
  }
1950
- /**
1951
- * Resolves the best start/end configuration by independently examining
1952
- * all conditions. Selects the tightest lower bound for start and the
1953
- * tightest upper bound for end (in asc; reversed for desc).
1954
- *
1955
- * @param condition The condition to analyze.
1956
- * @param order The sort order ('asc' or 'desc').
1957
- * @returns The resolved start/end keys, values, and traversal direction.
1958
- */
1959
- resolveStartEndConfigs(condition, order) {
1960
- const direction = order === "asc" ? 1 : -1;
1961
- const startCandidates = order === "asc" ? _BPTreeTransaction._lowerBoundKeys : _BPTreeTransaction._upperBoundKeys;
1962
- const endCandidates = order === "asc" ? _BPTreeTransaction._upperBoundKeys : _BPTreeTransaction._lowerBoundKeys;
1963
- let startKey = null;
1964
- let endKey = null;
1965
- let startValues = [];
2177
+ if (ctx.rootId === node.id && node.keys.length === 1 && !node.leaf) {
2178
+ const keys = node.keys;
2179
+ ops.deleteNode(node);
2180
+ const newRoot = cloneNode(ops.getNode(keys[0]));
2181
+ newRoot.parent = null;
2182
+ ops.updateNode(newRoot);
2183
+ ops.writeHead({
2184
+ root: newRoot.id,
2185
+ order: ctx.order,
2186
+ data: ctx.headData()
2187
+ });
2188
+ ctx.rootId = newRoot.id;
2189
+ return node;
2190
+ } else if (ctx.rootId === node.id) {
2191
+ ops.writeHead({
2192
+ root: node.id,
2193
+ order: ctx.order,
2194
+ data: ctx.headData()
2195
+ });
2196
+ return node;
2197
+ } else if (node.keys.length < Math.ceil(ctx.order / 2) && !node.leaf || node.values.length < Math.ceil((ctx.order - 1) / 2) && node.leaf) {
2198
+ if (node.parent === null) {
2199
+ return node;
2200
+ }
2201
+ let isPredecessor = false;
2202
+ let parentNode = ops.getNode(node.parent);
2203
+ let prevNode = null;
2204
+ let nextNode = null;
2205
+ let prevValue = null;
2206
+ let postValue = null;
2207
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2208
+ const nKey = parentNode.keys[i];
2209
+ if (nKey === node.id) {
2210
+ if (i > 0) {
2211
+ prevNode = ops.getNode(parentNode.keys[i - 1]);
2212
+ prevValue = parentNode.values[i - 1];
2213
+ }
2214
+ if (i < parentNode.keys.length - 1) {
2215
+ nextNode = ops.getNode(parentNode.keys[i + 1]);
2216
+ postValue = parentNode.values[i];
2217
+ }
2218
+ }
2219
+ }
2220
+ let siblingNode;
2221
+ let guess;
2222
+ if (prevNode === null) {
2223
+ siblingNode = nextNode;
2224
+ guess = postValue;
2225
+ } else if (nextNode === null) {
2226
+ isPredecessor = true;
2227
+ siblingNode = prevNode;
2228
+ guess = prevValue;
2229
+ } else {
2230
+ if (node.values.length + nextNode.values.length < ctx.order) {
2231
+ siblingNode = nextNode;
2232
+ guess = postValue;
2233
+ } else {
2234
+ isPredecessor = true;
2235
+ siblingNode = prevNode;
2236
+ guess = prevValue;
2237
+ }
2238
+ }
2239
+ if (!siblingNode) {
2240
+ return node;
2241
+ }
2242
+ node = cloneNode(node);
2243
+ siblingNode = cloneNode(siblingNode);
2244
+ if (node.values.length + siblingNode.values.length < ctx.order) {
2245
+ if (!isPredecessor) {
2246
+ const pTemp = siblingNode;
2247
+ siblingNode = node;
2248
+ node = pTemp;
2249
+ }
2250
+ siblingNode.keys.push(...node.keys);
2251
+ if (!node.leaf) {
2252
+ siblingNode.values.push(guess);
2253
+ } else {
2254
+ siblingNode.next = node.next;
2255
+ if (siblingNode.next) {
2256
+ const n = cloneNode(ops.getNode(siblingNode.next));
2257
+ n.prev = siblingNode.id;
2258
+ ops.updateNode(n);
2259
+ }
2260
+ }
2261
+ siblingNode.values.push(...node.values);
2262
+ if (!siblingNode.leaf) {
2263
+ const keys = siblingNode.keys;
2264
+ for (let i = 0, len = keys.length; i < len; i++) {
2265
+ const k = keys[i];
2266
+ const n = cloneNode(ops.getNode(k));
2267
+ n.parent = siblingNode.id;
2268
+ ops.updateNode(n);
2269
+ }
2270
+ }
2271
+ ops.deleteNode(node);
2272
+ ops.updateNode(siblingNode);
2273
+ deleteEntry(ops, ctx, ops.getNode(node.parent), node.id, comparator);
2274
+ } else {
2275
+ if (isPredecessor) {
2276
+ let pointerPm;
2277
+ let pointerKm;
2278
+ if (!node.leaf) {
2279
+ pointerPm = siblingNode.keys.splice(-1)[0];
2280
+ pointerKm = siblingNode.values.splice(-1)[0];
2281
+ node.keys = [pointerPm, ...node.keys];
2282
+ node.values = [guess, ...node.values];
2283
+ parentNode = cloneNode(ops.getNode(node.parent));
2284
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2285
+ if (nodeIndex > 0) {
2286
+ parentNode.values[nodeIndex - 1] = pointerKm;
2287
+ ops.updateNode(parentNode);
2288
+ }
2289
+ } else {
2290
+ pointerPm = siblingNode.keys.splice(-1)[0];
2291
+ pointerKm = siblingNode.values.splice(-1)[0];
2292
+ node.keys = [pointerPm, ...node.keys];
2293
+ node.values = [pointerKm, ...node.values];
2294
+ parentNode = cloneNode(ops.getNode(node.parent));
2295
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2296
+ if (nodeIndex > 0) {
2297
+ parentNode.values[nodeIndex - 1] = pointerKm;
2298
+ ops.updateNode(parentNode);
2299
+ }
2300
+ }
2301
+ ops.updateNode(node);
2302
+ ops.updateNode(siblingNode);
2303
+ } else {
2304
+ let pointerP0;
2305
+ let pointerK0;
2306
+ if (!node.leaf) {
2307
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
2308
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
2309
+ node.keys = [...node.keys, pointerP0];
2310
+ node.values = [...node.values, guess];
2311
+ parentNode = cloneNode(ops.getNode(node.parent));
2312
+ const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2313
+ if (pointerIndex > 0) {
2314
+ parentNode.values[pointerIndex - 1] = pointerK0;
2315
+ ops.updateNode(parentNode);
2316
+ }
2317
+ } else {
2318
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
2319
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
2320
+ node.keys = [...node.keys, pointerP0];
2321
+ node.values = [...node.values, pointerK0];
2322
+ parentNode = cloneNode(ops.getNode(node.parent));
2323
+ const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2324
+ if (pointerIndex > 0) {
2325
+ parentNode.values[pointerIndex - 1] = siblingNode.values[0];
2326
+ ops.updateNode(parentNode);
2327
+ }
2328
+ }
2329
+ ops.updateNode(node);
2330
+ ops.updateNode(siblingNode);
2331
+ }
2332
+ if (!siblingNode.leaf) {
2333
+ for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
2334
+ const k = siblingNode.keys[i];
2335
+ const n = cloneNode(ops.getNode(k));
2336
+ n.parent = siblingNode.id;
2337
+ ops.updateNode(n);
2338
+ }
2339
+ }
2340
+ if (!node.leaf) {
2341
+ for (let i = 0, len = node.keys.length; i < len; i++) {
2342
+ const k = node.keys[i];
2343
+ const n = cloneNode(ops.getNode(k));
2344
+ n.parent = node.id;
2345
+ ops.updateNode(n);
2346
+ }
2347
+ }
2348
+ if (!parentNode.leaf) {
2349
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2350
+ const k = parentNode.keys[i];
2351
+ const n = cloneNode(ops.getNode(k));
2352
+ n.parent = parentNode.id;
2353
+ ops.updateNode(n);
2354
+ }
2355
+ }
2356
+ }
2357
+ } else {
2358
+ ops.updateNode(cloneNode(node));
2359
+ }
2360
+ return node;
2361
+ }
2362
+ function deleteOp(ops, ctx, key, comparator, value) {
2363
+ if (value === void 0) {
2364
+ value = getOp(ops, ctx.rootId, key);
2365
+ }
2366
+ if (value === void 0) {
2367
+ return;
2368
+ }
2369
+ let node = findLowerBoundLeaf(ops, ctx.rootId, value, comparator);
2370
+ let found = false;
2371
+ while (true) {
2372
+ let i = node.values.length;
2373
+ while (i--) {
2374
+ const nValue = node.values[i];
2375
+ if (comparator.isSame(value, nValue)) {
2376
+ const keys = node.keys[i];
2377
+ const keyIndex = keys.indexOf(key);
2378
+ if (keyIndex !== -1) {
2379
+ node = cloneNode(node);
2380
+ const freshKeys = node.keys[i];
2381
+ freshKeys.splice(keyIndex, 1);
2382
+ if (freshKeys.length === 0) {
2383
+ node.keys.splice(i, 1);
2384
+ node.values.splice(i, 1);
2385
+ }
2386
+ ops.updateNode(node);
2387
+ node = deleteEntry(ops, ctx, node, key, comparator);
2388
+ found = true;
2389
+ break;
2390
+ }
2391
+ }
2392
+ }
2393
+ if (found) break;
2394
+ if (node.next) {
2395
+ node = ops.getNode(node.next);
2396
+ continue;
2397
+ }
2398
+ break;
2399
+ }
2400
+ }
2401
+ function batchInsertOp(ops, ctx, entries, comparator) {
2402
+ if (entries.length === 0) return;
2403
+ const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
2404
+ let currentLeaf = null;
2405
+ let modified = false;
2406
+ let cachedLeafId = null;
2407
+ let cachedLeafMaxValue = null;
2408
+ for (let i = 0, len = sorted.length; i < len; i++) {
2409
+ const [key, value] = sorted[i];
2410
+ let targetLeaf;
2411
+ if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (comparator.isLower(value, cachedLeafMaxValue) || comparator.isSame(value, cachedLeafMaxValue))) {
2412
+ targetLeaf = currentLeaf;
2413
+ } else {
2414
+ targetLeaf = locateLeaf(ops, ctx.rootId, value, comparator);
2415
+ }
2416
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2417
+ } else {
2418
+ if (currentLeaf !== null && modified) {
2419
+ ops.updateNode(currentLeaf);
2420
+ }
2421
+ currentLeaf = cloneNode(targetLeaf);
2422
+ modified = false;
2423
+ }
2424
+ cachedLeafId = currentLeaf.id;
2425
+ const changed = insertValueIntoLeaf(currentLeaf, key, value, comparator);
2426
+ modified = modified || changed;
2427
+ cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
2428
+ if (currentLeaf.values.length === ctx.order) {
2429
+ ops.updateNode(currentLeaf);
2430
+ let after = ops.createNode(
2431
+ true,
2432
+ [],
2433
+ [],
2434
+ currentLeaf.parent,
2435
+ null,
2436
+ null
2437
+ );
2438
+ const mid = Math.ceil(ctx.order / 2) - 1;
2439
+ after = cloneNode(after);
2440
+ after.values = currentLeaf.values.slice(mid + 1);
2441
+ after.keys = currentLeaf.keys.slice(mid + 1);
2442
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
2443
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
2444
+ ops.updateNode(currentLeaf);
2445
+ ops.updateNode(after);
2446
+ insertInParent(ops, ctx, currentLeaf, after.values[0], after);
2447
+ currentLeaf = null;
2448
+ cachedLeafId = null;
2449
+ cachedLeafMaxValue = null;
2450
+ modified = false;
2451
+ }
2452
+ }
2453
+ if (currentLeaf !== null && modified) {
2454
+ ops.updateNode(currentLeaf);
2455
+ }
2456
+ }
2457
+ function bulkLoadOp(ops, ctx, entries, comparator) {
2458
+ if (entries.length === 0) return;
2459
+ const root = ops.getNode(ctx.rootId);
2460
+ if (!root.leaf || root.values.length > 0) {
2461
+ throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
2462
+ }
2463
+ const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
2464
+ const grouped = [];
2465
+ for (let i = 0, len = sorted.length; i < len; i++) {
2466
+ const [key, value] = sorted[i];
2467
+ const last = grouped[grouped.length - 1];
2468
+ if (last && comparator.isSame(last.value, value)) {
2469
+ if (!last.keys.includes(key)) {
2470
+ last.keys.push(key);
2471
+ }
2472
+ } else {
2473
+ grouped.push({ keys: [key], value });
2474
+ }
2475
+ }
2476
+ ops.deleteNode(root);
2477
+ const maxLeafSize = ctx.order - 1;
2478
+ const leaves = [];
2479
+ for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
2480
+ const chunk = grouped.slice(i, i + maxLeafSize);
2481
+ const leafKeys = chunk.map((g) => g.keys);
2482
+ const leafValues = chunk.map((g) => g.value);
2483
+ const leaf = ops.createNode(
2484
+ true,
2485
+ leafKeys,
2486
+ leafValues,
2487
+ null,
2488
+ null,
2489
+ null
2490
+ );
2491
+ leaves.push(leaf);
2492
+ }
2493
+ for (let i = 0, len = leaves.length; i < len; i++) {
2494
+ if (i > 0) {
2495
+ leaves[i].prev = leaves[i - 1].id;
2496
+ }
2497
+ if (i < len - 1) {
2498
+ leaves[i].next = leaves[i + 1].id;
2499
+ }
2500
+ ops.updateNode(leaves[i]);
2501
+ }
2502
+ let currentLevel = leaves;
2503
+ while (currentLevel.length > 1) {
2504
+ const nextLevel = [];
2505
+ for (let i = 0, len = currentLevel.length; i < len; i += ctx.order) {
2506
+ const children = currentLevel.slice(i, i + ctx.order);
2507
+ const childIds = children.map((c) => c.id);
2508
+ const separators = [];
2509
+ for (let j = 1, cLen = children.length; j < cLen; j++) {
2510
+ separators.push(children[j].values[0]);
2511
+ }
2512
+ const internalNode = ops.createNode(
2513
+ false,
2514
+ childIds,
2515
+ separators,
2516
+ null,
2517
+ null,
2518
+ null
2519
+ );
2520
+ for (let j = 0, cLen = children.length; j < cLen; j++) {
2521
+ const child = children[j];
2522
+ child.parent = internalNode.id;
2523
+ ops.updateNode(child);
2524
+ }
2525
+ nextLevel.push(internalNode);
2526
+ }
2527
+ currentLevel = nextLevel;
2528
+ }
2529
+ const newRoot = currentLevel[0];
2530
+ ops.writeHead({
2531
+ root: newRoot.id,
2532
+ order: ctx.order,
2533
+ data: ctx.headData()
2534
+ });
2535
+ ctx.rootId = newRoot.id;
2536
+ }
2537
+ function existsOp(ops, rootId, key, value, comparator) {
2538
+ const node = locateLeaf(ops, rootId, value, comparator);
2539
+ const { index, found } = binarySearchValues(node.values, value, comparator);
2540
+ if (found) {
2541
+ const keys = node.keys[index];
2542
+ if (keys.includes(key)) {
2543
+ return true;
2544
+ }
2545
+ }
2546
+ return false;
2547
+ }
2548
+ function getOp(ops, rootId, key) {
2549
+ let node = leftestNode(ops, rootId);
2550
+ while (true) {
2551
+ for (let i = 0, len = node.values.length; i < len; i++) {
2552
+ const keys = node.keys[i];
2553
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
2554
+ if (keys[j] === key) {
2555
+ return node.values[i];
2556
+ }
2557
+ }
2558
+ }
2559
+ if (!node.next) break;
2560
+ node = ops.getNode(node.next);
2561
+ }
2562
+ return void 0;
2563
+ }
2564
+ function* whereStreamOp(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
2565
+ const { filterValues, limit, order = "asc" } = options ?? {};
2566
+ const conditionKeys = Object.keys(condition);
2567
+ if (conditionKeys.length === 0) return;
2568
+ const resolved = resolveStartEndConfigs(condition, order, comparator, ensureValues);
2569
+ const direction = resolved.direction;
2570
+ let startNode;
2571
+ if (resolved.startKey) {
2572
+ const startConfig = searchConfigs[resolved.startKey][order];
2573
+ startNode = startConfig.start(rootId, ops, resolved.startValues);
2574
+ } else {
2575
+ startNode = order === "asc" ? leftestNode(ops, rootId) : rightestNode(ops, rootId);
2576
+ }
2577
+ let endNode = null;
2578
+ if (resolved.endKey) {
2579
+ const endConfig = searchConfigs[resolved.endKey][order];
2580
+ endNode = endConfig.end(rootId, ops, resolved.endValues);
2581
+ }
2582
+ if (!startNode) return;
2583
+ const generator = getPairsGenerator(ops, startNode, endNode, direction);
2584
+ let count = 0;
2585
+ const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2586
+ for (const pair of generator) {
2587
+ const [k, v] = pair;
2588
+ if (intersection && !intersection.has(k)) {
2589
+ continue;
2590
+ }
2591
+ if (verify(v, condition, verifierMap)) {
2592
+ yield pair;
2593
+ count++;
2594
+ if (limit !== void 0 && count >= limit) {
2595
+ break;
2596
+ }
2597
+ }
2598
+ }
2599
+ }
2600
+ function* keysStreamOp(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
2601
+ const { filterValues, limit } = options ?? {};
2602
+ const stream = whereStreamOp(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options);
2603
+ const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2604
+ let count = 0;
2605
+ for (const [key] of stream) {
2606
+ if (intersection && !intersection.has(key)) {
2607
+ continue;
2608
+ }
2609
+ yield key;
2610
+ count++;
2611
+ if (limit !== void 0 && count >= limit) {
2612
+ break;
2613
+ }
2614
+ }
2615
+ }
2616
+ function initOp(ops, ctx, strategyOrder, strategyHead, setStrategyHead) {
2617
+ const head = ops.readHead();
2618
+ if (head === null) {
2619
+ ctx.order = strategyOrder;
2620
+ const root = ops.createNode(true, [], []);
2621
+ ops.writeHead({
2622
+ root: root.id,
2623
+ order: ctx.order,
2624
+ data: strategyHead.data
2625
+ });
2626
+ ctx.rootId = root.id;
2627
+ } else {
2628
+ const { root, order } = head;
2629
+ setStrategyHead(head);
2630
+ ctx.order = order;
2631
+ ctx.rootId = root;
2632
+ }
2633
+ if (ctx.order < 3) {
2634
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${ctx.order}'.`);
2635
+ }
2636
+ }
2637
+
2638
+ // src/base/BPTreeTransaction.ts
2639
+ var BPTreeTransaction = class _BPTreeTransaction {
2640
+ _cachedRegexp = /* @__PURE__ */ new Map();
2641
+ rootTx;
2642
+ mvccRoot;
2643
+ mvcc;
2644
+ strategy;
2645
+ comparator;
2646
+ option;
2647
+ order;
2648
+ rootId;
2649
+ isInitialized = false;
2650
+ isDestroyed = false;
2651
+ verifierMap = {
2652
+ gt: (nv, v) => this.comparator.isHigher(nv, v),
2653
+ gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
2654
+ lt: (nv, v) => this.comparator.isLower(nv, v),
2655
+ lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
2656
+ equal: (nv, v) => this.comparator.isSame(nv, v),
2657
+ notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
2658
+ or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
2659
+ primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
2660
+ primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
2661
+ primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
2662
+ primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
2663
+ primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
2664
+ primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
2665
+ primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
2666
+ like: (nv, v) => {
2667
+ const nodeValue = this.comparator.match(nv);
2668
+ const value = v;
2669
+ if (!this._cachedRegexp.has(value)) {
2670
+ const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
2671
+ const regexp2 = new RegExp(`^${pattern}$`, "i");
2672
+ this._cachedRegexp.set(value, regexp2);
2673
+ }
2674
+ const regexp = this._cachedRegexp.get(value);
2675
+ return regexp.test(nodeValue);
2676
+ }
2677
+ };
2678
+ searchConfigs = {
2679
+ gt: {
2680
+ asc: {
2681
+ start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
2682
+ end: () => null,
2683
+ direction: 1,
2684
+ earlyTerminate: false
2685
+ },
2686
+ desc: {
2687
+ start: (tx) => tx.rightestNode(),
2688
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
2689
+ direction: -1,
2690
+ earlyTerminate: true
2691
+ }
2692
+ },
2693
+ gte: {
2694
+ asc: {
2695
+ start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
2696
+ end: () => null,
2697
+ direction: 1,
2698
+ earlyTerminate: false
2699
+ },
2700
+ desc: {
2701
+ start: (tx) => tx.rightestNode(),
2702
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
2703
+ direction: -1,
2704
+ earlyTerminate: true
2705
+ }
2706
+ },
2707
+ lt: {
2708
+ asc: {
2709
+ start: (tx) => tx.leftestNode(),
2710
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
2711
+ direction: 1,
2712
+ earlyTerminate: true
2713
+ },
2714
+ desc: {
2715
+ start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
2716
+ end: () => null,
2717
+ direction: -1,
2718
+ earlyTerminate: false
2719
+ }
2720
+ },
2721
+ lte: {
2722
+ asc: {
2723
+ start: (tx) => tx.leftestNode(),
2724
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
2725
+ direction: 1,
2726
+ earlyTerminate: true
2727
+ },
2728
+ desc: {
2729
+ start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
2730
+ end: () => null,
2731
+ direction: -1,
2732
+ earlyTerminate: false
2733
+ }
2734
+ },
2735
+ equal: {
2736
+ asc: {
2737
+ start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
2738
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
2739
+ direction: 1,
2740
+ earlyTerminate: true
2741
+ },
2742
+ desc: {
2743
+ start: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
2744
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
2745
+ direction: -1,
2746
+ earlyTerminate: true
2747
+ }
2748
+ },
2749
+ notEqual: {
2750
+ asc: {
2751
+ start: (tx) => tx.leftestNode(),
2752
+ end: () => null,
2753
+ direction: 1,
2754
+ earlyTerminate: false
2755
+ },
2756
+ desc: {
2757
+ start: (tx) => tx.rightestNode(),
2758
+ end: () => null,
2759
+ direction: -1,
2760
+ earlyTerminate: false
2761
+ }
2762
+ },
2763
+ or: {
2764
+ asc: {
2765
+ start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestValue(v)),
2766
+ end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
2767
+ direction: 1,
2768
+ earlyTerminate: false
2769
+ },
2770
+ desc: {
2771
+ start: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
2772
+ end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestValue(v), -1),
2773
+ direction: -1,
2774
+ earlyTerminate: false
2775
+ }
2776
+ },
2777
+ primaryGt: {
2778
+ asc: {
2779
+ start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
2780
+ end: () => null,
2781
+ direction: 1,
2782
+ earlyTerminate: false
2783
+ },
2784
+ desc: {
2785
+ start: (tx) => tx.rightestNode(),
2786
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
2787
+ direction: -1,
2788
+ earlyTerminate: true
2789
+ }
2790
+ },
2791
+ primaryGte: {
2792
+ asc: {
2793
+ start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
2794
+ end: () => null,
2795
+ direction: 1,
2796
+ earlyTerminate: false
2797
+ },
2798
+ desc: {
2799
+ start: (tx) => tx.rightestNode(),
2800
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
2801
+ direction: -1,
2802
+ earlyTerminate: true
2803
+ }
2804
+ },
2805
+ primaryLt: {
2806
+ asc: {
2807
+ start: (tx) => tx.leftestNode(),
2808
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
2809
+ direction: 1,
2810
+ earlyTerminate: true
2811
+ },
2812
+ desc: {
2813
+ start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
2814
+ end: () => null,
2815
+ direction: -1,
2816
+ earlyTerminate: false
2817
+ }
2818
+ },
2819
+ primaryLte: {
2820
+ asc: {
2821
+ start: (tx) => tx.leftestNode(),
2822
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
2823
+ direction: 1,
2824
+ earlyTerminate: true
2825
+ },
2826
+ desc: {
2827
+ start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
2828
+ end: () => null,
2829
+ direction: -1,
2830
+ earlyTerminate: false
2831
+ }
2832
+ },
2833
+ primaryEqual: {
2834
+ asc: {
2835
+ start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
2836
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
2837
+ direction: 1,
2838
+ earlyTerminate: true
2839
+ },
2840
+ desc: {
2841
+ start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
2842
+ end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
2843
+ direction: -1,
2844
+ earlyTerminate: true
2845
+ }
2846
+ },
2847
+ primaryNotEqual: {
2848
+ asc: {
2849
+ start: (tx) => tx.leftestNode(),
2850
+ end: () => null,
2851
+ direction: 1,
2852
+ earlyTerminate: false
2853
+ },
2854
+ desc: {
2855
+ start: (tx) => tx.rightestNode(),
2856
+ end: () => null,
2857
+ direction: -1,
2858
+ earlyTerminate: false
2859
+ }
2860
+ },
2861
+ primaryOr: {
2862
+ asc: {
2863
+ start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestPrimaryValue(v)),
2864
+ end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestPrimaryValue(v), 1),
2865
+ direction: 1,
2866
+ earlyTerminate: false
2867
+ },
2868
+ desc: {
2869
+ start: (tx, v) => tx.findUpperBoundLeaf(tx.highestPrimaryValue(v)),
2870
+ end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestPrimaryValue(v), -1),
2871
+ direction: -1,
2872
+ earlyTerminate: false
2873
+ }
2874
+ },
2875
+ like: {
2876
+ asc: {
2877
+ start: (tx) => tx.leftestNode(),
2878
+ end: () => null,
2879
+ direction: 1,
2880
+ earlyTerminate: false
2881
+ },
2882
+ desc: {
2883
+ start: (tx) => tx.rightestNode(),
2884
+ end: () => null,
2885
+ direction: -1,
2886
+ earlyTerminate: false
2887
+ }
2888
+ }
2889
+ };
2890
+ /**
2891
+ * Priority map for condition types.
2892
+ * Higher value = higher selectivity (fewer expected results).
2893
+ * Used by `chooseDriver` to select the most selective index.
2894
+ */
2895
+ static conditionPriority = {
2896
+ equal: 100,
2897
+ primaryEqual: 100,
2898
+ or: 80,
2899
+ primaryOr: 80,
2900
+ gt: 50,
2901
+ gte: 50,
2902
+ lt: 50,
2903
+ lte: 50,
2904
+ primaryGt: 50,
2905
+ primaryGte: 50,
2906
+ primaryLt: 50,
2907
+ primaryLte: 50,
2908
+ like: 30,
2909
+ notEqual: 10,
2910
+ primaryNotEqual: 10
2911
+ };
2912
+ /**
2913
+ * Selects the best driver tree from multiple tree/condition pairs.
2914
+ * Uses rule-based optimization to choose the tree with highest estimated selectivity.
2915
+ *
2916
+ * @param candidates Array of { tree, condition } pairs to evaluate
2917
+ * @returns The candidate with highest priority condition, or null if empty
2918
+ *
2919
+ * @example
2920
+ * ```typescript
2921
+ * const driver = BPTreeSync.chooseDriver([
2922
+ * { tree: idxId, condition: { equal: 100 } },
2923
+ * { tree: idxAge, condition: { gt: 20 } }
2924
+ * ])
2925
+ * // Returns { tree: idxId, condition: { equal: 100 } } because 'equal' has higher priority
2926
+ * ```
2927
+ */
2928
+ static ChooseDriver(candidates) {
2929
+ if (candidates.length === 0) return null;
2930
+ if (candidates.length === 1) return candidates[0];
2931
+ let best = candidates[0];
2932
+ let bestScore = 0;
2933
+ for (const candidate of candidates) {
2934
+ let score = 0;
2935
+ for (const key in candidate.condition) {
2936
+ const condKey = key;
2937
+ const priority = _BPTreeTransaction.conditionPriority[condKey] ?? 0;
2938
+ if (priority > score) {
2939
+ score = priority;
2940
+ }
2941
+ }
2942
+ if (score > bestScore) {
2943
+ bestScore = score;
2944
+ best = candidate;
2945
+ }
2946
+ }
2947
+ return best;
2948
+ }
2949
+ /**
2950
+ * Checks for conflicts between multiple transactions.
2951
+ *
2952
+ * @param transactions Array of BPTreeTransaction instances to check
2953
+ * @returns An array of keys that are in conflict. Empty array if no conflicts.
2954
+ */
2955
+ static CheckConflicts(transactions) {
2956
+ return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
2957
+ }
2958
+ /**
2959
+ * Returns the ID of the root node.
2960
+ * @returns The root node ID.
2961
+ */
2962
+ getRootId() {
2963
+ return this.rootId;
2964
+ }
2965
+ /**
2966
+ * Returns the order of the B+Tree.
2967
+ * @returns The order of the tree.
2968
+ */
2969
+ getOrder() {
2970
+ return this.order;
2971
+ }
2972
+ /**
2973
+ * Verified if the value satisfies the condition.
2974
+ *
2975
+ * @param nodeValue The value to verify.
2976
+ * @param condition The condition to verify against.
2977
+ * @returns Returns true if the value satisfies the condition.
2978
+ */
2979
+ verify(nodeValue, condition) {
2980
+ for (const key in condition) {
2981
+ const verify2 = this.verifierMap[key];
2982
+ const condValue = condition[key];
2983
+ if (!verify2(nodeValue, condValue)) {
2984
+ return false;
2985
+ }
2986
+ }
2987
+ return true;
2988
+ }
2989
+ /**
2990
+ * Inserts a key-value pair into an already-cloned leaf node in-place.
2991
+ * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
2992
+ * Used by batchInsert to batch multiple insertions with a single clone/update.
2993
+ * @returns true if the leaf was modified, false if the key already exists.
2994
+ */
2995
+ _insertValueIntoLeaf(leaf, key, value) {
2996
+ if (leaf.values.length) {
2997
+ const { index, found } = this._binarySearchValues(leaf.values, value);
2998
+ if (found) {
2999
+ if (leaf.keys[index].includes(key)) {
3000
+ return false;
3001
+ }
3002
+ leaf.keys[index].push(key);
3003
+ return true;
3004
+ }
3005
+ leaf.values.splice(index, 0, value);
3006
+ leaf.keys.splice(index, 0, [key]);
3007
+ return true;
3008
+ } else {
3009
+ leaf.values = [value];
3010
+ leaf.keys = [[key]];
3011
+ return true;
3012
+ }
3013
+ }
3014
+ _cloneNode(node) {
3015
+ return JSON.parse(JSON.stringify(node));
3016
+ }
3017
+ /**
3018
+ * Resolves the best start/end configuration by independently examining
3019
+ * all conditions. Selects the tightest lower bound for start and the
3020
+ * tightest upper bound for end (in asc; reversed for desc).
3021
+ *
3022
+ * @param condition The condition to analyze.
3023
+ * @param order The sort order ('asc' or 'desc').
3024
+ * @returns The resolved start/end keys, values, and traversal direction.
3025
+ */
3026
+ resolveStartEndConfigs(condition, order) {
3027
+ const direction = order === "asc" ? 1 : -1;
3028
+ const startCandidates = order === "asc" ? _BPTreeTransaction._lowerBoundKeys : _BPTreeTransaction._upperBoundKeys;
3029
+ const endCandidates = order === "asc" ? _BPTreeTransaction._upperBoundKeys : _BPTreeTransaction._lowerBoundKeys;
3030
+ let startKey = null;
3031
+ let endKey = null;
3032
+ let startValues = [];
1966
3033
  let endValues = [];
1967
3034
  for (let i = 0, len = startCandidates.length; i < len; i++) {
1968
3035
  const key = startCandidates[i];
@@ -2051,6 +3118,12 @@ var BPTreeTransaction = class _BPTreeTransaction {
2051
3118
  _clearCache() {
2052
3119
  this._cachedRegexp.clear();
2053
3120
  }
3121
+ _resetForReload() {
3122
+ this._cachedRegexp.clear();
3123
+ this.isInitialized = false;
3124
+ this.isDestroyed = false;
3125
+ this.mvccRoot.diskCache.clear();
3126
+ }
2054
3127
  /**
2055
3128
  * Clears all cached nodes.
2056
3129
  * This method is useful for freeing up memory when the tree is no longer needed.
@@ -2091,6 +3164,10 @@ var BPTreeTransaction = class _BPTreeTransaction {
2091
3164
 
2092
3165
  // src/transaction/BPTreeSyncTransaction.ts
2093
3166
  var BPTreeSyncTransaction = class extends BPTreeTransaction {
3167
+ _ops;
3168
+ _ctx;
3169
+ _verifierMapCached;
3170
+ _searchConfigsCached;
2094
3171
  constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
2095
3172
  super(
2096
3173
  rootTx,
@@ -2100,248 +3177,113 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2100
3177
  comparator,
2101
3178
  option
2102
3179
  );
3180
+ this._initAlgoContext();
3181
+ }
3182
+ _initAlgoContext() {
3183
+ const mvcc = this.mvcc;
3184
+ const strategy = this.strategy;
3185
+ const self = this;
3186
+ this._ops = {
3187
+ getNode(id) {
3188
+ return mvcc.read(id);
3189
+ },
3190
+ createNode(leaf, keys, values, parent = null, next = null, prev = null) {
3191
+ const id = strategy.id(leaf);
3192
+ const node = { id, keys, values, leaf, parent, next, prev };
3193
+ mvcc.create(id, node);
3194
+ return node;
3195
+ },
3196
+ updateNode(node) {
3197
+ if (mvcc.isDeleted(node.id)) {
3198
+ return;
3199
+ }
3200
+ mvcc.write(node.id, node);
3201
+ },
3202
+ deleteNode(node) {
3203
+ if (mvcc.isDeleted(node.id)) {
3204
+ return;
3205
+ }
3206
+ mvcc.delete(node.id);
3207
+ },
3208
+ readHead() {
3209
+ return mvcc.read("__HEAD__");
3210
+ },
3211
+ writeHead(head) {
3212
+ if (!mvcc.exists("__HEAD__")) {
3213
+ mvcc.create("__HEAD__", head);
3214
+ } else {
3215
+ mvcc.write("__HEAD__", head);
3216
+ }
3217
+ self.rootId = head.root;
3218
+ }
3219
+ };
3220
+ this._ctx = {
3221
+ get rootId() {
3222
+ return self.rootId;
3223
+ },
3224
+ set rootId(v) {
3225
+ self.rootId = v;
3226
+ },
3227
+ get order() {
3228
+ return self.order;
3229
+ },
3230
+ set order(v) {
3231
+ self.order = v;
3232
+ },
3233
+ headData: () => this.strategy.head.data
3234
+ };
3235
+ const ensureValues = (v) => this.ensureValues(v);
3236
+ this._verifierMapCached = createVerifierMap(this.comparator, this._cachedRegexp, ensureValues);
3237
+ this._searchConfigsCached = createSearchConfigs(this.comparator, ensureValues);
2103
3238
  }
3239
+ // ─── Legacy protected methods (delegating to ops) ────────────────
2104
3240
  getNode(id) {
2105
- return this.mvcc.read(id);
3241
+ return this._ops.getNode(id);
2106
3242
  }
2107
- /**
2108
- * Create a new node with a unique ID.
2109
- */
2110
3243
  _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
2111
- const id = this.strategy.id(leaf);
2112
- const node = {
2113
- id,
2114
- keys,
2115
- values,
2116
- leaf,
2117
- parent,
2118
- next,
2119
- prev
2120
- };
2121
- this.mvcc.create(id, node);
2122
- return node;
3244
+ return this._ops.createNode(leaf, keys, values, parent, next, prev);
2123
3245
  }
2124
3246
  _updateNode(node) {
2125
- if (this.mvcc.isDeleted(node.id)) {
2126
- return;
2127
- }
2128
- this.mvcc.write(node.id, node);
3247
+ this._ops.updateNode(node);
2129
3248
  }
2130
3249
  _deleteNode(node) {
2131
- if (this.mvcc.isDeleted(node.id)) {
2132
- return;
2133
- }
2134
- this.mvcc.delete(node.id);
3250
+ this._ops.deleteNode(node);
2135
3251
  }
2136
3252
  _readHead() {
2137
- return this.mvcc.read("__HEAD__");
3253
+ return this._ops.readHead();
2138
3254
  }
2139
3255
  _writeHead(head) {
2140
- if (!this.mvcc.exists("__HEAD__")) {
2141
- this.mvcc.create("__HEAD__", head);
2142
- } else {
2143
- this.mvcc.write("__HEAD__", head);
2144
- }
2145
- this.rootId = head.root;
3256
+ this._ops.writeHead(head);
2146
3257
  }
3258
+ // ─── Tree traversal (delegating to algorithm) ────────────────────
2147
3259
  _insertAtLeaf(node, key, value) {
2148
- let leaf = node;
2149
- if (leaf.values.length) {
2150
- for (let i = 0, len = leaf.values.length; i < len; i++) {
2151
- const nValue = leaf.values[i];
2152
- if (this.comparator.isSame(value, nValue)) {
2153
- const keys = leaf.keys[i];
2154
- if (keys.includes(key)) {
2155
- break;
2156
- }
2157
- leaf = this._cloneNode(leaf);
2158
- leaf.keys[i].push(key);
2159
- this._updateNode(leaf);
2160
- return leaf;
2161
- } else if (this.comparator.isLower(value, nValue)) {
2162
- leaf = this._cloneNode(leaf);
2163
- leaf.values.splice(i, 0, value);
2164
- leaf.keys.splice(i, 0, [key]);
2165
- this._updateNode(leaf);
2166
- return leaf;
2167
- } else if (i + 1 === leaf.values.length) {
2168
- leaf = this._cloneNode(leaf);
2169
- leaf.values.push(value);
2170
- leaf.keys.push([key]);
2171
- this._updateNode(leaf);
2172
- return leaf;
2173
- }
2174
- }
2175
- } else {
2176
- leaf = this._cloneNode(leaf);
2177
- leaf.values = [value];
2178
- leaf.keys = [[key]];
2179
- this._updateNode(leaf);
2180
- return leaf;
2181
- }
2182
- return leaf;
3260
+ return insertAtLeaf(this._ops, node, key, value, this.comparator);
2183
3261
  }
2184
3262
  _insertInParent(node, value, newSiblingNode) {
2185
- if (this.rootId === node.id) {
2186
- node = this._cloneNode(node);
2187
- newSiblingNode = this._cloneNode(newSiblingNode);
2188
- const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
2189
- this.rootId = root.id;
2190
- node.parent = root.id;
2191
- newSiblingNode.parent = root.id;
2192
- if (newSiblingNode.leaf) {
2193
- node.next = newSiblingNode.id;
2194
- newSiblingNode.prev = node.id;
2195
- }
2196
- this._writeHead({
2197
- root: root.id,
2198
- order: this.order,
2199
- data: this.strategy.head.data
2200
- });
2201
- this._updateNode(node);
2202
- this._updateNode(newSiblingNode);
2203
- return;
2204
- }
2205
- const parentNode = this._cloneNode(this.getNode(node.parent));
2206
- const nodeIndex = parentNode.keys.indexOf(node.id);
2207
- if (nodeIndex === -1) {
2208
- throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2209
- }
2210
- parentNode.values.splice(nodeIndex, 0, value);
2211
- parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
2212
- newSiblingNode = this._cloneNode(newSiblingNode);
2213
- newSiblingNode.parent = parentNode.id;
2214
- if (newSiblingNode.leaf) {
2215
- const leftSibling = this._cloneNode(node);
2216
- const oldNextId = leftSibling.next;
2217
- newSiblingNode.prev = leftSibling.id;
2218
- newSiblingNode.next = oldNextId;
2219
- leftSibling.next = newSiblingNode.id;
2220
- this._updateNode(leftSibling);
2221
- if (oldNextId) {
2222
- const oldNext = this._cloneNode(this.getNode(oldNextId));
2223
- oldNext.prev = newSiblingNode.id;
2224
- this._updateNode(oldNext);
2225
- }
2226
- }
2227
- this._updateNode(parentNode);
2228
- this._updateNode(newSiblingNode);
2229
- if (parentNode.keys.length > this.order) {
2230
- const newSiblingNodeRecursive = this._createNode(false, [], []);
2231
- newSiblingNodeRecursive.parent = parentNode.parent;
2232
- const mid = Math.ceil(this.order / 2) - 1;
2233
- newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
2234
- newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
2235
- const midValue = parentNode.values[mid];
2236
- parentNode.values = parentNode.values.slice(0, mid);
2237
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
2238
- for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
2239
- const k = newSiblingNodeRecursive.keys[i];
2240
- const n = this._cloneNode(this.getNode(k));
2241
- n.parent = newSiblingNodeRecursive.id;
2242
- this._updateNode(n);
2243
- }
2244
- this._updateNode(parentNode);
2245
- this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
2246
- }
3263
+ insertInParent(this._ops, this._ctx, node, value, newSiblingNode);
2247
3264
  }
2248
3265
  locateLeaf(value) {
2249
- let node = this.getNode(this.rootId);
2250
- while (!node.leaf) {
2251
- const { index } = this._binarySearchValues(node.values, value, false, true);
2252
- node = this.getNode(node.keys[index]);
2253
- }
2254
- return node;
3266
+ return locateLeaf(this._ops, this._ctx.rootId, value, this.comparator);
2255
3267
  }
2256
3268
  findLowerBoundLeaf(value) {
2257
- let node = this.getNode(this.rootId);
2258
- while (!node.leaf) {
2259
- const { index } = this._binarySearchValues(node.values, value, true, false);
2260
- node = this.getNode(node.keys[index]);
2261
- }
2262
- return node;
3269
+ return findLowerBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
2263
3270
  }
2264
3271
  findUpperBoundLeaf(value) {
2265
- let node = this.getNode(this.rootId);
2266
- while (!node.leaf) {
2267
- const { index } = this._binarySearchValues(node.values, value, true, true);
2268
- node = this.getNode(node.keys[index]);
2269
- }
2270
- return node;
3272
+ return findUpperBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
2271
3273
  }
2272
3274
  findOuterBoundaryLeaf(value, direction) {
2273
- const insertableNode = direction === -1 ? this.findLowerBoundLeaf(value) : this.findUpperBoundLeaf(value);
2274
- let key;
2275
- switch (direction) {
2276
- case -1:
2277
- key = "prev";
2278
- break;
2279
- case 1:
2280
- key = "next";
2281
- break;
2282
- default:
2283
- throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
2284
- }
2285
- const guessNode = insertableNode[key];
2286
- if (!guessNode) {
2287
- return null;
2288
- }
2289
- return this.getNode(guessNode);
3275
+ return findOuterBoundaryLeaf(this._ops, this._ctx.rootId, value, direction, this.comparator);
2290
3276
  }
2291
3277
  leftestNode() {
2292
- let node = this.getNode(this.rootId);
2293
- if (node === null) {
2294
- debugger;
2295
- }
2296
- while (!node.leaf) {
2297
- const keys = node.keys;
2298
- node = this.getNode(keys[0]);
2299
- }
2300
- return node;
3278
+ return leftestNode(this._ops, this._ctx.rootId);
2301
3279
  }
2302
3280
  rightestNode() {
2303
- let node = this.getNode(this.rootId);
2304
- while (!node.leaf) {
2305
- const keys = node.keys;
2306
- node = this.getNode(keys[keys.length - 1]);
2307
- }
2308
- return node;
3281
+ return rightestNode(this._ops, this._ctx.rootId);
2309
3282
  }
2310
3283
  *getPairsGenerator(startNode, endNode, direction) {
2311
- let node = startNode;
2312
- while (true) {
2313
- if (endNode && node.id === endNode.id) {
2314
- break;
2315
- }
2316
- const len = node.values.length;
2317
- if (direction === 1) {
2318
- for (let i = 0; i < len; i++) {
2319
- const nValue = node.values[i];
2320
- const keys = node.keys[i];
2321
- for (let j = 0, len2 = keys.length; j < len2; j++) {
2322
- yield [keys[j], nValue];
2323
- }
2324
- }
2325
- } else {
2326
- let i = len;
2327
- while (i--) {
2328
- const nValue = node.values[i];
2329
- const keys = node.keys[i];
2330
- let j = keys.length;
2331
- while (j--) {
2332
- yield [keys[j], nValue];
2333
- }
2334
- }
2335
- }
2336
- if (direction === 1) {
2337
- if (!node.next) break;
2338
- node = this.getNode(node.next);
2339
- } else {
2340
- if (!node.prev) break;
2341
- node = this.getNode(node.prev);
2342
- }
2343
- }
3284
+ yield* getPairsGenerator(this._ops, startNode, endNode, direction);
2344
3285
  }
3286
+ // ─── Lifecycle ───────────────────────────────────────────────────
2345
3287
  init() {
2346
3288
  if (this.rootTx !== this) {
2347
3289
  throw new Error("Cannot call init on a nested transaction");
@@ -2357,525 +3299,93 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2357
3299
  }
2358
3300
  this.isInitialized = true;
2359
3301
  try {
2360
- this._clearCache();
2361
- const head = this._readHead();
2362
- if (head === null) {
2363
- this.order = this.strategy.order;
2364
- const root = this._createNode(true, [], []);
2365
- this._writeHead({
2366
- root: root.id,
2367
- order: this.order,
2368
- data: this.strategy.head.data
2369
- });
2370
- } else {
2371
- const { root, order } = head;
2372
- this.strategy.head = head;
2373
- this.order = order;
2374
- this.rootId = root;
2375
- }
2376
- if (this.order < 3) {
2377
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2378
- }
2379
- } catch (e) {
2380
- this.isInitialized = false;
2381
- throw e;
2382
- }
2383
- }
2384
- exists(key, value) {
2385
- const node = this.locateLeaf(value);
2386
- const { index, found } = this._binarySearchValues(node.values, value);
2387
- if (found) {
2388
- const keys = node.keys[index];
2389
- if (keys.includes(key)) {
2390
- return true;
2391
- }
2392
- }
2393
- return false;
2394
- }
2395
- get(key) {
2396
- let node = this.leftestNode();
2397
- while (true) {
2398
- for (let i = 0, len = node.values.length; i < len; i++) {
2399
- const keys = node.keys[i];
2400
- for (let j = 0, len2 = keys.length; j < len2; j++) {
2401
- if (keys[j] === key) {
2402
- return node.values[i];
2403
- }
2404
- }
2405
- }
2406
- if (!node.next) break;
2407
- node = this.getNode(node.next);
2408
- }
2409
- return void 0;
2410
- }
2411
- *keysStream(condition, options) {
2412
- const { filterValues, limit, order = "asc" } = options ?? {};
2413
- const stream = this.whereStream(condition, options);
2414
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2415
- let count = 0;
2416
- for (const [key] of stream) {
2417
- if (intersection && !intersection.has(key)) {
2418
- continue;
2419
- }
2420
- yield key;
2421
- count++;
2422
- if (limit !== void 0 && count >= limit) {
2423
- break;
2424
- }
2425
- }
2426
- }
2427
- *whereStream(condition, options) {
2428
- const { filterValues, limit, order = "asc" } = options ?? {};
2429
- const conditionKeys = Object.keys(condition);
2430
- if (conditionKeys.length === 0) return;
2431
- const resolved = this.resolveStartEndConfigs(condition, order);
2432
- const direction = resolved.direction;
2433
- let startNode;
2434
- if (resolved.startKey) {
2435
- const startConfig = this.searchConfigs[resolved.startKey][order];
2436
- startNode = startConfig.start(this, resolved.startValues);
2437
- } else {
2438
- startNode = order === "asc" ? this.leftestNode() : this.rightestNode();
2439
- }
2440
- let endNode = null;
2441
- if (resolved.endKey) {
2442
- const endConfig = this.searchConfigs[resolved.endKey][order];
2443
- endNode = endConfig.end(this, resolved.endValues);
2444
- }
2445
- if (!startNode) return;
2446
- const generator = this.getPairsGenerator(
2447
- startNode,
2448
- endNode,
2449
- direction
2450
- );
2451
- let count = 0;
2452
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2453
- for (const pair of generator) {
2454
- const [k, v] = pair;
2455
- if (intersection && !intersection.has(k)) {
2456
- continue;
2457
- }
2458
- if (this.verify(v, condition)) {
2459
- yield pair;
2460
- count++;
2461
- if (limit !== void 0 && count >= limit) {
2462
- break;
2463
- }
2464
- }
2465
- }
2466
- }
2467
- keys(condition, options) {
2468
- const set = /* @__PURE__ */ new Set();
2469
- for (const key of this.keysStream(condition, options)) {
2470
- set.add(key);
2471
- }
2472
- return set;
2473
- }
2474
- where(condition, options) {
2475
- const map = /* @__PURE__ */ new Map();
2476
- for (const [key, value] of this.whereStream(condition, options)) {
2477
- map.set(key, value);
2478
- }
2479
- return map;
2480
- }
2481
- insert(key, value) {
2482
- let before = this.locateLeaf(value);
2483
- before = this._insertAtLeaf(before, key, value);
2484
- if (before.values.length === this.order) {
2485
- let after = this._createNode(
2486
- true,
2487
- [],
2488
- [],
2489
- before.parent,
2490
- null,
2491
- null
2492
- );
2493
- const mid = Math.ceil(this.order / 2) - 1;
2494
- after = this._cloneNode(after);
2495
- after.values = before.values.slice(mid + 1);
2496
- after.keys = before.keys.slice(mid + 1);
2497
- before.values = before.values.slice(0, mid + 1);
2498
- before.keys = before.keys.slice(0, mid + 1);
2499
- this._updateNode(before);
2500
- this._updateNode(after);
2501
- this._insertInParent(before, after.values[0], after);
2502
- }
2503
- }
2504
- batchInsert(entries) {
2505
- if (entries.length === 0) return;
2506
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2507
- let currentLeaf = null;
2508
- let modified = false;
2509
- let cachedLeafId = null;
2510
- let cachedLeafMaxValue = null;
2511
- for (let i = 0, len = sorted.length; i < len; i++) {
2512
- const [key, value] = sorted[i];
2513
- let targetLeaf;
2514
- if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
2515
- targetLeaf = currentLeaf;
2516
- } else {
2517
- targetLeaf = this.locateLeaf(value);
2518
- }
2519
- if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2520
- } else {
2521
- if (currentLeaf !== null && modified) {
2522
- this._updateNode(currentLeaf);
2523
- }
2524
- currentLeaf = this._cloneNode(targetLeaf);
2525
- modified = false;
2526
- }
2527
- cachedLeafId = currentLeaf.id;
2528
- const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2529
- modified = modified || changed;
2530
- cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
2531
- if (currentLeaf.values.length === this.order) {
2532
- this._updateNode(currentLeaf);
2533
- let after = this._createNode(
2534
- true,
2535
- [],
2536
- [],
2537
- currentLeaf.parent,
2538
- null,
2539
- null
2540
- );
2541
- const mid = Math.ceil(this.order / 2) - 1;
2542
- after = this._cloneNode(after);
2543
- after.values = currentLeaf.values.slice(mid + 1);
2544
- after.keys = currentLeaf.keys.slice(mid + 1);
2545
- currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
2546
- currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
2547
- this._updateNode(currentLeaf);
2548
- this._updateNode(after);
2549
- this._insertInParent(currentLeaf, after.values[0], after);
2550
- currentLeaf = null;
2551
- cachedLeafId = null;
2552
- cachedLeafMaxValue = null;
2553
- modified = false;
2554
- }
2555
- }
2556
- if (currentLeaf !== null && modified) {
2557
- this._updateNode(currentLeaf);
2558
- }
2559
- }
2560
- bulkLoad(entries) {
2561
- if (entries.length === 0) return;
2562
- const root = this.getNode(this.rootId);
2563
- if (!root.leaf || root.values.length > 0) {
2564
- throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
2565
- }
2566
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2567
- const grouped = [];
2568
- for (let i = 0, len = sorted.length; i < len; i++) {
2569
- const [key, value] = sorted[i];
2570
- const last = grouped[grouped.length - 1];
2571
- if (last && this.comparator.isSame(last.value, value)) {
2572
- if (!last.keys.includes(key)) {
2573
- last.keys.push(key);
2574
- }
2575
- } else {
2576
- grouped.push({ keys: [key], value });
2577
- }
2578
- }
2579
- this._deleteNode(root);
2580
- const maxLeafSize = this.order - 1;
2581
- const leaves = [];
2582
- for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
2583
- const chunk = grouped.slice(i, i + maxLeafSize);
2584
- const leafKeys = chunk.map((g) => g.keys);
2585
- const leafValues = chunk.map((g) => g.value);
2586
- const leaf = this._createNode(
2587
- true,
2588
- leafKeys,
2589
- leafValues,
2590
- null,
2591
- null,
2592
- null
2593
- );
2594
- leaves.push(leaf);
2595
- }
2596
- for (let i = 0, len = leaves.length; i < len; i++) {
2597
- if (i > 0) {
2598
- leaves[i].prev = leaves[i - 1].id;
2599
- }
2600
- if (i < len - 1) {
2601
- leaves[i].next = leaves[i + 1].id;
2602
- }
2603
- this._updateNode(leaves[i]);
2604
- }
2605
- let currentLevel = leaves;
2606
- while (currentLevel.length > 1) {
2607
- const nextLevel = [];
2608
- for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
2609
- const children = currentLevel.slice(i, i + this.order);
2610
- const childIds = children.map((c) => c.id);
2611
- const separators = [];
2612
- for (let j = 1, len2 = children.length; j < len2; j++) {
2613
- separators.push(children[j].values[0]);
2614
- }
2615
- const internalNode = this._createNode(
2616
- false,
2617
- childIds,
2618
- separators,
2619
- null,
2620
- null,
2621
- null
2622
- );
2623
- for (let j = 0, len2 = children.length; j < len2; j++) {
2624
- const child = children[j];
2625
- child.parent = internalNode.id;
2626
- this._updateNode(child);
2627
- }
2628
- nextLevel.push(internalNode);
2629
- }
2630
- currentLevel = nextLevel;
2631
- }
2632
- const newRoot = currentLevel[0];
2633
- this._writeHead({
2634
- root: newRoot.id,
2635
- order: this.order,
2636
- data: this.strategy.head.data
2637
- });
2638
- }
2639
- _deleteEntry(node, key) {
2640
- if (!node.leaf) {
2641
- let keyIndex = -1;
2642
- for (let i = 0, len = node.keys.length; i < len; i++) {
2643
- if (node.keys[i] === key) {
2644
- keyIndex = i;
2645
- break;
2646
- }
2647
- }
2648
- if (keyIndex !== -1) {
2649
- node = this._cloneNode(node);
2650
- node.keys.splice(keyIndex, 1);
2651
- const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2652
- node.values.splice(valueIndex, 1);
2653
- this._updateNode(node);
2654
- }
2655
- }
2656
- if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
2657
- const keys = node.keys;
2658
- this._deleteNode(node);
2659
- const newRoot = this._cloneNode(this.getNode(keys[0]));
2660
- newRoot.parent = null;
2661
- this._updateNode(newRoot);
2662
- this._writeHead({
2663
- root: newRoot.id,
2664
- order: this.order,
2665
- data: this.strategy.head.data
2666
- });
2667
- return node;
2668
- } else if (this.rootId === node.id) {
2669
- this._writeHead({
2670
- root: node.id,
2671
- order: this.order,
2672
- data: this.strategy.head.data
2673
- });
2674
- return node;
2675
- } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
2676
- if (node.parent === null) {
2677
- return node;
2678
- }
2679
- let isPredecessor = false;
2680
- let parentNode = this.getNode(node.parent);
2681
- let prevNode = null;
2682
- let nextNode = null;
2683
- let prevValue = null;
2684
- let postValue = null;
2685
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2686
- const nKey = parentNode.keys[i];
2687
- if (nKey === node.id) {
2688
- if (i > 0) {
2689
- prevNode = this.getNode(parentNode.keys[i - 1]);
2690
- prevValue = parentNode.values[i - 1];
2691
- }
2692
- if (i < parentNode.keys.length - 1) {
2693
- nextNode = this.getNode(parentNode.keys[i + 1]);
2694
- postValue = parentNode.values[i];
2695
- }
2696
- }
2697
- }
2698
- let siblingNode;
2699
- let guess;
2700
- if (prevNode === null) {
2701
- siblingNode = nextNode;
2702
- guess = postValue;
2703
- } else if (nextNode === null) {
2704
- isPredecessor = true;
2705
- siblingNode = prevNode;
2706
- guess = prevValue;
2707
- } else {
2708
- if (node.values.length + nextNode.values.length < this.order) {
2709
- siblingNode = nextNode;
2710
- guess = postValue;
2711
- } else {
2712
- isPredecessor = true;
2713
- siblingNode = prevNode;
2714
- guess = prevValue;
2715
- }
2716
- }
2717
- if (!siblingNode) {
2718
- return node;
2719
- }
2720
- node = this._cloneNode(node);
2721
- siblingNode = this._cloneNode(siblingNode);
2722
- if (node.values.length + siblingNode.values.length < this.order) {
2723
- if (!isPredecessor) {
2724
- const pTemp = siblingNode;
2725
- siblingNode = node;
2726
- node = pTemp;
2727
- }
2728
- siblingNode.keys.push(...node.keys);
2729
- if (!node.leaf) {
2730
- siblingNode.values.push(guess);
2731
- } else {
2732
- siblingNode.next = node.next;
2733
- if (siblingNode.next) {
2734
- const n = this._cloneNode(this.getNode(siblingNode.next));
2735
- n.prev = siblingNode.id;
2736
- this._updateNode(n);
2737
- }
2738
- }
2739
- siblingNode.values.push(...node.values);
2740
- if (!siblingNode.leaf) {
2741
- const keys = siblingNode.keys;
2742
- for (let i = 0, len = keys.length; i < len; i++) {
2743
- const key2 = keys[i];
2744
- const node2 = this._cloneNode(this.getNode(key2));
2745
- node2.parent = siblingNode.id;
2746
- this._updateNode(node2);
2747
- }
2748
- }
2749
- this._deleteNode(node);
2750
- this._updateNode(siblingNode);
2751
- this._deleteEntry(this.getNode(node.parent), node.id);
2752
- } else {
2753
- if (isPredecessor) {
2754
- let pointerPm;
2755
- let pointerKm;
2756
- if (!node.leaf) {
2757
- pointerPm = siblingNode.keys.splice(-1)[0];
2758
- pointerKm = siblingNode.values.splice(-1)[0];
2759
- node.keys = [pointerPm, ...node.keys];
2760
- node.values = [guess, ...node.values];
2761
- parentNode = this._cloneNode(this.getNode(node.parent));
2762
- const nodeIndex = parentNode.keys.indexOf(node.id);
2763
- if (nodeIndex > 0) {
2764
- parentNode.values[nodeIndex - 1] = pointerKm;
2765
- this._updateNode(parentNode);
2766
- }
2767
- } else {
2768
- pointerPm = siblingNode.keys.splice(-1)[0];
2769
- pointerKm = siblingNode.values.splice(-1)[0];
2770
- node.keys = [pointerPm, ...node.keys];
2771
- node.values = [pointerKm, ...node.values];
2772
- parentNode = this._cloneNode(this.getNode(node.parent));
2773
- const nodeIndex = parentNode.keys.indexOf(node.id);
2774
- if (nodeIndex > 0) {
2775
- parentNode.values[nodeIndex - 1] = pointerKm;
2776
- this._updateNode(parentNode);
2777
- }
2778
- }
2779
- this._updateNode(node);
2780
- this._updateNode(siblingNode);
2781
- } else {
2782
- let pointerP0;
2783
- let pointerK0;
2784
- if (!node.leaf) {
2785
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
2786
- pointerK0 = siblingNode.values.splice(0, 1)[0];
2787
- node.keys = [...node.keys, pointerP0];
2788
- node.values = [...node.values, guess];
2789
- parentNode = this._cloneNode(this.getNode(node.parent));
2790
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2791
- if (pointerIndex > 0) {
2792
- parentNode.values[pointerIndex - 1] = pointerK0;
2793
- this._updateNode(parentNode);
2794
- }
2795
- } else {
2796
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
2797
- pointerK0 = siblingNode.values.splice(0, 1)[0];
2798
- node.keys = [...node.keys, pointerP0];
2799
- node.values = [...node.values, pointerK0];
2800
- parentNode = this._cloneNode(this.getNode(node.parent));
2801
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2802
- if (pointerIndex > 0) {
2803
- parentNode.values[pointerIndex - 1] = siblingNode.values[0];
2804
- this._updateNode(parentNode);
2805
- }
2806
- }
2807
- this._updateNode(node);
2808
- this._updateNode(siblingNode);
2809
- }
2810
- if (!siblingNode.leaf) {
2811
- for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
2812
- const key2 = siblingNode.keys[i];
2813
- const n = this._cloneNode(this.getNode(key2));
2814
- n.parent = siblingNode.id;
2815
- this._updateNode(n);
2816
- }
2817
- }
2818
- if (!node.leaf) {
2819
- for (let i = 0, len = node.keys.length; i < len; i++) {
2820
- const key2 = node.keys[i];
2821
- const n = this._cloneNode(this.getNode(key2));
2822
- n.parent = node.id;
2823
- this._updateNode(n);
2824
- }
2825
- }
2826
- if (!parentNode.leaf) {
2827
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2828
- const key2 = parentNode.keys[i];
2829
- const n = this._cloneNode(this.getNode(key2));
2830
- n.parent = parentNode.id;
2831
- this._updateNode(n);
2832
- }
3302
+ this._clearCache();
3303
+ initOp(
3304
+ this._ops,
3305
+ this._ctx,
3306
+ this.strategy.order,
3307
+ this.strategy.head,
3308
+ (head) => {
3309
+ this.strategy.head = head;
2833
3310
  }
2834
- }
2835
- } else {
2836
- this._updateNode(this._cloneNode(node));
3311
+ );
3312
+ } catch (e) {
3313
+ this.isInitialized = false;
3314
+ throw e;
2837
3315
  }
2838
- return node;
2839
3316
  }
2840
- delete(key, value) {
2841
- if (value === void 0) {
2842
- value = this.get(key);
3317
+ reload() {
3318
+ if (this.rootTx !== this) {
3319
+ throw new Error("Cannot call reload on a nested transaction");
2843
3320
  }
2844
- if (value === void 0) {
2845
- return;
3321
+ this._reloadInternal();
3322
+ }
3323
+ _reloadInternal() {
3324
+ this._resetForReload();
3325
+ this._initInternal();
3326
+ }
3327
+ // ─── Query (delegating to algorithm) ─────────────────────────────
3328
+ exists(key, value) {
3329
+ return existsOp(this._ops, this._ctx.rootId, key, value, this.comparator);
3330
+ }
3331
+ get(key) {
3332
+ return getOp(this._ops, this._ctx.rootId, key);
3333
+ }
3334
+ *keysStream(condition, options) {
3335
+ yield* keysStreamOp(
3336
+ this._ops,
3337
+ this._ctx.rootId,
3338
+ condition,
3339
+ this.comparator,
3340
+ this._verifierMapCached,
3341
+ this._searchConfigsCached,
3342
+ this.ensureValues.bind(this),
3343
+ options
3344
+ );
3345
+ }
3346
+ *whereStream(condition, options) {
3347
+ yield* whereStreamOp(
3348
+ this._ops,
3349
+ this._ctx.rootId,
3350
+ condition,
3351
+ this.comparator,
3352
+ this._verifierMapCached,
3353
+ this._searchConfigsCached,
3354
+ this.ensureValues.bind(this),
3355
+ options
3356
+ );
3357
+ }
3358
+ keys(condition, options) {
3359
+ const set = /* @__PURE__ */ new Set();
3360
+ for (const key of this.keysStream(condition, options)) {
3361
+ set.add(key);
2846
3362
  }
2847
- let node = this.findLowerBoundLeaf(value);
2848
- let found = false;
2849
- while (true) {
2850
- let i = node.values.length;
2851
- while (i--) {
2852
- const nValue = node.values[i];
2853
- if (this.comparator.isSame(value, nValue)) {
2854
- const keys = node.keys[i];
2855
- const keyIndex = keys.indexOf(key);
2856
- if (keyIndex !== -1) {
2857
- node = this._cloneNode(node);
2858
- const freshKeys = node.keys[i];
2859
- freshKeys.splice(keyIndex, 1);
2860
- if (freshKeys.length === 0) {
2861
- node.keys.splice(i, 1);
2862
- node.values.splice(i, 1);
2863
- }
2864
- this._updateNode(node);
2865
- node = this._deleteEntry(node, key);
2866
- found = true;
2867
- break;
2868
- }
2869
- }
2870
- }
2871
- if (found) break;
2872
- if (node.next) {
2873
- node = this.getNode(node.next);
2874
- continue;
2875
- }
2876
- break;
3363
+ return set;
3364
+ }
3365
+ where(condition, options) {
3366
+ const map = /* @__PURE__ */ new Map();
3367
+ for (const [key, value] of this.whereStream(condition, options)) {
3368
+ map.set(key, value);
2877
3369
  }
3370
+ return map;
2878
3371
  }
3372
+ // ─── Mutation (delegating to algorithm) ──────────────────────────
3373
+ insert(key, value) {
3374
+ insertOp(this._ops, this._ctx, key, value, this.comparator);
3375
+ }
3376
+ batchInsert(entries) {
3377
+ batchInsertOp(this._ops, this._ctx, entries, this.comparator);
3378
+ }
3379
+ bulkLoad(entries) {
3380
+ bulkLoadOp(this._ops, this._ctx, entries, this.comparator);
3381
+ }
3382
+ _deleteEntry(node, key) {
3383
+ return deleteEntry(this._ops, this._ctx, node, key, this.comparator);
3384
+ }
3385
+ delete(key, value) {
3386
+ deleteOp(this._ops, this._ctx, key, this.comparator, value);
3387
+ }
3388
+ // ─── Head Data ───────────────────────────────────────────────────
2879
3389
  getHeadData() {
2880
3390
  const head = this._readHead();
2881
3391
  if (head === null) {
@@ -2894,6 +3404,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2894
3404
  data
2895
3405
  });
2896
3406
  }
3407
+ // ─── Transaction ─────────────────────────────────────────────────
2897
3408
  commit(label) {
2898
3409
  let result = this.mvcc.commit(label);
2899
3410
  if (result.success) {
@@ -3213,71 +3724,878 @@ var Ryoiki2 = class _Ryoiki2 {
3213
3724
  rangeTask: [Array, Function],
3214
3725
  rangeTaskTimeout: [Array, Function, Number]
3215
3726
  }
3216
- );
3217
- return this._lock(
3218
- this.readQueue,
3219
- range,
3220
- timeout,
3221
- task,
3222
- () => !this.rangeOverlapping(this.writings, range)
3223
- );
3224
- }
3225
- /**
3226
- * Internal implementation of the write lock. Handles both overloads.
3227
- * @template T - The return type of the task.
3228
- * @param arg0 - Either a range or a task callback.
3229
- * If a range is provided, the task is the second argument.
3230
- * @param arg1 - The task to execute, required if a range is provided.
3231
- * @param arg2 - The timeout for acquiring the lock.
3232
- * If the lock cannot be acquired within this period, an error will be thrown.
3233
- * If this value is not provided, no timeout will be set.
3234
- * @returns A promise resolving to the result of the task execution.
3235
- */
3236
- writeLock(arg0, arg1, arg2) {
3237
- const [range, task, timeout] = this._handleOverload(
3238
- [arg0, arg1, arg2],
3239
- {
3240
- rangeTask: (range2, task2) => [range2, task2, -1],
3241
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3242
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3243
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3727
+ );
3728
+ return this._lock(
3729
+ this.readQueue,
3730
+ range,
3731
+ timeout,
3732
+ task,
3733
+ () => !this.rangeOverlapping(this.writings, range)
3734
+ );
3735
+ }
3736
+ /**
3737
+ * Internal implementation of the write lock. Handles both overloads.
3738
+ * @template T - The return type of the task.
3739
+ * @param arg0 - Either a range or a task callback.
3740
+ * If a range is provided, the task is the second argument.
3741
+ * @param arg1 - The task to execute, required if a range is provided.
3742
+ * @param arg2 - The timeout for acquiring the lock.
3743
+ * If the lock cannot be acquired within this period, an error will be thrown.
3744
+ * If this value is not provided, no timeout will be set.
3745
+ * @returns A promise resolving to the result of the task execution.
3746
+ */
3747
+ writeLock(arg0, arg1, arg2) {
3748
+ const [range, task, timeout] = this._handleOverload(
3749
+ [arg0, arg1, arg2],
3750
+ {
3751
+ rangeTask: (range2, task2) => [range2, task2, -1],
3752
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3753
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
3754
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3755
+ },
3756
+ {
3757
+ task: [Function],
3758
+ taskTimeout: [Function, Number],
3759
+ rangeTask: [Array, Function],
3760
+ rangeTaskTimeout: [Array, Function, Number]
3761
+ }
3762
+ );
3763
+ return this._lock(
3764
+ this.writeQueue,
3765
+ range,
3766
+ timeout,
3767
+ task,
3768
+ () => {
3769
+ return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
3770
+ }
3771
+ );
3772
+ }
3773
+ /**
3774
+ * Releases a read lock by its lock ID.
3775
+ * @param lockId - The unique identifier for the lock to release.
3776
+ */
3777
+ readUnlock(lockId) {
3778
+ this._free(this.readings, lockId);
3779
+ }
3780
+ /**
3781
+ * Releases a write lock by its lock ID.
3782
+ * @param lockId - The unique identifier for the lock to release.
3783
+ */
3784
+ writeUnlock(lockId) {
3785
+ this._free(this.writings, lockId);
3786
+ }
3787
+ };
3788
+
3789
+ // src/base/BPTreeAlgorithmAsync.ts
3790
+ function createSearchConfigsAsync(comparator, ensureValues) {
3791
+ const lowest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[0];
3792
+ const highest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[v.length - 1];
3793
+ const lowestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[0];
3794
+ const highestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[v.length - 1];
3795
+ return {
3796
+ gt: {
3797
+ asc: {
3798
+ start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
3799
+ end: async () => null,
3800
+ direction: 1,
3801
+ earlyTerminate: false
3802
+ },
3803
+ desc: {
3804
+ start: (r, ops) => rightestNodeAsync(ops, r),
3805
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
3806
+ direction: -1,
3807
+ earlyTerminate: true
3808
+ }
3809
+ },
3810
+ gte: {
3811
+ asc: {
3812
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
3813
+ end: async () => null,
3814
+ direction: 1,
3815
+ earlyTerminate: false
3816
+ },
3817
+ desc: {
3818
+ start: (r, ops) => rightestNodeAsync(ops, r),
3819
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
3820
+ direction: -1,
3821
+ earlyTerminate: true
3822
+ }
3823
+ },
3824
+ lt: {
3825
+ asc: {
3826
+ start: (r, ops) => leftestNodeAsync(ops, r),
3827
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
3828
+ direction: 1,
3829
+ earlyTerminate: true
3830
+ },
3831
+ desc: {
3832
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
3833
+ end: async () => null,
3834
+ direction: -1,
3835
+ earlyTerminate: false
3836
+ }
3837
+ },
3838
+ lte: {
3839
+ asc: {
3840
+ start: (r, ops) => leftestNodeAsync(ops, r),
3841
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
3842
+ direction: 1,
3843
+ earlyTerminate: true
3844
+ },
3845
+ desc: {
3846
+ start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
3847
+ end: async () => null,
3848
+ direction: -1,
3849
+ earlyTerminate: false
3850
+ }
3851
+ },
3852
+ equal: {
3853
+ asc: {
3854
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
3855
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
3856
+ direction: 1,
3857
+ earlyTerminate: true
3858
+ },
3859
+ desc: {
3860
+ start: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
3861
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
3862
+ direction: -1,
3863
+ earlyTerminate: true
3864
+ }
3865
+ },
3866
+ notEqual: {
3867
+ asc: {
3868
+ start: (r, ops) => leftestNodeAsync(ops, r),
3869
+ end: async () => null,
3870
+ direction: 1,
3871
+ earlyTerminate: false
3872
+ },
3873
+ desc: {
3874
+ start: (r, ops) => rightestNodeAsync(ops, r),
3875
+ end: async () => null,
3876
+ direction: -1,
3877
+ earlyTerminate: false
3878
+ }
3879
+ },
3880
+ or: {
3881
+ asc: {
3882
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, lowest(ensureValues(v)), comparator),
3883
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, highest(ensureValues(v)), 1, comparator),
3884
+ direction: 1,
3885
+ earlyTerminate: false
3886
+ },
3887
+ desc: {
3888
+ start: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, highest(ensureValues(v)), 1, comparator),
3889
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, lowest(ensureValues(v)), -1, comparator),
3890
+ direction: -1,
3891
+ earlyTerminate: false
3892
+ }
3893
+ },
3894
+ primaryGt: {
3895
+ asc: {
3896
+ start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
3897
+ end: async () => null,
3898
+ direction: 1,
3899
+ earlyTerminate: false
3900
+ },
3901
+ desc: {
3902
+ start: (r, ops) => rightestNodeAsync(ops, r),
3903
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
3904
+ direction: -1,
3905
+ earlyTerminate: true
3906
+ }
3907
+ },
3908
+ primaryGte: {
3909
+ asc: {
3910
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
3911
+ end: async () => null,
3912
+ direction: 1,
3913
+ earlyTerminate: false
3914
+ },
3915
+ desc: {
3916
+ start: (r, ops) => rightestNodeAsync(ops, r),
3917
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
3918
+ direction: -1,
3919
+ earlyTerminate: true
3920
+ }
3921
+ },
3922
+ primaryLt: {
3923
+ asc: {
3924
+ start: (r, ops) => leftestNodeAsync(ops, r),
3925
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
3926
+ direction: 1,
3927
+ earlyTerminate: true
3928
+ },
3929
+ desc: {
3930
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
3931
+ end: async () => null,
3932
+ direction: -1,
3933
+ earlyTerminate: false
3934
+ }
3935
+ },
3936
+ primaryLte: {
3937
+ asc: {
3938
+ start: (r, ops) => leftestNodeAsync(ops, r),
3939
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
3940
+ direction: 1,
3941
+ earlyTerminate: true
3942
+ },
3943
+ desc: {
3944
+ start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
3945
+ end: async () => null,
3946
+ direction: -1,
3947
+ earlyTerminate: false
3948
+ }
3949
+ },
3950
+ primaryEqual: {
3951
+ asc: {
3952
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
3953
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
3954
+ direction: 1,
3955
+ earlyTerminate: true
3956
+ },
3957
+ desc: {
3958
+ start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
3959
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
3960
+ direction: -1,
3961
+ earlyTerminate: true
3962
+ }
3963
+ },
3964
+ primaryNotEqual: {
3965
+ asc: {
3966
+ start: (r, ops) => leftestNodeAsync(ops, r),
3967
+ end: async () => null,
3968
+ direction: 1,
3969
+ earlyTerminate: false
3970
+ },
3971
+ desc: {
3972
+ start: (r, ops) => rightestNodeAsync(ops, r),
3973
+ end: async () => null,
3974
+ direction: -1,
3975
+ earlyTerminate: false
3976
+ }
3977
+ },
3978
+ primaryOr: {
3979
+ asc: {
3980
+ start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, lowestPrimary(ensureValues(v)), comparator),
3981
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, highestPrimary(ensureValues(v)), 1, comparator),
3982
+ direction: 1,
3983
+ earlyTerminate: false
3984
+ },
3985
+ desc: {
3986
+ start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, highestPrimary(ensureValues(v)), comparator),
3987
+ end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, lowestPrimary(ensureValues(v)), -1, comparator),
3988
+ direction: -1,
3989
+ earlyTerminate: false
3990
+ }
3991
+ },
3992
+ like: {
3993
+ asc: {
3994
+ start: (r, ops) => leftestNodeAsync(ops, r),
3995
+ end: async () => null,
3996
+ direction: 1,
3997
+ earlyTerminate: false
3244
3998
  },
3245
- {
3246
- task: [Function],
3247
- taskTimeout: [Function, Number],
3248
- rangeTask: [Array, Function],
3249
- rangeTaskTimeout: [Array, Function, Number]
3999
+ desc: {
4000
+ start: (r, ops) => rightestNodeAsync(ops, r),
4001
+ end: async () => null,
4002
+ direction: -1,
4003
+ earlyTerminate: false
3250
4004
  }
3251
- );
3252
- return this._lock(
3253
- this.writeQueue,
3254
- range,
3255
- timeout,
3256
- task,
3257
- () => {
3258
- return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
4005
+ }
4006
+ };
4007
+ }
4008
+ async function locateLeafAsync(ops, rootId, value, comparator) {
4009
+ let node = await ops.getNode(rootId);
4010
+ while (!node.leaf) {
4011
+ const { index } = binarySearchValues(node.values, value, comparator, false, true);
4012
+ node = await ops.getNode(node.keys[index]);
4013
+ }
4014
+ return node;
4015
+ }
4016
+ async function findLowerBoundLeafAsync(ops, rootId, value, comparator) {
4017
+ let node = await ops.getNode(rootId);
4018
+ while (!node.leaf) {
4019
+ const { index } = binarySearchValues(node.values, value, comparator, true, false);
4020
+ node = await ops.getNode(node.keys[index]);
4021
+ }
4022
+ return node;
4023
+ }
4024
+ async function findUpperBoundLeafAsync(ops, rootId, value, comparator) {
4025
+ let node = await ops.getNode(rootId);
4026
+ while (!node.leaf) {
4027
+ const { index } = binarySearchValues(node.values, value, comparator, true, true);
4028
+ node = await ops.getNode(node.keys[index]);
4029
+ }
4030
+ return node;
4031
+ }
4032
+ async function findOuterBoundaryLeafAsync(ops, rootId, value, direction, comparator) {
4033
+ const insertableNode = direction === -1 ? await findLowerBoundLeafAsync(ops, rootId, value, comparator) : await findUpperBoundLeafAsync(ops, rootId, value, comparator);
4034
+ const key = direction === -1 ? "prev" : "next";
4035
+ const guessNode = insertableNode[key];
4036
+ if (!guessNode) return null;
4037
+ return await ops.getNode(guessNode);
4038
+ }
4039
+ async function leftestNodeAsync(ops, rootId) {
4040
+ let node = await ops.getNode(rootId);
4041
+ while (!node.leaf) {
4042
+ node = await ops.getNode(node.keys[0]);
4043
+ }
4044
+ return node;
4045
+ }
4046
+ async function rightestNodeAsync(ops, rootId) {
4047
+ let node = await ops.getNode(rootId);
4048
+ while (!node.leaf) {
4049
+ node = await ops.getNode(node.keys[node.keys.length - 1]);
4050
+ }
4051
+ return node;
4052
+ }
4053
+ async function* getPairsGeneratorAsync(ops, startNode, endNode, direction) {
4054
+ let node = startNode;
4055
+ let nextNodePromise = null;
4056
+ while (true) {
4057
+ if (endNode && node.id === endNode.id) break;
4058
+ if (direction === 1) {
4059
+ if (node.next) nextNodePromise = ops.getNode(node.next);
4060
+ } else {
4061
+ if (node.prev) nextNodePromise = ops.getNode(node.prev);
4062
+ }
4063
+ const len = node.values.length;
4064
+ if (direction === 1) {
4065
+ for (let i = 0; i < len; i++) {
4066
+ const nValue = node.values[i];
4067
+ const keys = node.keys[i];
4068
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
4069
+ yield [keys[j], nValue];
4070
+ }
3259
4071
  }
3260
- );
4072
+ } else {
4073
+ let i = len;
4074
+ while (i--) {
4075
+ const nValue = node.values[i];
4076
+ const keys = node.keys[i];
4077
+ let j = keys.length;
4078
+ while (j--) {
4079
+ yield [keys[j], nValue];
4080
+ }
4081
+ }
4082
+ }
4083
+ if (nextNodePromise) {
4084
+ node = await nextNodePromise;
4085
+ nextNodePromise = null;
4086
+ } else {
4087
+ break;
4088
+ }
3261
4089
  }
3262
- /**
3263
- * Releases a read lock by its lock ID.
3264
- * @param lockId - The unique identifier for the lock to release.
3265
- */
3266
- readUnlock(lockId) {
3267
- this._free(this.readings, lockId);
4090
+ }
4091
+ async function insertAtLeafAsync(ops, node, key, value, comparator) {
4092
+ let leaf = node;
4093
+ if (leaf.values.length) {
4094
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
4095
+ const nValue = leaf.values[i];
4096
+ if (comparator.isSame(value, nValue)) {
4097
+ if (leaf.keys[i].includes(key)) break;
4098
+ leaf = cloneNode(leaf);
4099
+ leaf.keys[i].push(key);
4100
+ await ops.updateNode(leaf);
4101
+ return leaf;
4102
+ } else if (comparator.isLower(value, nValue)) {
4103
+ leaf = cloneNode(leaf);
4104
+ leaf.values.splice(i, 0, value);
4105
+ leaf.keys.splice(i, 0, [key]);
4106
+ await ops.updateNode(leaf);
4107
+ return leaf;
4108
+ } else if (i + 1 === leaf.values.length) {
4109
+ leaf = cloneNode(leaf);
4110
+ leaf.values.push(value);
4111
+ leaf.keys.push([key]);
4112
+ await ops.updateNode(leaf);
4113
+ return leaf;
4114
+ }
4115
+ }
4116
+ } else {
4117
+ leaf = cloneNode(leaf);
4118
+ leaf.values = [value];
4119
+ leaf.keys = [[key]];
4120
+ await ops.updateNode(leaf);
4121
+ return leaf;
3268
4122
  }
3269
- /**
3270
- * Releases a write lock by its lock ID.
3271
- * @param lockId - The unique identifier for the lock to release.
3272
- */
3273
- writeUnlock(lockId) {
3274
- this._free(this.writings, lockId);
4123
+ return leaf;
4124
+ }
4125
+ async function insertInParentAsync(ops, ctx, node, value, newSiblingNode) {
4126
+ if (ctx.rootId === node.id) {
4127
+ node = cloneNode(node);
4128
+ newSiblingNode = cloneNode(newSiblingNode);
4129
+ const root = await ops.createNode(false, [node.id, newSiblingNode.id], [value]);
4130
+ ctx.rootId = root.id;
4131
+ node.parent = root.id;
4132
+ newSiblingNode.parent = root.id;
4133
+ if (newSiblingNode.leaf) {
4134
+ ;
4135
+ node.next = newSiblingNode.id;
4136
+ newSiblingNode.prev = node.id;
4137
+ }
4138
+ await ops.writeHead({ root: root.id, order: ctx.order, data: ctx.headData() });
4139
+ await ops.updateNode(node);
4140
+ await ops.updateNode(newSiblingNode);
4141
+ return;
4142
+ }
4143
+ const parentNode = cloneNode(await ops.getNode(node.parent));
4144
+ const nodeIndex = parentNode.keys.indexOf(node.id);
4145
+ if (nodeIndex === -1) throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
4146
+ parentNode.values.splice(nodeIndex, 0, value);
4147
+ parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
4148
+ newSiblingNode = cloneNode(newSiblingNode);
4149
+ newSiblingNode.parent = parentNode.id;
4150
+ if (newSiblingNode.leaf) {
4151
+ const leftSibling = cloneNode(node);
4152
+ const oldNextId = leftSibling.next;
4153
+ newSiblingNode.prev = leftSibling.id;
4154
+ newSiblingNode.next = oldNextId;
4155
+ leftSibling.next = newSiblingNode.id;
4156
+ await ops.updateNode(leftSibling);
4157
+ if (oldNextId) {
4158
+ const oldNext = cloneNode(await ops.getNode(oldNextId));
4159
+ oldNext.prev = newSiblingNode.id;
4160
+ await ops.updateNode(oldNext);
4161
+ }
4162
+ }
4163
+ await ops.updateNode(parentNode);
4164
+ await ops.updateNode(newSiblingNode);
4165
+ if (parentNode.keys.length > ctx.order) {
4166
+ const rec = await ops.createNode(false, [], []);
4167
+ rec.parent = parentNode.parent;
4168
+ const mid = Math.ceil(ctx.order / 2) - 1;
4169
+ rec.values = parentNode.values.slice(mid + 1);
4170
+ rec.keys = parentNode.keys.slice(mid + 1);
4171
+ const midValue = parentNode.values[mid];
4172
+ parentNode.values = parentNode.values.slice(0, mid);
4173
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
4174
+ for (let i = 0, len = rec.keys.length; i < len; i++) {
4175
+ const n = cloneNode(await ops.getNode(rec.keys[i]));
4176
+ n.parent = rec.id;
4177
+ await ops.updateNode(n);
4178
+ }
4179
+ await ops.updateNode(parentNode);
4180
+ await insertInParentAsync(ops, ctx, parentNode, midValue, rec);
4181
+ }
4182
+ }
4183
+ async function insertOpAsync(ops, ctx, key, value, comparator) {
4184
+ let before = await locateLeafAsync(ops, ctx.rootId, value, comparator);
4185
+ before = await insertAtLeafAsync(ops, before, key, value, comparator);
4186
+ if (before.values.length === ctx.order) {
4187
+ let after = await ops.createNode(true, [], [], before.parent, null, null);
4188
+ const mid = Math.ceil(ctx.order / 2) - 1;
4189
+ after = cloneNode(after);
4190
+ after.values = before.values.slice(mid + 1);
4191
+ after.keys = before.keys.slice(mid + 1);
4192
+ before.values = before.values.slice(0, mid + 1);
4193
+ before.keys = before.keys.slice(0, mid + 1);
4194
+ await ops.updateNode(before);
4195
+ await ops.updateNode(after);
4196
+ await insertInParentAsync(ops, ctx, before, after.values[0], after);
4197
+ }
4198
+ }
4199
+ async function deleteEntryAsync(ops, ctx, node, key, comparator) {
4200
+ if (!node.leaf) {
4201
+ let keyIndex = -1;
4202
+ for (let i = 0, len = node.keys.length; i < len; i++) {
4203
+ if (node.keys[i] === key) {
4204
+ keyIndex = i;
4205
+ break;
4206
+ }
4207
+ }
4208
+ if (keyIndex !== -1) {
4209
+ node = cloneNode(node);
4210
+ node.keys.splice(keyIndex, 1);
4211
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
4212
+ node.values.splice(valueIndex, 1);
4213
+ await ops.updateNode(node);
4214
+ }
3275
4215
  }
3276
- };
4216
+ if (ctx.rootId === node.id && node.keys.length === 1 && !node.leaf) {
4217
+ const keys = node.keys;
4218
+ await ops.deleteNode(node);
4219
+ const newRoot = cloneNode(await ops.getNode(keys[0]));
4220
+ newRoot.parent = null;
4221
+ await ops.updateNode(newRoot);
4222
+ await ops.writeHead({ root: newRoot.id, order: ctx.order, data: ctx.headData() });
4223
+ ctx.rootId = newRoot.id;
4224
+ return node;
4225
+ } else if (ctx.rootId === node.id) {
4226
+ await ops.writeHead({ root: node.id, order: ctx.order, data: ctx.headData() });
4227
+ return node;
4228
+ } else if (node.keys.length < Math.ceil(ctx.order / 2) && !node.leaf || node.values.length < Math.ceil((ctx.order - 1) / 2) && node.leaf) {
4229
+ if (node.parent === null) return node;
4230
+ let isPredecessor = false;
4231
+ let parentNode = await ops.getNode(node.parent);
4232
+ let prevNode = null;
4233
+ let nextNode = null;
4234
+ let prevValue = null;
4235
+ let postValue = null;
4236
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
4237
+ if (parentNode.keys[i] === node.id) {
4238
+ if (i > 0) {
4239
+ prevNode = await ops.getNode(parentNode.keys[i - 1]);
4240
+ prevValue = parentNode.values[i - 1];
4241
+ }
4242
+ if (i < parentNode.keys.length - 1) {
4243
+ nextNode = await ops.getNode(parentNode.keys[i + 1]);
4244
+ postValue = parentNode.values[i];
4245
+ }
4246
+ }
4247
+ }
4248
+ let siblingNode;
4249
+ let guess;
4250
+ if (prevNode === null) {
4251
+ siblingNode = nextNode;
4252
+ guess = postValue;
4253
+ } else if (nextNode === null) {
4254
+ isPredecessor = true;
4255
+ siblingNode = prevNode;
4256
+ guess = prevValue;
4257
+ } else {
4258
+ if (node.values.length + nextNode.values.length < ctx.order) {
4259
+ siblingNode = nextNode;
4260
+ guess = postValue;
4261
+ } else {
4262
+ isPredecessor = true;
4263
+ siblingNode = prevNode;
4264
+ guess = prevValue;
4265
+ }
4266
+ }
4267
+ if (!siblingNode) return node;
4268
+ node = cloneNode(node);
4269
+ siblingNode = cloneNode(siblingNode);
4270
+ if (node.values.length + siblingNode.values.length < ctx.order) {
4271
+ if (!isPredecessor) {
4272
+ const t = siblingNode;
4273
+ siblingNode = node;
4274
+ node = t;
4275
+ }
4276
+ siblingNode.keys.push(...node.keys);
4277
+ if (!node.leaf) {
4278
+ siblingNode.values.push(guess);
4279
+ } else {
4280
+ siblingNode.next = node.next;
4281
+ if (siblingNode.next) {
4282
+ const n = cloneNode(await ops.getNode(siblingNode.next));
4283
+ n.prev = siblingNode.id;
4284
+ await ops.updateNode(n);
4285
+ }
4286
+ }
4287
+ siblingNode.values.push(...node.values);
4288
+ if (!siblingNode.leaf) {
4289
+ for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
4290
+ const n = cloneNode(await ops.getNode(siblingNode.keys[i]));
4291
+ n.parent = siblingNode.id;
4292
+ await ops.updateNode(n);
4293
+ }
4294
+ }
4295
+ await ops.deleteNode(node);
4296
+ await ops.updateNode(siblingNode);
4297
+ await deleteEntryAsync(ops, ctx, await ops.getNode(node.parent), node.id, comparator);
4298
+ } else {
4299
+ if (isPredecessor) {
4300
+ let pointerPm, pointerKm;
4301
+ if (!node.leaf) {
4302
+ pointerPm = siblingNode.keys.splice(-1)[0];
4303
+ pointerKm = siblingNode.values.splice(-1)[0];
4304
+ node.keys = [pointerPm, ...node.keys];
4305
+ node.values = [guess, ...node.values];
4306
+ parentNode = cloneNode(await ops.getNode(node.parent));
4307
+ const ni = parentNode.keys.indexOf(node.id);
4308
+ if (ni > 0) {
4309
+ parentNode.values[ni - 1] = pointerKm;
4310
+ await ops.updateNode(parentNode);
4311
+ }
4312
+ } else {
4313
+ pointerPm = siblingNode.keys.splice(-1)[0];
4314
+ pointerKm = siblingNode.values.splice(-1)[0];
4315
+ node.keys = [pointerPm, ...node.keys];
4316
+ node.values = [pointerKm, ...node.values];
4317
+ parentNode = cloneNode(await ops.getNode(node.parent));
4318
+ const ni = parentNode.keys.indexOf(node.id);
4319
+ if (ni > 0) {
4320
+ parentNode.values[ni - 1] = pointerKm;
4321
+ await ops.updateNode(parentNode);
4322
+ }
4323
+ }
4324
+ await ops.updateNode(node);
4325
+ await ops.updateNode(siblingNode);
4326
+ } else {
4327
+ let pointerP0, pointerK0;
4328
+ if (!node.leaf) {
4329
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
4330
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
4331
+ node.keys = [...node.keys, pointerP0];
4332
+ node.values = [...node.values, guess];
4333
+ parentNode = cloneNode(await ops.getNode(node.parent));
4334
+ const pi = parentNode.keys.indexOf(siblingNode.id);
4335
+ if (pi > 0) {
4336
+ parentNode.values[pi - 1] = pointerK0;
4337
+ await ops.updateNode(parentNode);
4338
+ }
4339
+ } else {
4340
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
4341
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
4342
+ node.keys = [...node.keys, pointerP0];
4343
+ node.values = [...node.values, pointerK0];
4344
+ parentNode = cloneNode(await ops.getNode(node.parent));
4345
+ const pi = parentNode.keys.indexOf(siblingNode.id);
4346
+ if (pi > 0) {
4347
+ parentNode.values[pi - 1] = siblingNode.values[0];
4348
+ await ops.updateNode(parentNode);
4349
+ }
4350
+ }
4351
+ await ops.updateNode(node);
4352
+ await ops.updateNode(siblingNode);
4353
+ }
4354
+ if (!siblingNode.leaf) {
4355
+ for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
4356
+ const n = cloneNode(await ops.getNode(siblingNode.keys[i]));
4357
+ n.parent = siblingNode.id;
4358
+ await ops.updateNode(n);
4359
+ }
4360
+ }
4361
+ if (!node.leaf) {
4362
+ for (let i = 0, len = node.keys.length; i < len; i++) {
4363
+ const n = cloneNode(await ops.getNode(node.keys[i]));
4364
+ n.parent = node.id;
4365
+ await ops.updateNode(n);
4366
+ }
4367
+ }
4368
+ if (!parentNode.leaf) {
4369
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
4370
+ const n = cloneNode(await ops.getNode(parentNode.keys[i]));
4371
+ n.parent = parentNode.id;
4372
+ await ops.updateNode(n);
4373
+ }
4374
+ }
4375
+ }
4376
+ } else {
4377
+ await ops.updateNode(cloneNode(node));
4378
+ }
4379
+ return node;
4380
+ }
4381
+ async function deleteOpAsync(ops, ctx, key, comparator, value) {
4382
+ if (value === void 0) {
4383
+ value = await getOpAsync(ops, ctx.rootId, key);
4384
+ }
4385
+ if (value === void 0) return;
4386
+ let node = await findLowerBoundLeafAsync(ops, ctx.rootId, value, comparator);
4387
+ let found = false;
4388
+ while (true) {
4389
+ let i = node.values.length;
4390
+ while (i--) {
4391
+ if (comparator.isSame(value, node.values[i])) {
4392
+ const keyIndex = node.keys[i].indexOf(key);
4393
+ if (keyIndex !== -1) {
4394
+ node = cloneNode(node);
4395
+ node.keys[i].splice(keyIndex, 1);
4396
+ if (node.keys[i].length === 0) {
4397
+ node.keys.splice(i, 1);
4398
+ node.values.splice(i, 1);
4399
+ }
4400
+ await ops.updateNode(node);
4401
+ node = await deleteEntryAsync(ops, ctx, node, key, comparator);
4402
+ found = true;
4403
+ break;
4404
+ }
4405
+ }
4406
+ }
4407
+ if (found) break;
4408
+ if (node.next) {
4409
+ node = await ops.getNode(node.next);
4410
+ continue;
4411
+ }
4412
+ break;
4413
+ }
4414
+ }
4415
+ async function batchInsertOpAsync(ops, ctx, entries, comparator) {
4416
+ if (entries.length === 0) return;
4417
+ const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
4418
+ let currentLeaf = null;
4419
+ let modified = false;
4420
+ let cachedLeafId = null;
4421
+ let cachedLeafMaxValue = null;
4422
+ for (let i = 0, len = sorted.length; i < len; i++) {
4423
+ const [key, value] = sorted[i];
4424
+ let targetLeaf;
4425
+ if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (comparator.isLower(value, cachedLeafMaxValue) || comparator.isSame(value, cachedLeafMaxValue))) {
4426
+ targetLeaf = currentLeaf;
4427
+ } else {
4428
+ targetLeaf = await locateLeafAsync(ops, ctx.rootId, value, comparator);
4429
+ }
4430
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
4431
+ } else {
4432
+ if (currentLeaf !== null && modified) await ops.updateNode(currentLeaf);
4433
+ currentLeaf = cloneNode(targetLeaf);
4434
+ modified = false;
4435
+ }
4436
+ cachedLeafId = currentLeaf.id;
4437
+ const changed = insertValueIntoLeaf(currentLeaf, key, value, comparator);
4438
+ modified = modified || changed;
4439
+ cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
4440
+ if (currentLeaf.values.length === ctx.order) {
4441
+ await ops.updateNode(currentLeaf);
4442
+ let after = await ops.createNode(true, [], [], currentLeaf.parent, null, null);
4443
+ const mid = Math.ceil(ctx.order / 2) - 1;
4444
+ after = cloneNode(after);
4445
+ after.values = currentLeaf.values.slice(mid + 1);
4446
+ after.keys = currentLeaf.keys.slice(mid + 1);
4447
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
4448
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
4449
+ await ops.updateNode(currentLeaf);
4450
+ await ops.updateNode(after);
4451
+ await insertInParentAsync(ops, ctx, currentLeaf, after.values[0], after);
4452
+ currentLeaf = null;
4453
+ cachedLeafId = null;
4454
+ cachedLeafMaxValue = null;
4455
+ modified = false;
4456
+ }
4457
+ }
4458
+ if (currentLeaf !== null && modified) await ops.updateNode(currentLeaf);
4459
+ }
4460
+ async function bulkLoadOpAsync(ops, ctx, entries, comparator) {
4461
+ if (entries.length === 0) return;
4462
+ const root = await ops.getNode(ctx.rootId);
4463
+ if (!root.leaf || root.values.length > 0) {
4464
+ throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
4465
+ }
4466
+ const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
4467
+ const grouped = [];
4468
+ for (let i = 0, len = sorted.length; i < len; i++) {
4469
+ const [key, value] = sorted[i];
4470
+ const last = grouped[grouped.length - 1];
4471
+ if (last && comparator.isSame(last.value, value)) {
4472
+ if (!last.keys.includes(key)) last.keys.push(key);
4473
+ } else {
4474
+ grouped.push({ keys: [key], value });
4475
+ }
4476
+ }
4477
+ await ops.deleteNode(root);
4478
+ const maxLeafSize = ctx.order - 1;
4479
+ const leaves = [];
4480
+ for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
4481
+ const chunk = grouped.slice(i, i + maxLeafSize);
4482
+ const leaf = await ops.createNode(true, chunk.map((g) => g.keys), chunk.map((g) => g.value), null, null, null);
4483
+ leaves.push(leaf);
4484
+ }
4485
+ for (let i = 0, len = leaves.length; i < len; i++) {
4486
+ if (i > 0) leaves[i].prev = leaves[i - 1].id;
4487
+ if (i < len - 1) leaves[i].next = leaves[i + 1].id;
4488
+ await ops.updateNode(leaves[i]);
4489
+ }
4490
+ let currentLevel = leaves;
4491
+ while (currentLevel.length > 1) {
4492
+ const nextLevel = [];
4493
+ for (let i = 0, len = currentLevel.length; i < len; i += ctx.order) {
4494
+ const children = currentLevel.slice(i, i + ctx.order);
4495
+ const separators = [];
4496
+ for (let j = 1, cLen = children.length; j < cLen; j++) separators.push(children[j].values[0]);
4497
+ const internalNode = await ops.createNode(false, children.map((c) => c.id), separators, null, null, null);
4498
+ for (let j = 0, cLen = children.length; j < cLen; j++) {
4499
+ children[j].parent = internalNode.id;
4500
+ await ops.updateNode(children[j]);
4501
+ }
4502
+ nextLevel.push(internalNode);
4503
+ }
4504
+ currentLevel = nextLevel;
4505
+ }
4506
+ const newRoot = currentLevel[0];
4507
+ await ops.writeHead({ root: newRoot.id, order: ctx.order, data: ctx.headData() });
4508
+ ctx.rootId = newRoot.id;
4509
+ }
4510
+ async function existsOpAsync(ops, rootId, key, value, comparator) {
4511
+ const node = await locateLeafAsync(ops, rootId, value, comparator);
4512
+ const { index, found } = binarySearchValues(node.values, value, comparator);
4513
+ if (found && node.keys[index].includes(key)) return true;
4514
+ return false;
4515
+ }
4516
+ async function getOpAsync(ops, rootId, key) {
4517
+ let node = await leftestNodeAsync(ops, rootId);
4518
+ while (true) {
4519
+ for (let i = 0, len = node.values.length; i < len; i++) {
4520
+ const keys = node.keys[i];
4521
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
4522
+ if (keys[j] === key) return node.values[i];
4523
+ }
4524
+ }
4525
+ if (!node.next) break;
4526
+ node = await ops.getNode(node.next);
4527
+ }
4528
+ return void 0;
4529
+ }
4530
+ async function* whereStreamOpAsync(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
4531
+ const { filterValues, limit, order = "asc" } = options ?? {};
4532
+ const conditionKeys = Object.keys(condition);
4533
+ if (conditionKeys.length === 0) return;
4534
+ const resolved = resolveStartEndConfigs(condition, order, comparator, ensureValues);
4535
+ const direction = resolved.direction;
4536
+ let startNode;
4537
+ if (resolved.startKey) {
4538
+ const startConfig = searchConfigs[resolved.startKey][order];
4539
+ startNode = await startConfig.start(rootId, ops, resolved.startValues);
4540
+ } else {
4541
+ startNode = order === "asc" ? await leftestNodeAsync(ops, rootId) : await rightestNodeAsync(ops, rootId);
4542
+ }
4543
+ let endNode = null;
4544
+ if (resolved.endKey) {
4545
+ const endConfig = searchConfigs[resolved.endKey][order];
4546
+ endNode = await endConfig.end(rootId, ops, resolved.endValues);
4547
+ }
4548
+ if (!startNode) return;
4549
+ const generator = getPairsGeneratorAsync(ops, startNode, endNode, direction);
4550
+ let count = 0;
4551
+ const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
4552
+ for await (const pair of generator) {
4553
+ const [k, v] = pair;
4554
+ if (intersection && !intersection.has(k)) continue;
4555
+ if (verify(v, condition, verifierMap)) {
4556
+ yield pair;
4557
+ count++;
4558
+ if (limit !== void 0 && count >= limit) break;
4559
+ }
4560
+ }
4561
+ }
4562
+ async function* keysStreamOpAsync(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
4563
+ const { filterValues, limit } = options ?? {};
4564
+ const stream = whereStreamOpAsync(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options);
4565
+ const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
4566
+ let count = 0;
4567
+ for await (const [key] of stream) {
4568
+ if (intersection && !intersection.has(key)) continue;
4569
+ yield key;
4570
+ count++;
4571
+ if (limit !== void 0 && count >= limit) break;
4572
+ }
4573
+ }
4574
+ async function initOpAsync(ops, ctx, strategyOrder, strategyHead, setStrategyHead) {
4575
+ const head = await ops.readHead();
4576
+ if (head === null) {
4577
+ ctx.order = strategyOrder;
4578
+ const root = await ops.createNode(true, [], []);
4579
+ await ops.writeHead({ root: root.id, order: ctx.order, data: strategyHead.data });
4580
+ ctx.rootId = root.id;
4581
+ } else {
4582
+ const { root, order } = head;
4583
+ setStrategyHead(head);
4584
+ ctx.order = order;
4585
+ ctx.rootId = root;
4586
+ }
4587
+ if (ctx.order < 3) {
4588
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${ctx.order}'.`);
4589
+ }
4590
+ }
3277
4591
 
3278
4592
  // src/transaction/BPTreeAsyncTransaction.ts
3279
4593
  var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3280
4594
  lock;
4595
+ _ops;
4596
+ _ctx;
4597
+ _verifierMapCached;
4598
+ _searchConfigsCached;
3281
4599
  constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
3282
4600
  super(
3283
4601
  rootTx,
@@ -3288,6 +4606,64 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3288
4606
  option
3289
4607
  );
3290
4608
  this.lock = new Ryoiki2();
4609
+ this._initAlgoContext();
4610
+ }
4611
+ _initAlgoContext() {
4612
+ const mvcc = this.mvcc;
4613
+ const strategy = this.strategy;
4614
+ const self = this;
4615
+ this._ops = {
4616
+ async getNode(id) {
4617
+ return await mvcc.read(id);
4618
+ },
4619
+ async createNode(leaf, keys, values, parent = null, next = null, prev = null) {
4620
+ const id = await strategy.id(leaf);
4621
+ const node = { id, keys, values, leaf, parent, next, prev };
4622
+ await mvcc.create(id, node);
4623
+ return node;
4624
+ },
4625
+ async updateNode(node) {
4626
+ if (mvcc.isDeleted(node.id)) {
4627
+ return;
4628
+ }
4629
+ await mvcc.write(node.id, node);
4630
+ },
4631
+ async deleteNode(node) {
4632
+ if (mvcc.isDeleted(node.id)) {
4633
+ return;
4634
+ }
4635
+ await mvcc.delete(node.id);
4636
+ },
4637
+ async readHead() {
4638
+ return await mvcc.read("__HEAD__");
4639
+ },
4640
+ async writeHead(head) {
4641
+ if (!await mvcc.exists("__HEAD__")) {
4642
+ await mvcc.create("__HEAD__", head);
4643
+ } else {
4644
+ await mvcc.write("__HEAD__", head);
4645
+ }
4646
+ self.rootId = head.root;
4647
+ }
4648
+ };
4649
+ this._ctx = {
4650
+ get rootId() {
4651
+ return self.rootId;
4652
+ },
4653
+ set rootId(v) {
4654
+ self.rootId = v;
4655
+ },
4656
+ get order() {
4657
+ return self.order;
4658
+ },
4659
+ set order(v) {
4660
+ self.order = v;
4661
+ },
4662
+ headData: () => this.strategy.head.data
4663
+ };
4664
+ const ensureValues = (v) => this.ensureValues(v);
4665
+ this._verifierMapCached = createVerifierMap(this.comparator, this._cachedRegexp, ensureValues);
4666
+ this._searchConfigsCached = createSearchConfigsAsync(this.comparator, ensureValues);
3291
4667
  }
3292
4668
  async writeLock(id, fn) {
3293
4669
  let lockId;
@@ -3298,256 +4674,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3298
4674
  this.lock.writeUnlock(lockId);
3299
4675
  });
3300
4676
  }
4677
+ // ─── Legacy protected methods (delegating to ops) ────────────────
3301
4678
  async getNode(id) {
3302
- return await this.mvcc.read(id);
4679
+ return this._ops.getNode(id);
3303
4680
  }
3304
- /**
3305
- * Create a new node with a unique ID.
3306
- */
3307
4681
  async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
3308
- const id = await this.strategy.id(leaf);
3309
- const node = {
3310
- id,
3311
- keys,
3312
- values,
3313
- leaf,
3314
- parent,
3315
- next,
3316
- prev
3317
- };
3318
- await this.mvcc.create(id, node);
3319
- return node;
4682
+ return this._ops.createNode(leaf, keys, values, parent, next, prev);
3320
4683
  }
3321
4684
  async _updateNode(node) {
3322
- if (this.mvcc.isDeleted(node.id)) {
3323
- return;
3324
- }
3325
- await this.mvcc.write(node.id, node);
4685
+ await this._ops.updateNode(node);
3326
4686
  }
3327
4687
  async _deleteNode(node) {
3328
- if (this.mvcc.isDeleted(node.id)) {
3329
- return;
3330
- }
3331
- await this.mvcc.delete(node.id);
4688
+ await this._ops.deleteNode(node);
3332
4689
  }
3333
4690
  async _readHead() {
3334
- return await this.mvcc.read("__HEAD__");
4691
+ return this._ops.readHead();
3335
4692
  }
3336
4693
  async _writeHead(head) {
3337
- if (!await this.mvcc.exists("__HEAD__")) {
3338
- await this.mvcc.create("__HEAD__", head);
3339
- } else {
3340
- await this.mvcc.write("__HEAD__", head);
3341
- }
3342
- this.rootId = head.root;
4694
+ await this._ops.writeHead(head);
3343
4695
  }
4696
+ // ─── Tree traversal (delegating to algorithm) ────────────────────
3344
4697
  async _insertAtLeaf(node, key, value) {
3345
- let leaf = node;
3346
- if (leaf.values.length) {
3347
- for (let i = 0, len = leaf.values.length; i < len; i++) {
3348
- const nValue = leaf.values[i];
3349
- if (this.comparator.isSame(value, nValue)) {
3350
- const keys = leaf.keys[i];
3351
- if (keys.includes(key)) {
3352
- break;
3353
- }
3354
- leaf = this._cloneNode(leaf);
3355
- leaf.keys[i].push(key);
3356
- await this._updateNode(leaf);
3357
- return leaf;
3358
- } else if (this.comparator.isLower(value, nValue)) {
3359
- leaf = this._cloneNode(leaf);
3360
- leaf.values.splice(i, 0, value);
3361
- leaf.keys.splice(i, 0, [key]);
3362
- await this._updateNode(leaf);
3363
- return leaf;
3364
- } else if (i + 1 === leaf.values.length) {
3365
- leaf = this._cloneNode(leaf);
3366
- leaf.values.push(value);
3367
- leaf.keys.push([key]);
3368
- await this._updateNode(leaf);
3369
- return leaf;
3370
- }
3371
- }
3372
- } else {
3373
- leaf = this._cloneNode(leaf);
3374
- leaf.values = [value];
3375
- leaf.keys = [[key]];
3376
- await this._updateNode(leaf);
3377
- return leaf;
3378
- }
3379
- return leaf;
4698
+ return insertAtLeafAsync(this._ops, node, key, value, this.comparator);
3380
4699
  }
3381
4700
  async _insertInParent(node, value, newSiblingNode) {
3382
- if (this.rootId === node.id) {
3383
- node = this._cloneNode(node);
3384
- newSiblingNode = this._cloneNode(newSiblingNode);
3385
- const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
3386
- this.rootId = root.id;
3387
- node.parent = root.id;
3388
- newSiblingNode.parent = root.id;
3389
- if (newSiblingNode.leaf) {
3390
- node.next = newSiblingNode.id;
3391
- newSiblingNode.prev = node.id;
3392
- }
3393
- await this._writeHead({
3394
- root: root.id,
3395
- order: this.order,
3396
- data: this.strategy.head.data
3397
- });
3398
- await this._updateNode(node);
3399
- await this._updateNode(newSiblingNode);
3400
- return;
3401
- }
3402
- const parentNode = this._cloneNode(await this.getNode(node.parent));
3403
- const nodeIndex = parentNode.keys.indexOf(node.id);
3404
- if (nodeIndex === -1) {
3405
- throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
3406
- }
3407
- parentNode.values.splice(nodeIndex, 0, value);
3408
- parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
3409
- newSiblingNode = this._cloneNode(newSiblingNode);
3410
- newSiblingNode.parent = parentNode.id;
3411
- if (newSiblingNode.leaf) {
3412
- const leftSibling = this._cloneNode(node);
3413
- const oldNextId = leftSibling.next;
3414
- newSiblingNode.prev = leftSibling.id;
3415
- newSiblingNode.next = oldNextId;
3416
- leftSibling.next = newSiblingNode.id;
3417
- await this._updateNode(leftSibling);
3418
- if (oldNextId) {
3419
- const oldNext = this._cloneNode(await this.getNode(oldNextId));
3420
- oldNext.prev = newSiblingNode.id;
3421
- await this._updateNode(oldNext);
3422
- }
3423
- }
3424
- await this._updateNode(parentNode);
3425
- await this._updateNode(newSiblingNode);
3426
- if (parentNode.keys.length > this.order) {
3427
- const newSiblingNodeRecursive = await this._createNode(false, [], []);
3428
- newSiblingNodeRecursive.parent = parentNode.parent;
3429
- const mid = Math.ceil(this.order / 2) - 1;
3430
- newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
3431
- newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
3432
- const midValue = parentNode.values[mid];
3433
- parentNode.values = parentNode.values.slice(0, mid);
3434
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
3435
- for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
3436
- const k = newSiblingNodeRecursive.keys[i];
3437
- const n = this._cloneNode(await this.getNode(k));
3438
- n.parent = newSiblingNodeRecursive.id;
3439
- await this._updateNode(n);
3440
- }
3441
- await this._updateNode(parentNode);
3442
- await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
3443
- }
4701
+ await insertInParentAsync(this._ops, this._ctx, node, value, newSiblingNode);
3444
4702
  }
3445
4703
  async locateLeaf(value) {
3446
- let node = await this.getNode(this.rootId);
3447
- while (!node.leaf) {
3448
- const { index } = this._binarySearchValues(node.values, value, false, true);
3449
- node = await this.getNode(node.keys[index]);
3450
- }
3451
- return node;
4704
+ return locateLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
3452
4705
  }
3453
4706
  async findLowerBoundLeaf(value) {
3454
- let node = await this.getNode(this.rootId);
3455
- while (!node.leaf) {
3456
- const { index } = this._binarySearchValues(node.values, value, true, false);
3457
- node = await this.getNode(node.keys[index]);
3458
- }
3459
- return node;
4707
+ return findLowerBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
3460
4708
  }
3461
4709
  async findUpperBoundLeaf(value) {
3462
- let node = await this.getNode(this.rootId);
3463
- while (!node.leaf) {
3464
- const { index } = this._binarySearchValues(node.values, value, true, true);
3465
- node = await this.getNode(node.keys[index]);
3466
- }
3467
- return node;
4710
+ return findUpperBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
3468
4711
  }
3469
4712
  async findOuterBoundaryLeaf(value, direction) {
3470
- const insertableNode = direction === -1 ? await this.findLowerBoundLeaf(value) : await this.findUpperBoundLeaf(value);
3471
- let key;
3472
- switch (direction) {
3473
- case -1:
3474
- key = "prev";
3475
- break;
3476
- case 1:
3477
- key = "next";
3478
- break;
3479
- default:
3480
- throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
3481
- }
3482
- const guessNode = insertableNode[key];
3483
- if (!guessNode) {
3484
- return null;
3485
- }
3486
- return await this.getNode(guessNode);
4713
+ return findOuterBoundaryLeafAsync(this._ops, this._ctx.rootId, value, direction, this.comparator);
3487
4714
  }
3488
4715
  async leftestNode() {
3489
- let node = await this.getNode(this.rootId);
3490
- if (node === null) {
3491
- debugger;
3492
- }
3493
- while (!node.leaf) {
3494
- const keys = node.keys;
3495
- node = await this.getNode(keys[0]);
3496
- }
3497
- return node;
4716
+ return leftestNodeAsync(this._ops, this._ctx.rootId);
3498
4717
  }
3499
4718
  async rightestNode() {
3500
- let node = await this.getNode(this.rootId);
3501
- while (!node.leaf) {
3502
- const keys = node.keys;
3503
- node = await this.getNode(keys[keys.length - 1]);
3504
- }
3505
- return node;
4719
+ return rightestNodeAsync(this._ops, this._ctx.rootId);
3506
4720
  }
3507
4721
  async *getPairsGenerator(startNode, endNode, direction) {
3508
- let node = startNode;
3509
- let nextNodePromise = null;
3510
- while (true) {
3511
- if (endNode && node.id === endNode.id) {
3512
- break;
3513
- }
3514
- if (direction === 1) {
3515
- if (node.next) {
3516
- nextNodePromise = this.getNode(node.next);
3517
- }
3518
- } else {
3519
- if (node.prev) {
3520
- nextNodePromise = this.getNode(node.prev);
3521
- }
3522
- }
3523
- const len = node.values.length;
3524
- if (direction === 1) {
3525
- for (let i = 0; i < len; i++) {
3526
- const nValue = node.values[i];
3527
- const keys = node.keys[i];
3528
- for (let j = 0, len2 = keys.length; j < len2; j++) {
3529
- yield [keys[j], nValue];
3530
- }
3531
- }
3532
- } else {
3533
- let i = len;
3534
- while (i--) {
3535
- const nValue = node.values[i];
3536
- const keys = node.keys[i];
3537
- let j = keys.length;
3538
- while (j--) {
3539
- yield [keys[j], nValue];
3540
- }
3541
- }
3542
- }
3543
- if (nextNodePromise) {
3544
- node = await nextNodePromise;
3545
- nextNodePromise = null;
3546
- } else {
3547
- break;
3548
- }
3549
- }
4722
+ yield* getPairsGeneratorAsync(this._ops, startNode, endNode, direction);
3550
4723
  }
4724
+ // ─── Lifecycle ───────────────────────────────────────────────────
3551
4725
  async init() {
3552
4726
  if (this.rootTx !== this) {
3553
4727
  throw new Error("Cannot call init on a nested transaction");
@@ -3564,111 +4738,60 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3564
4738
  this.isInitialized = true;
3565
4739
  try {
3566
4740
  this._clearCache();
3567
- const head = await this._readHead();
3568
- if (head === null) {
3569
- this.order = this.strategy.order;
3570
- const root = await this._createNode(true, [], []);
3571
- await this._writeHead({
3572
- root: root.id,
3573
- order: this.order,
3574
- data: this.strategy.head.data
3575
- });
3576
- } else {
3577
- const { root, order } = head;
3578
- this.strategy.head = head;
3579
- this.order = order;
3580
- this.rootId = root;
3581
- }
3582
- if (this.order < 3) {
3583
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
3584
- }
4741
+ await initOpAsync(
4742
+ this._ops,
4743
+ this._ctx,
4744
+ this.strategy.order,
4745
+ this.strategy.head,
4746
+ (head) => {
4747
+ this.strategy.head = head;
4748
+ }
4749
+ );
3585
4750
  } catch (e) {
3586
4751
  this.isInitialized = false;
3587
4752
  throw e;
3588
4753
  }
3589
4754
  }
3590
- async exists(key, value) {
3591
- const node = await this.locateLeaf(value);
3592
- const { index, found } = this._binarySearchValues(node.values, value);
3593
- if (found) {
3594
- const keys = node.keys[index];
3595
- if (keys.includes(key)) {
3596
- return true;
3597
- }
4755
+ async reload() {
4756
+ if (this.rootTx !== this) {
4757
+ throw new Error("Cannot call reload on a nested transaction");
3598
4758
  }
3599
- return false;
4759
+ return await this._reloadInternal();
4760
+ }
4761
+ async _reloadInternal() {
4762
+ this._resetForReload();
4763
+ await this._initInternal();
4764
+ }
4765
+ // ─── Query (delegating to algorithm) ─────────────────────────────
4766
+ async exists(key, value) {
4767
+ return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
3600
4768
  }
3601
4769
  async get(key) {
3602
- let node = await this.leftestNode();
3603
- while (true) {
3604
- for (let i = 0, len = node.values.length; i < len; i++) {
3605
- const keys = node.keys[i];
3606
- for (let j = 0, len2 = keys.length; j < len2; j++) {
3607
- if (keys[j] === key) {
3608
- return node.values[i];
3609
- }
3610
- }
3611
- }
3612
- if (!node.next) break;
3613
- node = await this.getNode(node.next);
3614
- }
3615
- return void 0;
4770
+ return getOpAsync(this._ops, this._ctx.rootId, key);
3616
4771
  }
3617
4772
  async *keysStream(condition, options) {
3618
- const { filterValues, limit, order = "asc" } = options ?? {};
3619
- const stream = this.whereStream(condition, options);
3620
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3621
- let count = 0;
3622
- for await (const [key] of stream) {
3623
- if (intersection && !intersection.has(key)) {
3624
- continue;
3625
- }
3626
- yield key;
3627
- count++;
3628
- if (limit !== void 0 && count >= limit) {
3629
- break;
3630
- }
3631
- }
4773
+ yield* keysStreamOpAsync(
4774
+ this._ops,
4775
+ this._ctx.rootId,
4776
+ condition,
4777
+ this.comparator,
4778
+ this._verifierMapCached,
4779
+ this._searchConfigsCached,
4780
+ this.ensureValues.bind(this),
4781
+ options
4782
+ );
3632
4783
  }
3633
4784
  async *whereStream(condition, options) {
3634
- const { filterValues, limit, order = "asc" } = options ?? {};
3635
- const conditionKeys = Object.keys(condition);
3636
- if (conditionKeys.length === 0) return;
3637
- const resolved = this.resolveStartEndConfigs(condition, order);
3638
- const direction = resolved.direction;
3639
- let startNode;
3640
- if (resolved.startKey) {
3641
- const startConfig = this.searchConfigs[resolved.startKey][order];
3642
- startNode = await startConfig.start(this, resolved.startValues);
3643
- } else {
3644
- startNode = order === "asc" ? await this.leftestNode() : await this.rightestNode();
3645
- }
3646
- let endNode = null;
3647
- if (resolved.endKey) {
3648
- const endConfig = this.searchConfigs[resolved.endKey][order];
3649
- endNode = await endConfig.end(this, resolved.endValues);
3650
- }
3651
- if (!startNode) return;
3652
- const generator = this.getPairsGenerator(
3653
- startNode,
3654
- endNode,
3655
- direction
4785
+ yield* whereStreamOpAsync(
4786
+ this._ops,
4787
+ this._ctx.rootId,
4788
+ condition,
4789
+ this.comparator,
4790
+ this._verifierMapCached,
4791
+ this._searchConfigsCached,
4792
+ this.ensureValues.bind(this),
4793
+ options
3656
4794
  );
3657
- let count = 0;
3658
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3659
- for await (const pair of generator) {
3660
- const [k, v] = pair;
3661
- if (intersection && !intersection.has(k)) {
3662
- continue;
3663
- }
3664
- if (this.verify(v, condition)) {
3665
- yield pair;
3666
- count++;
3667
- if (limit !== void 0 && count >= limit) {
3668
- break;
3669
- }
3670
- }
3671
- }
3672
4795
  }
3673
4796
  async keys(condition, options) {
3674
4797
  const set = /* @__PURE__ */ new Set();
@@ -3684,412 +4807,33 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3684
4807
  }
3685
4808
  return map;
3686
4809
  }
4810
+ // ─── Mutation (delegating to algorithm) ──────────────────────────
3687
4811
  async insert(key, value) {
3688
4812
  return this.writeLock(0, async () => {
3689
- let before = await this.locateLeaf(value);
3690
- before = await this._insertAtLeaf(before, key, value);
3691
- if (before.values.length === this.order) {
3692
- let after = await this._createNode(
3693
- true,
3694
- [],
3695
- [],
3696
- before.parent,
3697
- null,
3698
- null
3699
- );
3700
- const mid = Math.ceil(this.order / 2) - 1;
3701
- after = this._cloneNode(after);
3702
- after.values = before.values.slice(mid + 1);
3703
- after.keys = before.keys.slice(mid + 1);
3704
- before.values = before.values.slice(0, mid + 1);
3705
- before.keys = before.keys.slice(0, mid + 1);
3706
- await this._updateNode(before);
3707
- await this._updateNode(after);
3708
- await this._insertInParent(before, after.values[0], after);
3709
- }
4813
+ await insertOpAsync(this._ops, this._ctx, key, value, this.comparator);
3710
4814
  });
3711
4815
  }
3712
4816
  async batchInsert(entries) {
3713
4817
  if (entries.length === 0) return;
3714
4818
  return this.writeLock(0, async () => {
3715
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3716
- let currentLeaf = null;
3717
- let modified = false;
3718
- let cachedLeafId = null;
3719
- let cachedLeafMaxValue = null;
3720
- for (let i = 0, len = sorted.length; i < len; i++) {
3721
- const [key, value] = sorted[i];
3722
- let targetLeaf;
3723
- if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
3724
- targetLeaf = currentLeaf;
3725
- } else {
3726
- targetLeaf = await this.locateLeaf(value);
3727
- }
3728
- if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3729
- } else {
3730
- if (currentLeaf !== null && modified) {
3731
- await this._updateNode(currentLeaf);
3732
- }
3733
- currentLeaf = this._cloneNode(targetLeaf);
3734
- modified = false;
3735
- }
3736
- cachedLeafId = currentLeaf.id;
3737
- const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3738
- modified = modified || changed;
3739
- cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
3740
- if (currentLeaf.values.length === this.order) {
3741
- await this._updateNode(currentLeaf);
3742
- let after = await this._createNode(
3743
- true,
3744
- [],
3745
- [],
3746
- currentLeaf.parent,
3747
- null,
3748
- null
3749
- );
3750
- const mid = Math.ceil(this.order / 2) - 1;
3751
- after = this._cloneNode(after);
3752
- after.values = currentLeaf.values.slice(mid + 1);
3753
- after.keys = currentLeaf.keys.slice(mid + 1);
3754
- currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
3755
- currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
3756
- await this._updateNode(currentLeaf);
3757
- await this._updateNode(after);
3758
- await this._insertInParent(currentLeaf, after.values[0], after);
3759
- currentLeaf = null;
3760
- cachedLeafId = null;
3761
- cachedLeafMaxValue = null;
3762
- modified = false;
3763
- }
3764
- }
3765
- if (currentLeaf !== null && modified) {
3766
- await this._updateNode(currentLeaf);
3767
- }
4819
+ await batchInsertOpAsync(this._ops, this._ctx, entries, this.comparator);
3768
4820
  });
3769
4821
  }
3770
4822
  async bulkLoad(entries) {
3771
4823
  if (entries.length === 0) return;
3772
4824
  return this.writeLock(0, async () => {
3773
- const root = await this.getNode(this.rootId);
3774
- if (!root.leaf || root.values.length > 0) {
3775
- throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
3776
- }
3777
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3778
- const grouped = [];
3779
- for (let i = 0, len = sorted.length; i < len; i++) {
3780
- const [key, value] = sorted[i];
3781
- const last = grouped[grouped.length - 1];
3782
- if (last && this.comparator.isSame(last.value, value)) {
3783
- if (!last.keys.includes(key)) {
3784
- last.keys.push(key);
3785
- }
3786
- } else {
3787
- grouped.push({ keys: [key], value });
3788
- }
3789
- }
3790
- await this._deleteNode(root);
3791
- const maxLeafSize = this.order - 1;
3792
- const leaves = [];
3793
- for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
3794
- const chunk = grouped.slice(i, i + maxLeafSize);
3795
- const leafKeys = chunk.map((g) => g.keys);
3796
- const leafValues = chunk.map((g) => g.value);
3797
- const leaf = await this._createNode(
3798
- true,
3799
- leafKeys,
3800
- leafValues,
3801
- null,
3802
- null,
3803
- null
3804
- );
3805
- leaves.push(leaf);
3806
- }
3807
- for (let i = 0, len = leaves.length; i < len; i++) {
3808
- if (i > 0) {
3809
- leaves[i].prev = leaves[i - 1].id;
3810
- }
3811
- if (i < len - 1) {
3812
- leaves[i].next = leaves[i + 1].id;
3813
- }
3814
- await this._updateNode(leaves[i]);
3815
- }
3816
- let currentLevel = leaves;
3817
- while (currentLevel.length > 1) {
3818
- const nextLevel = [];
3819
- for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
3820
- const children = currentLevel.slice(i, i + this.order);
3821
- const childIds = children.map((c) => c.id);
3822
- const separators = [];
3823
- for (let j = 1, len2 = children.length; j < len2; j++) {
3824
- separators.push(children[j].values[0]);
3825
- }
3826
- const internalNode = await this._createNode(
3827
- false,
3828
- childIds,
3829
- separators,
3830
- null,
3831
- null,
3832
- null
3833
- );
3834
- for (let j = 0, len2 = children.length; j < len2; j++) {
3835
- const child = children[j];
3836
- child.parent = internalNode.id;
3837
- await this._updateNode(child);
3838
- }
3839
- nextLevel.push(internalNode);
3840
- }
3841
- currentLevel = nextLevel;
3842
- }
3843
- const newRoot = currentLevel[0];
3844
- await this._writeHead({
3845
- root: newRoot.id,
3846
- order: this.order,
3847
- data: this.strategy.head.data
3848
- });
4825
+ await bulkLoadOpAsync(this._ops, this._ctx, entries, this.comparator);
3849
4826
  });
3850
4827
  }
3851
4828
  async _deleteEntry(node, key) {
3852
- if (!node.leaf) {
3853
- let keyIndex = -1;
3854
- for (let i = 0, len = node.keys.length; i < len; i++) {
3855
- if (node.keys[i] === key) {
3856
- keyIndex = i;
3857
- break;
3858
- }
3859
- }
3860
- if (keyIndex !== -1) {
3861
- node = this._cloneNode(node);
3862
- node.keys.splice(keyIndex, 1);
3863
- const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
3864
- node.values.splice(valueIndex, 1);
3865
- await this._updateNode(node);
3866
- }
3867
- }
3868
- if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
3869
- const keys = node.keys;
3870
- this._deleteNode(node);
3871
- const newRoot = this._cloneNode(await this.getNode(keys[0]));
3872
- newRoot.parent = null;
3873
- await this._updateNode(newRoot);
3874
- await this._writeHead({
3875
- root: newRoot.id,
3876
- order: this.order,
3877
- data: this.strategy.head.data
3878
- });
3879
- return node;
3880
- } else if (this.rootId === node.id) {
3881
- await this._writeHead({
3882
- root: node.id,
3883
- order: this.order,
3884
- data: this.strategy.head.data
3885
- });
3886
- return node;
3887
- } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
3888
- if (node.parent === null) {
3889
- return node;
3890
- }
3891
- let isPredecessor = false;
3892
- let parentNode = await this.getNode(node.parent);
3893
- let prevNode = null;
3894
- let nextNode = null;
3895
- let prevValue = null;
3896
- let postValue = null;
3897
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
3898
- const nKey = parentNode.keys[i];
3899
- if (nKey === node.id) {
3900
- if (i > 0) {
3901
- prevNode = await this.getNode(parentNode.keys[i - 1]);
3902
- prevValue = parentNode.values[i - 1];
3903
- }
3904
- if (i < parentNode.keys.length - 1) {
3905
- nextNode = await this.getNode(parentNode.keys[i + 1]);
3906
- postValue = parentNode.values[i];
3907
- }
3908
- }
3909
- }
3910
- let siblingNode;
3911
- let guess;
3912
- if (prevNode === null) {
3913
- siblingNode = nextNode;
3914
- guess = postValue;
3915
- } else if (nextNode === null) {
3916
- isPredecessor = true;
3917
- siblingNode = prevNode;
3918
- guess = prevValue;
3919
- } else {
3920
- if (node.values.length + nextNode.values.length < this.order) {
3921
- siblingNode = nextNode;
3922
- guess = postValue;
3923
- } else {
3924
- isPredecessor = true;
3925
- siblingNode = prevNode;
3926
- guess = prevValue;
3927
- }
3928
- }
3929
- if (!siblingNode) {
3930
- return node;
3931
- }
3932
- node = this._cloneNode(node);
3933
- siblingNode = this._cloneNode(siblingNode);
3934
- if (node.values.length + siblingNode.values.length < this.order) {
3935
- if (!isPredecessor) {
3936
- const pTemp = siblingNode;
3937
- siblingNode = node;
3938
- node = pTemp;
3939
- }
3940
- siblingNode.keys.push(...node.keys);
3941
- if (!node.leaf) {
3942
- siblingNode.values.push(guess);
3943
- } else {
3944
- siblingNode.next = node.next;
3945
- if (siblingNode.next) {
3946
- const n = this._cloneNode(await this.getNode(siblingNode.next));
3947
- n.prev = siblingNode.id;
3948
- await this._updateNode(n);
3949
- }
3950
- }
3951
- siblingNode.values.push(...node.values);
3952
- if (!siblingNode.leaf) {
3953
- const keys = siblingNode.keys;
3954
- for (let i = 0, len = keys.length; i < len; i++) {
3955
- const key2 = keys[i];
3956
- const node2 = this._cloneNode(await this.getNode(key2));
3957
- node2.parent = siblingNode.id;
3958
- await this._updateNode(node2);
3959
- }
3960
- }
3961
- this._deleteNode(node);
3962
- await this._updateNode(siblingNode);
3963
- await this._deleteEntry(await this.getNode(node.parent), node.id);
3964
- } else {
3965
- if (isPredecessor) {
3966
- let pointerPm;
3967
- let pointerKm;
3968
- if (!node.leaf) {
3969
- pointerPm = siblingNode.keys.splice(-1)[0];
3970
- pointerKm = siblingNode.values.splice(-1)[0];
3971
- node.keys = [pointerPm, ...node.keys];
3972
- node.values = [guess, ...node.values];
3973
- parentNode = this._cloneNode(await this.getNode(node.parent));
3974
- const nodeIndex = parentNode.keys.indexOf(node.id);
3975
- if (nodeIndex > 0) {
3976
- parentNode.values[nodeIndex - 1] = pointerKm;
3977
- await this._updateNode(parentNode);
3978
- }
3979
- } else {
3980
- pointerPm = siblingNode.keys.splice(-1)[0];
3981
- pointerKm = siblingNode.values.splice(-1)[0];
3982
- node.keys = [pointerPm, ...node.keys];
3983
- node.values = [pointerKm, ...node.values];
3984
- parentNode = this._cloneNode(await this.getNode(node.parent));
3985
- const nodeIndex = parentNode.keys.indexOf(node.id);
3986
- if (nodeIndex > 0) {
3987
- parentNode.values[nodeIndex - 1] = pointerKm;
3988
- await this._updateNode(parentNode);
3989
- }
3990
- }
3991
- await this._updateNode(node);
3992
- await this._updateNode(siblingNode);
3993
- } else {
3994
- let pointerP0;
3995
- let pointerK0;
3996
- if (!node.leaf) {
3997
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
3998
- pointerK0 = siblingNode.values.splice(0, 1)[0];
3999
- node.keys = [...node.keys, pointerP0];
4000
- node.values = [...node.values, guess];
4001
- parentNode = this._cloneNode(await this.getNode(node.parent));
4002
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
4003
- if (pointerIndex > 0) {
4004
- parentNode.values[pointerIndex - 1] = pointerK0;
4005
- await this._updateNode(parentNode);
4006
- }
4007
- } else {
4008
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
4009
- pointerK0 = siblingNode.values.splice(0, 1)[0];
4010
- node.keys = [...node.keys, pointerP0];
4011
- node.values = [...node.values, pointerK0];
4012
- parentNode = this._cloneNode(await this.getNode(node.parent));
4013
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
4014
- if (pointerIndex > 0) {
4015
- parentNode.values[pointerIndex - 1] = siblingNode.values[0];
4016
- await this._updateNode(parentNode);
4017
- }
4018
- }
4019
- await this._updateNode(node);
4020
- await this._updateNode(siblingNode);
4021
- }
4022
- if (!siblingNode.leaf) {
4023
- for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
4024
- const key2 = siblingNode.keys[i];
4025
- const n = this._cloneNode(await this.getNode(key2));
4026
- n.parent = siblingNode.id;
4027
- await this._updateNode(n);
4028
- }
4029
- }
4030
- if (!node.leaf) {
4031
- for (let i = 0, len = node.keys.length; i < len; i++) {
4032
- const key2 = node.keys[i];
4033
- const n = this._cloneNode(await this.getNode(key2));
4034
- n.parent = node.id;
4035
- await this._updateNode(n);
4036
- }
4037
- }
4038
- if (!parentNode.leaf) {
4039
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
4040
- const key2 = parentNode.keys[i];
4041
- const n = this._cloneNode(await this.getNode(key2));
4042
- n.parent = parentNode.id;
4043
- await this._updateNode(n);
4044
- }
4045
- }
4046
- }
4047
- } else {
4048
- await this._updateNode(this._cloneNode(node));
4049
- }
4050
- return node;
4829
+ return deleteEntryAsync(this._ops, this._ctx, node, key, this.comparator);
4051
4830
  }
4052
4831
  async delete(key, value) {
4053
4832
  return this.writeLock(0, async () => {
4054
- if (value === void 0) {
4055
- value = await this.get(key);
4056
- }
4057
- if (value === void 0) {
4058
- return;
4059
- }
4060
- let node = await this.findLowerBoundLeaf(value);
4061
- let found = false;
4062
- while (true) {
4063
- let i = node.values.length;
4064
- while (i--) {
4065
- const nValue = node.values[i];
4066
- if (this.comparator.isSame(value, nValue)) {
4067
- const keys = node.keys[i];
4068
- const keyIndex = keys.indexOf(key);
4069
- if (keyIndex !== -1) {
4070
- node = this._cloneNode(node);
4071
- const freshKeys = node.keys[i];
4072
- freshKeys.splice(keyIndex, 1);
4073
- if (freshKeys.length === 0) {
4074
- node.keys.splice(i, 1);
4075
- node.values.splice(i, 1);
4076
- }
4077
- await this._updateNode(node);
4078
- node = await this._deleteEntry(node, key);
4079
- found = true;
4080
- break;
4081
- }
4082
- }
4083
- }
4084
- if (found) break;
4085
- if (node.next) {
4086
- node = await this.getNode(node.next);
4087
- continue;
4088
- }
4089
- break;
4090
- }
4833
+ await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
4091
4834
  });
4092
4835
  }
4836
+ // ─── Head Data ───────────────────────────────────────────────────
4093
4837
  async getHeadData() {
4094
4838
  const head = await this._readHead();
4095
4839
  if (head === null) {
@@ -4108,6 +4852,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
4108
4852
  data
4109
4853
  });
4110
4854
  }
4855
+ // ─── Transaction ─────────────────────────────────────────────────
4111
4856
  async commit(label) {
4112
4857
  let result = await this.mvcc.commit(label);
4113
4858
  if (result.success) {
@@ -4239,6 +4984,327 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
4239
4984
  }
4240
4985
  };
4241
4986
 
4987
+ // src/BPTreePureSync.ts
4988
+ var BPTreePureSync = class {
4989
+ strategy;
4990
+ comparator;
4991
+ option;
4992
+ _cachedRegexp = /* @__PURE__ */ new Map();
4993
+ _ctx;
4994
+ _ops;
4995
+ _verifierMap;
4996
+ _searchConfigs;
4997
+ constructor(strategy, comparator, option) {
4998
+ this.strategy = strategy;
4999
+ this.comparator = comparator;
5000
+ this.option = option ?? {};
5001
+ const ensureValues = (v) => Array.isArray(v) ? v : [v];
5002
+ this._verifierMap = createVerifierMap(comparator, this._cachedRegexp, ensureValues);
5003
+ this._searchConfigs = createSearchConfigs(comparator, ensureValues);
5004
+ }
5005
+ _ensureValues(v) {
5006
+ return Array.isArray(v) ? v : [v];
5007
+ }
5008
+ _createOps() {
5009
+ const strategy = this.strategy;
5010
+ return {
5011
+ getNode(id) {
5012
+ return strategy.read(id);
5013
+ },
5014
+ createNode(leaf, keys, values, parent = null, next = null, prev = null) {
5015
+ const id = strategy.id(leaf);
5016
+ const node = { id, keys, values, leaf, parent, next, prev };
5017
+ strategy.write(id, node);
5018
+ return node;
5019
+ },
5020
+ updateNode(node) {
5021
+ strategy.write(node.id, node);
5022
+ },
5023
+ deleteNode(node) {
5024
+ strategy.delete(node.id);
5025
+ },
5026
+ readHead() {
5027
+ return strategy.readHead();
5028
+ },
5029
+ writeHead(head) {
5030
+ strategy.writeHead(head);
5031
+ }
5032
+ };
5033
+ }
5034
+ init() {
5035
+ this._ops = this._createOps();
5036
+ this._ctx = {
5037
+ rootId: "",
5038
+ order: this.strategy.order,
5039
+ headData: () => this.strategy.head.data
5040
+ };
5041
+ initOp(
5042
+ this._ops,
5043
+ this._ctx,
5044
+ this.strategy.order,
5045
+ this.strategy.head,
5046
+ (head) => {
5047
+ this.strategy.head = head;
5048
+ }
5049
+ );
5050
+ }
5051
+ /**
5052
+ * Returns the ID of the root node.
5053
+ */
5054
+ getRootId() {
5055
+ return this._ctx.rootId;
5056
+ }
5057
+ /**
5058
+ * Returns the order of the B+Tree.
5059
+ */
5060
+ getOrder() {
5061
+ return this._ctx.order;
5062
+ }
5063
+ /**
5064
+ * Verified if the value satisfies the condition.
5065
+ */
5066
+ verify(nodeValue, condition) {
5067
+ for (const key in condition) {
5068
+ const verifyFn = this._verifierMap[key];
5069
+ const condValue = condition[key];
5070
+ if (!verifyFn(nodeValue, condValue)) {
5071
+ return false;
5072
+ }
5073
+ }
5074
+ return true;
5075
+ }
5076
+ // ─── Query ───────────────────────────────────────────────────────
5077
+ get(key) {
5078
+ return getOp(this._ops, this._ctx.rootId, key);
5079
+ }
5080
+ exists(key, value) {
5081
+ return existsOp(this._ops, this._ctx.rootId, key, value, this.comparator);
5082
+ }
5083
+ *keysStream(condition, options) {
5084
+ yield* keysStreamOp(
5085
+ this._ops,
5086
+ this._ctx.rootId,
5087
+ condition,
5088
+ this.comparator,
5089
+ this._verifierMap,
5090
+ this._searchConfigs,
5091
+ this._ensureValues,
5092
+ options
5093
+ );
5094
+ }
5095
+ *whereStream(condition, options) {
5096
+ yield* whereStreamOp(
5097
+ this._ops,
5098
+ this._ctx.rootId,
5099
+ condition,
5100
+ this.comparator,
5101
+ this._verifierMap,
5102
+ this._searchConfigs,
5103
+ this._ensureValues,
5104
+ options
5105
+ );
5106
+ }
5107
+ keys(condition, options) {
5108
+ const set = /* @__PURE__ */ new Set();
5109
+ for (const key of this.keysStream(condition, options)) {
5110
+ set.add(key);
5111
+ }
5112
+ return set;
5113
+ }
5114
+ where(condition, options) {
5115
+ const map = /* @__PURE__ */ new Map();
5116
+ for (const [key, value] of this.whereStream(condition, options)) {
5117
+ map.set(key, value);
5118
+ }
5119
+ return map;
5120
+ }
5121
+ // ─── Mutation ────────────────────────────────────────────────────
5122
+ insert(key, value) {
5123
+ insertOp(this._ops, this._ctx, key, value, this.comparator);
5124
+ }
5125
+ delete(key, value) {
5126
+ deleteOp(this._ops, this._ctx, key, this.comparator, value);
5127
+ }
5128
+ batchInsert(entries) {
5129
+ batchInsertOp(this._ops, this._ctx, entries, this.comparator);
5130
+ }
5131
+ bulkLoad(entries) {
5132
+ bulkLoadOp(this._ops, this._ctx, entries, this.comparator);
5133
+ }
5134
+ // ─── Head Data ───────────────────────────────────────────────────
5135
+ getHeadData() {
5136
+ const head = this._ops.readHead();
5137
+ if (head === null) {
5138
+ throw new Error("Head not found");
5139
+ }
5140
+ return head.data;
5141
+ }
5142
+ setHeadData(data) {
5143
+ const head = this._ops.readHead();
5144
+ if (head === null) {
5145
+ throw new Error("Head not found");
5146
+ }
5147
+ this._ops.writeHead({
5148
+ root: head.root,
5149
+ order: head.order,
5150
+ data
5151
+ });
5152
+ }
5153
+ // ─── Static utilities ────────────────────────────────────────────
5154
+ static ChooseDriver = BPTreeTransaction.ChooseDriver;
5155
+ };
5156
+
5157
+ // src/BPTreePureAsync.ts
5158
+ var BPTreePureAsync = class {
5159
+ strategy;
5160
+ comparator;
5161
+ option;
5162
+ _cachedRegexp = /* @__PURE__ */ new Map();
5163
+ _ctx;
5164
+ _ops;
5165
+ _verifierMap;
5166
+ _searchConfigs;
5167
+ constructor(strategy, comparator, option) {
5168
+ this.strategy = strategy;
5169
+ this.comparator = comparator;
5170
+ this.option = option ?? {};
5171
+ const ensureValues = (v) => Array.isArray(v) ? v : [v];
5172
+ this._verifierMap = createVerifierMap(comparator, this._cachedRegexp, ensureValues);
5173
+ this._searchConfigs = createSearchConfigsAsync(comparator, ensureValues);
5174
+ }
5175
+ _ensureValues(v) {
5176
+ return Array.isArray(v) ? v : [v];
5177
+ }
5178
+ _createOps() {
5179
+ const strategy = this.strategy;
5180
+ return {
5181
+ async getNode(id) {
5182
+ return await strategy.read(id);
5183
+ },
5184
+ async createNode(leaf, keys, values, parent = null, next = null, prev = null) {
5185
+ const id = await strategy.id(leaf);
5186
+ const node = { id, keys, values, leaf, parent, next, prev };
5187
+ await strategy.write(id, node);
5188
+ return node;
5189
+ },
5190
+ async updateNode(node) {
5191
+ await strategy.write(node.id, node);
5192
+ },
5193
+ async deleteNode(node) {
5194
+ await strategy.delete(node.id);
5195
+ },
5196
+ async readHead() {
5197
+ return await strategy.readHead();
5198
+ },
5199
+ async writeHead(head) {
5200
+ await strategy.writeHead(head);
5201
+ }
5202
+ };
5203
+ }
5204
+ async init() {
5205
+ this._ops = this._createOps();
5206
+ this._ctx = {
5207
+ rootId: "",
5208
+ order: this.strategy.order,
5209
+ headData: () => this.strategy.head.data
5210
+ };
5211
+ await initOpAsync(
5212
+ this._ops,
5213
+ this._ctx,
5214
+ this.strategy.order,
5215
+ this.strategy.head,
5216
+ (head) => {
5217
+ this.strategy.head = head;
5218
+ }
5219
+ );
5220
+ }
5221
+ getRootId() {
5222
+ return this._ctx.rootId;
5223
+ }
5224
+ getOrder() {
5225
+ return this._ctx.order;
5226
+ }
5227
+ verify(nodeValue, condition) {
5228
+ for (const key in condition) {
5229
+ const verifyFn = this._verifierMap[key];
5230
+ const condValue = condition[key];
5231
+ if (!verifyFn(nodeValue, condValue)) return false;
5232
+ }
5233
+ return true;
5234
+ }
5235
+ // ─── Query ───────────────────────────────────────────────────────
5236
+ async get(key) {
5237
+ return getOpAsync(this._ops, this._ctx.rootId, key);
5238
+ }
5239
+ async exists(key, value) {
5240
+ return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
5241
+ }
5242
+ async *keysStream(condition, options) {
5243
+ yield* keysStreamOpAsync(
5244
+ this._ops,
5245
+ this._ctx.rootId,
5246
+ condition,
5247
+ this.comparator,
5248
+ this._verifierMap,
5249
+ this._searchConfigs,
5250
+ this._ensureValues,
5251
+ options
5252
+ );
5253
+ }
5254
+ async *whereStream(condition, options) {
5255
+ yield* whereStreamOpAsync(
5256
+ this._ops,
5257
+ this._ctx.rootId,
5258
+ condition,
5259
+ this.comparator,
5260
+ this._verifierMap,
5261
+ this._searchConfigs,
5262
+ this._ensureValues,
5263
+ options
5264
+ );
5265
+ }
5266
+ async keys(condition, options) {
5267
+ const set = /* @__PURE__ */ new Set();
5268
+ for await (const key of this.keysStream(condition, options)) {
5269
+ set.add(key);
5270
+ }
5271
+ return set;
5272
+ }
5273
+ async where(condition, options) {
5274
+ const map = /* @__PURE__ */ new Map();
5275
+ for await (const [key, value] of this.whereStream(condition, options)) {
5276
+ map.set(key, value);
5277
+ }
5278
+ return map;
5279
+ }
5280
+ // ─── Mutation ────────────────────────────────────────────────────
5281
+ async insert(key, value) {
5282
+ await insertOpAsync(this._ops, this._ctx, key, value, this.comparator);
5283
+ }
5284
+ async delete(key, value) {
5285
+ await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
5286
+ }
5287
+ async batchInsert(entries) {
5288
+ await batchInsertOpAsync(this._ops, this._ctx, entries, this.comparator);
5289
+ }
5290
+ async bulkLoad(entries) {
5291
+ await bulkLoadOpAsync(this._ops, this._ctx, entries, this.comparator);
5292
+ }
5293
+ // ─── Head Data ───────────────────────────────────────────────────
5294
+ async getHeadData() {
5295
+ const head = await this._ops.readHead();
5296
+ if (head === null) throw new Error("Head not found");
5297
+ return head.data;
5298
+ }
5299
+ async setHeadData(data) {
5300
+ const head = await this._ops.readHead();
5301
+ if (head === null) throw new Error("Head not found");
5302
+ await this._ops.writeHead({ root: head.root, order: head.order, data });
5303
+ }
5304
+ // ─── Static utilities ────────────────────────────────────────────
5305
+ static ChooseDriver = BPTreeTransaction.ChooseDriver;
5306
+ };
5307
+
4242
5308
  // src/base/SerializeStrategy.ts
4243
5309
  var SerializeStrategy = class {
4244
5310
  order;