serializable-bptree 8.4.2 → 9.0.1

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