document-dataply 0.0.9-alpha.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +882 -498
- package/dist/types/core/documentAPI.d.ts +26 -3
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -157,39 +157,125 @@ var require_cjs = __commonJS({
|
|
|
157
157
|
var MVCCStrategy = class {
|
|
158
158
|
};
|
|
159
159
|
var LRUMap = class {
|
|
160
|
-
cache = /* @__PURE__ */ new Map();
|
|
161
160
|
capacity;
|
|
161
|
+
map;
|
|
162
|
+
head = null;
|
|
163
|
+
tail = null;
|
|
164
|
+
/**
|
|
165
|
+
* Creates an instance of LRUMap.
|
|
166
|
+
* @param capacity The maximum number of items the cache can hold.
|
|
167
|
+
*/
|
|
162
168
|
constructor(capacity) {
|
|
163
169
|
this.capacity = capacity;
|
|
170
|
+
this.map = /* @__PURE__ */ new Map();
|
|
164
171
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Promotes a node to the head of the linked list (marks as most recently used).
|
|
174
|
+
* @param node The node to promote.
|
|
175
|
+
*/
|
|
176
|
+
promote(node) {
|
|
177
|
+
this.extract(node);
|
|
178
|
+
this.prepend(node);
|
|
171
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Disconnects a node from the doubly linked list.
|
|
182
|
+
* @param node The node to extract.
|
|
183
|
+
*/
|
|
184
|
+
extract(node) {
|
|
185
|
+
if (node.prev) node.prev.next = node.next;
|
|
186
|
+
else this.head = node.next;
|
|
187
|
+
if (node.next) node.next.prev = node.prev;
|
|
188
|
+
else this.tail = node.prev;
|
|
189
|
+
node.prev = null;
|
|
190
|
+
node.next = null;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Inserts a node at the head of the doubly linked list.
|
|
194
|
+
* @param node The node to prepend.
|
|
195
|
+
*/
|
|
196
|
+
prepend(node) {
|
|
197
|
+
node.next = this.head;
|
|
198
|
+
if (this.head) this.head.prev = node;
|
|
199
|
+
this.head = node;
|
|
200
|
+
if (!this.tail) this.tail = node;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Stores or updates a value by key.
|
|
204
|
+
* If the capacity is exceeded, the least recently used item (tail) is removed.
|
|
205
|
+
* @param key The key to store.
|
|
206
|
+
* @param value The value to store.
|
|
207
|
+
*/
|
|
172
208
|
set(key, value) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
209
|
+
const existing = this.map.get(key);
|
|
210
|
+
if (existing) {
|
|
211
|
+
existing.value = value;
|
|
212
|
+
this.promote(existing);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const newNode = { key, value, prev: null, next: null };
|
|
216
|
+
this.map.set(key, newNode);
|
|
217
|
+
this.prepend(newNode);
|
|
218
|
+
if (this.map.size > this.capacity && this.tail) {
|
|
219
|
+
this.map.delete(this.tail.key);
|
|
220
|
+
this.extract(this.tail);
|
|
178
221
|
}
|
|
179
|
-
this.cache.set(key, value);
|
|
180
|
-
return this;
|
|
181
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Retrieves a value by key.
|
|
225
|
+
* Accessing the item moves it to the "most recently used" position.
|
|
226
|
+
* @param key The key to look for.
|
|
227
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
228
|
+
*/
|
|
229
|
+
get(key) {
|
|
230
|
+
const node = this.map.get(key);
|
|
231
|
+
if (!node) return void 0;
|
|
232
|
+
this.promote(node);
|
|
233
|
+
return node.value;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Checks if a key exists in the cache without changing its access order.
|
|
237
|
+
* @param key The key to check.
|
|
238
|
+
* @returns True if the key exists, false otherwise.
|
|
239
|
+
*/
|
|
182
240
|
has(key) {
|
|
183
|
-
return this.
|
|
241
|
+
return this.map.has(key);
|
|
184
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* Removes a key and its associated value from the cache.
|
|
245
|
+
* @param key The key to remove.
|
|
246
|
+
* @returns True if the key was found and removed, false otherwise.
|
|
247
|
+
*/
|
|
185
248
|
delete(key) {
|
|
186
|
-
|
|
249
|
+
const node = this.map.get(key);
|
|
250
|
+
if (!node) return false;
|
|
251
|
+
this.extract(node);
|
|
252
|
+
this.map.delete(key);
|
|
253
|
+
return true;
|
|
187
254
|
}
|
|
188
|
-
|
|
189
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Returns an iterator of keys in the order of most recently used to least recently used.
|
|
257
|
+
* @returns An iterable iterator of keys.
|
|
258
|
+
*/
|
|
259
|
+
*keys() {
|
|
260
|
+
let current = this.head;
|
|
261
|
+
while (current) {
|
|
262
|
+
yield current.key;
|
|
263
|
+
current = current.next;
|
|
264
|
+
}
|
|
190
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Returns the current number of items in the cache.
|
|
268
|
+
*/
|
|
191
269
|
get size() {
|
|
192
|
-
return this.
|
|
270
|
+
return this.map.size;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Clears all items from the cache.
|
|
274
|
+
*/
|
|
275
|
+
clear() {
|
|
276
|
+
this.map.clear();
|
|
277
|
+
this.head = null;
|
|
278
|
+
this.tail = null;
|
|
193
279
|
}
|
|
194
280
|
};
|
|
195
281
|
var MVCCTransaction = class {
|
|
@@ -873,7 +959,7 @@ var require_cjs = __commonJS({
|
|
|
873
959
|
};
|
|
874
960
|
var AsyncMVCCStrategy = class extends MVCCStrategy {
|
|
875
961
|
};
|
|
876
|
-
var
|
|
962
|
+
var Ryoiki = class _Ryoiki {
|
|
877
963
|
readings;
|
|
878
964
|
writings;
|
|
879
965
|
readQueue;
|
|
@@ -1130,7 +1216,7 @@ var require_cjs = __commonJS({
|
|
|
1130
1216
|
}
|
|
1131
1217
|
};
|
|
1132
1218
|
var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
1133
|
-
lock = new
|
|
1219
|
+
lock = new Ryoiki();
|
|
1134
1220
|
async writeLock(fn) {
|
|
1135
1221
|
let lockId;
|
|
1136
1222
|
return this.lock.writeLock(async (_lockId) => {
|
|
@@ -1583,28 +1669,28 @@ var require_cjs = __commonJS({
|
|
|
1583
1669
|
searchConfigs = {
|
|
1584
1670
|
gt: {
|
|
1585
1671
|
asc: {
|
|
1586
|
-
start: (tx, v) => tx.
|
|
1672
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1587
1673
|
end: () => null,
|
|
1588
1674
|
direction: 1,
|
|
1589
1675
|
earlyTerminate: false
|
|
1590
1676
|
},
|
|
1591
1677
|
desc: {
|
|
1592
1678
|
start: (tx) => tx.rightestNode(),
|
|
1593
|
-
end: (tx, v) => tx.
|
|
1679
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1594
1680
|
direction: -1,
|
|
1595
1681
|
earlyTerminate: true
|
|
1596
1682
|
}
|
|
1597
1683
|
},
|
|
1598
1684
|
gte: {
|
|
1599
1685
|
asc: {
|
|
1600
|
-
start: (tx, v) => tx.
|
|
1686
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1601
1687
|
end: () => null,
|
|
1602
1688
|
direction: 1,
|
|
1603
1689
|
earlyTerminate: false
|
|
1604
1690
|
},
|
|
1605
1691
|
desc: {
|
|
1606
1692
|
start: (tx) => tx.rightestNode(),
|
|
1607
|
-
end: (tx, v) => tx.
|
|
1693
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1608
1694
|
direction: -1,
|
|
1609
1695
|
earlyTerminate: true
|
|
1610
1696
|
}
|
|
@@ -1612,12 +1698,12 @@ var require_cjs = __commonJS({
|
|
|
1612
1698
|
lt: {
|
|
1613
1699
|
asc: {
|
|
1614
1700
|
start: (tx) => tx.leftestNode(),
|
|
1615
|
-
end: (tx, v) => tx.
|
|
1701
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1616
1702
|
direction: 1,
|
|
1617
1703
|
earlyTerminate: true
|
|
1618
1704
|
},
|
|
1619
1705
|
desc: {
|
|
1620
|
-
start: (tx, v) => tx.
|
|
1706
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1621
1707
|
end: () => null,
|
|
1622
1708
|
direction: -1,
|
|
1623
1709
|
earlyTerminate: false
|
|
@@ -1626,12 +1712,12 @@ var require_cjs = __commonJS({
|
|
|
1626
1712
|
lte: {
|
|
1627
1713
|
asc: {
|
|
1628
1714
|
start: (tx) => tx.leftestNode(),
|
|
1629
|
-
end: (tx, v) => tx.
|
|
1715
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1630
1716
|
direction: 1,
|
|
1631
1717
|
earlyTerminate: true
|
|
1632
1718
|
},
|
|
1633
1719
|
desc: {
|
|
1634
|
-
start: (tx, v) => tx.
|
|
1720
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1635
1721
|
end: () => null,
|
|
1636
1722
|
direction: -1,
|
|
1637
1723
|
earlyTerminate: false
|
|
@@ -1639,14 +1725,14 @@ var require_cjs = __commonJS({
|
|
|
1639
1725
|
},
|
|
1640
1726
|
equal: {
|
|
1641
1727
|
asc: {
|
|
1642
|
-
start: (tx, v) => tx.
|
|
1643
|
-
end: (tx, v) => tx.
|
|
1728
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1729
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1644
1730
|
direction: 1,
|
|
1645
1731
|
earlyTerminate: true
|
|
1646
1732
|
},
|
|
1647
1733
|
desc: {
|
|
1648
|
-
start: (tx, v) => tx.
|
|
1649
|
-
end: (tx, v) => tx.
|
|
1734
|
+
start: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1735
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1650
1736
|
direction: -1,
|
|
1651
1737
|
earlyTerminate: true
|
|
1652
1738
|
}
|
|
@@ -1667,42 +1753,42 @@ var require_cjs = __commonJS({
|
|
|
1667
1753
|
},
|
|
1668
1754
|
or: {
|
|
1669
1755
|
asc: {
|
|
1670
|
-
start: (tx, v) => tx.
|
|
1671
|
-
end: (tx, v) => tx.
|
|
1756
|
+
start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestValue(v)),
|
|
1757
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
|
|
1672
1758
|
direction: 1,
|
|
1673
1759
|
earlyTerminate: false
|
|
1674
1760
|
},
|
|
1675
1761
|
desc: {
|
|
1676
|
-
start: (tx, v) => tx.
|
|
1677
|
-
end: (tx, v) => tx.
|
|
1762
|
+
start: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
|
|
1763
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestValue(v), -1),
|
|
1678
1764
|
direction: -1,
|
|
1679
1765
|
earlyTerminate: false
|
|
1680
1766
|
}
|
|
1681
1767
|
},
|
|
1682
1768
|
primaryGt: {
|
|
1683
1769
|
asc: {
|
|
1684
|
-
start: (tx, v) => tx.
|
|
1770
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1685
1771
|
end: () => null,
|
|
1686
1772
|
direction: 1,
|
|
1687
1773
|
earlyTerminate: false
|
|
1688
1774
|
},
|
|
1689
1775
|
desc: {
|
|
1690
1776
|
start: (tx) => tx.rightestNode(),
|
|
1691
|
-
end: (tx, v) => tx.
|
|
1777
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1692
1778
|
direction: -1,
|
|
1693
1779
|
earlyTerminate: true
|
|
1694
1780
|
}
|
|
1695
1781
|
},
|
|
1696
1782
|
primaryGte: {
|
|
1697
1783
|
asc: {
|
|
1698
|
-
start: (tx, v) => tx.
|
|
1784
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1699
1785
|
end: () => null,
|
|
1700
1786
|
direction: 1,
|
|
1701
1787
|
earlyTerminate: false
|
|
1702
1788
|
},
|
|
1703
1789
|
desc: {
|
|
1704
1790
|
start: (tx) => tx.rightestNode(),
|
|
1705
|
-
end: (tx, v) => tx.
|
|
1791
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1706
1792
|
direction: -1,
|
|
1707
1793
|
earlyTerminate: true
|
|
1708
1794
|
}
|
|
@@ -1710,12 +1796,12 @@ var require_cjs = __commonJS({
|
|
|
1710
1796
|
primaryLt: {
|
|
1711
1797
|
asc: {
|
|
1712
1798
|
start: (tx) => tx.leftestNode(),
|
|
1713
|
-
end: (tx, v) => tx.
|
|
1799
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1714
1800
|
direction: 1,
|
|
1715
1801
|
earlyTerminate: true
|
|
1716
1802
|
},
|
|
1717
1803
|
desc: {
|
|
1718
|
-
start: (tx, v) => tx.
|
|
1804
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1719
1805
|
end: () => null,
|
|
1720
1806
|
direction: -1,
|
|
1721
1807
|
earlyTerminate: false
|
|
@@ -1724,12 +1810,12 @@ var require_cjs = __commonJS({
|
|
|
1724
1810
|
primaryLte: {
|
|
1725
1811
|
asc: {
|
|
1726
1812
|
start: (tx) => tx.leftestNode(),
|
|
1727
|
-
end: (tx, v) => tx.
|
|
1813
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1728
1814
|
direction: 1,
|
|
1729
1815
|
earlyTerminate: true
|
|
1730
1816
|
},
|
|
1731
1817
|
desc: {
|
|
1732
|
-
start: (tx, v) => tx.
|
|
1818
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1733
1819
|
end: () => null,
|
|
1734
1820
|
direction: -1,
|
|
1735
1821
|
earlyTerminate: false
|
|
@@ -1737,14 +1823,14 @@ var require_cjs = __commonJS({
|
|
|
1737
1823
|
},
|
|
1738
1824
|
primaryEqual: {
|
|
1739
1825
|
asc: {
|
|
1740
|
-
start: (tx, v) => tx.
|
|
1741
|
-
end: (tx, v) => tx.
|
|
1826
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1827
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1742
1828
|
direction: 1,
|
|
1743
1829
|
earlyTerminate: true
|
|
1744
1830
|
},
|
|
1745
1831
|
desc: {
|
|
1746
|
-
start: (tx, v) => tx.
|
|
1747
|
-
end: (tx, v) => tx.
|
|
1832
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1833
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1748
1834
|
direction: -1,
|
|
1749
1835
|
earlyTerminate: true
|
|
1750
1836
|
}
|
|
@@ -1765,14 +1851,14 @@ var require_cjs = __commonJS({
|
|
|
1765
1851
|
},
|
|
1766
1852
|
primaryOr: {
|
|
1767
1853
|
asc: {
|
|
1768
|
-
start: (tx, v) => tx.
|
|
1769
|
-
end: (tx, v) => tx.
|
|
1854
|
+
start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestPrimaryValue(v)),
|
|
1855
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestPrimaryValue(v), 1),
|
|
1770
1856
|
direction: 1,
|
|
1771
1857
|
earlyTerminate: false
|
|
1772
1858
|
},
|
|
1773
1859
|
desc: {
|
|
1774
|
-
start: (tx, v) => tx.
|
|
1775
|
-
end: (tx, v) => tx.
|
|
1860
|
+
start: (tx, v) => tx.findUpperBoundLeaf(tx.highestPrimaryValue(v)),
|
|
1861
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestPrimaryValue(v), -1),
|
|
1776
1862
|
direction: -1,
|
|
1777
1863
|
earlyTerminate: false
|
|
1778
1864
|
}
|
|
@@ -1928,30 +2014,69 @@ var require_cjs = __commonJS({
|
|
|
1928
2014
|
return JSON.parse(JSON.stringify(node));
|
|
1929
2015
|
}
|
|
1930
2016
|
/**
|
|
1931
|
-
*
|
|
1932
|
-
*
|
|
1933
|
-
*
|
|
2017
|
+
* Resolves the best start/end configuration by independently examining
|
|
2018
|
+
* all conditions. Selects the tightest lower bound for start and the
|
|
2019
|
+
* tightest upper bound for end (in asc; reversed for desc).
|
|
2020
|
+
*
|
|
1934
2021
|
* @param condition The condition to analyze.
|
|
1935
|
-
* @
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2022
|
+
* @param order The sort order ('asc' or 'desc').
|
|
2023
|
+
* @returns The resolved start/end keys, values, and traversal direction.
|
|
2024
|
+
*/
|
|
2025
|
+
resolveStartEndConfigs(condition, order) {
|
|
2026
|
+
const direction = order === "asc" ? 1 : -1;
|
|
2027
|
+
const startCandidates = order === "asc" ? _BPTreeTransaction._lowerBoundKeys : _BPTreeTransaction._upperBoundKeys;
|
|
2028
|
+
const endCandidates = order === "asc" ? _BPTreeTransaction._upperBoundKeys : _BPTreeTransaction._lowerBoundKeys;
|
|
2029
|
+
let startKey = null;
|
|
2030
|
+
let endKey = null;
|
|
2031
|
+
let startValues = [];
|
|
2032
|
+
let endValues = [];
|
|
2033
|
+
for (let i = 0, len = startCandidates.length; i < len; i++) {
|
|
2034
|
+
const key = startCandidates[i];
|
|
2035
|
+
if (key in condition) {
|
|
2036
|
+
startKey = key;
|
|
2037
|
+
startValues = _BPTreeTransaction._multiValueKeys.includes(key) ? this.ensureValues(condition[key]) : [condition[key]];
|
|
2038
|
+
break;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
for (let i = 0, len = endCandidates.length; i < len; i++) {
|
|
2042
|
+
const key = endCandidates[i];
|
|
2043
|
+
if (key in condition) {
|
|
2044
|
+
endKey = key;
|
|
2045
|
+
endValues = _BPTreeTransaction._multiValueKeys.includes(key) ? this.ensureValues(condition[key]) : [condition[key]];
|
|
2046
|
+
break;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
return { startKey, endKey, startValues, endValues, direction };
|
|
2050
|
+
}
|
|
2051
|
+
// Lower bound providers, ordered by selectivity (tightest first)
|
|
2052
|
+
// Used for asc start / desc end
|
|
2053
|
+
static _lowerBoundKeys = [
|
|
2054
|
+
"primaryEqual",
|
|
2055
|
+
"equal",
|
|
2056
|
+
"primaryGt",
|
|
2057
|
+
"gt",
|
|
2058
|
+
"primaryGte",
|
|
2059
|
+
"gte",
|
|
2060
|
+
"primaryOr",
|
|
2061
|
+
"or"
|
|
2062
|
+
];
|
|
2063
|
+
// Upper bound providers, ordered by selectivity (tightest first)
|
|
2064
|
+
// Used for asc end / desc start
|
|
2065
|
+
static _upperBoundKeys = [
|
|
2066
|
+
"primaryEqual",
|
|
2067
|
+
"equal",
|
|
2068
|
+
"primaryLt",
|
|
2069
|
+
"lt",
|
|
2070
|
+
"primaryLte",
|
|
2071
|
+
"lte",
|
|
2072
|
+
"primaryOr",
|
|
2073
|
+
"or"
|
|
2074
|
+
];
|
|
2075
|
+
// Condition keys that accept multiple values (V[]) rather than a single value (V)
|
|
2076
|
+
static _multiValueKeys = [
|
|
2077
|
+
"or",
|
|
2078
|
+
"primaryOr"
|
|
2079
|
+
];
|
|
1955
2080
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
1956
2081
|
this.rootTx = rootTx === null ? this : rootTx;
|
|
1957
2082
|
this.mvccRoot = mvccRoot;
|
|
@@ -2188,7 +2313,7 @@ var require_cjs = __commonJS({
|
|
|
2188
2313
|
this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2189
2314
|
}
|
|
2190
2315
|
}
|
|
2191
|
-
|
|
2316
|
+
locateLeaf(value) {
|
|
2192
2317
|
let node = this.getNode(this.rootId);
|
|
2193
2318
|
while (!node.leaf) {
|
|
2194
2319
|
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
@@ -2196,7 +2321,7 @@ var require_cjs = __commonJS({
|
|
|
2196
2321
|
}
|
|
2197
2322
|
return node;
|
|
2198
2323
|
}
|
|
2199
|
-
|
|
2324
|
+
findLowerBoundLeaf(value) {
|
|
2200
2325
|
let node = this.getNode(this.rootId);
|
|
2201
2326
|
while (!node.leaf) {
|
|
2202
2327
|
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
@@ -2204,7 +2329,7 @@ var require_cjs = __commonJS({
|
|
|
2204
2329
|
}
|
|
2205
2330
|
return node;
|
|
2206
2331
|
}
|
|
2207
|
-
|
|
2332
|
+
findUpperBoundLeaf(value) {
|
|
2208
2333
|
let node = this.getNode(this.rootId);
|
|
2209
2334
|
while (!node.leaf) {
|
|
2210
2335
|
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
@@ -2212,15 +2337,8 @@ var require_cjs = __commonJS({
|
|
|
2212
2337
|
}
|
|
2213
2338
|
return node;
|
|
2214
2339
|
}
|
|
2215
|
-
|
|
2216
|
-
const
|
|
2217
|
-
if (!node.next) {
|
|
2218
|
-
return null;
|
|
2219
|
-
}
|
|
2220
|
-
return this.getNode(node.next);
|
|
2221
|
-
}
|
|
2222
|
-
insertableEndNode(value, direction) {
|
|
2223
|
-
const insertableNode = this.insertableNode(value);
|
|
2340
|
+
findOuterBoundaryLeaf(value, direction) {
|
|
2341
|
+
const insertableNode = direction === -1 ? this.findLowerBoundLeaf(value) : this.findUpperBoundLeaf(value);
|
|
2224
2342
|
let key;
|
|
2225
2343
|
switch (direction) {
|
|
2226
2344
|
case -1:
|
|
@@ -2257,13 +2375,10 @@ var require_cjs = __commonJS({
|
|
|
2257
2375
|
}
|
|
2258
2376
|
return node;
|
|
2259
2377
|
}
|
|
2260
|
-
*getPairsGenerator(
|
|
2378
|
+
*getPairsGenerator(startNode, endNode, direction) {
|
|
2261
2379
|
let node = startNode;
|
|
2262
|
-
|
|
2263
|
-
let hasMatched = false;
|
|
2264
|
-
while (!done) {
|
|
2380
|
+
while (true) {
|
|
2265
2381
|
if (endNode && node.id === endNode.id) {
|
|
2266
|
-
done = true;
|
|
2267
2382
|
break;
|
|
2268
2383
|
}
|
|
2269
2384
|
const len = node.values.length;
|
|
@@ -2271,14 +2386,8 @@ var require_cjs = __commonJS({
|
|
|
2271
2386
|
for (let i = 0; i < len; i++) {
|
|
2272
2387
|
const nValue = node.values[i];
|
|
2273
2388
|
const keys = node.keys[i];
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
for (let j = 0; j < keys.length; j++) {
|
|
2277
|
-
yield [keys[j], nValue];
|
|
2278
|
-
}
|
|
2279
|
-
} else if (earlyTerminate && hasMatched) {
|
|
2280
|
-
done = true;
|
|
2281
|
-
break;
|
|
2389
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
2390
|
+
yield [keys[j], nValue];
|
|
2282
2391
|
}
|
|
2283
2392
|
}
|
|
2284
2393
|
} else {
|
|
@@ -2286,30 +2395,17 @@ var require_cjs = __commonJS({
|
|
|
2286
2395
|
while (i--) {
|
|
2287
2396
|
const nValue = node.values[i];
|
|
2288
2397
|
const keys = node.keys[i];
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
while (j--) {
|
|
2293
|
-
yield [keys[j], nValue];
|
|
2294
|
-
}
|
|
2295
|
-
} else if (earlyTerminate && hasMatched) {
|
|
2296
|
-
done = true;
|
|
2297
|
-
break;
|
|
2398
|
+
let j = keys.length;
|
|
2399
|
+
while (j--) {
|
|
2400
|
+
yield [keys[j], nValue];
|
|
2298
2401
|
}
|
|
2299
2402
|
}
|
|
2300
2403
|
}
|
|
2301
|
-
if (done) break;
|
|
2302
2404
|
if (direction === 1) {
|
|
2303
|
-
if (!node.next)
|
|
2304
|
-
done = true;
|
|
2305
|
-
break;
|
|
2306
|
-
}
|
|
2405
|
+
if (!node.next) break;
|
|
2307
2406
|
node = this.getNode(node.next);
|
|
2308
2407
|
} else {
|
|
2309
|
-
if (!node.prev)
|
|
2310
|
-
done = true;
|
|
2311
|
-
break;
|
|
2312
|
-
}
|
|
2408
|
+
if (!node.prev) break;
|
|
2313
2409
|
node = this.getNode(node.prev);
|
|
2314
2410
|
}
|
|
2315
2411
|
}
|
|
@@ -2354,7 +2450,7 @@ var require_cjs = __commonJS({
|
|
|
2354
2450
|
}
|
|
2355
2451
|
}
|
|
2356
2452
|
exists(key, value) {
|
|
2357
|
-
const node = this.
|
|
2453
|
+
const node = this.locateLeaf(value);
|
|
2358
2454
|
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2359
2455
|
if (found) {
|
|
2360
2456
|
const keys = node.keys[index];
|
|
@@ -2398,49 +2494,36 @@ var require_cjs = __commonJS({
|
|
|
2398
2494
|
}
|
|
2399
2495
|
*whereStream(condition, options) {
|
|
2400
2496
|
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2401
|
-
const
|
|
2402
|
-
if (
|
|
2403
|
-
const
|
|
2404
|
-
const
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
if (
|
|
2414
|
-
|
|
2497
|
+
const conditionKeys = Object.keys(condition);
|
|
2498
|
+
if (conditionKeys.length === 0) return;
|
|
2499
|
+
const resolved = this.resolveStartEndConfigs(condition, order);
|
|
2500
|
+
const direction = resolved.direction;
|
|
2501
|
+
let startNode;
|
|
2502
|
+
if (resolved.startKey) {
|
|
2503
|
+
const startConfig = this.searchConfigs[resolved.startKey][order];
|
|
2504
|
+
startNode = startConfig.start(this, resolved.startValues);
|
|
2505
|
+
} else {
|
|
2506
|
+
startNode = order === "asc" ? this.leftestNode() : this.rightestNode();
|
|
2507
|
+
}
|
|
2508
|
+
let endNode = null;
|
|
2509
|
+
if (resolved.endKey) {
|
|
2510
|
+
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
2511
|
+
endNode = endConfig.end(this, resolved.endValues);
|
|
2415
2512
|
}
|
|
2416
2513
|
if (!startNode) return;
|
|
2417
|
-
const comparator = this.verifierMap[driverKey];
|
|
2418
2514
|
const generator = this.getPairsGenerator(
|
|
2419
|
-
value,
|
|
2420
2515
|
startNode,
|
|
2421
2516
|
endNode,
|
|
2422
|
-
|
|
2423
|
-
direction,
|
|
2424
|
-
earlyTerminate
|
|
2517
|
+
direction
|
|
2425
2518
|
);
|
|
2426
2519
|
let count = 0;
|
|
2427
2520
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2428
2521
|
for (const pair of generator) {
|
|
2429
|
-
const [k,
|
|
2522
|
+
const [k, v] = pair;
|
|
2430
2523
|
if (intersection && !intersection.has(k)) {
|
|
2431
2524
|
continue;
|
|
2432
2525
|
}
|
|
2433
|
-
|
|
2434
|
-
for (const key in condition) {
|
|
2435
|
-
if (key === driverKey) continue;
|
|
2436
|
-
const verify = this.verifierMap[key];
|
|
2437
|
-
const condValue = condition[key];
|
|
2438
|
-
if (!verify(v2, condValue)) {
|
|
2439
|
-
isMatch = false;
|
|
2440
|
-
break;
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
if (isMatch) {
|
|
2526
|
+
if (this.verify(v, condition)) {
|
|
2444
2527
|
yield pair;
|
|
2445
2528
|
count++;
|
|
2446
2529
|
if (limit !== void 0 && count >= limit) {
|
|
@@ -2464,7 +2547,7 @@ var require_cjs = __commonJS({
|
|
|
2464
2547
|
return map;
|
|
2465
2548
|
}
|
|
2466
2549
|
insert(key, value) {
|
|
2467
|
-
let before = this.
|
|
2550
|
+
let before = this.locateLeaf(value);
|
|
2468
2551
|
before = this._insertAtLeaf(before, key, value);
|
|
2469
2552
|
if (before.values.length === this.order) {
|
|
2470
2553
|
let after = this._createNode(
|
|
@@ -2492,7 +2575,7 @@ var require_cjs = __commonJS({
|
|
|
2492
2575
|
let currentLeaf = null;
|
|
2493
2576
|
let modified = false;
|
|
2494
2577
|
for (const [key, value] of sorted) {
|
|
2495
|
-
const targetLeaf = this.
|
|
2578
|
+
const targetLeaf = this.locateLeaf(value);
|
|
2496
2579
|
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
2497
2580
|
} else {
|
|
2498
2581
|
if (currentLeaf !== null && modified) {
|
|
@@ -2734,7 +2817,7 @@ var require_cjs = __commonJS({
|
|
|
2734
2817
|
if (value === void 0) {
|
|
2735
2818
|
return;
|
|
2736
2819
|
}
|
|
2737
|
-
let node = this.
|
|
2820
|
+
let node = this.findLowerBoundLeaf(value);
|
|
2738
2821
|
let found = false;
|
|
2739
2822
|
while (true) {
|
|
2740
2823
|
let i = node.values.length;
|
|
@@ -2890,7 +2973,7 @@ var require_cjs = __commonJS({
|
|
|
2890
2973
|
}
|
|
2891
2974
|
}
|
|
2892
2975
|
};
|
|
2893
|
-
var
|
|
2976
|
+
var Ryoiki2 = class _Ryoiki2 {
|
|
2894
2977
|
readings;
|
|
2895
2978
|
writings;
|
|
2896
2979
|
readQueue;
|
|
@@ -3157,7 +3240,7 @@ var require_cjs = __commonJS({
|
|
|
3157
3240
|
comparator,
|
|
3158
3241
|
option
|
|
3159
3242
|
);
|
|
3160
|
-
this.lock = new
|
|
3243
|
+
this.lock = new Ryoiki2();
|
|
3161
3244
|
}
|
|
3162
3245
|
async writeLock(id, fn) {
|
|
3163
3246
|
let lockId;
|
|
@@ -3316,7 +3399,7 @@ var require_cjs = __commonJS({
|
|
|
3316
3399
|
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
3317
3400
|
}
|
|
3318
3401
|
}
|
|
3319
|
-
async
|
|
3402
|
+
async locateLeaf(value) {
|
|
3320
3403
|
let node = await this.getNode(this.rootId);
|
|
3321
3404
|
while (!node.leaf) {
|
|
3322
3405
|
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
@@ -3324,7 +3407,7 @@ var require_cjs = __commonJS({
|
|
|
3324
3407
|
}
|
|
3325
3408
|
return node;
|
|
3326
3409
|
}
|
|
3327
|
-
async
|
|
3410
|
+
async findLowerBoundLeaf(value) {
|
|
3328
3411
|
let node = await this.getNode(this.rootId);
|
|
3329
3412
|
while (!node.leaf) {
|
|
3330
3413
|
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
@@ -3332,7 +3415,7 @@ var require_cjs = __commonJS({
|
|
|
3332
3415
|
}
|
|
3333
3416
|
return node;
|
|
3334
3417
|
}
|
|
3335
|
-
async
|
|
3418
|
+
async findUpperBoundLeaf(value) {
|
|
3336
3419
|
let node = await this.getNode(this.rootId);
|
|
3337
3420
|
while (!node.leaf) {
|
|
3338
3421
|
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
@@ -3340,15 +3423,8 @@ var require_cjs = __commonJS({
|
|
|
3340
3423
|
}
|
|
3341
3424
|
return node;
|
|
3342
3425
|
}
|
|
3343
|
-
async
|
|
3344
|
-
const
|
|
3345
|
-
if (!node.next) {
|
|
3346
|
-
return null;
|
|
3347
|
-
}
|
|
3348
|
-
return await this.getNode(node.next);
|
|
3349
|
-
}
|
|
3350
|
-
async insertableEndNode(value, direction) {
|
|
3351
|
-
const insertableNode = await this.insertableNode(value);
|
|
3426
|
+
async findOuterBoundaryLeaf(value, direction) {
|
|
3427
|
+
const insertableNode = direction === -1 ? await this.findLowerBoundLeaf(value) : await this.findUpperBoundLeaf(value);
|
|
3352
3428
|
let key;
|
|
3353
3429
|
switch (direction) {
|
|
3354
3430
|
case -1:
|
|
@@ -3385,22 +3461,19 @@ var require_cjs = __commonJS({
|
|
|
3385
3461
|
}
|
|
3386
3462
|
return node;
|
|
3387
3463
|
}
|
|
3388
|
-
async *getPairsGenerator(
|
|
3464
|
+
async *getPairsGenerator(startNode, endNode, direction) {
|
|
3389
3465
|
let node = startNode;
|
|
3390
|
-
let done = false;
|
|
3391
|
-
let hasMatched = false;
|
|
3392
3466
|
let nextNodePromise = null;
|
|
3393
|
-
while (
|
|
3467
|
+
while (true) {
|
|
3394
3468
|
if (endNode && node.id === endNode.id) {
|
|
3395
|
-
done = true;
|
|
3396
3469
|
break;
|
|
3397
3470
|
}
|
|
3398
3471
|
if (direction === 1) {
|
|
3399
|
-
if (node.next
|
|
3472
|
+
if (node.next) {
|
|
3400
3473
|
nextNodePromise = this.getNode(node.next);
|
|
3401
3474
|
}
|
|
3402
3475
|
} else {
|
|
3403
|
-
if (node.prev
|
|
3476
|
+
if (node.prev) {
|
|
3404
3477
|
nextNodePromise = this.getNode(node.prev);
|
|
3405
3478
|
}
|
|
3406
3479
|
}
|
|
@@ -3409,14 +3482,8 @@ var require_cjs = __commonJS({
|
|
|
3409
3482
|
for (let i = 0; i < len; i++) {
|
|
3410
3483
|
const nValue = node.values[i];
|
|
3411
3484
|
const keys = node.keys[i];
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
for (let j = 0; j < keys.length; j++) {
|
|
3415
|
-
yield [keys[j], nValue];
|
|
3416
|
-
}
|
|
3417
|
-
} else if (earlyTerminate && hasMatched) {
|
|
3418
|
-
done = true;
|
|
3419
|
-
break;
|
|
3485
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
3486
|
+
yield [keys[j], nValue];
|
|
3420
3487
|
}
|
|
3421
3488
|
}
|
|
3422
3489
|
} else {
|
|
@@ -3424,27 +3491,17 @@ var require_cjs = __commonJS({
|
|
|
3424
3491
|
while (i--) {
|
|
3425
3492
|
const nValue = node.values[i];
|
|
3426
3493
|
const keys = node.keys[i];
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
while (j--) {
|
|
3431
|
-
yield [keys[j], nValue];
|
|
3432
|
-
}
|
|
3433
|
-
} else if (earlyTerminate && hasMatched) {
|
|
3434
|
-
done = true;
|
|
3435
|
-
break;
|
|
3494
|
+
let j = keys.length;
|
|
3495
|
+
while (j--) {
|
|
3496
|
+
yield [keys[j], nValue];
|
|
3436
3497
|
}
|
|
3437
3498
|
}
|
|
3438
3499
|
}
|
|
3439
|
-
if (done) {
|
|
3440
|
-
if (nextNodePromise) await nextNodePromise;
|
|
3441
|
-
break;
|
|
3442
|
-
}
|
|
3443
3500
|
if (nextNodePromise) {
|
|
3444
3501
|
node = await nextNodePromise;
|
|
3445
3502
|
nextNodePromise = null;
|
|
3446
3503
|
} else {
|
|
3447
|
-
|
|
3504
|
+
break;
|
|
3448
3505
|
}
|
|
3449
3506
|
}
|
|
3450
3507
|
}
|
|
@@ -3488,7 +3545,7 @@ var require_cjs = __commonJS({
|
|
|
3488
3545
|
}
|
|
3489
3546
|
}
|
|
3490
3547
|
async exists(key, value) {
|
|
3491
|
-
const node = await this.
|
|
3548
|
+
const node = await this.locateLeaf(value);
|
|
3492
3549
|
const { index, found } = this._binarySearchValues(node.values, value);
|
|
3493
3550
|
if (found) {
|
|
3494
3551
|
const keys = node.keys[index];
|
|
@@ -3532,49 +3589,36 @@ var require_cjs = __commonJS({
|
|
|
3532
3589
|
}
|
|
3533
3590
|
async *whereStream(condition, options) {
|
|
3534
3591
|
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
3535
|
-
const
|
|
3536
|
-
if (
|
|
3537
|
-
const
|
|
3538
|
-
const
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
if (
|
|
3548
|
-
|
|
3592
|
+
const conditionKeys = Object.keys(condition);
|
|
3593
|
+
if (conditionKeys.length === 0) return;
|
|
3594
|
+
const resolved = this.resolveStartEndConfigs(condition, order);
|
|
3595
|
+
const direction = resolved.direction;
|
|
3596
|
+
let startNode;
|
|
3597
|
+
if (resolved.startKey) {
|
|
3598
|
+
const startConfig = this.searchConfigs[resolved.startKey][order];
|
|
3599
|
+
startNode = await startConfig.start(this, resolved.startValues);
|
|
3600
|
+
} else {
|
|
3601
|
+
startNode = order === "asc" ? await this.leftestNode() : await this.rightestNode();
|
|
3602
|
+
}
|
|
3603
|
+
let endNode = null;
|
|
3604
|
+
if (resolved.endKey) {
|
|
3605
|
+
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
3606
|
+
endNode = await endConfig.end(this, resolved.endValues);
|
|
3549
3607
|
}
|
|
3550
3608
|
if (!startNode) return;
|
|
3551
|
-
const comparator = this.verifierMap[driverKey];
|
|
3552
3609
|
const generator = this.getPairsGenerator(
|
|
3553
|
-
value,
|
|
3554
3610
|
startNode,
|
|
3555
3611
|
endNode,
|
|
3556
|
-
|
|
3557
|
-
direction,
|
|
3558
|
-
earlyTerminate
|
|
3612
|
+
direction
|
|
3559
3613
|
);
|
|
3560
3614
|
let count = 0;
|
|
3561
3615
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3562
3616
|
for await (const pair of generator) {
|
|
3563
|
-
const [k,
|
|
3617
|
+
const [k, v] = pair;
|
|
3564
3618
|
if (intersection && !intersection.has(k)) {
|
|
3565
3619
|
continue;
|
|
3566
3620
|
}
|
|
3567
|
-
|
|
3568
|
-
for (const key in condition) {
|
|
3569
|
-
if (key === driverKey) continue;
|
|
3570
|
-
const verify = this.verifierMap[key];
|
|
3571
|
-
const condValue = condition[key];
|
|
3572
|
-
if (!verify(v2, condValue)) {
|
|
3573
|
-
isMatch = false;
|
|
3574
|
-
break;
|
|
3575
|
-
}
|
|
3576
|
-
}
|
|
3577
|
-
if (isMatch) {
|
|
3621
|
+
if (this.verify(v, condition)) {
|
|
3578
3622
|
yield pair;
|
|
3579
3623
|
count++;
|
|
3580
3624
|
if (limit !== void 0 && count >= limit) {
|
|
@@ -3599,7 +3643,7 @@ var require_cjs = __commonJS({
|
|
|
3599
3643
|
}
|
|
3600
3644
|
async insert(key, value) {
|
|
3601
3645
|
return this.writeLock(0, async () => {
|
|
3602
|
-
let before = await this.
|
|
3646
|
+
let before = await this.locateLeaf(value);
|
|
3603
3647
|
before = await this._insertAtLeaf(before, key, value);
|
|
3604
3648
|
if (before.values.length === this.order) {
|
|
3605
3649
|
let after = await this._createNode(
|
|
@@ -3629,7 +3673,7 @@ var require_cjs = __commonJS({
|
|
|
3629
3673
|
let currentLeaf = null;
|
|
3630
3674
|
let modified = false;
|
|
3631
3675
|
for (const [key, value] of sorted) {
|
|
3632
|
-
const targetLeaf = await this.
|
|
3676
|
+
const targetLeaf = await this.locateLeaf(value);
|
|
3633
3677
|
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
3634
3678
|
} else {
|
|
3635
3679
|
if (currentLeaf !== null && modified) {
|
|
@@ -3873,7 +3917,7 @@ var require_cjs = __commonJS({
|
|
|
3873
3917
|
if (value === void 0) {
|
|
3874
3918
|
return;
|
|
3875
3919
|
}
|
|
3876
|
-
let node = await this.
|
|
3920
|
+
let node = await this.findLowerBoundLeaf(value);
|
|
3877
3921
|
let found = false;
|
|
3878
3922
|
while (true) {
|
|
3879
3923
|
let i = node.values.length;
|
|
@@ -4099,7 +4143,7 @@ var require_cjs = __commonJS({
|
|
|
4099
4143
|
}
|
|
4100
4144
|
};
|
|
4101
4145
|
var SerializeStrategyAsync2 = class extends SerializeStrategy {
|
|
4102
|
-
lock = new
|
|
4146
|
+
lock = new Ryoiki2();
|
|
4103
4147
|
async acquireLock(action) {
|
|
4104
4148
|
let lockId;
|
|
4105
4149
|
return this.lock.writeLock((_lockId) => {
|
|
@@ -4869,39 +4913,125 @@ var require_cjs = __commonJS({
|
|
|
4869
4913
|
var MVCCStrategy2 = class {
|
|
4870
4914
|
};
|
|
4871
4915
|
var LRUMap3 = class {
|
|
4872
|
-
cache = /* @__PURE__ */ new Map();
|
|
4873
4916
|
capacity;
|
|
4917
|
+
map;
|
|
4918
|
+
head = null;
|
|
4919
|
+
tail = null;
|
|
4920
|
+
/**
|
|
4921
|
+
* Creates an instance of LRUMap.
|
|
4922
|
+
* @param capacity The maximum number of items the cache can hold.
|
|
4923
|
+
*/
|
|
4874
4924
|
constructor(capacity) {
|
|
4875
4925
|
this.capacity = capacity;
|
|
4926
|
+
this.map = /* @__PURE__ */ new Map();
|
|
4876
4927
|
}
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4928
|
+
/**
|
|
4929
|
+
* Promotes a node to the head of the linked list (marks as most recently used).
|
|
4930
|
+
* @param node The node to promote.
|
|
4931
|
+
*/
|
|
4932
|
+
promote(node) {
|
|
4933
|
+
this.extract(node);
|
|
4934
|
+
this.prepend(node);
|
|
4935
|
+
}
|
|
4936
|
+
/**
|
|
4937
|
+
* Disconnects a node from the doubly linked list.
|
|
4938
|
+
* @param node The node to extract.
|
|
4939
|
+
*/
|
|
4940
|
+
extract(node) {
|
|
4941
|
+
if (node.prev) node.prev.next = node.next;
|
|
4942
|
+
else this.head = node.next;
|
|
4943
|
+
if (node.next) node.next.prev = node.prev;
|
|
4944
|
+
else this.tail = node.prev;
|
|
4945
|
+
node.prev = null;
|
|
4946
|
+
node.next = null;
|
|
4883
4947
|
}
|
|
4948
|
+
/**
|
|
4949
|
+
* Inserts a node at the head of the doubly linked list.
|
|
4950
|
+
* @param node The node to prepend.
|
|
4951
|
+
*/
|
|
4952
|
+
prepend(node) {
|
|
4953
|
+
node.next = this.head;
|
|
4954
|
+
if (this.head) this.head.prev = node;
|
|
4955
|
+
this.head = node;
|
|
4956
|
+
if (!this.tail) this.tail = node;
|
|
4957
|
+
}
|
|
4958
|
+
/**
|
|
4959
|
+
* Stores or updates a value by key.
|
|
4960
|
+
* If the capacity is exceeded, the least recently used item (tail) is removed.
|
|
4961
|
+
* @param key The key to store.
|
|
4962
|
+
* @param value The value to store.
|
|
4963
|
+
*/
|
|
4884
4964
|
set(key, value) {
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4965
|
+
const existing = this.map.get(key);
|
|
4966
|
+
if (existing) {
|
|
4967
|
+
existing.value = value;
|
|
4968
|
+
this.promote(existing);
|
|
4969
|
+
return;
|
|
4970
|
+
}
|
|
4971
|
+
const newNode = { key, value, prev: null, next: null };
|
|
4972
|
+
this.map.set(key, newNode);
|
|
4973
|
+
this.prepend(newNode);
|
|
4974
|
+
if (this.map.size > this.capacity && this.tail) {
|
|
4975
|
+
this.map.delete(this.tail.key);
|
|
4976
|
+
this.extract(this.tail);
|
|
4890
4977
|
}
|
|
4891
|
-
this.cache.set(key, value);
|
|
4892
|
-
return this;
|
|
4893
4978
|
}
|
|
4979
|
+
/**
|
|
4980
|
+
* Retrieves a value by key.
|
|
4981
|
+
* Accessing the item moves it to the "most recently used" position.
|
|
4982
|
+
* @param key The key to look for.
|
|
4983
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
4984
|
+
*/
|
|
4985
|
+
get(key) {
|
|
4986
|
+
const node = this.map.get(key);
|
|
4987
|
+
if (!node) return void 0;
|
|
4988
|
+
this.promote(node);
|
|
4989
|
+
return node.value;
|
|
4990
|
+
}
|
|
4991
|
+
/**
|
|
4992
|
+
* Checks if a key exists in the cache without changing its access order.
|
|
4993
|
+
* @param key The key to check.
|
|
4994
|
+
* @returns True if the key exists, false otherwise.
|
|
4995
|
+
*/
|
|
4894
4996
|
has(key) {
|
|
4895
|
-
return this.
|
|
4997
|
+
return this.map.has(key);
|
|
4896
4998
|
}
|
|
4999
|
+
/**
|
|
5000
|
+
* Removes a key and its associated value from the cache.
|
|
5001
|
+
* @param key The key to remove.
|
|
5002
|
+
* @returns True if the key was found and removed, false otherwise.
|
|
5003
|
+
*/
|
|
4897
5004
|
delete(key) {
|
|
4898
|
-
|
|
5005
|
+
const node = this.map.get(key);
|
|
5006
|
+
if (!node) return false;
|
|
5007
|
+
this.extract(node);
|
|
5008
|
+
this.map.delete(key);
|
|
5009
|
+
return true;
|
|
4899
5010
|
}
|
|
4900
|
-
|
|
4901
|
-
|
|
5011
|
+
/**
|
|
5012
|
+
* Returns an iterator of keys in the order of most recently used to least recently used.
|
|
5013
|
+
* @returns An iterable iterator of keys.
|
|
5014
|
+
*/
|
|
5015
|
+
*keys() {
|
|
5016
|
+
let current = this.head;
|
|
5017
|
+
while (current) {
|
|
5018
|
+
yield current.key;
|
|
5019
|
+
current = current.next;
|
|
5020
|
+
}
|
|
4902
5021
|
}
|
|
5022
|
+
/**
|
|
5023
|
+
* Returns the current number of items in the cache.
|
|
5024
|
+
*/
|
|
4903
5025
|
get size() {
|
|
4904
|
-
return this.
|
|
5026
|
+
return this.map.size;
|
|
5027
|
+
}
|
|
5028
|
+
/**
|
|
5029
|
+
* Clears all items from the cache.
|
|
5030
|
+
*/
|
|
5031
|
+
clear() {
|
|
5032
|
+
this.map.clear();
|
|
5033
|
+
this.head = null;
|
|
5034
|
+
this.tail = null;
|
|
4905
5035
|
}
|
|
4906
5036
|
};
|
|
4907
5037
|
var MVCCTransaction2 = class {
|
|
@@ -6348,21 +6478,66 @@ var require_cjs = __commonJS({
|
|
|
6348
6478
|
}
|
|
6349
6479
|
return (crc ^ -1) >>> 0;
|
|
6350
6480
|
}
|
|
6351
|
-
function
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6481
|
+
function calcThreshold(sortedGaps, n) {
|
|
6482
|
+
const gLen = sortedGaps.length;
|
|
6483
|
+
if (gLen === 0) return 0;
|
|
6484
|
+
const median = sortedGaps[Math.floor(gLen * 0.5)];
|
|
6485
|
+
const q1 = sortedGaps[Math.floor(gLen * 0.25)];
|
|
6486
|
+
const q3 = sortedGaps[Math.floor(gLen * 0.75)];
|
|
6487
|
+
const iqr = q3 - q1;
|
|
6488
|
+
const logN = Math.max(1, Math.log10(n));
|
|
6489
|
+
if (iqr > 0) {
|
|
6490
|
+
const threshold2 = q3 + iqr * 1.5 * logN;
|
|
6491
|
+
const minJump = Math.max(median * 5, 20);
|
|
6492
|
+
return Math.max(threshold2, minJump);
|
|
6493
|
+
}
|
|
6494
|
+
const baseGap = median > 0 ? median : 1;
|
|
6495
|
+
const p90 = sortedGaps[Math.floor(gLen * 0.9)];
|
|
6496
|
+
if (p90 > baseGap) {
|
|
6497
|
+
const threshold2 = baseGap + (p90 - baseGap) * 0.5 * logN;
|
|
6498
|
+
return Math.max(threshold2, baseGap * 5, 20);
|
|
6499
|
+
}
|
|
6500
|
+
let mean = 0;
|
|
6501
|
+
for (let i = 0; i < gLen; i++) mean += sortedGaps[i];
|
|
6502
|
+
mean /= gLen;
|
|
6503
|
+
let variance = 0;
|
|
6504
|
+
for (let i = 0; i < gLen; i++) {
|
|
6505
|
+
const d = sortedGaps[i] - mean;
|
|
6506
|
+
variance += d * d;
|
|
6507
|
+
}
|
|
6508
|
+
const stddev = Math.sqrt(variance / gLen);
|
|
6509
|
+
if (stddev === 0) {
|
|
6510
|
+
return baseGap * 2;
|
|
6511
|
+
}
|
|
6512
|
+
const threshold = mean + stddev * logN;
|
|
6513
|
+
return Math.max(threshold, baseGap * 5, 20);
|
|
6514
|
+
}
|
|
6515
|
+
function clusterNumbers(numbers, maxGap) {
|
|
6516
|
+
const n = numbers.length;
|
|
6517
|
+
if (n === 0) return [];
|
|
6518
|
+
if (n === 1) return [new Float64Array([numbers[0]])];
|
|
6519
|
+
const sorted = (numbers instanceof Float64Array ? numbers.slice() : Float64Array.from(numbers)).sort();
|
|
6520
|
+
const gaps = new Float64Array(n - 1);
|
|
6521
|
+
for (let i = 0, len = n - 1; i < len; i++) {
|
|
6522
|
+
gaps[i] = sorted[i + 1] - sorted[i];
|
|
6523
|
+
}
|
|
6524
|
+
const sortedGaps = gaps.slice().sort();
|
|
6525
|
+
let threshold;
|
|
6526
|
+
if (maxGap !== void 0) {
|
|
6527
|
+
threshold = maxGap;
|
|
6528
|
+
} else {
|
|
6529
|
+
threshold = calcThreshold(sortedGaps, n);
|
|
6530
|
+
}
|
|
6531
|
+
const clusters = [];
|
|
6532
|
+
let clusterStart = 0;
|
|
6533
|
+
for (let i = 0, len = n - 1; i < len; i++) {
|
|
6534
|
+
if (gaps[i] > threshold) {
|
|
6535
|
+
clusters.push(sorted.subarray(clusterStart, i + 1));
|
|
6536
|
+
clusterStart = i + 1;
|
|
6362
6537
|
}
|
|
6363
|
-
i++;
|
|
6364
6538
|
}
|
|
6365
|
-
|
|
6539
|
+
clusters.push(sorted.subarray(clusterStart));
|
|
6540
|
+
return clusters;
|
|
6366
6541
|
}
|
|
6367
6542
|
var Row = class _Row {
|
|
6368
6543
|
static CONSTANT = {
|
|
@@ -8180,9 +8355,6 @@ var require_cjs = __commonJS({
|
|
|
8180
8355
|
*/
|
|
8181
8356
|
async write(pageId, data) {
|
|
8182
8357
|
const pageStartPos = pageId * this.pageSize;
|
|
8183
|
-
if (pageStartPos + this.pageSize > 512 * 1024 * 1024) {
|
|
8184
|
-
throw new Error(`[Safety Limit] File write exceeds 512MB limit at position ${pageStartPos}`);
|
|
8185
|
-
}
|
|
8186
8358
|
const dataCopy = new Uint8Array(this.pageSize);
|
|
8187
8359
|
dataCopy.set(data);
|
|
8188
8360
|
this.dirtyPages.set(pageId, dataCopy);
|
|
@@ -8209,6 +8381,22 @@ var require_cjs = __commonJS({
|
|
|
8209
8381
|
this.dirtyPages.delete(pageId);
|
|
8210
8382
|
}
|
|
8211
8383
|
}
|
|
8384
|
+
/**
|
|
8385
|
+
* 지정된 페이지들만 디스크에 기록합니다.
|
|
8386
|
+
* WAL 없이 트랜잭션 커밋 시, 해당 트랜잭션의 dirty pages만 선택적으로 flush합니다.
|
|
8387
|
+
* @param pages 기록할 페이지 맵 (PageID -> PageData)
|
|
8388
|
+
*/
|
|
8389
|
+
async flushPages(pages) {
|
|
8390
|
+
if (pages.size === 0) {
|
|
8391
|
+
return;
|
|
8392
|
+
}
|
|
8393
|
+
const sortedPageIds = Array.from(pages.keys()).sort((a, b) => a - b);
|
|
8394
|
+
for (const pageId of sortedPageIds) {
|
|
8395
|
+
const data = pages.get(pageId);
|
|
8396
|
+
const position = pageId * this.pageSize;
|
|
8397
|
+
await this._writeToDisk(data, position);
|
|
8398
|
+
}
|
|
8399
|
+
}
|
|
8212
8400
|
/**
|
|
8213
8401
|
* 메인 DB 파일의 물리적 동기화를 수행합니다 (fsync).
|
|
8214
8402
|
*/
|
|
@@ -8499,7 +8687,6 @@ var require_cjs = __commonJS({
|
|
|
8499
8687
|
const nextFreePageId = reusedPageManager.getNextPageId(reusedPage);
|
|
8500
8688
|
metadataManager.setFreePageId(metadata, nextFreePageId);
|
|
8501
8689
|
await this.setPage(0, metadata, tx);
|
|
8502
|
-
await this.updateBitmap(reusedPageId, false, tx);
|
|
8503
8690
|
const manager2 = this.pageFactory.getManagerFromType(pageType);
|
|
8504
8691
|
const newPage2 = manager2.create(this.pageSize, reusedPageId);
|
|
8505
8692
|
await this.setPage(reusedPageId, newPage2, tx);
|
|
@@ -8525,7 +8712,6 @@ var require_cjs = __commonJS({
|
|
|
8525
8712
|
const nextId = i < lastFreeIndex ? i + 1 : -1;
|
|
8526
8713
|
emptyManager.setNextPageId(emptyPage, nextId);
|
|
8527
8714
|
await this.setPage(i, emptyPage, tx);
|
|
8528
|
-
await this.updateBitmap(i, true, tx);
|
|
8529
8715
|
}
|
|
8530
8716
|
return newPageIndex;
|
|
8531
8717
|
}
|
|
@@ -8623,7 +8809,6 @@ var require_cjs = __commonJS({
|
|
|
8623
8809
|
const emptyPage = emptyPageManager.create(this.pageSize, pageId);
|
|
8624
8810
|
emptyPageManager.setNextPageId(emptyPage, currentHeadFreePageId);
|
|
8625
8811
|
await this.setPage(pageId, emptyPage, tx);
|
|
8626
|
-
await this.updateBitmap(pageId, true, tx);
|
|
8627
8812
|
metadataManager.setFreePageId(metadata, pageId);
|
|
8628
8813
|
await this.setPage(0, metadata, tx);
|
|
8629
8814
|
}
|
|
@@ -9292,17 +9477,40 @@ var require_cjs = __commonJS({
|
|
|
9292
9477
|
for (let i = 0, len = pks.length; i < len; i++) {
|
|
9293
9478
|
pkIndexMap.set(pks[i], i);
|
|
9294
9479
|
}
|
|
9295
|
-
const
|
|
9296
|
-
const
|
|
9480
|
+
const validCount = pks.length;
|
|
9481
|
+
const pkArray = new Float64Array(validCount).fill(0);
|
|
9482
|
+
const ridArray = new Float64Array(validCount).fill(0);
|
|
9483
|
+
const indexArray = new Float64Array(validCount).fill(0);
|
|
9297
9484
|
const btx = await this.getBPTreeTransaction(tx);
|
|
9298
|
-
const
|
|
9299
|
-
for
|
|
9300
|
-
const
|
|
9301
|
-
|
|
9302
|
-
|
|
9485
|
+
const clusters = clusterNumbers(pks, this.order / 2);
|
|
9486
|
+
for (let i = 0, len = clusters.length; i < len; i++) {
|
|
9487
|
+
const cluster = clusters[i];
|
|
9488
|
+
const minPk = cluster[0];
|
|
9489
|
+
const maxPk = cluster[cluster.length - 1];
|
|
9490
|
+
if (minPk === maxPk) {
|
|
9491
|
+
const keys = await btx.keys({ equal: minPk });
|
|
9492
|
+
if (keys.size > 0) {
|
|
9493
|
+
const rid = keys.values().next().value;
|
|
9494
|
+
const index = pkIndexMap.get(minPk);
|
|
9495
|
+
if (index !== void 0) {
|
|
9496
|
+
pkArray[index] = minPk;
|
|
9497
|
+
ridArray[index] = rid;
|
|
9498
|
+
indexArray[index] = index;
|
|
9499
|
+
}
|
|
9500
|
+
}
|
|
9501
|
+
continue;
|
|
9502
|
+
}
|
|
9503
|
+
const stream = btx.whereStream({ gte: minPk, lte: maxPk });
|
|
9504
|
+
for await (const [rid, pk] of stream) {
|
|
9505
|
+
const index = pkIndexMap.get(pk);
|
|
9506
|
+
if (index !== void 0) {
|
|
9507
|
+
pkArray[index] = pk;
|
|
9508
|
+
ridArray[index] = rid;
|
|
9509
|
+
indexArray[index] = index;
|
|
9510
|
+
}
|
|
9303
9511
|
}
|
|
9304
9512
|
}
|
|
9305
|
-
return this.fetchRowsByRids(
|
|
9513
|
+
return this.fetchRowsByRids(validCount, pkArray, ridArray, indexArray, tx);
|
|
9306
9514
|
}
|
|
9307
9515
|
/**
|
|
9308
9516
|
* Fetches multiple rows by their RID and PK combinations, grouping by page ID to minimize I/O.
|
|
@@ -9310,19 +9518,21 @@ var require_cjs = __commonJS({
|
|
|
9310
9518
|
* @param tx Transaction
|
|
9311
9519
|
* @returns Array of row data in the same order as input PKs
|
|
9312
9520
|
*/
|
|
9313
|
-
async fetchRowsByRids(
|
|
9314
|
-
const result = new Array(
|
|
9315
|
-
if (
|
|
9521
|
+
async fetchRowsByRids(validCount, pkArray, ridArray, indexArray, tx) {
|
|
9522
|
+
const result = new Array(validCount).fill(null);
|
|
9523
|
+
if (validCount === 0) return result;
|
|
9316
9524
|
const pageGroupMap = /* @__PURE__ */ new Map();
|
|
9317
|
-
for (
|
|
9318
|
-
|
|
9319
|
-
const rid =
|
|
9525
|
+
for (let i = 0; i < validCount; i++) {
|
|
9526
|
+
const pk = pkArray[i];
|
|
9527
|
+
const rid = ridArray[i];
|
|
9528
|
+
const index = indexArray[i];
|
|
9529
|
+
if (pk === 0 && rid === 0 && index === 0) continue;
|
|
9320
9530
|
const slotIndex = rid % 65536;
|
|
9321
9531
|
const pageId = Math.floor(rid / 65536);
|
|
9322
9532
|
if (!pageGroupMap.has(pageId)) {
|
|
9323
9533
|
pageGroupMap.set(pageId, []);
|
|
9324
9534
|
}
|
|
9325
|
-
pageGroupMap.get(pageId).push({ pk
|
|
9535
|
+
pageGroupMap.get(pageId).push({ pk, slotIndex, index });
|
|
9326
9536
|
}
|
|
9327
9537
|
const sortedPageIds = Array.from(pageGroupMap.keys()).sort((a, b) => a - b);
|
|
9328
9538
|
await Promise.all(sortedPageIds.map(async (pageId) => {
|
|
@@ -9332,7 +9542,8 @@ var require_cjs = __commonJS({
|
|
|
9332
9542
|
throw new Error(`Page ${pageId} is not a data page`);
|
|
9333
9543
|
}
|
|
9334
9544
|
const manager = this.factory.getManager(page);
|
|
9335
|
-
for (
|
|
9545
|
+
for (let i = 0, len = items.length; i < len; i++) {
|
|
9546
|
+
const item = items[i];
|
|
9336
9547
|
const row = manager.getRow(page, item.slotIndex);
|
|
9337
9548
|
if (this.rowManager.getDeletedFlag(row)) {
|
|
9338
9549
|
result[item.index] = null;
|
|
@@ -9460,6 +9671,8 @@ var require_cjs = __commonJS({
|
|
|
9460
9671
|
commitHooks = [];
|
|
9461
9672
|
/** Page MVCC Strategy for disk access */
|
|
9462
9673
|
pageStrategy;
|
|
9674
|
+
/** Release function for global write lock, set by DataplyAPI */
|
|
9675
|
+
_writeLockRelease = null;
|
|
9463
9676
|
/**
|
|
9464
9677
|
* Sets the BPTree transaction.
|
|
9465
9678
|
* @param tx BPTree transaction
|
|
@@ -9494,6 +9707,19 @@ var require_cjs = __commonJS({
|
|
|
9494
9707
|
onCommit(hook) {
|
|
9495
9708
|
this.commitHooks.push(hook);
|
|
9496
9709
|
}
|
|
9710
|
+
/**
|
|
9711
|
+
* Sets the global write lock release function.
|
|
9712
|
+
* Called by DataplyAPI.runWithDefaultWrite when acquiring the lock.
|
|
9713
|
+
*/
|
|
9714
|
+
__setWriteLockRelease(release) {
|
|
9715
|
+
this._writeLockRelease = release;
|
|
9716
|
+
}
|
|
9717
|
+
/**
|
|
9718
|
+
* Returns whether this transaction already has a write lock.
|
|
9719
|
+
*/
|
|
9720
|
+
__hasWriteLockRelease() {
|
|
9721
|
+
return this._writeLockRelease !== null;
|
|
9722
|
+
}
|
|
9497
9723
|
/**
|
|
9498
9724
|
* Reads a page. Uses dirty buffer if available, otherwise disk.
|
|
9499
9725
|
* @param pageId Page ID
|
|
@@ -9539,44 +9765,60 @@ var require_cjs = __commonJS({
|
|
|
9539
9765
|
* Commits the transaction.
|
|
9540
9766
|
*/
|
|
9541
9767
|
async commit() {
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
this.pfs.wal
|
|
9558
|
-
|
|
9559
|
-
|
|
9768
|
+
try {
|
|
9769
|
+
await this.context.run(this, async () => {
|
|
9770
|
+
for (const hook of this.commitHooks) {
|
|
9771
|
+
await hook();
|
|
9772
|
+
}
|
|
9773
|
+
});
|
|
9774
|
+
let shouldTriggerCheckpoint = false;
|
|
9775
|
+
await this.pfs.runGlobalLock(async () => {
|
|
9776
|
+
if (this.pfs.wal && this.dirtyPages.size > 0) {
|
|
9777
|
+
await this.pfs.wal.prepareCommit(this.dirtyPages);
|
|
9778
|
+
await this.pfs.wal.writeCommitMarker();
|
|
9779
|
+
}
|
|
9780
|
+
for (const [pageId, data] of this.dirtyPages) {
|
|
9781
|
+
await this.pageStrategy.write(pageId, data);
|
|
9782
|
+
}
|
|
9783
|
+
if (!this.pfs.wal) {
|
|
9784
|
+
await this.pfs.strategy.flushPages(this.dirtyPages);
|
|
9785
|
+
} else {
|
|
9786
|
+
this.pfs.wal.incrementWrittenPages(this.dirtyPages.size);
|
|
9787
|
+
if (this.pfs.wal.shouldCheckpoint(this.pfs.options.walCheckpointThreshold)) {
|
|
9788
|
+
shouldTriggerCheckpoint = true;
|
|
9789
|
+
}
|
|
9560
9790
|
}
|
|
9791
|
+
});
|
|
9792
|
+
if (shouldTriggerCheckpoint) {
|
|
9793
|
+
await this.pfs.checkpoint();
|
|
9794
|
+
}
|
|
9795
|
+
this.dirtyPages.clear();
|
|
9796
|
+
this.undoPages.clear();
|
|
9797
|
+
this.releaseAllLocks();
|
|
9798
|
+
} finally {
|
|
9799
|
+
if (this._writeLockRelease) {
|
|
9800
|
+
this._writeLockRelease();
|
|
9801
|
+
this._writeLockRelease = null;
|
|
9561
9802
|
}
|
|
9562
|
-
});
|
|
9563
|
-
if (shouldTriggerCheckpoint) {
|
|
9564
|
-
await this.pfs.checkpoint();
|
|
9565
9803
|
}
|
|
9566
|
-
this.dirtyPages.clear();
|
|
9567
|
-
this.undoPages.clear();
|
|
9568
|
-
this.releaseAllLocks();
|
|
9569
9804
|
}
|
|
9570
9805
|
/**
|
|
9571
9806
|
* Rolls back the transaction.
|
|
9572
9807
|
*/
|
|
9573
9808
|
async rollback() {
|
|
9574
|
-
|
|
9575
|
-
this.bptreeTx
|
|
9809
|
+
try {
|
|
9810
|
+
if (this.bptreeTx) {
|
|
9811
|
+
this.bptreeTx.rollback();
|
|
9812
|
+
}
|
|
9813
|
+
this.dirtyPages.clear();
|
|
9814
|
+
this.undoPages.clear();
|
|
9815
|
+
this.releaseAllLocks();
|
|
9816
|
+
} finally {
|
|
9817
|
+
if (this._writeLockRelease) {
|
|
9818
|
+
this._writeLockRelease();
|
|
9819
|
+
this._writeLockRelease = null;
|
|
9820
|
+
}
|
|
9576
9821
|
}
|
|
9577
|
-
this.dirtyPages.clear();
|
|
9578
|
-
this.undoPages.clear();
|
|
9579
|
-
this.releaseAllLocks();
|
|
9580
9822
|
}
|
|
9581
9823
|
/**
|
|
9582
9824
|
* Returns the dirty pages map.
|
|
@@ -9653,6 +9895,8 @@ var require_cjs = __commonJS({
|
|
|
9653
9895
|
/** Whether the database was created this time. */
|
|
9654
9896
|
isNewlyCreated;
|
|
9655
9897
|
txIdCounter;
|
|
9898
|
+
/** Promise-chain mutex for serializing write operations */
|
|
9899
|
+
writeQueue = Promise.resolve();
|
|
9656
9900
|
/**
|
|
9657
9901
|
* Verifies if the page file is a valid Dataply file.
|
|
9658
9902
|
* The metadata page must be located at the beginning of the Dataply file.
|
|
@@ -9810,6 +10054,52 @@ var require_cjs = __commonJS({
|
|
|
9810
10054
|
* @param tx The transaction to use. If not provided, a new transaction is created.
|
|
9811
10055
|
* @returns The result of the callback function.
|
|
9812
10056
|
*/
|
|
10057
|
+
/**
|
|
10058
|
+
* Acquires the global write lock.
|
|
10059
|
+
* Returns a release function that MUST be called to unlock.
|
|
10060
|
+
* Used internally by runWithDefaultWrite.
|
|
10061
|
+
* @returns A release function
|
|
10062
|
+
*/
|
|
10063
|
+
acquireWriteLock() {
|
|
10064
|
+
const previous = this.writeQueue;
|
|
10065
|
+
let release;
|
|
10066
|
+
this.writeQueue = new Promise((resolve) => {
|
|
10067
|
+
release = resolve;
|
|
10068
|
+
});
|
|
10069
|
+
return previous.then(() => release);
|
|
10070
|
+
}
|
|
10071
|
+
/**
|
|
10072
|
+
* Runs a write callback within a transaction context with global write serialization.
|
|
10073
|
+
* If no transaction is provided, a new transaction is created, committed on success, rolled back on error.
|
|
10074
|
+
* If a transaction is provided (external), the write lock is acquired on first call and held until commit/rollback.
|
|
10075
|
+
* Subclasses MUST use this method for all write operations instead of runWithDefault.
|
|
10076
|
+
* @param callback The callback function to run.
|
|
10077
|
+
* @param tx Optional external transaction.
|
|
10078
|
+
* @returns The result of the callback.
|
|
10079
|
+
*/
|
|
10080
|
+
async runWithDefaultWrite(callback, tx) {
|
|
10081
|
+
if (!tx) {
|
|
10082
|
+
const release = await this.acquireWriteLock();
|
|
10083
|
+
const internalTx = this.createTransaction();
|
|
10084
|
+
internalTx.__setWriteLockRelease(release);
|
|
10085
|
+
const [error2, result2] = await catchPromise2(this.txContext.run(internalTx, () => callback(internalTx)));
|
|
10086
|
+
if (error2) {
|
|
10087
|
+
await internalTx.rollback();
|
|
10088
|
+
throw error2;
|
|
10089
|
+
}
|
|
10090
|
+
await internalTx.commit();
|
|
10091
|
+
return result2;
|
|
10092
|
+
}
|
|
10093
|
+
if (!tx.__hasWriteLockRelease()) {
|
|
10094
|
+
const release = await this.acquireWriteLock();
|
|
10095
|
+
tx.__setWriteLockRelease(release);
|
|
10096
|
+
}
|
|
10097
|
+
const [error, result] = await catchPromise2(this.txContext.run(tx, () => callback(tx)));
|
|
10098
|
+
if (error) {
|
|
10099
|
+
throw error;
|
|
10100
|
+
}
|
|
10101
|
+
return result;
|
|
10102
|
+
}
|
|
9813
10103
|
async runWithDefault(callback, tx) {
|
|
9814
10104
|
const isInternalTx = !tx;
|
|
9815
10105
|
if (!tx) {
|
|
@@ -9881,7 +10171,7 @@ var require_cjs = __commonJS({
|
|
|
9881
10171
|
if (!this.initialized) {
|
|
9882
10172
|
throw new Error("Dataply instance is not initialized");
|
|
9883
10173
|
}
|
|
9884
|
-
return this.
|
|
10174
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
9885
10175
|
incrementRowCount = incrementRowCount ?? true;
|
|
9886
10176
|
if (typeof data === "string") {
|
|
9887
10177
|
data = this.textCodec.encode(data);
|
|
@@ -9901,7 +10191,7 @@ var require_cjs = __commonJS({
|
|
|
9901
10191
|
if (!this.initialized) {
|
|
9902
10192
|
throw new Error("Dataply instance is not initialized");
|
|
9903
10193
|
}
|
|
9904
|
-
return this.
|
|
10194
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
9905
10195
|
incrementRowCount = incrementRowCount ?? true;
|
|
9906
10196
|
if (typeof data === "string") {
|
|
9907
10197
|
data = this.textCodec.encode(data);
|
|
@@ -9922,7 +10212,7 @@ var require_cjs = __commonJS({
|
|
|
9922
10212
|
if (!this.initialized) {
|
|
9923
10213
|
throw new Error("Dataply instance is not initialized");
|
|
9924
10214
|
}
|
|
9925
|
-
return this.
|
|
10215
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
9926
10216
|
incrementRowCount = incrementRowCount ?? true;
|
|
9927
10217
|
const encodedList = dataList.map(
|
|
9928
10218
|
(data) => typeof data === "string" ? this.textCodec.encode(data) : data
|
|
@@ -9940,7 +10230,7 @@ var require_cjs = __commonJS({
|
|
|
9940
10230
|
if (!this.initialized) {
|
|
9941
10231
|
throw new Error("Dataply instance is not initialized");
|
|
9942
10232
|
}
|
|
9943
|
-
return this.
|
|
10233
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
9944
10234
|
if (typeof data === "string") {
|
|
9945
10235
|
data = this.textCodec.encode(data);
|
|
9946
10236
|
}
|
|
@@ -9957,7 +10247,7 @@ var require_cjs = __commonJS({
|
|
|
9957
10247
|
if (!this.initialized) {
|
|
9958
10248
|
throw new Error("Dataply instance is not initialized");
|
|
9959
10249
|
}
|
|
9960
|
-
return this.
|
|
10250
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
9961
10251
|
decrementRowCount = decrementRowCount ?? true;
|
|
9962
10252
|
await this.rowTableEngine.delete(pk, decrementRowCount, tx2);
|
|
9963
10253
|
}, tx);
|
|
@@ -10212,61 +10502,36 @@ var DocumentSerializeStrategyAsync = class extends import_dataply.SerializeStrat
|
|
|
10212
10502
|
|
|
10213
10503
|
// src/core/bptree/documentComparator.ts
|
|
10214
10504
|
var import_dataply2 = __toESM(require_cjs());
|
|
10215
|
-
function
|
|
10216
|
-
if (a
|
|
10217
|
-
|
|
10218
|
-
if (b === null) return 1;
|
|
10219
|
-
if (typeof a !== typeof b) {
|
|
10220
|
-
const typeOrder = (v) => typeof v === "boolean" ? 0 : typeof v === "number" ? 1 : 2;
|
|
10221
|
-
return typeOrder(a) - typeOrder(b);
|
|
10222
|
-
}
|
|
10223
|
-
if (typeof a === "string" && typeof b === "string") {
|
|
10224
|
-
return a.localeCompare(b);
|
|
10505
|
+
function compareDiff(a, b) {
|
|
10506
|
+
if (typeof a !== "string" && typeof b !== "string") {
|
|
10507
|
+
return +a - +b;
|
|
10225
10508
|
}
|
|
10226
|
-
return
|
|
10509
|
+
return (a + "").localeCompare(b + "");
|
|
10227
10510
|
}
|
|
10228
10511
|
function compareValue(a, b) {
|
|
10229
10512
|
const aArr = Array.isArray(a);
|
|
10230
10513
|
const bArr = Array.isArray(b);
|
|
10231
10514
|
if (!aArr && !bArr) {
|
|
10232
|
-
return
|
|
10515
|
+
return compareDiff(a, b);
|
|
10233
10516
|
}
|
|
10234
10517
|
const aList = aArr ? a : [a];
|
|
10235
10518
|
const bList = bArr ? b : [b];
|
|
10236
10519
|
const len = Math.min(aList.length, bList.length);
|
|
10237
10520
|
for (let i = 0; i < len; i++) {
|
|
10238
|
-
const diff =
|
|
10239
|
-
if (diff !== 0) return diff;
|
|
10240
|
-
}
|
|
10241
|
-
return aList.length - bList.length;
|
|
10242
|
-
}
|
|
10243
|
-
function comparePrimaryValue(a, b) {
|
|
10244
|
-
const aArr = Array.isArray(a);
|
|
10245
|
-
const bArr = Array.isArray(b);
|
|
10246
|
-
if (!aArr && !bArr) {
|
|
10247
|
-
return comparePrimitive(a, b);
|
|
10248
|
-
}
|
|
10249
|
-
const aList = aArr ? a : [a];
|
|
10250
|
-
const bList = bArr ? b : [b];
|
|
10251
|
-
const len = Math.min(aList.length, bList.length);
|
|
10252
|
-
for (let i = 0; i < len; i++) {
|
|
10253
|
-
const diff = comparePrimitive(aList[i], bList[i]);
|
|
10521
|
+
const diff = compareDiff(aList[i], bList[i]);
|
|
10254
10522
|
if (diff !== 0) return diff;
|
|
10255
10523
|
}
|
|
10256
10524
|
return 0;
|
|
10257
10525
|
}
|
|
10258
10526
|
var DocumentValueComparator = class extends import_dataply2.ValueComparator {
|
|
10259
10527
|
primaryAsc(a, b) {
|
|
10260
|
-
return
|
|
10528
|
+
return compareValue(a.v, b.v);
|
|
10261
10529
|
}
|
|
10262
10530
|
asc(a, b) {
|
|
10263
10531
|
const diff = compareValue(a.v, b.v);
|
|
10264
10532
|
return diff === 0 ? a.k - b.k : diff;
|
|
10265
10533
|
}
|
|
10266
10534
|
match(value) {
|
|
10267
|
-
if (Array.isArray(value.v)) {
|
|
10268
|
-
return value.v[0] + "";
|
|
10269
|
-
}
|
|
10270
10535
|
return value.v + "";
|
|
10271
10536
|
}
|
|
10272
10537
|
};
|
|
@@ -10378,7 +10643,6 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10378
10643
|
trees = /* @__PURE__ */ new Map();
|
|
10379
10644
|
comparator = new DocumentValueComparator();
|
|
10380
10645
|
pendingBackfillFields = [];
|
|
10381
|
-
lock;
|
|
10382
10646
|
_initialized = false;
|
|
10383
10647
|
indexedFields;
|
|
10384
10648
|
/**
|
|
@@ -10409,7 +10673,6 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10409
10673
|
constructor(file, options) {
|
|
10410
10674
|
super(file, options);
|
|
10411
10675
|
this.trees = /* @__PURE__ */ new Map();
|
|
10412
|
-
this.lock = new import_dataply3.Ryoiki();
|
|
10413
10676
|
this.indexedFields = /* @__PURE__ */ new Set(["_id"]);
|
|
10414
10677
|
this.hook.onceAfter("init", async (tx, isNewlyCreated) => {
|
|
10415
10678
|
if (isNewlyCreated) {
|
|
@@ -10511,17 +10774,17 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10511
10774
|
async registerIndexRuntime(name, option, tx) {
|
|
10512
10775
|
const config = this.toIndexMetaConfig(option);
|
|
10513
10776
|
if (this.registeredIndices.has(name)) {
|
|
10514
|
-
|
|
10515
|
-
if (JSON.stringify(existing) === JSON.stringify(config)) return;
|
|
10777
|
+
throw new Error(`Index "${name}" already exists.`);
|
|
10516
10778
|
}
|
|
10517
|
-
await this.
|
|
10779
|
+
await this.runWithDefaultWrite(async (tx2) => {
|
|
10518
10780
|
const metadata = await this.getDocumentInnerMetadata(tx2);
|
|
10519
10781
|
metadata.indices[name] = [-1, config];
|
|
10520
10782
|
await this.updateDocumentInnerMetadata(metadata, tx2);
|
|
10521
10783
|
this.indices = metadata.indices;
|
|
10522
10784
|
this.registeredIndices.set(name, config);
|
|
10523
10785
|
const fields = this.getFieldsFromConfig(config);
|
|
10524
|
-
for (
|
|
10786
|
+
for (let i = 0; i < fields.length; i++) {
|
|
10787
|
+
const field = fields[i];
|
|
10525
10788
|
this.indexedFields.add(field);
|
|
10526
10789
|
if (!this.fieldToIndices.has(field)) {
|
|
10527
10790
|
this.fieldToIndices.set(field, []);
|
|
@@ -10553,16 +10816,16 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10553
10816
|
*/
|
|
10554
10817
|
async dropIndex(name, tx) {
|
|
10555
10818
|
if (name === "_id") {
|
|
10556
|
-
throw new Error(
|
|
10819
|
+
throw new Error('Cannot drop the "_id" index.');
|
|
10557
10820
|
}
|
|
10558
10821
|
if (!this._initialized) {
|
|
10559
10822
|
this.pendingCreateIndices.delete(name);
|
|
10560
10823
|
return;
|
|
10561
10824
|
}
|
|
10562
10825
|
if (!this.registeredIndices.has(name)) {
|
|
10563
|
-
throw new Error(`Index
|
|
10826
|
+
throw new Error(`Index "${name}" does not exist.`);
|
|
10564
10827
|
}
|
|
10565
|
-
await this.
|
|
10828
|
+
await this.runWithDefaultWrite(async (tx2) => {
|
|
10566
10829
|
const config = this.registeredIndices.get(name);
|
|
10567
10830
|
const metadata = await this.getDocumentInnerMetadata(tx2);
|
|
10568
10831
|
delete metadata.indices[name];
|
|
@@ -10570,7 +10833,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10570
10833
|
this.indices = metadata.indices;
|
|
10571
10834
|
this.registeredIndices.delete(name);
|
|
10572
10835
|
const fields = this.getFieldsFromConfig(config);
|
|
10573
|
-
for (
|
|
10836
|
+
for (let i = 0; i < fields.length; i++) {
|
|
10837
|
+
const field = fields[i];
|
|
10574
10838
|
const indexNames = this.fieldToIndices.get(field);
|
|
10575
10839
|
if (indexNames) {
|
|
10576
10840
|
const filtered = indexNames.filter((n) => n !== name);
|
|
@@ -10601,7 +10865,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10601
10865
|
if (!Array.isArray(option.fields) || option.fields.length === 0) {
|
|
10602
10866
|
throw new Error('btree index requires a non-empty "fields" array');
|
|
10603
10867
|
}
|
|
10604
|
-
for (let i = 0
|
|
10868
|
+
for (let i = 0, len = option.fields.length; i < len; i++) {
|
|
10605
10869
|
if (typeof option.fields[i] !== "string" || option.fields[i].length === 0) {
|
|
10606
10870
|
throw new Error(`btree index "fields[${i}]" must be a non-empty string, got: ${JSON.stringify(option.fields[i])}`);
|
|
10607
10871
|
}
|
|
@@ -10697,24 +10961,6 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10697
10961
|
return JSON.parse(row);
|
|
10698
10962
|
}, tx);
|
|
10699
10963
|
}
|
|
10700
|
-
async readLock(fn) {
|
|
10701
|
-
let lockId;
|
|
10702
|
-
return this.lock.readLock(async (_lockId) => {
|
|
10703
|
-
lockId = _lockId;
|
|
10704
|
-
return await fn();
|
|
10705
|
-
}).finally(() => {
|
|
10706
|
-
this.lock.readUnlock(lockId);
|
|
10707
|
-
});
|
|
10708
|
-
}
|
|
10709
|
-
async writeLock(fn) {
|
|
10710
|
-
let lockId;
|
|
10711
|
-
return this.lock.writeLock(async (_lockId) => {
|
|
10712
|
-
lockId = _lockId;
|
|
10713
|
-
return await fn();
|
|
10714
|
-
}).finally(() => {
|
|
10715
|
-
this.lock.writeUnlock(lockId);
|
|
10716
|
-
});
|
|
10717
|
-
}
|
|
10718
10964
|
/**
|
|
10719
10965
|
* Backfill indices for newly created indices after data was inserted.
|
|
10720
10966
|
* This method should be called after `init()`.
|
|
@@ -10722,7 +10968,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10722
10968
|
* @returns Number of documents that were backfilled
|
|
10723
10969
|
*/
|
|
10724
10970
|
async backfillIndices(tx) {
|
|
10725
|
-
return this.
|
|
10971
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
10726
10972
|
if (this.pendingBackfillFields.length === 0) {
|
|
10727
10973
|
return 0;
|
|
10728
10974
|
}
|
|
@@ -10752,7 +10998,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10752
10998
|
const doc = await this.getDocument(k, tx2);
|
|
10753
10999
|
if (!doc) continue;
|
|
10754
11000
|
const flatDoc = this.flattenDocument(doc);
|
|
10755
|
-
for (
|
|
11001
|
+
for (let i = 0, len = backfillTargets.length; i < len; i++) {
|
|
11002
|
+
const indexName = backfillTargets[i];
|
|
10756
11003
|
if (!(indexName in indexTxMap)) continue;
|
|
10757
11004
|
const config = this.registeredIndices.get(indexName);
|
|
10758
11005
|
if (!config) continue;
|
|
@@ -10764,8 +11011,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10764
11011
|
const ftsConfig = this.getFtsConfig(config);
|
|
10765
11012
|
const tokens = ftsConfig ? tokenize(v, ftsConfig) : [v];
|
|
10766
11013
|
const batchInsertData = [];
|
|
10767
|
-
for (let
|
|
10768
|
-
const token = tokens[
|
|
11014
|
+
for (let i2 = 0, len2 = tokens.length; i2 < len2; i2++) {
|
|
11015
|
+
const token = tokens[i2];
|
|
10769
11016
|
const keyToInsert = this.getTokenKey(k, token);
|
|
10770
11017
|
const entry = { k, v: token };
|
|
10771
11018
|
batchInsertData.push([keyToInsert, entry]);
|
|
@@ -10900,7 +11147,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10900
11147
|
* @param tx Optional transaction
|
|
10901
11148
|
*/
|
|
10902
11149
|
async migration(version, callback, tx) {
|
|
10903
|
-
await this.
|
|
11150
|
+
await this.runWithDefaultWrite(async (tx2) => {
|
|
10904
11151
|
const innerMetadata = await this.getDocumentInnerMetadata(tx2);
|
|
10905
11152
|
const currentVersion = innerMetadata.schemeVersion ?? 0;
|
|
10906
11153
|
if (currentVersion < version) {
|
|
@@ -10949,6 +11196,191 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10949
11196
|
}
|
|
10950
11197
|
return result;
|
|
10951
11198
|
}
|
|
11199
|
+
/**
|
|
11200
|
+
* B-Tree 타입 인덱스의 선택도를 평가하고 트리에 부여할 조건을 산출합니다.
|
|
11201
|
+
* 필드 매칭 여부를 검사하고, 연속된(Prefix) 조건에 대해 점수를 부여하며 Start/End 바운드를 구성합니다.
|
|
11202
|
+
*
|
|
11203
|
+
* @param indexName 평가할 인덱스의 이름 (예: idx_nickname_createdat)
|
|
11204
|
+
* @param config 등록된 인덱스의 설정 객체
|
|
11205
|
+
* @param query 쿼리 객체
|
|
11206
|
+
* @param queryFields 쿼리에 포함된 필드 목록 집합
|
|
11207
|
+
* @param treeTx 조회를 수행할 B-Tree 트랜잭션 객체
|
|
11208
|
+
* @param orderByField 정렬에 사용할 필드명 (옵션)
|
|
11209
|
+
* @returns B-Tree 인덱스 후보 정보 (조건, 점수, 커버된 필드 등), 적합하지 않으면 null
|
|
11210
|
+
*/
|
|
11211
|
+
evaluateBTreeCandidate(indexName, config, query, queryFields, treeTx, orderByField) {
|
|
11212
|
+
const primaryField = config.fields[0];
|
|
11213
|
+
if (!queryFields.has(primaryField)) return null;
|
|
11214
|
+
const builtCondition = {};
|
|
11215
|
+
let score = 0;
|
|
11216
|
+
let isConsecutive = true;
|
|
11217
|
+
const coveredFields = [];
|
|
11218
|
+
const compositeVerifyFields = [];
|
|
11219
|
+
const startValues = [];
|
|
11220
|
+
const endValues = [];
|
|
11221
|
+
let startOperator = null;
|
|
11222
|
+
let endOperator = null;
|
|
11223
|
+
for (let i = 0, len = config.fields.length; i < len; i++) {
|
|
11224
|
+
const field = config.fields[i];
|
|
11225
|
+
if (!queryFields.has(field)) {
|
|
11226
|
+
isConsecutive = false;
|
|
11227
|
+
continue;
|
|
11228
|
+
}
|
|
11229
|
+
coveredFields.push(field);
|
|
11230
|
+
score += 1;
|
|
11231
|
+
if (isConsecutive) {
|
|
11232
|
+
const cond = query[field];
|
|
11233
|
+
if (cond !== void 0) {
|
|
11234
|
+
let isBounded = false;
|
|
11235
|
+
if (typeof cond !== "object" || cond === null) {
|
|
11236
|
+
score += 100;
|
|
11237
|
+
startValues.push(cond);
|
|
11238
|
+
endValues.push(cond);
|
|
11239
|
+
startOperator = "primaryGte";
|
|
11240
|
+
endOperator = "primaryLte";
|
|
11241
|
+
isBounded = true;
|
|
11242
|
+
} else if ("primaryEqual" in cond || "equal" in cond) {
|
|
11243
|
+
const val = cond.primaryEqual?.v ?? cond.equal?.v ?? cond.primaryEqual ?? cond.equal;
|
|
11244
|
+
score += 100;
|
|
11245
|
+
startValues.push(val);
|
|
11246
|
+
endValues.push(val);
|
|
11247
|
+
startOperator = "primaryGte";
|
|
11248
|
+
endOperator = "primaryLte";
|
|
11249
|
+
isBounded = true;
|
|
11250
|
+
} else if ("primaryGte" in cond || "gte" in cond) {
|
|
11251
|
+
const val = cond.primaryGte?.v ?? cond.gte?.v ?? cond.primaryGte ?? cond.gte;
|
|
11252
|
+
score += 50;
|
|
11253
|
+
isConsecutive = false;
|
|
11254
|
+
startValues.push(val);
|
|
11255
|
+
startOperator = "primaryGte";
|
|
11256
|
+
if (endValues.length > 0) endOperator = "primaryLte";
|
|
11257
|
+
isBounded = true;
|
|
11258
|
+
} else if ("primaryGt" in cond || "gt" in cond) {
|
|
11259
|
+
const val = cond.primaryGt?.v ?? cond.gt?.v ?? cond.primaryGt ?? cond.gt;
|
|
11260
|
+
score += 50;
|
|
11261
|
+
isConsecutive = false;
|
|
11262
|
+
startValues.push(val);
|
|
11263
|
+
startOperator = "primaryGt";
|
|
11264
|
+
if (endValues.length > 0) endOperator = "primaryLte";
|
|
11265
|
+
isBounded = true;
|
|
11266
|
+
} else if ("primaryLte" in cond || "lte" in cond) {
|
|
11267
|
+
const val = cond.primaryLte?.v ?? cond.lte?.v ?? cond.primaryLte ?? cond.lte;
|
|
11268
|
+
score += 50;
|
|
11269
|
+
isConsecutive = false;
|
|
11270
|
+
endValues.push(val);
|
|
11271
|
+
endOperator = "primaryLte";
|
|
11272
|
+
if (startValues.length > 0) startOperator = "primaryGte";
|
|
11273
|
+
isBounded = true;
|
|
11274
|
+
} else if ("primaryLt" in cond || "lt" in cond) {
|
|
11275
|
+
const val = cond.primaryLt?.v ?? cond.lt?.v ?? cond.primaryLt ?? cond.lt;
|
|
11276
|
+
score += 50;
|
|
11277
|
+
isConsecutive = false;
|
|
11278
|
+
endValues.push(val);
|
|
11279
|
+
endOperator = "primaryLt";
|
|
11280
|
+
if (startValues.length > 0) startOperator = "primaryGte";
|
|
11281
|
+
isBounded = true;
|
|
11282
|
+
} else if ("primaryOr" in cond || "or" in cond) {
|
|
11283
|
+
score += 20;
|
|
11284
|
+
isConsecutive = false;
|
|
11285
|
+
} else if ("like" in cond) {
|
|
11286
|
+
score += 15;
|
|
11287
|
+
isConsecutive = false;
|
|
11288
|
+
} else {
|
|
11289
|
+
score += 10;
|
|
11290
|
+
isConsecutive = false;
|
|
11291
|
+
}
|
|
11292
|
+
if (!isBounded && field !== primaryField) {
|
|
11293
|
+
compositeVerifyFields.push(field);
|
|
11294
|
+
}
|
|
11295
|
+
}
|
|
11296
|
+
} else {
|
|
11297
|
+
if (field !== primaryField) {
|
|
11298
|
+
compositeVerifyFields.push(field);
|
|
11299
|
+
}
|
|
11300
|
+
}
|
|
11301
|
+
}
|
|
11302
|
+
if (coveredFields.length === 1 && config.fields.length === 1) {
|
|
11303
|
+
Object.assign(builtCondition, query[primaryField]);
|
|
11304
|
+
} else {
|
|
11305
|
+
if (startOperator && startValues.length > 0) {
|
|
11306
|
+
builtCondition[startOperator] = { v: startValues.length === 1 ? startValues[0] : startValues };
|
|
11307
|
+
}
|
|
11308
|
+
if (endOperator && endValues.length > 0) {
|
|
11309
|
+
if (startOperator && startValues.length === endValues.length && startValues.every((val, i) => val === endValues[i])) {
|
|
11310
|
+
delete builtCondition[startOperator];
|
|
11311
|
+
builtCondition["primaryEqual"] = { v: startValues.length === 1 ? startValues[0] : startValues };
|
|
11312
|
+
} else {
|
|
11313
|
+
builtCondition[endOperator] = { v: endValues.length === 1 ? endValues[0] : endValues };
|
|
11314
|
+
}
|
|
11315
|
+
}
|
|
11316
|
+
if (Object.keys(builtCondition).length === 0) {
|
|
11317
|
+
Object.assign(builtCondition, query[primaryField] || {});
|
|
11318
|
+
}
|
|
11319
|
+
}
|
|
11320
|
+
let isIndexOrderSupported = false;
|
|
11321
|
+
if (orderByField) {
|
|
11322
|
+
for (let i = 0, len = config.fields.length; i < len; i++) {
|
|
11323
|
+
const field = config.fields[i];
|
|
11324
|
+
if (field === orderByField) {
|
|
11325
|
+
isIndexOrderSupported = true;
|
|
11326
|
+
break;
|
|
11327
|
+
}
|
|
11328
|
+
const cond = query[field];
|
|
11329
|
+
let isExactMatch = false;
|
|
11330
|
+
if (cond !== void 0) {
|
|
11331
|
+
if (typeof cond !== "object" || cond === null) isExactMatch = true;
|
|
11332
|
+
else if ("primaryEqual" in cond || "equal" in cond) isExactMatch = true;
|
|
11333
|
+
}
|
|
11334
|
+
if (!isExactMatch) break;
|
|
11335
|
+
}
|
|
11336
|
+
if (isIndexOrderSupported) {
|
|
11337
|
+
score += 200;
|
|
11338
|
+
}
|
|
11339
|
+
}
|
|
11340
|
+
return {
|
|
11341
|
+
tree: treeTx,
|
|
11342
|
+
condition: builtCondition,
|
|
11343
|
+
field: primaryField,
|
|
11344
|
+
indexName,
|
|
11345
|
+
isFtsMatch: false,
|
|
11346
|
+
score,
|
|
11347
|
+
compositeVerifyFields,
|
|
11348
|
+
coveredFields,
|
|
11349
|
+
isIndexOrderSupported
|
|
11350
|
+
};
|
|
11351
|
+
}
|
|
11352
|
+
/**
|
|
11353
|
+
* FTS (Full Text Search) 타입 인덱스의 선택도를 평가합니다.
|
|
11354
|
+
* 'match' 연산자가 쿼리에 존재하는지 확인하고, 검색용 토큰으로 분해(tokenize)하여 점수를 매깁니다.
|
|
11355
|
+
*
|
|
11356
|
+
* @param indexName 평가할 인덱스의 이름
|
|
11357
|
+
* @param config 등록된 인덱스의 설정 객체
|
|
11358
|
+
* @param query 쿼리 객체
|
|
11359
|
+
* @param queryFields 쿼리에 포함된 필드 목록 집합
|
|
11360
|
+
* @param treeTx 조회를 수행할 B-Tree 트랜잭션 객체
|
|
11361
|
+
* @returns FTS 인덱스 후보 정보 (조건, 점수, 분석된 토큰 등), 적합하지 않으면 null
|
|
11362
|
+
*/
|
|
11363
|
+
evaluateFTSCandidate(indexName, config, query, queryFields, treeTx) {
|
|
11364
|
+
const field = config.fields;
|
|
11365
|
+
if (!queryFields.has(field)) return null;
|
|
11366
|
+
const condition = query[field];
|
|
11367
|
+
if (!condition || typeof condition !== "object" || !("match" in condition)) return null;
|
|
11368
|
+
const ftsConfig = this.getFtsConfig(config);
|
|
11369
|
+
const matchTokens = ftsConfig ? tokenize(condition.match, ftsConfig) : [];
|
|
11370
|
+
return {
|
|
11371
|
+
tree: treeTx,
|
|
11372
|
+
condition,
|
|
11373
|
+
field,
|
|
11374
|
+
indexName,
|
|
11375
|
+
isFtsMatch: true,
|
|
11376
|
+
matchTokens,
|
|
11377
|
+
score: 90,
|
|
11378
|
+
// FTS 쿼리는 기본적인 B-Tree 단일 검색(대략 101점)보다는 우선순위를 조금 낮게 가져가도록 90점 부여
|
|
11379
|
+
compositeVerifyFields: [],
|
|
11380
|
+
coveredFields: [field],
|
|
11381
|
+
isIndexOrderSupported: false
|
|
11382
|
+
};
|
|
11383
|
+
}
|
|
10952
11384
|
/**
|
|
10953
11385
|
* Choose the best index (driver) for the given query.
|
|
10954
11386
|
* Scores each index based on field coverage and condition type.
|
|
@@ -10964,95 +11396,26 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10964
11396
|
const tree = this.trees.get(indexName);
|
|
10965
11397
|
if (!tree) continue;
|
|
10966
11398
|
if (config.type === "btree") {
|
|
10967
|
-
const primaryField = config.fields[0];
|
|
10968
|
-
if (!queryFields.has(primaryField)) continue;
|
|
10969
|
-
const condition = query[primaryField];
|
|
10970
11399
|
const treeTx = await tree.createTransaction();
|
|
10971
|
-
|
|
10972
|
-
let isConsecutive = true;
|
|
10973
|
-
const coveredFields = [];
|
|
10974
|
-
const compositeVerifyFields = [];
|
|
10975
|
-
for (const field of config.fields) {
|
|
10976
|
-
if (!queryFields.has(field)) {
|
|
10977
|
-
isConsecutive = false;
|
|
10978
|
-
continue;
|
|
10979
|
-
}
|
|
10980
|
-
coveredFields.push(field);
|
|
10981
|
-
if (field !== primaryField) {
|
|
10982
|
-
compositeVerifyFields.push(field);
|
|
10983
|
-
}
|
|
10984
|
-
score += 1;
|
|
10985
|
-
if (isConsecutive) {
|
|
10986
|
-
const cond = query[field];
|
|
10987
|
-
if (cond !== void 0) {
|
|
10988
|
-
if (typeof cond !== "object" || cond === null) {
|
|
10989
|
-
score += 100;
|
|
10990
|
-
} else if ("primaryEqual" in cond || "equal" in cond) {
|
|
10991
|
-
score += 100;
|
|
10992
|
-
} else if ("primaryGte" in cond || "primaryLte" in cond || "primaryGt" in cond || "primaryLt" in cond || "gte" in cond || "lte" in cond || "gt" in cond || "lt" in cond) {
|
|
10993
|
-
score += 50;
|
|
10994
|
-
isConsecutive = false;
|
|
10995
|
-
} else if ("primaryOr" in cond || "or" in cond) {
|
|
10996
|
-
score += 20;
|
|
10997
|
-
isConsecutive = false;
|
|
10998
|
-
} else if ("like" in cond) {
|
|
10999
|
-
score += 15;
|
|
11000
|
-
isConsecutive = false;
|
|
11001
|
-
} else {
|
|
11002
|
-
score += 10;
|
|
11003
|
-
isConsecutive = false;
|
|
11004
|
-
}
|
|
11005
|
-
}
|
|
11006
|
-
}
|
|
11007
|
-
}
|
|
11008
|
-
let isIndexOrderSupported = false;
|
|
11009
|
-
if (orderByField) {
|
|
11010
|
-
for (const field of config.fields) {
|
|
11011
|
-
if (field === orderByField) {
|
|
11012
|
-
isIndexOrderSupported = true;
|
|
11013
|
-
break;
|
|
11014
|
-
}
|
|
11015
|
-
const cond = query[field];
|
|
11016
|
-
let isExactMatch = false;
|
|
11017
|
-
if (cond !== void 0) {
|
|
11018
|
-
if (typeof cond !== "object" || cond === null) isExactMatch = true;
|
|
11019
|
-
else if ("primaryEqual" in cond || "equal" in cond) isExactMatch = true;
|
|
11020
|
-
}
|
|
11021
|
-
if (!isExactMatch) break;
|
|
11022
|
-
}
|
|
11023
|
-
if (isIndexOrderSupported) {
|
|
11024
|
-
score += 200;
|
|
11025
|
-
}
|
|
11026
|
-
}
|
|
11027
|
-
candidates.push({
|
|
11028
|
-
tree: treeTx,
|
|
11029
|
-
condition,
|
|
11030
|
-
field: primaryField,
|
|
11400
|
+
const candidate = this.evaluateBTreeCandidate(
|
|
11031
11401
|
indexName,
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11402
|
+
config,
|
|
11403
|
+
query,
|
|
11404
|
+
queryFields,
|
|
11405
|
+
treeTx,
|
|
11406
|
+
orderByField
|
|
11407
|
+
);
|
|
11408
|
+
if (candidate) candidates.push(candidate);
|
|
11037
11409
|
} else if (config.type === "fts") {
|
|
11038
|
-
const field = config.fields;
|
|
11039
|
-
if (!queryFields.has(field)) continue;
|
|
11040
|
-
const condition = query[field];
|
|
11041
|
-
if (!condition || typeof condition !== "object" || !("match" in condition)) continue;
|
|
11042
11410
|
const treeTx = await tree.createTransaction();
|
|
11043
|
-
const
|
|
11044
|
-
const matchTokens = ftsConfig ? tokenize(condition.match, ftsConfig) : [];
|
|
11045
|
-
candidates.push({
|
|
11046
|
-
tree: treeTx,
|
|
11047
|
-
condition,
|
|
11048
|
-
field,
|
|
11411
|
+
const candidate = this.evaluateFTSCandidate(
|
|
11049
11412
|
indexName,
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11413
|
+
config,
|
|
11414
|
+
query,
|
|
11415
|
+
queryFields,
|
|
11416
|
+
treeTx
|
|
11417
|
+
);
|
|
11418
|
+
if (candidate) candidates.push(candidate);
|
|
11056
11419
|
}
|
|
11057
11420
|
}
|
|
11058
11421
|
const rollback = () => {
|
|
@@ -11064,11 +11427,20 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11064
11427
|
rollback();
|
|
11065
11428
|
return null;
|
|
11066
11429
|
}
|
|
11067
|
-
candidates.sort((a, b) =>
|
|
11430
|
+
candidates.sort((a, b) => {
|
|
11431
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
11432
|
+
const aConfig = this.registeredIndices.get(a.indexName);
|
|
11433
|
+
const bConfig = this.registeredIndices.get(b.indexName);
|
|
11434
|
+
const aFieldCount = aConfig ? Array.isArray(aConfig.fields) ? aConfig.fields.length : 1 : 0;
|
|
11435
|
+
const bFieldCount = bConfig ? Array.isArray(bConfig.fields) ? bConfig.fields.length : 1 : 0;
|
|
11436
|
+
return aFieldCount - bFieldCount;
|
|
11437
|
+
});
|
|
11068
11438
|
const driver = candidates[0];
|
|
11069
|
-
const
|
|
11439
|
+
const driverCoveredFields = new Set(driver.coveredFields);
|
|
11440
|
+
const others = candidates.slice(1).filter((c) => !driverCoveredFields.has(c.field));
|
|
11070
11441
|
const compositeVerifyConditions = [];
|
|
11071
|
-
for (
|
|
11442
|
+
for (let i = 0, len = driver.compositeVerifyFields.length; i < len; i++) {
|
|
11443
|
+
const field = driver.compositeVerifyFields[i];
|
|
11072
11444
|
if (query[field]) {
|
|
11073
11445
|
compositeVerifyConditions.push({ field, condition: query[field] });
|
|
11074
11446
|
}
|
|
@@ -11213,7 +11585,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11213
11585
|
* @returns The primary key of the inserted document
|
|
11214
11586
|
*/
|
|
11215
11587
|
async insertSingleDocument(document, tx) {
|
|
11216
|
-
return this.
|
|
11588
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
11217
11589
|
const { pk: dpk, document: dataplyDocument } = await this.insertDocumentInternal(document, tx2);
|
|
11218
11590
|
const flattenDocument = this.flattenDocument(dataplyDocument);
|
|
11219
11591
|
for (const [indexName, config] of this.registeredIndices) {
|
|
@@ -11239,7 +11611,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11239
11611
|
}
|
|
11240
11612
|
}
|
|
11241
11613
|
return dataplyDocument._id;
|
|
11242
|
-
}, tx)
|
|
11614
|
+
}, tx);
|
|
11243
11615
|
}
|
|
11244
11616
|
/**
|
|
11245
11617
|
* Insert a batch of documents into the database
|
|
@@ -11248,7 +11620,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11248
11620
|
* @returns The primary keys of the inserted documents
|
|
11249
11621
|
*/
|
|
11250
11622
|
async insertBatchDocuments(documents, tx) {
|
|
11251
|
-
return this.
|
|
11623
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
11252
11624
|
const metadata = await this.getDocumentInnerMetadata(tx2);
|
|
11253
11625
|
const startId = metadata.lastId + 1;
|
|
11254
11626
|
metadata.lastId += documents.length;
|
|
@@ -11307,7 +11679,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11307
11679
|
}
|
|
11308
11680
|
}
|
|
11309
11681
|
return ids;
|
|
11310
|
-
}, tx)
|
|
11682
|
+
}, tx);
|
|
11311
11683
|
}
|
|
11312
11684
|
/**
|
|
11313
11685
|
* Internal update method used by both fullUpdate and partialUpdate
|
|
@@ -11388,12 +11760,12 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11388
11760
|
* @returns The number of updated documents
|
|
11389
11761
|
*/
|
|
11390
11762
|
async fullUpdate(query, newRecord, tx) {
|
|
11391
|
-
return
|
|
11763
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
11392
11764
|
return this.updateInternal(query, (doc) => {
|
|
11393
11765
|
const newDoc = typeof newRecord === "function" ? newRecord(doc) : newRecord;
|
|
11394
11766
|
return { _id: doc._id, ...newDoc };
|
|
11395
11767
|
}, tx2);
|
|
11396
|
-
}, tx)
|
|
11768
|
+
}, tx);
|
|
11397
11769
|
}
|
|
11398
11770
|
/**
|
|
11399
11771
|
* Partially update documents from the database that match the query
|
|
@@ -11403,14 +11775,14 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11403
11775
|
* @returns The number of updated documents
|
|
11404
11776
|
*/
|
|
11405
11777
|
async partialUpdate(query, newRecord, tx) {
|
|
11406
|
-
return this.
|
|
11778
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
11407
11779
|
return this.updateInternal(query, (doc) => {
|
|
11408
11780
|
const partialUpdateContent = typeof newRecord === "function" ? newRecord(doc) : newRecord;
|
|
11409
11781
|
const finalUpdate = { ...partialUpdateContent };
|
|
11410
11782
|
delete finalUpdate._id;
|
|
11411
11783
|
return { ...doc, ...finalUpdate };
|
|
11412
11784
|
}, tx2);
|
|
11413
|
-
}, tx)
|
|
11785
|
+
}, tx);
|
|
11414
11786
|
}
|
|
11415
11787
|
/**
|
|
11416
11788
|
* Delete documents from the database that match the query
|
|
@@ -11419,7 +11791,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11419
11791
|
* @returns The number of deleted documents
|
|
11420
11792
|
*/
|
|
11421
11793
|
async deleteDocuments(query, tx) {
|
|
11422
|
-
return this.
|
|
11794
|
+
return this.runWithDefaultWrite(async (tx2) => {
|
|
11423
11795
|
const pks = await this.getKeys(query);
|
|
11424
11796
|
let deletedCount = 0;
|
|
11425
11797
|
for (let i = 0, len = pks.length; i < len; i++) {
|
|
@@ -11449,7 +11821,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11449
11821
|
deletedCount++;
|
|
11450
11822
|
}
|
|
11451
11823
|
return deletedCount;
|
|
11452
|
-
}, tx)
|
|
11824
|
+
}, tx);
|
|
11453
11825
|
}
|
|
11454
11826
|
/**
|
|
11455
11827
|
* Count documents from the database that match the query
|
|
@@ -11458,10 +11830,10 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11458
11830
|
* @returns The number of documents that match the query
|
|
11459
11831
|
*/
|
|
11460
11832
|
async countDocuments(query, tx) {
|
|
11461
|
-
return this.
|
|
11833
|
+
return this.runWithDefault(async (tx2) => {
|
|
11462
11834
|
const pks = await this.getKeys(query);
|
|
11463
11835
|
return pks.length;
|
|
11464
|
-
}, tx)
|
|
11836
|
+
}, tx);
|
|
11465
11837
|
}
|
|
11466
11838
|
/**
|
|
11467
11839
|
* FTS 조건에 대해 문서가 유효한지 검증합니다.
|
|
@@ -11538,10 +11910,15 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11538
11910
|
* Prefetch 방식으로 키 스트림을 청크 단위로 조회하여 문서를 순회합니다.
|
|
11539
11911
|
* FTS 검증, 복합 인덱스 검증, others 후보에 대한 tree.verify() 검증을 통과한 문서만 yield 합니다.
|
|
11540
11912
|
*/
|
|
11541
|
-
async *processChunkedKeysWithVerify(keysStream, startIdx, initialChunkSize, ftsConditions, compositeVerifyConditions, others, tx) {
|
|
11913
|
+
async *processChunkedKeysWithVerify(keysStream, startIdx, initialChunkSize, limit, ftsConditions, compositeVerifyConditions, others, tx) {
|
|
11542
11914
|
const verifyOthers = others.filter((o) => !o.isFtsMatch);
|
|
11543
|
-
|
|
11915
|
+
const isFts = ftsConditions.length > 0;
|
|
11916
|
+
const isCompositeVerify = compositeVerifyConditions.length > 0;
|
|
11917
|
+
const isVerifyOthers = verifyOthers.length > 0;
|
|
11918
|
+
const isInfiniteLimit = isFinite(limit);
|
|
11919
|
+
let currentChunkSize = isInfiniteLimit ? initialChunkSize : limit;
|
|
11544
11920
|
let chunk = [];
|
|
11921
|
+
let chunkSize = 0;
|
|
11545
11922
|
let dropped = 0;
|
|
11546
11923
|
const processChunk = async (pks) => {
|
|
11547
11924
|
const docs = [];
|
|
@@ -11552,9 +11929,9 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11552
11929
|
if (!s) continue;
|
|
11553
11930
|
const doc = JSON.parse(s);
|
|
11554
11931
|
chunkTotalSize += s.length * 2;
|
|
11555
|
-
if (
|
|
11556
|
-
if (
|
|
11557
|
-
if (
|
|
11932
|
+
if (isFts && !this.verifyFts(doc, ftsConditions)) continue;
|
|
11933
|
+
if (isCompositeVerify && this.verifyCompositeConditions(doc, compositeVerifyConditions) === false) continue;
|
|
11934
|
+
if (isVerifyOthers) {
|
|
11558
11935
|
const flatDoc = this.flattenDocument(doc);
|
|
11559
11936
|
let passed = true;
|
|
11560
11937
|
for (let k = 0, kLen = verifyOthers.length; k < kLen; k++) {
|
|
@@ -11574,7 +11951,9 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11574
11951
|
}
|
|
11575
11952
|
docs.push(doc);
|
|
11576
11953
|
}
|
|
11577
|
-
|
|
11954
|
+
if (isInfiniteLimit) {
|
|
11955
|
+
currentChunkSize = this.adjustChunkSize(currentChunkSize, chunkTotalSize);
|
|
11956
|
+
}
|
|
11578
11957
|
return docs;
|
|
11579
11958
|
};
|
|
11580
11959
|
for await (const pk of keysStream) {
|
|
@@ -11583,15 +11962,17 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11583
11962
|
continue;
|
|
11584
11963
|
}
|
|
11585
11964
|
chunk.push(pk);
|
|
11586
|
-
|
|
11965
|
+
chunkSize++;
|
|
11966
|
+
if (chunkSize >= currentChunkSize) {
|
|
11587
11967
|
const docs = await processChunk(chunk);
|
|
11588
|
-
for (let j = 0
|
|
11968
|
+
for (let j = 0, dLen = docs.length; j < dLen; j++) yield docs[j];
|
|
11589
11969
|
chunk = [];
|
|
11970
|
+
chunkSize = 0;
|
|
11590
11971
|
}
|
|
11591
11972
|
}
|
|
11592
|
-
if (
|
|
11973
|
+
if (chunkSize > 0) {
|
|
11593
11974
|
const docs = await processChunk(chunk);
|
|
11594
|
-
for (let j = 0
|
|
11975
|
+
for (let j = 0, dLen = docs.length; j < dLen; j++) yield docs[j];
|
|
11595
11976
|
}
|
|
11596
11977
|
}
|
|
11597
11978
|
/**
|
|
@@ -11640,6 +12021,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11640
12021
|
const driverResult = await self.getDriverKeys(query, orderByField, sortOrder);
|
|
11641
12022
|
if (!driverResult) return;
|
|
11642
12023
|
const { keysStream, others, compositeVerifyConditions, isDriverOrderByField, rollback } = driverResult;
|
|
12024
|
+
const initialChunkSize = self.options.pageSize;
|
|
11643
12025
|
try {
|
|
11644
12026
|
if (!isDriverOrderByField && orderByField) {
|
|
11645
12027
|
const topK = limit === Infinity ? Infinity : offset + limit;
|
|
@@ -11656,7 +12038,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11656
12038
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
11657
12039
|
keysStream,
|
|
11658
12040
|
0,
|
|
11659
|
-
|
|
12041
|
+
initialChunkSize,
|
|
12042
|
+
Infinity,
|
|
11660
12043
|
ftsConditions,
|
|
11661
12044
|
compositeVerifyConditions,
|
|
11662
12045
|
others,
|
|
@@ -11697,7 +12080,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11697
12080
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
11698
12081
|
keysStream,
|
|
11699
12082
|
startIdx,
|
|
11700
|
-
|
|
12083
|
+
initialChunkSize,
|
|
12084
|
+
limit,
|
|
11701
12085
|
ftsConditions,
|
|
11702
12086
|
compositeVerifyConditions,
|
|
11703
12087
|
others,
|