serializable-bptree 8.4.2 → 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,84 +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
- rootTx;
1573
- mvccRoot;
1574
- mvcc;
1575
- strategy;
1576
- comparator;
1577
- option;
1578
- order;
1579
- rootId;
1580
- isInitialized = false;
1581
- isDestroyed = false;
1582
- verifierMap = {
1583
- gt: (nv, v) => this.comparator.isHigher(nv, v),
1584
- gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
1585
- lt: (nv, v) => this.comparator.isLower(nv, v),
1586
- lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
1587
- equal: (nv, v) => this.comparator.isSame(nv, v),
1588
- notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
1589
- or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
1590
- primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
1591
- primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
1592
- primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
1593
- primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
1594
- primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
1595
- primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
1596
- 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)),
1597
1650
  like: (nv, v) => {
1598
- const nodeValue = this.comparator.match(nv);
1651
+ const nodeValue = comparator.match(nv);
1599
1652
  const value = v;
1600
- if (!this._cachedRegexp.has(value)) {
1653
+ if (!cachedRegexp.has(value)) {
1601
1654
  const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
1602
1655
  const regexp2 = new RegExp(`^${pattern}$`, "i");
1603
- this._cachedRegexp.set(value, regexp2);
1656
+ cachedRegexp.set(value, regexp2);
1604
1657
  }
1605
- const regexp = this._cachedRegexp.get(value);
1658
+ const regexp = cachedRegexp.get(value);
1606
1659
  return regexp.test(nodeValue);
1607
1660
  }
1608
1661
  };
1609
- 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 {
1610
1669
  gt: {
1611
1670
  asc: {
1612
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1671
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1613
1672
  end: () => null,
1614
1673
  direction: 1,
1615
1674
  earlyTerminate: false
1616
1675
  },
1617
1676
  desc: {
1618
- start: (tx) => tx.rightestNode(),
1619
- 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),
1620
1679
  direction: -1,
1621
1680
  earlyTerminate: true
1622
1681
  }
1623
1682
  },
1624
1683
  gte: {
1625
1684
  asc: {
1626
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1685
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1627
1686
  end: () => null,
1628
1687
  direction: 1,
1629
1688
  earlyTerminate: false
1630
1689
  },
1631
1690
  desc: {
1632
- start: (tx) => tx.rightestNode(),
1633
- 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),
1634
1693
  direction: -1,
1635
1694
  earlyTerminate: true
1636
1695
  }
1637
1696
  },
1638
1697
  lt: {
1639
1698
  asc: {
1640
- start: (tx) => tx.leftestNode(),
1641
- 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),
1642
1701
  direction: 1,
1643
1702
  earlyTerminate: true
1644
1703
  },
1645
1704
  desc: {
1646
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1705
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1647
1706
  end: () => null,
1648
1707
  direction: -1,
1649
1708
  earlyTerminate: false
@@ -1651,13 +1710,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
1651
1710
  },
1652
1711
  lte: {
1653
1712
  asc: {
1654
- start: (tx) => tx.leftestNode(),
1655
- 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),
1656
1715
  direction: 1,
1657
1716
  earlyTerminate: true
1658
1717
  },
1659
1718
  desc: {
1660
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1719
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1661
1720
  end: () => null,
1662
1721
  direction: -1,
1663
1722
  earlyTerminate: false
@@ -1665,27 +1724,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
1665
1724
  },
1666
1725
  equal: {
1667
1726
  asc: {
1668
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1669
- 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),
1670
1729
  direction: 1,
1671
1730
  earlyTerminate: true
1672
1731
  },
1673
1732
  desc: {
1674
- start: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
1675
- 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),
1676
1735
  direction: -1,
1677
1736
  earlyTerminate: true
1678
1737
  }
1679
1738
  },
1680
1739
  notEqual: {
1681
1740
  asc: {
1682
- start: (tx) => tx.leftestNode(),
1741
+ start: (r, ops) => leftestNode(ops, r),
1683
1742
  end: () => null,
1684
1743
  direction: 1,
1685
1744
  earlyTerminate: false
1686
1745
  },
1687
1746
  desc: {
1688
- start: (tx) => tx.rightestNode(),
1747
+ start: (r, ops) => rightestNode(ops, r),
1689
1748
  end: () => null,
1690
1749
  direction: -1,
1691
1750
  earlyTerminate: false
@@ -1693,55 +1752,55 @@ var BPTreeTransaction = class _BPTreeTransaction {
1693
1752
  },
1694
1753
  or: {
1695
1754
  asc: {
1696
- start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestValue(v)),
1697
- 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),
1698
1757
  direction: 1,
1699
1758
  earlyTerminate: false
1700
1759
  },
1701
1760
  desc: {
1702
- start: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
1703
- 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),
1704
1763
  direction: -1,
1705
1764
  earlyTerminate: false
1706
1765
  }
1707
1766
  },
1708
1767
  primaryGt: {
1709
1768
  asc: {
1710
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1769
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1711
1770
  end: () => null,
1712
1771
  direction: 1,
1713
1772
  earlyTerminate: false
1714
1773
  },
1715
1774
  desc: {
1716
- start: (tx) => tx.rightestNode(),
1717
- 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),
1718
1777
  direction: -1,
1719
1778
  earlyTerminate: true
1720
1779
  }
1721
1780
  },
1722
1781
  primaryGte: {
1723
1782
  asc: {
1724
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1783
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1725
1784
  end: () => null,
1726
1785
  direction: 1,
1727
1786
  earlyTerminate: false
1728
1787
  },
1729
1788
  desc: {
1730
- start: (tx) => tx.rightestNode(),
1731
- 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),
1732
1791
  direction: -1,
1733
1792
  earlyTerminate: true
1734
1793
  }
1735
1794
  },
1736
1795
  primaryLt: {
1737
1796
  asc: {
1738
- start: (tx) => tx.leftestNode(),
1739
- 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),
1740
1799
  direction: 1,
1741
1800
  earlyTerminate: true
1742
1801
  },
1743
1802
  desc: {
1744
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1803
+ start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
1745
1804
  end: () => null,
1746
1805
  direction: -1,
1747
1806
  earlyTerminate: false
@@ -1749,13 +1808,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
1749
1808
  },
1750
1809
  primaryLte: {
1751
1810
  asc: {
1752
- start: (tx) => tx.leftestNode(),
1753
- 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),
1754
1813
  direction: 1,
1755
1814
  earlyTerminate: true
1756
1815
  },
1757
1816
  desc: {
1758
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1817
+ start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
1759
1818
  end: () => null,
1760
1819
  direction: -1,
1761
1820
  earlyTerminate: false
@@ -1763,27 +1822,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
1763
1822
  },
1764
1823
  primaryEqual: {
1765
1824
  asc: {
1766
- start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
1767
- 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),
1768
1827
  direction: 1,
1769
1828
  earlyTerminate: true
1770
1829
  },
1771
1830
  desc: {
1772
- start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
1773
- 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),
1774
1833
  direction: -1,
1775
1834
  earlyTerminate: true
1776
1835
  }
1777
1836
  },
1778
1837
  primaryNotEqual: {
1779
1838
  asc: {
1780
- start: (tx) => tx.leftestNode(),
1839
+ start: (r, ops) => leftestNode(ops, r),
1781
1840
  end: () => null,
1782
1841
  direction: 1,
1783
1842
  earlyTerminate: false
1784
1843
  },
1785
1844
  desc: {
1786
- start: (tx) => tx.rightestNode(),
1845
+ start: (r, ops) => rightestNode(ops, r),
1787
1846
  end: () => null,
1788
1847
  direction: -1,
1789
1848
  earlyTerminate: false
@@ -1791,176 +1850,1186 @@ var BPTreeTransaction = class _BPTreeTransaction {
1791
1850
  },
1792
1851
  primaryOr: {
1793
1852
  asc: {
1794
- start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestPrimaryValue(v)),
1795
- 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),
1796
1855
  direction: 1,
1797
1856
  earlyTerminate: false
1798
1857
  },
1799
1858
  desc: {
1800
- start: (tx, v) => tx.findUpperBoundLeaf(tx.highestPrimaryValue(v)),
1801
- 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),
1802
1861
  direction: -1,
1803
1862
  earlyTerminate: false
1804
1863
  }
1805
1864
  },
1806
1865
  like: {
1807
1866
  asc: {
1808
- start: (tx) => tx.leftestNode(),
1867
+ start: (r, ops) => leftestNode(ops, r),
1809
1868
  end: () => null,
1810
1869
  direction: 1,
1811
1870
  earlyTerminate: false
1812
1871
  },
1813
1872
  desc: {
1814
- start: (tx) => tx.rightestNode(),
1873
+ start: (r, ops) => rightestNode(ops, r),
1815
1874
  end: () => null,
1816
1875
  direction: -1,
1817
1876
  earlyTerminate: false
1818
1877
  }
1819
1878
  }
1820
1879
  };
1821
- /**
1822
- * Priority map for condition types.
1823
- * Higher value = higher selectivity (fewer expected results).
1824
- * Used by `chooseDriver` to select the most selective index.
1825
- */
1826
- static conditionPriority = {
1827
- equal: 100,
1828
- primaryEqual: 100,
1829
- or: 80,
1830
- primaryOr: 80,
1831
- gt: 50,
1832
- gte: 50,
1833
- lt: 50,
1834
- lte: 50,
1835
- primaryGt: 50,
1836
- primaryGte: 50,
1837
- primaryLt: 50,
1838
- primaryLte: 50,
1839
- like: 30,
1840
- notEqual: 10,
1841
- primaryNotEqual: 10
1842
- };
1843
- /**
1844
- * Selects the best driver tree from multiple tree/condition pairs.
1845
- * Uses rule-based optimization to choose the tree with highest estimated selectivity.
1846
- *
1847
- * @param candidates Array of { tree, condition } pairs to evaluate
1848
- * @returns The candidate with highest priority condition, or null if empty
1849
- *
1850
- * @example
1851
- * ```typescript
1852
- * const driver = BPTreeSync.chooseDriver([
1853
- * { tree: idxId, condition: { equal: 100 } },
1854
- * { tree: idxAge, condition: { gt: 20 } }
1855
- * ])
1856
- * // Returns { tree: idxId, condition: { equal: 100 } } because 'equal' has higher priority
1857
- * ```
1858
- */
1859
- static ChooseDriver(candidates) {
1860
- if (candidates.length === 0) return null;
1861
- if (candidates.length === 1) return candidates[0];
1862
- let best = candidates[0];
1863
- let bestScore = 0;
1864
- for (const candidate of candidates) {
1865
- let score = 0;
1866
- for (const key in candidate.condition) {
1867
- const condKey = key;
1868
- const priority = _BPTreeTransaction.conditionPriority[condKey] ?? 0;
1869
- if (priority > score) {
1870
- score = priority;
1871
- }
1872
- }
1873
- if (score > bestScore) {
1874
- bestScore = score;
1875
- best = candidate;
1876
- }
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;
1877
1919
  }
1878
- return best;
1879
1920
  }
1880
- /**
1881
- * Checks for conflicts between multiple transactions.
1882
- *
1883
- * @param transactions Array of BPTreeTransaction instances to check
1884
- * @returns An array of keys that are in conflict. Empty array if no conflicts.
1885
- */
1886
- static CheckConflicts(transactions) {
1887
- 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
+ }
1888
1928
  }
1889
- /**
1890
- * Returns the ID of the root node.
1891
- * @returns The root node ID.
1892
- */
1893
- getRootId() {
1894
- 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
+ }
1895
1938
  }
1896
- /**
1897
- * Returns the order of the B+Tree.
1898
- * @returns The order of the tree.
1899
- */
1900
- getOrder() {
1901
- 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}`);
1902
1977
  }
1903
- /**
1904
- * Verified if the value satisfies the condition.
1905
- *
1906
- * @param nodeValue The value to verify.
1907
- * @param condition The condition to verify against.
1908
- * @returns Returns true if the value satisfies the condition.
1909
- */
1910
- verify(nodeValue, condition) {
1911
- for (const key in condition) {
1912
- const verify = this.verifierMap[key];
1913
- const condValue = condition[key];
1914
- if (!verify(nodeValue, condValue)) {
1915
- return false;
1916
- }
1917
- }
1918
- return true;
1978
+ const guessNode = insertableNode[key];
1979
+ if (!guessNode) {
1980
+ return null;
1919
1981
  }
1920
- /**
1921
- * Inserts a key-value pair into an already-cloned leaf node in-place.
1922
- * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
1923
- * Used by batchInsert to batch multiple insertions with a single clone/update.
1924
- * @returns true if the leaf was modified, false if the key already exists.
1925
- */
1926
- _insertValueIntoLeaf(leaf, key, value) {
1927
- if (leaf.values.length) {
1928
- const { index, found } = this._binarySearchValues(leaf.values, value);
1929
- if (found) {
1930
- if (leaf.keys[index].includes(key)) {
1931
- 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];
1932
2013
  }
1933
- leaf.keys[index].push(key);
1934
- return true;
1935
2014
  }
1936
- leaf.values.splice(index, 0, value);
1937
- leaf.keys.splice(index, 0, [key]);
1938
- return true;
1939
2015
  } else {
1940
- leaf.values = [value];
1941
- leaf.keys = [[key]];
1942
- 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
+ }
1943
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;
1944
2069
  }
1945
- _cloneNode(node) {
1946
- 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
+ }
1947
2176
  }
1948
- /**
1949
- * Resolves the best start/end configuration by independently examining
1950
- * all conditions. Selects the tightest lower bound for start and the
1951
- * tightest upper bound for end (in asc; reversed for desc).
1952
- *
1953
- * @param condition The condition to analyze.
1954
- * @param order The sort order ('asc' or 'desc').
1955
- * @returns The resolved start/end keys, values, and traversal direction.
1956
- */
1957
- resolveStartEndConfigs(condition, order) {
1958
- const direction = order === "asc" ? 1 : -1;
1959
- const startCandidates = order === "asc" ? _BPTreeTransaction._lowerBoundKeys : _BPTreeTransaction._upperBoundKeys;
1960
- const endCandidates = order === "asc" ? _BPTreeTransaction._upperBoundKeys : _BPTreeTransaction._lowerBoundKeys;
1961
- let startKey = null;
1962
- let endKey = null;
1963
- 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 = [];
1964
3033
  let endValues = [];
1965
3034
  for (let i = 0, len = startCandidates.length; i < len; i++) {
1966
3035
  const key = startCandidates[i];
@@ -2095,6 +3164,10 @@ var BPTreeTransaction = class _BPTreeTransaction {
2095
3164
 
2096
3165
  // src/transaction/BPTreeSyncTransaction.ts
2097
3166
  var BPTreeSyncTransaction = class extends BPTreeTransaction {
3167
+ _ops;
3168
+ _ctx;
3169
+ _verifierMapCached;
3170
+ _searchConfigsCached;
2098
3171
  constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
2099
3172
  super(
2100
3173
  rootTx,
@@ -2104,248 +3177,113 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2104
3177
  comparator,
2105
3178
  option
2106
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);
2107
3238
  }
3239
+ // ─── Legacy protected methods (delegating to ops) ────────────────
2108
3240
  getNode(id) {
2109
- return this.mvcc.read(id);
3241
+ return this._ops.getNode(id);
2110
3242
  }
2111
- /**
2112
- * Create a new node with a unique ID.
2113
- */
2114
3243
  _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
2115
- const id = this.strategy.id(leaf);
2116
- const node = {
2117
- id,
2118
- keys,
2119
- values,
2120
- leaf,
2121
- parent,
2122
- next,
2123
- prev
2124
- };
2125
- this.mvcc.create(id, node);
2126
- return node;
3244
+ return this._ops.createNode(leaf, keys, values, parent, next, prev);
2127
3245
  }
2128
3246
  _updateNode(node) {
2129
- if (this.mvcc.isDeleted(node.id)) {
2130
- return;
2131
- }
2132
- this.mvcc.write(node.id, node);
3247
+ this._ops.updateNode(node);
2133
3248
  }
2134
3249
  _deleteNode(node) {
2135
- if (this.mvcc.isDeleted(node.id)) {
2136
- return;
2137
- }
2138
- this.mvcc.delete(node.id);
3250
+ this._ops.deleteNode(node);
2139
3251
  }
2140
3252
  _readHead() {
2141
- return this.mvcc.read("__HEAD__");
3253
+ return this._ops.readHead();
2142
3254
  }
2143
3255
  _writeHead(head) {
2144
- if (!this.mvcc.exists("__HEAD__")) {
2145
- this.mvcc.create("__HEAD__", head);
2146
- } else {
2147
- this.mvcc.write("__HEAD__", head);
2148
- }
2149
- this.rootId = head.root;
3256
+ this._ops.writeHead(head);
2150
3257
  }
3258
+ // ─── Tree traversal (delegating to algorithm) ────────────────────
2151
3259
  _insertAtLeaf(node, key, value) {
2152
- let leaf = node;
2153
- if (leaf.values.length) {
2154
- for (let i = 0, len = leaf.values.length; i < len; i++) {
2155
- const nValue = leaf.values[i];
2156
- if (this.comparator.isSame(value, nValue)) {
2157
- const keys = leaf.keys[i];
2158
- if (keys.includes(key)) {
2159
- break;
2160
- }
2161
- leaf = this._cloneNode(leaf);
2162
- leaf.keys[i].push(key);
2163
- this._updateNode(leaf);
2164
- return leaf;
2165
- } else if (this.comparator.isLower(value, nValue)) {
2166
- leaf = this._cloneNode(leaf);
2167
- leaf.values.splice(i, 0, value);
2168
- leaf.keys.splice(i, 0, [key]);
2169
- this._updateNode(leaf);
2170
- return leaf;
2171
- } else if (i + 1 === leaf.values.length) {
2172
- leaf = this._cloneNode(leaf);
2173
- leaf.values.push(value);
2174
- leaf.keys.push([key]);
2175
- this._updateNode(leaf);
2176
- return leaf;
2177
- }
2178
- }
2179
- } else {
2180
- leaf = this._cloneNode(leaf);
2181
- leaf.values = [value];
2182
- leaf.keys = [[key]];
2183
- this._updateNode(leaf);
2184
- return leaf;
2185
- }
2186
- return leaf;
3260
+ return insertAtLeaf(this._ops, node, key, value, this.comparator);
2187
3261
  }
2188
3262
  _insertInParent(node, value, newSiblingNode) {
2189
- if (this.rootId === node.id) {
2190
- node = this._cloneNode(node);
2191
- newSiblingNode = this._cloneNode(newSiblingNode);
2192
- const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
2193
- this.rootId = root.id;
2194
- node.parent = root.id;
2195
- newSiblingNode.parent = root.id;
2196
- if (newSiblingNode.leaf) {
2197
- node.next = newSiblingNode.id;
2198
- newSiblingNode.prev = node.id;
2199
- }
2200
- this._writeHead({
2201
- root: root.id,
2202
- order: this.order,
2203
- data: this.strategy.head.data
2204
- });
2205
- this._updateNode(node);
2206
- this._updateNode(newSiblingNode);
2207
- return;
2208
- }
2209
- const parentNode = this._cloneNode(this.getNode(node.parent));
2210
- const nodeIndex = parentNode.keys.indexOf(node.id);
2211
- if (nodeIndex === -1) {
2212
- throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2213
- }
2214
- parentNode.values.splice(nodeIndex, 0, value);
2215
- parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
2216
- newSiblingNode = this._cloneNode(newSiblingNode);
2217
- newSiblingNode.parent = parentNode.id;
2218
- if (newSiblingNode.leaf) {
2219
- const leftSibling = this._cloneNode(node);
2220
- const oldNextId = leftSibling.next;
2221
- newSiblingNode.prev = leftSibling.id;
2222
- newSiblingNode.next = oldNextId;
2223
- leftSibling.next = newSiblingNode.id;
2224
- this._updateNode(leftSibling);
2225
- if (oldNextId) {
2226
- const oldNext = this._cloneNode(this.getNode(oldNextId));
2227
- oldNext.prev = newSiblingNode.id;
2228
- this._updateNode(oldNext);
2229
- }
2230
- }
2231
- this._updateNode(parentNode);
2232
- this._updateNode(newSiblingNode);
2233
- if (parentNode.keys.length > this.order) {
2234
- const newSiblingNodeRecursive = this._createNode(false, [], []);
2235
- newSiblingNodeRecursive.parent = parentNode.parent;
2236
- const mid = Math.ceil(this.order / 2) - 1;
2237
- newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
2238
- newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
2239
- const midValue = parentNode.values[mid];
2240
- parentNode.values = parentNode.values.slice(0, mid);
2241
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
2242
- for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
2243
- const k = newSiblingNodeRecursive.keys[i];
2244
- const n = this._cloneNode(this.getNode(k));
2245
- n.parent = newSiblingNodeRecursive.id;
2246
- this._updateNode(n);
2247
- }
2248
- this._updateNode(parentNode);
2249
- this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
2250
- }
3263
+ insertInParent(this._ops, this._ctx, node, value, newSiblingNode);
2251
3264
  }
2252
3265
  locateLeaf(value) {
2253
- let node = this.getNode(this.rootId);
2254
- while (!node.leaf) {
2255
- const { index } = this._binarySearchValues(node.values, value, false, true);
2256
- node = this.getNode(node.keys[index]);
2257
- }
2258
- return node;
3266
+ return locateLeaf(this._ops, this._ctx.rootId, value, this.comparator);
2259
3267
  }
2260
3268
  findLowerBoundLeaf(value) {
2261
- let node = this.getNode(this.rootId);
2262
- while (!node.leaf) {
2263
- const { index } = this._binarySearchValues(node.values, value, true, false);
2264
- node = this.getNode(node.keys[index]);
2265
- }
2266
- return node;
3269
+ return findLowerBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
2267
3270
  }
2268
3271
  findUpperBoundLeaf(value) {
2269
- let node = this.getNode(this.rootId);
2270
- while (!node.leaf) {
2271
- const { index } = this._binarySearchValues(node.values, value, true, true);
2272
- node = this.getNode(node.keys[index]);
2273
- }
2274
- return node;
3272
+ return findUpperBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
2275
3273
  }
2276
3274
  findOuterBoundaryLeaf(value, direction) {
2277
- const insertableNode = direction === -1 ? this.findLowerBoundLeaf(value) : this.findUpperBoundLeaf(value);
2278
- let key;
2279
- switch (direction) {
2280
- case -1:
2281
- key = "prev";
2282
- break;
2283
- case 1:
2284
- key = "next";
2285
- break;
2286
- default:
2287
- throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
2288
- }
2289
- const guessNode = insertableNode[key];
2290
- if (!guessNode) {
2291
- return null;
2292
- }
2293
- return this.getNode(guessNode);
3275
+ return findOuterBoundaryLeaf(this._ops, this._ctx.rootId, value, direction, this.comparator);
2294
3276
  }
2295
3277
  leftestNode() {
2296
- let node = this.getNode(this.rootId);
2297
- if (node === null) {
2298
- debugger;
2299
- }
2300
- while (!node.leaf) {
2301
- const keys = node.keys;
2302
- node = this.getNode(keys[0]);
2303
- }
2304
- return node;
3278
+ return leftestNode(this._ops, this._ctx.rootId);
2305
3279
  }
2306
3280
  rightestNode() {
2307
- let node = this.getNode(this.rootId);
2308
- while (!node.leaf) {
2309
- const keys = node.keys;
2310
- node = this.getNode(keys[keys.length - 1]);
2311
- }
2312
- return node;
3281
+ return rightestNode(this._ops, this._ctx.rootId);
2313
3282
  }
2314
3283
  *getPairsGenerator(startNode, endNode, direction) {
2315
- let node = startNode;
2316
- while (true) {
2317
- if (endNode && node.id === endNode.id) {
2318
- break;
2319
- }
2320
- const len = node.values.length;
2321
- if (direction === 1) {
2322
- for (let i = 0; i < len; i++) {
2323
- const nValue = node.values[i];
2324
- const keys = node.keys[i];
2325
- for (let j = 0, len2 = keys.length; j < len2; j++) {
2326
- yield [keys[j], nValue];
2327
- }
2328
- }
2329
- } else {
2330
- let i = len;
2331
- while (i--) {
2332
- const nValue = node.values[i];
2333
- const keys = node.keys[i];
2334
- let j = keys.length;
2335
- while (j--) {
2336
- yield [keys[j], nValue];
2337
- }
2338
- }
2339
- }
2340
- if (direction === 1) {
2341
- if (!node.next) break;
2342
- node = this.getNode(node.next);
2343
- } else {
2344
- if (!node.prev) break;
2345
- node = this.getNode(node.prev);
2346
- }
2347
- }
3284
+ yield* getPairsGenerator(this._ops, startNode, endNode, direction);
2348
3285
  }
3286
+ // ─── Lifecycle ───────────────────────────────────────────────────
2349
3287
  init() {
2350
3288
  if (this.rootTx !== this) {
2351
3289
  throw new Error("Cannot call init on a nested transaction");
@@ -2362,534 +3300,92 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2362
3300
  this.isInitialized = true;
2363
3301
  try {
2364
3302
  this._clearCache();
2365
- const head = this._readHead();
2366
- if (head === null) {
2367
- this.order = this.strategy.order;
2368
- const root = this._createNode(true, [], []);
2369
- this._writeHead({
2370
- root: root.id,
2371
- order: this.order,
2372
- data: this.strategy.head.data
2373
- });
2374
- } else {
2375
- const { root, order } = head;
2376
- this.strategy.head = head;
2377
- this.order = order;
2378
- this.rootId = root;
2379
- }
2380
- if (this.order < 3) {
2381
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2382
- }
2383
- } catch (e) {
2384
- this.isInitialized = false;
2385
- throw e;
2386
- }
2387
- }
2388
- reload() {
2389
- if (this.rootTx !== this) {
2390
- throw new Error("Cannot call reload on a nested transaction");
2391
- }
2392
- this._reloadInternal();
2393
- }
2394
- _reloadInternal() {
2395
- this._resetForReload();
2396
- this._initInternal();
2397
- }
2398
- exists(key, value) {
2399
- const node = this.locateLeaf(value);
2400
- const { index, found } = this._binarySearchValues(node.values, value);
2401
- if (found) {
2402
- const keys = node.keys[index];
2403
- if (keys.includes(key)) {
2404
- return true;
2405
- }
2406
- }
2407
- return false;
2408
- }
2409
- get(key) {
2410
- let node = this.leftestNode();
2411
- while (true) {
2412
- for (let i = 0, len = node.values.length; i < len; i++) {
2413
- const keys = node.keys[i];
2414
- for (let j = 0, len2 = keys.length; j < len2; j++) {
2415
- if (keys[j] === key) {
2416
- return node.values[i];
2417
- }
2418
- }
2419
- }
2420
- if (!node.next) break;
2421
- node = this.getNode(node.next);
2422
- }
2423
- return void 0;
2424
- }
2425
- *keysStream(condition, options) {
2426
- const { filterValues, limit, order = "asc" } = options ?? {};
2427
- const stream = this.whereStream(condition, options);
2428
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2429
- let count = 0;
2430
- for (const [key] of stream) {
2431
- if (intersection && !intersection.has(key)) {
2432
- continue;
2433
- }
2434
- yield key;
2435
- count++;
2436
- if (limit !== void 0 && count >= limit) {
2437
- break;
2438
- }
2439
- }
2440
- }
2441
- *whereStream(condition, options) {
2442
- const { filterValues, limit, order = "asc" } = options ?? {};
2443
- const conditionKeys = Object.keys(condition);
2444
- if (conditionKeys.length === 0) return;
2445
- const resolved = this.resolveStartEndConfigs(condition, order);
2446
- const direction = resolved.direction;
2447
- let startNode;
2448
- if (resolved.startKey) {
2449
- const startConfig = this.searchConfigs[resolved.startKey][order];
2450
- startNode = startConfig.start(this, resolved.startValues);
2451
- } else {
2452
- startNode = order === "asc" ? this.leftestNode() : this.rightestNode();
2453
- }
2454
- let endNode = null;
2455
- if (resolved.endKey) {
2456
- const endConfig = this.searchConfigs[resolved.endKey][order];
2457
- endNode = endConfig.end(this, resolved.endValues);
2458
- }
2459
- if (!startNode) return;
2460
- const generator = this.getPairsGenerator(
2461
- startNode,
2462
- endNode,
2463
- direction
2464
- );
2465
- let count = 0;
2466
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2467
- for (const pair of generator) {
2468
- const [k, v] = pair;
2469
- if (intersection && !intersection.has(k)) {
2470
- continue;
2471
- }
2472
- if (this.verify(v, condition)) {
2473
- yield pair;
2474
- count++;
2475
- if (limit !== void 0 && count >= limit) {
2476
- break;
2477
- }
2478
- }
2479
- }
2480
- }
2481
- keys(condition, options) {
2482
- const set = /* @__PURE__ */ new Set();
2483
- for (const key of this.keysStream(condition, options)) {
2484
- set.add(key);
2485
- }
2486
- return set;
2487
- }
2488
- where(condition, options) {
2489
- const map = /* @__PURE__ */ new Map();
2490
- for (const [key, value] of this.whereStream(condition, options)) {
2491
- map.set(key, value);
2492
- }
2493
- return map;
2494
- }
2495
- insert(key, value) {
2496
- let before = this.locateLeaf(value);
2497
- before = this._insertAtLeaf(before, key, value);
2498
- if (before.values.length === this.order) {
2499
- let after = this._createNode(
2500
- true,
2501
- [],
2502
- [],
2503
- before.parent,
2504
- null,
2505
- null
2506
- );
2507
- const mid = Math.ceil(this.order / 2) - 1;
2508
- after = this._cloneNode(after);
2509
- after.values = before.values.slice(mid + 1);
2510
- after.keys = before.keys.slice(mid + 1);
2511
- before.values = before.values.slice(0, mid + 1);
2512
- before.keys = before.keys.slice(0, mid + 1);
2513
- this._updateNode(before);
2514
- this._updateNode(after);
2515
- this._insertInParent(before, after.values[0], after);
2516
- }
2517
- }
2518
- batchInsert(entries) {
2519
- if (entries.length === 0) return;
2520
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2521
- let currentLeaf = null;
2522
- let modified = false;
2523
- let cachedLeafId = null;
2524
- let cachedLeafMaxValue = null;
2525
- for (let i = 0, len = sorted.length; i < len; i++) {
2526
- const [key, value] = sorted[i];
2527
- let targetLeaf;
2528
- if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
2529
- targetLeaf = currentLeaf;
2530
- } else {
2531
- targetLeaf = this.locateLeaf(value);
2532
- }
2533
- if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2534
- } else {
2535
- if (currentLeaf !== null && modified) {
2536
- this._updateNode(currentLeaf);
2537
- }
2538
- currentLeaf = this._cloneNode(targetLeaf);
2539
- modified = false;
2540
- }
2541
- cachedLeafId = currentLeaf.id;
2542
- const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2543
- modified = modified || changed;
2544
- cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
2545
- if (currentLeaf.values.length === this.order) {
2546
- this._updateNode(currentLeaf);
2547
- let after = this._createNode(
2548
- true,
2549
- [],
2550
- [],
2551
- currentLeaf.parent,
2552
- null,
2553
- null
2554
- );
2555
- const mid = Math.ceil(this.order / 2) - 1;
2556
- after = this._cloneNode(after);
2557
- after.values = currentLeaf.values.slice(mid + 1);
2558
- after.keys = currentLeaf.keys.slice(mid + 1);
2559
- currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
2560
- currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
2561
- this._updateNode(currentLeaf);
2562
- this._updateNode(after);
2563
- this._insertInParent(currentLeaf, after.values[0], after);
2564
- currentLeaf = null;
2565
- cachedLeafId = null;
2566
- cachedLeafMaxValue = null;
2567
- modified = false;
2568
- }
2569
- }
2570
- if (currentLeaf !== null && modified) {
2571
- this._updateNode(currentLeaf);
2572
- }
2573
- }
2574
- bulkLoad(entries) {
2575
- if (entries.length === 0) return;
2576
- const root = this.getNode(this.rootId);
2577
- if (!root.leaf || root.values.length > 0) {
2578
- throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
2579
- }
2580
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2581
- const grouped = [];
2582
- for (let i = 0, len = sorted.length; i < len; i++) {
2583
- const [key, value] = sorted[i];
2584
- const last = grouped[grouped.length - 1];
2585
- if (last && this.comparator.isSame(last.value, value)) {
2586
- if (!last.keys.includes(key)) {
2587
- last.keys.push(key);
2588
- }
2589
- } else {
2590
- grouped.push({ keys: [key], value });
2591
- }
2592
- }
2593
- this._deleteNode(root);
2594
- const maxLeafSize = this.order - 1;
2595
- const leaves = [];
2596
- for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
2597
- const chunk = grouped.slice(i, i + maxLeafSize);
2598
- const leafKeys = chunk.map((g) => g.keys);
2599
- const leafValues = chunk.map((g) => g.value);
2600
- const leaf = this._createNode(
2601
- true,
2602
- leafKeys,
2603
- leafValues,
2604
- null,
2605
- null,
2606
- null
2607
- );
2608
- leaves.push(leaf);
2609
- }
2610
- for (let i = 0, len = leaves.length; i < len; i++) {
2611
- if (i > 0) {
2612
- leaves[i].prev = leaves[i - 1].id;
2613
- }
2614
- if (i < len - 1) {
2615
- leaves[i].next = leaves[i + 1].id;
2616
- }
2617
- this._updateNode(leaves[i]);
2618
- }
2619
- let currentLevel = leaves;
2620
- while (currentLevel.length > 1) {
2621
- const nextLevel = [];
2622
- for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
2623
- const children = currentLevel.slice(i, i + this.order);
2624
- const childIds = children.map((c) => c.id);
2625
- const separators = [];
2626
- for (let j = 1, len2 = children.length; j < len2; j++) {
2627
- separators.push(children[j].values[0]);
2628
- }
2629
- const internalNode = this._createNode(
2630
- false,
2631
- childIds,
2632
- separators,
2633
- null,
2634
- null,
2635
- null
2636
- );
2637
- for (let j = 0, len2 = children.length; j < len2; j++) {
2638
- const child = children[j];
2639
- child.parent = internalNode.id;
2640
- this._updateNode(child);
2641
- }
2642
- nextLevel.push(internalNode);
2643
- }
2644
- currentLevel = nextLevel;
2645
- }
2646
- const newRoot = currentLevel[0];
2647
- this._writeHead({
2648
- root: newRoot.id,
2649
- order: this.order,
2650
- data: this.strategy.head.data
2651
- });
2652
- }
2653
- _deleteEntry(node, key) {
2654
- if (!node.leaf) {
2655
- let keyIndex = -1;
2656
- for (let i = 0, len = node.keys.length; i < len; i++) {
2657
- if (node.keys[i] === key) {
2658
- keyIndex = i;
2659
- break;
2660
- }
2661
- }
2662
- if (keyIndex !== -1) {
2663
- node = this._cloneNode(node);
2664
- node.keys.splice(keyIndex, 1);
2665
- const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2666
- node.values.splice(valueIndex, 1);
2667
- this._updateNode(node);
2668
- }
2669
- }
2670
- if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
2671
- const keys = node.keys;
2672
- this._deleteNode(node);
2673
- const newRoot = this._cloneNode(this.getNode(keys[0]));
2674
- newRoot.parent = null;
2675
- this._updateNode(newRoot);
2676
- this._writeHead({
2677
- root: newRoot.id,
2678
- order: this.order,
2679
- data: this.strategy.head.data
2680
- });
2681
- return node;
2682
- } else if (this.rootId === node.id) {
2683
- this._writeHead({
2684
- root: node.id,
2685
- order: this.order,
2686
- data: this.strategy.head.data
2687
- });
2688
- return node;
2689
- } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
2690
- if (node.parent === null) {
2691
- return node;
2692
- }
2693
- let isPredecessor = false;
2694
- let parentNode = this.getNode(node.parent);
2695
- let prevNode = null;
2696
- let nextNode = null;
2697
- let prevValue = null;
2698
- let postValue = null;
2699
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2700
- const nKey = parentNode.keys[i];
2701
- if (nKey === node.id) {
2702
- if (i > 0) {
2703
- prevNode = this.getNode(parentNode.keys[i - 1]);
2704
- prevValue = parentNode.values[i - 1];
2705
- }
2706
- if (i < parentNode.keys.length - 1) {
2707
- nextNode = this.getNode(parentNode.keys[i + 1]);
2708
- postValue = parentNode.values[i];
2709
- }
2710
- }
2711
- }
2712
- let siblingNode;
2713
- let guess;
2714
- if (prevNode === null) {
2715
- siblingNode = nextNode;
2716
- guess = postValue;
2717
- } else if (nextNode === null) {
2718
- isPredecessor = true;
2719
- siblingNode = prevNode;
2720
- guess = prevValue;
2721
- } else {
2722
- if (node.values.length + nextNode.values.length < this.order) {
2723
- siblingNode = nextNode;
2724
- guess = postValue;
2725
- } else {
2726
- isPredecessor = true;
2727
- siblingNode = prevNode;
2728
- guess = prevValue;
2729
- }
2730
- }
2731
- if (!siblingNode) {
2732
- return node;
2733
- }
2734
- node = this._cloneNode(node);
2735
- siblingNode = this._cloneNode(siblingNode);
2736
- if (node.values.length + siblingNode.values.length < this.order) {
2737
- if (!isPredecessor) {
2738
- const pTemp = siblingNode;
2739
- siblingNode = node;
2740
- node = pTemp;
2741
- }
2742
- siblingNode.keys.push(...node.keys);
2743
- if (!node.leaf) {
2744
- siblingNode.values.push(guess);
2745
- } else {
2746
- siblingNode.next = node.next;
2747
- if (siblingNode.next) {
2748
- const n = this._cloneNode(this.getNode(siblingNode.next));
2749
- n.prev = siblingNode.id;
2750
- this._updateNode(n);
2751
- }
2752
- }
2753
- siblingNode.values.push(...node.values);
2754
- if (!siblingNode.leaf) {
2755
- const keys = siblingNode.keys;
2756
- for (let i = 0, len = keys.length; i < len; i++) {
2757
- const key2 = keys[i];
2758
- const node2 = this._cloneNode(this.getNode(key2));
2759
- node2.parent = siblingNode.id;
2760
- this._updateNode(node2);
2761
- }
2762
- }
2763
- this._deleteNode(node);
2764
- this._updateNode(siblingNode);
2765
- this._deleteEntry(this.getNode(node.parent), node.id);
2766
- } else {
2767
- if (isPredecessor) {
2768
- let pointerPm;
2769
- let pointerKm;
2770
- if (!node.leaf) {
2771
- pointerPm = siblingNode.keys.splice(-1)[0];
2772
- pointerKm = siblingNode.values.splice(-1)[0];
2773
- node.keys = [pointerPm, ...node.keys];
2774
- node.values = [guess, ...node.values];
2775
- parentNode = this._cloneNode(this.getNode(node.parent));
2776
- const nodeIndex = parentNode.keys.indexOf(node.id);
2777
- if (nodeIndex > 0) {
2778
- parentNode.values[nodeIndex - 1] = pointerKm;
2779
- this._updateNode(parentNode);
2780
- }
2781
- } else {
2782
- pointerPm = siblingNode.keys.splice(-1)[0];
2783
- pointerKm = siblingNode.values.splice(-1)[0];
2784
- node.keys = [pointerPm, ...node.keys];
2785
- node.values = [pointerKm, ...node.values];
2786
- parentNode = this._cloneNode(this.getNode(node.parent));
2787
- const nodeIndex = parentNode.keys.indexOf(node.id);
2788
- if (nodeIndex > 0) {
2789
- parentNode.values[nodeIndex - 1] = pointerKm;
2790
- this._updateNode(parentNode);
2791
- }
2792
- }
2793
- this._updateNode(node);
2794
- this._updateNode(siblingNode);
2795
- } else {
2796
- let pointerP0;
2797
- let pointerK0;
2798
- if (!node.leaf) {
2799
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
2800
- pointerK0 = siblingNode.values.splice(0, 1)[0];
2801
- node.keys = [...node.keys, pointerP0];
2802
- node.values = [...node.values, guess];
2803
- parentNode = this._cloneNode(this.getNode(node.parent));
2804
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2805
- if (pointerIndex > 0) {
2806
- parentNode.values[pointerIndex - 1] = pointerK0;
2807
- this._updateNode(parentNode);
2808
- }
2809
- } else {
2810
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
2811
- pointerK0 = siblingNode.values.splice(0, 1)[0];
2812
- node.keys = [...node.keys, pointerP0];
2813
- node.values = [...node.values, pointerK0];
2814
- parentNode = this._cloneNode(this.getNode(node.parent));
2815
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2816
- if (pointerIndex > 0) {
2817
- parentNode.values[pointerIndex - 1] = siblingNode.values[0];
2818
- this._updateNode(parentNode);
2819
- }
2820
- }
2821
- this._updateNode(node);
2822
- this._updateNode(siblingNode);
2823
- }
2824
- if (!siblingNode.leaf) {
2825
- for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
2826
- const key2 = siblingNode.keys[i];
2827
- const n = this._cloneNode(this.getNode(key2));
2828
- n.parent = siblingNode.id;
2829
- this._updateNode(n);
2830
- }
2831
- }
2832
- if (!node.leaf) {
2833
- for (let i = 0, len = node.keys.length; i < len; i++) {
2834
- const key2 = node.keys[i];
2835
- const n = this._cloneNode(this.getNode(key2));
2836
- n.parent = node.id;
2837
- this._updateNode(n);
2838
- }
2839
- }
2840
- if (!parentNode.leaf) {
2841
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2842
- const key2 = parentNode.keys[i];
2843
- const n = this._cloneNode(this.getNode(key2));
2844
- n.parent = parentNode.id;
2845
- this._updateNode(n);
2846
- }
3303
+ initOp(
3304
+ this._ops,
3305
+ this._ctx,
3306
+ this.strategy.order,
3307
+ this.strategy.head,
3308
+ (head) => {
3309
+ this.strategy.head = head;
2847
3310
  }
2848
- }
2849
- } else {
2850
- this._updateNode(this._cloneNode(node));
3311
+ );
3312
+ } catch (e) {
3313
+ this.isInitialized = false;
3314
+ throw e;
2851
3315
  }
2852
- return node;
2853
3316
  }
2854
- delete(key, value) {
2855
- if (value === void 0) {
2856
- value = this.get(key);
3317
+ reload() {
3318
+ if (this.rootTx !== this) {
3319
+ throw new Error("Cannot call reload on a nested transaction");
2857
3320
  }
2858
- if (value === void 0) {
2859
- 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);
2860
3362
  }
2861
- let node = this.findLowerBoundLeaf(value);
2862
- let found = false;
2863
- while (true) {
2864
- let i = node.values.length;
2865
- while (i--) {
2866
- const nValue = node.values[i];
2867
- if (this.comparator.isSame(value, nValue)) {
2868
- const keys = node.keys[i];
2869
- const keyIndex = keys.indexOf(key);
2870
- if (keyIndex !== -1) {
2871
- node = this._cloneNode(node);
2872
- const freshKeys = node.keys[i];
2873
- freshKeys.splice(keyIndex, 1);
2874
- if (freshKeys.length === 0) {
2875
- node.keys.splice(i, 1);
2876
- node.values.splice(i, 1);
2877
- }
2878
- this._updateNode(node);
2879
- node = this._deleteEntry(node, key);
2880
- found = true;
2881
- break;
2882
- }
2883
- }
2884
- }
2885
- if (found) break;
2886
- if (node.next) {
2887
- node = this.getNode(node.next);
2888
- continue;
2889
- }
2890
- 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);
2891
3369
  }
3370
+ return map;
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);
2892
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 ───────────────────────────────────────────────────
2893
3389
  getHeadData() {
2894
3390
  const head = this._readHead();
2895
3391
  if (head === null) {
@@ -2908,6 +3404,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2908
3404
  data
2909
3405
  });
2910
3406
  }
3407
+ // ─── Transaction ─────────────────────────────────────────────────
2911
3408
  commit(label) {
2912
3409
  let result = this.mvcc.commit(label);
2913
3410
  if (result.success) {
@@ -3227,71 +3724,878 @@ var Ryoiki2 = class _Ryoiki2 {
3227
3724
  rangeTask: [Array, Function],
3228
3725
  rangeTaskTimeout: [Array, Function, Number]
3229
3726
  }
3230
- );
3231
- return this._lock(
3232
- this.readQueue,
3233
- range,
3234
- timeout,
3235
- task,
3236
- () => !this.rangeOverlapping(this.writings, range)
3237
- );
3238
- }
3239
- /**
3240
- * Internal implementation of the write lock. Handles both overloads.
3241
- * @template T - The return type of the task.
3242
- * @param arg0 - Either a range or a task callback.
3243
- * If a range is provided, the task is the second argument.
3244
- * @param arg1 - The task to execute, required if a range is provided.
3245
- * @param arg2 - The timeout for acquiring the lock.
3246
- * If the lock cannot be acquired within this period, an error will be thrown.
3247
- * If this value is not provided, no timeout will be set.
3248
- * @returns A promise resolving to the result of the task execution.
3249
- */
3250
- writeLock(arg0, arg1, arg2) {
3251
- const [range, task, timeout] = this._handleOverload(
3252
- [arg0, arg1, arg2],
3253
- {
3254
- rangeTask: (range2, task2) => [range2, task2, -1],
3255
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3256
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3257
- 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
3258
3998
  },
3259
- {
3260
- task: [Function],
3261
- taskTimeout: [Function, Number],
3262
- rangeTask: [Array, Function],
3263
- rangeTaskTimeout: [Array, Function, Number]
3999
+ desc: {
4000
+ start: (r, ops) => rightestNodeAsync(ops, r),
4001
+ end: async () => null,
4002
+ direction: -1,
4003
+ earlyTerminate: false
3264
4004
  }
3265
- );
3266
- return this._lock(
3267
- this.writeQueue,
3268
- range,
3269
- timeout,
3270
- task,
3271
- () => {
3272
- 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
+ }
3273
4071
  }
3274
- );
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
+ }
3275
4089
  }
3276
- /**
3277
- * Releases a read lock by its lock ID.
3278
- * @param lockId - The unique identifier for the lock to release.
3279
- */
3280
- readUnlock(lockId) {
3281
- 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;
3282
4122
  }
3283
- /**
3284
- * Releases a write lock by its lock ID.
3285
- * @param lockId - The unique identifier for the lock to release.
3286
- */
3287
- writeUnlock(lockId) {
3288
- 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
+ }
3289
4215
  }
3290
- };
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
+ }
3291
4591
 
3292
4592
  // src/transaction/BPTreeAsyncTransaction.ts
3293
4593
  var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3294
4594
  lock;
4595
+ _ops;
4596
+ _ctx;
4597
+ _verifierMapCached;
4598
+ _searchConfigsCached;
3295
4599
  constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
3296
4600
  super(
3297
4601
  rootTx,
@@ -3302,6 +4606,64 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3302
4606
  option
3303
4607
  );
3304
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);
3305
4667
  }
3306
4668
  async writeLock(id, fn) {
3307
4669
  let lockId;
@@ -3312,256 +4674,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3312
4674
  this.lock.writeUnlock(lockId);
3313
4675
  });
3314
4676
  }
4677
+ // ─── Legacy protected methods (delegating to ops) ────────────────
3315
4678
  async getNode(id) {
3316
- return await this.mvcc.read(id);
4679
+ return this._ops.getNode(id);
3317
4680
  }
3318
- /**
3319
- * Create a new node with a unique ID.
3320
- */
3321
4681
  async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
3322
- const id = await this.strategy.id(leaf);
3323
- const node = {
3324
- id,
3325
- keys,
3326
- values,
3327
- leaf,
3328
- parent,
3329
- next,
3330
- prev
3331
- };
3332
- await this.mvcc.create(id, node);
3333
- return node;
4682
+ return this._ops.createNode(leaf, keys, values, parent, next, prev);
3334
4683
  }
3335
4684
  async _updateNode(node) {
3336
- if (this.mvcc.isDeleted(node.id)) {
3337
- return;
3338
- }
3339
- await this.mvcc.write(node.id, node);
4685
+ await this._ops.updateNode(node);
3340
4686
  }
3341
4687
  async _deleteNode(node) {
3342
- if (this.mvcc.isDeleted(node.id)) {
3343
- return;
3344
- }
3345
- await this.mvcc.delete(node.id);
4688
+ await this._ops.deleteNode(node);
3346
4689
  }
3347
4690
  async _readHead() {
3348
- return await this.mvcc.read("__HEAD__");
4691
+ return this._ops.readHead();
3349
4692
  }
3350
4693
  async _writeHead(head) {
3351
- if (!await this.mvcc.exists("__HEAD__")) {
3352
- await this.mvcc.create("__HEAD__", head);
3353
- } else {
3354
- await this.mvcc.write("__HEAD__", head);
3355
- }
3356
- this.rootId = head.root;
4694
+ await this._ops.writeHead(head);
3357
4695
  }
4696
+ // ─── Tree traversal (delegating to algorithm) ────────────────────
3358
4697
  async _insertAtLeaf(node, key, value) {
3359
- let leaf = node;
3360
- if (leaf.values.length) {
3361
- for (let i = 0, len = leaf.values.length; i < len; i++) {
3362
- const nValue = leaf.values[i];
3363
- if (this.comparator.isSame(value, nValue)) {
3364
- const keys = leaf.keys[i];
3365
- if (keys.includes(key)) {
3366
- break;
3367
- }
3368
- leaf = this._cloneNode(leaf);
3369
- leaf.keys[i].push(key);
3370
- await this._updateNode(leaf);
3371
- return leaf;
3372
- } else if (this.comparator.isLower(value, nValue)) {
3373
- leaf = this._cloneNode(leaf);
3374
- leaf.values.splice(i, 0, value);
3375
- leaf.keys.splice(i, 0, [key]);
3376
- await this._updateNode(leaf);
3377
- return leaf;
3378
- } else if (i + 1 === leaf.values.length) {
3379
- leaf = this._cloneNode(leaf);
3380
- leaf.values.push(value);
3381
- leaf.keys.push([key]);
3382
- await this._updateNode(leaf);
3383
- return leaf;
3384
- }
3385
- }
3386
- } else {
3387
- leaf = this._cloneNode(leaf);
3388
- leaf.values = [value];
3389
- leaf.keys = [[key]];
3390
- await this._updateNode(leaf);
3391
- return leaf;
3392
- }
3393
- return leaf;
4698
+ return insertAtLeafAsync(this._ops, node, key, value, this.comparator);
3394
4699
  }
3395
4700
  async _insertInParent(node, value, newSiblingNode) {
3396
- if (this.rootId === node.id) {
3397
- node = this._cloneNode(node);
3398
- newSiblingNode = this._cloneNode(newSiblingNode);
3399
- const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
3400
- this.rootId = root.id;
3401
- node.parent = root.id;
3402
- newSiblingNode.parent = root.id;
3403
- if (newSiblingNode.leaf) {
3404
- node.next = newSiblingNode.id;
3405
- newSiblingNode.prev = node.id;
3406
- }
3407
- await this._writeHead({
3408
- root: root.id,
3409
- order: this.order,
3410
- data: this.strategy.head.data
3411
- });
3412
- await this._updateNode(node);
3413
- await this._updateNode(newSiblingNode);
3414
- return;
3415
- }
3416
- const parentNode = this._cloneNode(await this.getNode(node.parent));
3417
- const nodeIndex = parentNode.keys.indexOf(node.id);
3418
- if (nodeIndex === -1) {
3419
- throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
3420
- }
3421
- parentNode.values.splice(nodeIndex, 0, value);
3422
- parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
3423
- newSiblingNode = this._cloneNode(newSiblingNode);
3424
- newSiblingNode.parent = parentNode.id;
3425
- if (newSiblingNode.leaf) {
3426
- const leftSibling = this._cloneNode(node);
3427
- const oldNextId = leftSibling.next;
3428
- newSiblingNode.prev = leftSibling.id;
3429
- newSiblingNode.next = oldNextId;
3430
- leftSibling.next = newSiblingNode.id;
3431
- await this._updateNode(leftSibling);
3432
- if (oldNextId) {
3433
- const oldNext = this._cloneNode(await this.getNode(oldNextId));
3434
- oldNext.prev = newSiblingNode.id;
3435
- await this._updateNode(oldNext);
3436
- }
3437
- }
3438
- await this._updateNode(parentNode);
3439
- await this._updateNode(newSiblingNode);
3440
- if (parentNode.keys.length > this.order) {
3441
- const newSiblingNodeRecursive = await this._createNode(false, [], []);
3442
- newSiblingNodeRecursive.parent = parentNode.parent;
3443
- const mid = Math.ceil(this.order / 2) - 1;
3444
- newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
3445
- newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
3446
- const midValue = parentNode.values[mid];
3447
- parentNode.values = parentNode.values.slice(0, mid);
3448
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
3449
- for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
3450
- const k = newSiblingNodeRecursive.keys[i];
3451
- const n = this._cloneNode(await this.getNode(k));
3452
- n.parent = newSiblingNodeRecursive.id;
3453
- await this._updateNode(n);
3454
- }
3455
- await this._updateNode(parentNode);
3456
- await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
3457
- }
4701
+ await insertInParentAsync(this._ops, this._ctx, node, value, newSiblingNode);
3458
4702
  }
3459
4703
  async locateLeaf(value) {
3460
- let node = await this.getNode(this.rootId);
3461
- while (!node.leaf) {
3462
- const { index } = this._binarySearchValues(node.values, value, false, true);
3463
- node = await this.getNode(node.keys[index]);
3464
- }
3465
- return node;
4704
+ return locateLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
3466
4705
  }
3467
4706
  async findLowerBoundLeaf(value) {
3468
- let node = await this.getNode(this.rootId);
3469
- while (!node.leaf) {
3470
- const { index } = this._binarySearchValues(node.values, value, true, false);
3471
- node = await this.getNode(node.keys[index]);
3472
- }
3473
- return node;
4707
+ return findLowerBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
3474
4708
  }
3475
4709
  async findUpperBoundLeaf(value) {
3476
- let node = await this.getNode(this.rootId);
3477
- while (!node.leaf) {
3478
- const { index } = this._binarySearchValues(node.values, value, true, true);
3479
- node = await this.getNode(node.keys[index]);
3480
- }
3481
- return node;
4710
+ return findUpperBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
3482
4711
  }
3483
4712
  async findOuterBoundaryLeaf(value, direction) {
3484
- const insertableNode = direction === -1 ? await this.findLowerBoundLeaf(value) : await this.findUpperBoundLeaf(value);
3485
- let key;
3486
- switch (direction) {
3487
- case -1:
3488
- key = "prev";
3489
- break;
3490
- case 1:
3491
- key = "next";
3492
- break;
3493
- default:
3494
- throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
3495
- }
3496
- const guessNode = insertableNode[key];
3497
- if (!guessNode) {
3498
- return null;
3499
- }
3500
- return await this.getNode(guessNode);
4713
+ return findOuterBoundaryLeafAsync(this._ops, this._ctx.rootId, value, direction, this.comparator);
3501
4714
  }
3502
4715
  async leftestNode() {
3503
- let node = await this.getNode(this.rootId);
3504
- if (node === null) {
3505
- debugger;
3506
- }
3507
- while (!node.leaf) {
3508
- const keys = node.keys;
3509
- node = await this.getNode(keys[0]);
3510
- }
3511
- return node;
4716
+ return leftestNodeAsync(this._ops, this._ctx.rootId);
3512
4717
  }
3513
4718
  async rightestNode() {
3514
- let node = await this.getNode(this.rootId);
3515
- while (!node.leaf) {
3516
- const keys = node.keys;
3517
- node = await this.getNode(keys[keys.length - 1]);
3518
- }
3519
- return node;
4719
+ return rightestNodeAsync(this._ops, this._ctx.rootId);
3520
4720
  }
3521
4721
  async *getPairsGenerator(startNode, endNode, direction) {
3522
- let node = startNode;
3523
- let nextNodePromise = null;
3524
- while (true) {
3525
- if (endNode && node.id === endNode.id) {
3526
- break;
3527
- }
3528
- if (direction === 1) {
3529
- if (node.next) {
3530
- nextNodePromise = this.getNode(node.next);
3531
- }
3532
- } else {
3533
- if (node.prev) {
3534
- nextNodePromise = this.getNode(node.prev);
3535
- }
3536
- }
3537
- const len = node.values.length;
3538
- if (direction === 1) {
3539
- for (let i = 0; i < len; i++) {
3540
- const nValue = node.values[i];
3541
- const keys = node.keys[i];
3542
- for (let j = 0, len2 = keys.length; j < len2; j++) {
3543
- yield [keys[j], nValue];
3544
- }
3545
- }
3546
- } else {
3547
- let i = len;
3548
- while (i--) {
3549
- const nValue = node.values[i];
3550
- const keys = node.keys[i];
3551
- let j = keys.length;
3552
- while (j--) {
3553
- yield [keys[j], nValue];
3554
- }
3555
- }
3556
- }
3557
- if (nextNodePromise) {
3558
- node = await nextNodePromise;
3559
- nextNodePromise = null;
3560
- } else {
3561
- break;
3562
- }
3563
- }
4722
+ yield* getPairsGeneratorAsync(this._ops, startNode, endNode, direction);
3564
4723
  }
4724
+ // ─── Lifecycle ───────────────────────────────────────────────────
3565
4725
  async init() {
3566
4726
  if (this.rootTx !== this) {
3567
4727
  throw new Error("Cannot call init on a nested transaction");
@@ -3578,24 +4738,15 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3578
4738
  this.isInitialized = true;
3579
4739
  try {
3580
4740
  this._clearCache();
3581
- const head = await this._readHead();
3582
- if (head === null) {
3583
- this.order = this.strategy.order;
3584
- const root = await this._createNode(true, [], []);
3585
- await this._writeHead({
3586
- root: root.id,
3587
- order: this.order,
3588
- data: this.strategy.head.data
3589
- });
3590
- } else {
3591
- const { root, order } = head;
3592
- this.strategy.head = head;
3593
- this.order = order;
3594
- this.rootId = root;
3595
- }
3596
- if (this.order < 3) {
3597
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
3598
- }
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
+ );
3599
4750
  } catch (e) {
3600
4751
  this.isInitialized = false;
3601
4752
  throw e;
@@ -3611,88 +4762,36 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3611
4762
  this._resetForReload();
3612
4763
  await this._initInternal();
3613
4764
  }
4765
+ // ─── Query (delegating to algorithm) ─────────────────────────────
3614
4766
  async exists(key, value) {
3615
- const node = await this.locateLeaf(value);
3616
- const { index, found } = this._binarySearchValues(node.values, value);
3617
- if (found) {
3618
- const keys = node.keys[index];
3619
- if (keys.includes(key)) {
3620
- return true;
3621
- }
3622
- }
3623
- return false;
4767
+ return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
3624
4768
  }
3625
4769
  async get(key) {
3626
- let node = await this.leftestNode();
3627
- while (true) {
3628
- for (let i = 0, len = node.values.length; i < len; i++) {
3629
- const keys = node.keys[i];
3630
- for (let j = 0, len2 = keys.length; j < len2; j++) {
3631
- if (keys[j] === key) {
3632
- return node.values[i];
3633
- }
3634
- }
3635
- }
3636
- if (!node.next) break;
3637
- node = await this.getNode(node.next);
3638
- }
3639
- return void 0;
4770
+ return getOpAsync(this._ops, this._ctx.rootId, key);
3640
4771
  }
3641
4772
  async *keysStream(condition, options) {
3642
- const { filterValues, limit, order = "asc" } = options ?? {};
3643
- const stream = this.whereStream(condition, options);
3644
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3645
- let count = 0;
3646
- for await (const [key] of stream) {
3647
- if (intersection && !intersection.has(key)) {
3648
- continue;
3649
- }
3650
- yield key;
3651
- count++;
3652
- if (limit !== void 0 && count >= limit) {
3653
- break;
3654
- }
3655
- }
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
+ );
3656
4783
  }
3657
4784
  async *whereStream(condition, options) {
3658
- const { filterValues, limit, order = "asc" } = options ?? {};
3659
- const conditionKeys = Object.keys(condition);
3660
- if (conditionKeys.length === 0) return;
3661
- const resolved = this.resolveStartEndConfigs(condition, order);
3662
- const direction = resolved.direction;
3663
- let startNode;
3664
- if (resolved.startKey) {
3665
- const startConfig = this.searchConfigs[resolved.startKey][order];
3666
- startNode = await startConfig.start(this, resolved.startValues);
3667
- } else {
3668
- startNode = order === "asc" ? await this.leftestNode() : await this.rightestNode();
3669
- }
3670
- let endNode = null;
3671
- if (resolved.endKey) {
3672
- const endConfig = this.searchConfigs[resolved.endKey][order];
3673
- endNode = await endConfig.end(this, resolved.endValues);
3674
- }
3675
- if (!startNode) return;
3676
- const generator = this.getPairsGenerator(
3677
- startNode,
3678
- endNode,
3679
- 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
3680
4794
  );
3681
- let count = 0;
3682
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3683
- for await (const pair of generator) {
3684
- const [k, v] = pair;
3685
- if (intersection && !intersection.has(k)) {
3686
- continue;
3687
- }
3688
- if (this.verify(v, condition)) {
3689
- yield pair;
3690
- count++;
3691
- if (limit !== void 0 && count >= limit) {
3692
- break;
3693
- }
3694
- }
3695
- }
3696
4795
  }
3697
4796
  async keys(condition, options) {
3698
4797
  const set = /* @__PURE__ */ new Set();
@@ -3708,412 +4807,33 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3708
4807
  }
3709
4808
  return map;
3710
4809
  }
4810
+ // ─── Mutation (delegating to algorithm) ──────────────────────────
3711
4811
  async insert(key, value) {
3712
4812
  return this.writeLock(0, async () => {
3713
- let before = await this.locateLeaf(value);
3714
- before = await this._insertAtLeaf(before, key, value);
3715
- if (before.values.length === this.order) {
3716
- let after = await this._createNode(
3717
- true,
3718
- [],
3719
- [],
3720
- before.parent,
3721
- null,
3722
- null
3723
- );
3724
- const mid = Math.ceil(this.order / 2) - 1;
3725
- after = this._cloneNode(after);
3726
- after.values = before.values.slice(mid + 1);
3727
- after.keys = before.keys.slice(mid + 1);
3728
- before.values = before.values.slice(0, mid + 1);
3729
- before.keys = before.keys.slice(0, mid + 1);
3730
- await this._updateNode(before);
3731
- await this._updateNode(after);
3732
- await this._insertInParent(before, after.values[0], after);
3733
- }
4813
+ await insertOpAsync(this._ops, this._ctx, key, value, this.comparator);
3734
4814
  });
3735
4815
  }
3736
4816
  async batchInsert(entries) {
3737
4817
  if (entries.length === 0) return;
3738
4818
  return this.writeLock(0, async () => {
3739
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3740
- let currentLeaf = null;
3741
- let modified = false;
3742
- let cachedLeafId = null;
3743
- let cachedLeafMaxValue = null;
3744
- for (let i = 0, len = sorted.length; i < len; i++) {
3745
- const [key, value] = sorted[i];
3746
- let targetLeaf;
3747
- if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
3748
- targetLeaf = currentLeaf;
3749
- } else {
3750
- targetLeaf = await this.locateLeaf(value);
3751
- }
3752
- if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3753
- } else {
3754
- if (currentLeaf !== null && modified) {
3755
- await this._updateNode(currentLeaf);
3756
- }
3757
- currentLeaf = this._cloneNode(targetLeaf);
3758
- modified = false;
3759
- }
3760
- cachedLeafId = currentLeaf.id;
3761
- const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3762
- modified = modified || changed;
3763
- cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
3764
- if (currentLeaf.values.length === this.order) {
3765
- await this._updateNode(currentLeaf);
3766
- let after = await this._createNode(
3767
- true,
3768
- [],
3769
- [],
3770
- currentLeaf.parent,
3771
- null,
3772
- null
3773
- );
3774
- const mid = Math.ceil(this.order / 2) - 1;
3775
- after = this._cloneNode(after);
3776
- after.values = currentLeaf.values.slice(mid + 1);
3777
- after.keys = currentLeaf.keys.slice(mid + 1);
3778
- currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
3779
- currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
3780
- await this._updateNode(currentLeaf);
3781
- await this._updateNode(after);
3782
- await this._insertInParent(currentLeaf, after.values[0], after);
3783
- currentLeaf = null;
3784
- cachedLeafId = null;
3785
- cachedLeafMaxValue = null;
3786
- modified = false;
3787
- }
3788
- }
3789
- if (currentLeaf !== null && modified) {
3790
- await this._updateNode(currentLeaf);
3791
- }
4819
+ await batchInsertOpAsync(this._ops, this._ctx, entries, this.comparator);
3792
4820
  });
3793
4821
  }
3794
4822
  async bulkLoad(entries) {
3795
4823
  if (entries.length === 0) return;
3796
4824
  return this.writeLock(0, async () => {
3797
- const root = await this.getNode(this.rootId);
3798
- if (!root.leaf || root.values.length > 0) {
3799
- throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
3800
- }
3801
- const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3802
- const grouped = [];
3803
- for (let i = 0, len = sorted.length; i < len; i++) {
3804
- const [key, value] = sorted[i];
3805
- const last = grouped[grouped.length - 1];
3806
- if (last && this.comparator.isSame(last.value, value)) {
3807
- if (!last.keys.includes(key)) {
3808
- last.keys.push(key);
3809
- }
3810
- } else {
3811
- grouped.push({ keys: [key], value });
3812
- }
3813
- }
3814
- await this._deleteNode(root);
3815
- const maxLeafSize = this.order - 1;
3816
- const leaves = [];
3817
- for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
3818
- const chunk = grouped.slice(i, i + maxLeafSize);
3819
- const leafKeys = chunk.map((g) => g.keys);
3820
- const leafValues = chunk.map((g) => g.value);
3821
- const leaf = await this._createNode(
3822
- true,
3823
- leafKeys,
3824
- leafValues,
3825
- null,
3826
- null,
3827
- null
3828
- );
3829
- leaves.push(leaf);
3830
- }
3831
- for (let i = 0, len = leaves.length; i < len; i++) {
3832
- if (i > 0) {
3833
- leaves[i].prev = leaves[i - 1].id;
3834
- }
3835
- if (i < len - 1) {
3836
- leaves[i].next = leaves[i + 1].id;
3837
- }
3838
- await this._updateNode(leaves[i]);
3839
- }
3840
- let currentLevel = leaves;
3841
- while (currentLevel.length > 1) {
3842
- const nextLevel = [];
3843
- for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
3844
- const children = currentLevel.slice(i, i + this.order);
3845
- const childIds = children.map((c) => c.id);
3846
- const separators = [];
3847
- for (let j = 1, len2 = children.length; j < len2; j++) {
3848
- separators.push(children[j].values[0]);
3849
- }
3850
- const internalNode = await this._createNode(
3851
- false,
3852
- childIds,
3853
- separators,
3854
- null,
3855
- null,
3856
- null
3857
- );
3858
- for (let j = 0, len2 = children.length; j < len2; j++) {
3859
- const child = children[j];
3860
- child.parent = internalNode.id;
3861
- await this._updateNode(child);
3862
- }
3863
- nextLevel.push(internalNode);
3864
- }
3865
- currentLevel = nextLevel;
3866
- }
3867
- const newRoot = currentLevel[0];
3868
- await this._writeHead({
3869
- root: newRoot.id,
3870
- order: this.order,
3871
- data: this.strategy.head.data
3872
- });
4825
+ await bulkLoadOpAsync(this._ops, this._ctx, entries, this.comparator);
3873
4826
  });
3874
4827
  }
3875
4828
  async _deleteEntry(node, key) {
3876
- if (!node.leaf) {
3877
- let keyIndex = -1;
3878
- for (let i = 0, len = node.keys.length; i < len; i++) {
3879
- if (node.keys[i] === key) {
3880
- keyIndex = i;
3881
- break;
3882
- }
3883
- }
3884
- if (keyIndex !== -1) {
3885
- node = this._cloneNode(node);
3886
- node.keys.splice(keyIndex, 1);
3887
- const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
3888
- node.values.splice(valueIndex, 1);
3889
- await this._updateNode(node);
3890
- }
3891
- }
3892
- if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
3893
- const keys = node.keys;
3894
- this._deleteNode(node);
3895
- const newRoot = this._cloneNode(await this.getNode(keys[0]));
3896
- newRoot.parent = null;
3897
- await this._updateNode(newRoot);
3898
- await this._writeHead({
3899
- root: newRoot.id,
3900
- order: this.order,
3901
- data: this.strategy.head.data
3902
- });
3903
- return node;
3904
- } else if (this.rootId === node.id) {
3905
- await this._writeHead({
3906
- root: node.id,
3907
- order: this.order,
3908
- data: this.strategy.head.data
3909
- });
3910
- return node;
3911
- } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
3912
- if (node.parent === null) {
3913
- return node;
3914
- }
3915
- let isPredecessor = false;
3916
- let parentNode = await this.getNode(node.parent);
3917
- let prevNode = null;
3918
- let nextNode = null;
3919
- let prevValue = null;
3920
- let postValue = null;
3921
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
3922
- const nKey = parentNode.keys[i];
3923
- if (nKey === node.id) {
3924
- if (i > 0) {
3925
- prevNode = await this.getNode(parentNode.keys[i - 1]);
3926
- prevValue = parentNode.values[i - 1];
3927
- }
3928
- if (i < parentNode.keys.length - 1) {
3929
- nextNode = await this.getNode(parentNode.keys[i + 1]);
3930
- postValue = parentNode.values[i];
3931
- }
3932
- }
3933
- }
3934
- let siblingNode;
3935
- let guess;
3936
- if (prevNode === null) {
3937
- siblingNode = nextNode;
3938
- guess = postValue;
3939
- } else if (nextNode === null) {
3940
- isPredecessor = true;
3941
- siblingNode = prevNode;
3942
- guess = prevValue;
3943
- } else {
3944
- if (node.values.length + nextNode.values.length < this.order) {
3945
- siblingNode = nextNode;
3946
- guess = postValue;
3947
- } else {
3948
- isPredecessor = true;
3949
- siblingNode = prevNode;
3950
- guess = prevValue;
3951
- }
3952
- }
3953
- if (!siblingNode) {
3954
- return node;
3955
- }
3956
- node = this._cloneNode(node);
3957
- siblingNode = this._cloneNode(siblingNode);
3958
- if (node.values.length + siblingNode.values.length < this.order) {
3959
- if (!isPredecessor) {
3960
- const pTemp = siblingNode;
3961
- siblingNode = node;
3962
- node = pTemp;
3963
- }
3964
- siblingNode.keys.push(...node.keys);
3965
- if (!node.leaf) {
3966
- siblingNode.values.push(guess);
3967
- } else {
3968
- siblingNode.next = node.next;
3969
- if (siblingNode.next) {
3970
- const n = this._cloneNode(await this.getNode(siblingNode.next));
3971
- n.prev = siblingNode.id;
3972
- await this._updateNode(n);
3973
- }
3974
- }
3975
- siblingNode.values.push(...node.values);
3976
- if (!siblingNode.leaf) {
3977
- const keys = siblingNode.keys;
3978
- for (let i = 0, len = keys.length; i < len; i++) {
3979
- const key2 = keys[i];
3980
- const node2 = this._cloneNode(await this.getNode(key2));
3981
- node2.parent = siblingNode.id;
3982
- await this._updateNode(node2);
3983
- }
3984
- }
3985
- this._deleteNode(node);
3986
- await this._updateNode(siblingNode);
3987
- await this._deleteEntry(await this.getNode(node.parent), node.id);
3988
- } else {
3989
- if (isPredecessor) {
3990
- let pointerPm;
3991
- let pointerKm;
3992
- if (!node.leaf) {
3993
- pointerPm = siblingNode.keys.splice(-1)[0];
3994
- pointerKm = siblingNode.values.splice(-1)[0];
3995
- node.keys = [pointerPm, ...node.keys];
3996
- node.values = [guess, ...node.values];
3997
- parentNode = this._cloneNode(await this.getNode(node.parent));
3998
- const nodeIndex = parentNode.keys.indexOf(node.id);
3999
- if (nodeIndex > 0) {
4000
- parentNode.values[nodeIndex - 1] = pointerKm;
4001
- await this._updateNode(parentNode);
4002
- }
4003
- } else {
4004
- pointerPm = siblingNode.keys.splice(-1)[0];
4005
- pointerKm = siblingNode.values.splice(-1)[0];
4006
- node.keys = [pointerPm, ...node.keys];
4007
- node.values = [pointerKm, ...node.values];
4008
- parentNode = this._cloneNode(await this.getNode(node.parent));
4009
- const nodeIndex = parentNode.keys.indexOf(node.id);
4010
- if (nodeIndex > 0) {
4011
- parentNode.values[nodeIndex - 1] = pointerKm;
4012
- await this._updateNode(parentNode);
4013
- }
4014
- }
4015
- await this._updateNode(node);
4016
- await this._updateNode(siblingNode);
4017
- } else {
4018
- let pointerP0;
4019
- let pointerK0;
4020
- if (!node.leaf) {
4021
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
4022
- pointerK0 = siblingNode.values.splice(0, 1)[0];
4023
- node.keys = [...node.keys, pointerP0];
4024
- node.values = [...node.values, guess];
4025
- parentNode = this._cloneNode(await this.getNode(node.parent));
4026
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
4027
- if (pointerIndex > 0) {
4028
- parentNode.values[pointerIndex - 1] = pointerK0;
4029
- await this._updateNode(parentNode);
4030
- }
4031
- } else {
4032
- pointerP0 = siblingNode.keys.splice(0, 1)[0];
4033
- pointerK0 = siblingNode.values.splice(0, 1)[0];
4034
- node.keys = [...node.keys, pointerP0];
4035
- node.values = [...node.values, pointerK0];
4036
- parentNode = this._cloneNode(await this.getNode(node.parent));
4037
- const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
4038
- if (pointerIndex > 0) {
4039
- parentNode.values[pointerIndex - 1] = siblingNode.values[0];
4040
- await this._updateNode(parentNode);
4041
- }
4042
- }
4043
- await this._updateNode(node);
4044
- await this._updateNode(siblingNode);
4045
- }
4046
- if (!siblingNode.leaf) {
4047
- for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
4048
- const key2 = siblingNode.keys[i];
4049
- const n = this._cloneNode(await this.getNode(key2));
4050
- n.parent = siblingNode.id;
4051
- await this._updateNode(n);
4052
- }
4053
- }
4054
- if (!node.leaf) {
4055
- for (let i = 0, len = node.keys.length; i < len; i++) {
4056
- const key2 = node.keys[i];
4057
- const n = this._cloneNode(await this.getNode(key2));
4058
- n.parent = node.id;
4059
- await this._updateNode(n);
4060
- }
4061
- }
4062
- if (!parentNode.leaf) {
4063
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
4064
- const key2 = parentNode.keys[i];
4065
- const n = this._cloneNode(await this.getNode(key2));
4066
- n.parent = parentNode.id;
4067
- await this._updateNode(n);
4068
- }
4069
- }
4070
- }
4071
- } else {
4072
- await this._updateNode(this._cloneNode(node));
4073
- }
4074
- return node;
4829
+ return deleteEntryAsync(this._ops, this._ctx, node, key, this.comparator);
4075
4830
  }
4076
4831
  async delete(key, value) {
4077
4832
  return this.writeLock(0, async () => {
4078
- if (value === void 0) {
4079
- value = await this.get(key);
4080
- }
4081
- if (value === void 0) {
4082
- return;
4083
- }
4084
- let node = await this.findLowerBoundLeaf(value);
4085
- let found = false;
4086
- while (true) {
4087
- let i = node.values.length;
4088
- while (i--) {
4089
- const nValue = node.values[i];
4090
- if (this.comparator.isSame(value, nValue)) {
4091
- const keys = node.keys[i];
4092
- const keyIndex = keys.indexOf(key);
4093
- if (keyIndex !== -1) {
4094
- node = this._cloneNode(node);
4095
- const freshKeys = node.keys[i];
4096
- freshKeys.splice(keyIndex, 1);
4097
- if (freshKeys.length === 0) {
4098
- node.keys.splice(i, 1);
4099
- node.values.splice(i, 1);
4100
- }
4101
- await this._updateNode(node);
4102
- node = await this._deleteEntry(node, key);
4103
- found = true;
4104
- break;
4105
- }
4106
- }
4107
- }
4108
- if (found) break;
4109
- if (node.next) {
4110
- node = await this.getNode(node.next);
4111
- continue;
4112
- }
4113
- break;
4114
- }
4833
+ await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
4115
4834
  });
4116
4835
  }
4836
+ // ─── Head Data ───────────────────────────────────────────────────
4117
4837
  async getHeadData() {
4118
4838
  const head = await this._readHead();
4119
4839
  if (head === null) {
@@ -4132,6 +4852,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
4132
4852
  data
4133
4853
  });
4134
4854
  }
4855
+ // ─── Transaction ─────────────────────────────────────────────────
4135
4856
  async commit(label) {
4136
4857
  let result = await this.mvcc.commit(label);
4137
4858
  if (result.success) {
@@ -4263,6 +4984,327 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
4263
4984
  }
4264
4985
  };
4265
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
+
4266
5308
  // src/base/SerializeStrategy.ts
4267
5309
  var SerializeStrategy = class {
4268
5310
  order;