document-dataply 0.0.9-alpha.14 → 0.0.9-alpha.15
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 +300 -242
- package/dist/types/core/documentAPI.d.ts +25 -0
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -1669,28 +1669,28 @@ var require_cjs = __commonJS({
|
|
|
1669
1669
|
searchConfigs = {
|
|
1670
1670
|
gt: {
|
|
1671
1671
|
asc: {
|
|
1672
|
-
start: (tx, v) => tx.
|
|
1672
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1673
1673
|
end: () => null,
|
|
1674
1674
|
direction: 1,
|
|
1675
1675
|
earlyTerminate: false
|
|
1676
1676
|
},
|
|
1677
1677
|
desc: {
|
|
1678
1678
|
start: (tx) => tx.rightestNode(),
|
|
1679
|
-
end: (tx, v) => tx.
|
|
1679
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1680
1680
|
direction: -1,
|
|
1681
1681
|
earlyTerminate: true
|
|
1682
1682
|
}
|
|
1683
1683
|
},
|
|
1684
1684
|
gte: {
|
|
1685
1685
|
asc: {
|
|
1686
|
-
start: (tx, v) => tx.
|
|
1686
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1687
1687
|
end: () => null,
|
|
1688
1688
|
direction: 1,
|
|
1689
1689
|
earlyTerminate: false
|
|
1690
1690
|
},
|
|
1691
1691
|
desc: {
|
|
1692
1692
|
start: (tx) => tx.rightestNode(),
|
|
1693
|
-
end: (tx, v) => tx.
|
|
1693
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1694
1694
|
direction: -1,
|
|
1695
1695
|
earlyTerminate: true
|
|
1696
1696
|
}
|
|
@@ -1698,12 +1698,12 @@ var require_cjs = __commonJS({
|
|
|
1698
1698
|
lt: {
|
|
1699
1699
|
asc: {
|
|
1700
1700
|
start: (tx) => tx.leftestNode(),
|
|
1701
|
-
end: (tx, v) => tx.
|
|
1701
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1702
1702
|
direction: 1,
|
|
1703
1703
|
earlyTerminate: true
|
|
1704
1704
|
},
|
|
1705
1705
|
desc: {
|
|
1706
|
-
start: (tx, v) => tx.
|
|
1706
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1707
1707
|
end: () => null,
|
|
1708
1708
|
direction: -1,
|
|
1709
1709
|
earlyTerminate: false
|
|
@@ -1712,12 +1712,12 @@ var require_cjs = __commonJS({
|
|
|
1712
1712
|
lte: {
|
|
1713
1713
|
asc: {
|
|
1714
1714
|
start: (tx) => tx.leftestNode(),
|
|
1715
|
-
end: (tx, v) => tx.
|
|
1715
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1716
1716
|
direction: 1,
|
|
1717
1717
|
earlyTerminate: true
|
|
1718
1718
|
},
|
|
1719
1719
|
desc: {
|
|
1720
|
-
start: (tx, v) => tx.
|
|
1720
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1721
1721
|
end: () => null,
|
|
1722
1722
|
direction: -1,
|
|
1723
1723
|
earlyTerminate: false
|
|
@@ -1725,14 +1725,14 @@ var require_cjs = __commonJS({
|
|
|
1725
1725
|
},
|
|
1726
1726
|
equal: {
|
|
1727
1727
|
asc: {
|
|
1728
|
-
start: (tx, v) => tx.
|
|
1729
|
-
end: (tx, v) => tx.
|
|
1728
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1729
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1730
1730
|
direction: 1,
|
|
1731
1731
|
earlyTerminate: true
|
|
1732
1732
|
},
|
|
1733
1733
|
desc: {
|
|
1734
|
-
start: (tx, v) => tx.
|
|
1735
|
-
end: (tx, v) => tx.
|
|
1734
|
+
start: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1735
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1736
1736
|
direction: -1,
|
|
1737
1737
|
earlyTerminate: true
|
|
1738
1738
|
}
|
|
@@ -1753,42 +1753,42 @@ var require_cjs = __commonJS({
|
|
|
1753
1753
|
},
|
|
1754
1754
|
or: {
|
|
1755
1755
|
asc: {
|
|
1756
|
-
start: (tx, v) => tx.
|
|
1757
|
-
end: (tx, v) => tx.
|
|
1756
|
+
start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestValue(v)),
|
|
1757
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
|
|
1758
1758
|
direction: 1,
|
|
1759
1759
|
earlyTerminate: false
|
|
1760
1760
|
},
|
|
1761
1761
|
desc: {
|
|
1762
|
-
start: (tx, v) => tx.
|
|
1763
|
-
end: (tx, v) => tx.
|
|
1762
|
+
start: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
|
|
1763
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestValue(v), -1),
|
|
1764
1764
|
direction: -1,
|
|
1765
1765
|
earlyTerminate: false
|
|
1766
1766
|
}
|
|
1767
1767
|
},
|
|
1768
1768
|
primaryGt: {
|
|
1769
1769
|
asc: {
|
|
1770
|
-
start: (tx, v) => tx.
|
|
1770
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1771
1771
|
end: () => null,
|
|
1772
1772
|
direction: 1,
|
|
1773
1773
|
earlyTerminate: false
|
|
1774
1774
|
},
|
|
1775
1775
|
desc: {
|
|
1776
1776
|
start: (tx) => tx.rightestNode(),
|
|
1777
|
-
end: (tx, v) => tx.
|
|
1777
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1778
1778
|
direction: -1,
|
|
1779
1779
|
earlyTerminate: true
|
|
1780
1780
|
}
|
|
1781
1781
|
},
|
|
1782
1782
|
primaryGte: {
|
|
1783
1783
|
asc: {
|
|
1784
|
-
start: (tx, v) => tx.
|
|
1784
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1785
1785
|
end: () => null,
|
|
1786
1786
|
direction: 1,
|
|
1787
1787
|
earlyTerminate: false
|
|
1788
1788
|
},
|
|
1789
1789
|
desc: {
|
|
1790
1790
|
start: (tx) => tx.rightestNode(),
|
|
1791
|
-
end: (tx, v) => tx.
|
|
1791
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1792
1792
|
direction: -1,
|
|
1793
1793
|
earlyTerminate: true
|
|
1794
1794
|
}
|
|
@@ -1796,12 +1796,12 @@ var require_cjs = __commonJS({
|
|
|
1796
1796
|
primaryLt: {
|
|
1797
1797
|
asc: {
|
|
1798
1798
|
start: (tx) => tx.leftestNode(),
|
|
1799
|
-
end: (tx, v) => tx.
|
|
1799
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1800
1800
|
direction: 1,
|
|
1801
1801
|
earlyTerminate: true
|
|
1802
1802
|
},
|
|
1803
1803
|
desc: {
|
|
1804
|
-
start: (tx, v) => tx.
|
|
1804
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1805
1805
|
end: () => null,
|
|
1806
1806
|
direction: -1,
|
|
1807
1807
|
earlyTerminate: false
|
|
@@ -1810,12 +1810,12 @@ var require_cjs = __commonJS({
|
|
|
1810
1810
|
primaryLte: {
|
|
1811
1811
|
asc: {
|
|
1812
1812
|
start: (tx) => tx.leftestNode(),
|
|
1813
|
-
end: (tx, v) => tx.
|
|
1813
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1814
1814
|
direction: 1,
|
|
1815
1815
|
earlyTerminate: true
|
|
1816
1816
|
},
|
|
1817
1817
|
desc: {
|
|
1818
|
-
start: (tx, v) => tx.
|
|
1818
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1819
1819
|
end: () => null,
|
|
1820
1820
|
direction: -1,
|
|
1821
1821
|
earlyTerminate: false
|
|
@@ -1823,14 +1823,14 @@ var require_cjs = __commonJS({
|
|
|
1823
1823
|
},
|
|
1824
1824
|
primaryEqual: {
|
|
1825
1825
|
asc: {
|
|
1826
|
-
start: (tx, v) => tx.
|
|
1827
|
-
end: (tx, v) => tx.
|
|
1826
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
1827
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
1828
1828
|
direction: 1,
|
|
1829
1829
|
earlyTerminate: true
|
|
1830
1830
|
},
|
|
1831
1831
|
desc: {
|
|
1832
|
-
start: (tx, v) => tx.
|
|
1833
|
-
end: (tx, v) => tx.
|
|
1832
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
1833
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
1834
1834
|
direction: -1,
|
|
1835
1835
|
earlyTerminate: true
|
|
1836
1836
|
}
|
|
@@ -1851,14 +1851,14 @@ var require_cjs = __commonJS({
|
|
|
1851
1851
|
},
|
|
1852
1852
|
primaryOr: {
|
|
1853
1853
|
asc: {
|
|
1854
|
-
start: (tx, v) => tx.
|
|
1855
|
-
end: (tx, v) => tx.
|
|
1854
|
+
start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestPrimaryValue(v)),
|
|
1855
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestPrimaryValue(v), 1),
|
|
1856
1856
|
direction: 1,
|
|
1857
1857
|
earlyTerminate: false
|
|
1858
1858
|
},
|
|
1859
1859
|
desc: {
|
|
1860
|
-
start: (tx, v) => tx.
|
|
1861
|
-
end: (tx, v) => tx.
|
|
1860
|
+
start: (tx, v) => tx.findUpperBoundLeaf(tx.highestPrimaryValue(v)),
|
|
1861
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestPrimaryValue(v), -1),
|
|
1862
1862
|
direction: -1,
|
|
1863
1863
|
earlyTerminate: false
|
|
1864
1864
|
}
|
|
@@ -2030,17 +2030,19 @@ var require_cjs = __commonJS({
|
|
|
2030
2030
|
let endKey = null;
|
|
2031
2031
|
let startValues = [];
|
|
2032
2032
|
let endValues = [];
|
|
2033
|
-
for (
|
|
2033
|
+
for (let i = 0, len = startCandidates.length; i < len; i++) {
|
|
2034
|
+
const key = startCandidates[i];
|
|
2034
2035
|
if (key in condition) {
|
|
2035
2036
|
startKey = key;
|
|
2036
|
-
startValues = this.ensureValues(condition[key]);
|
|
2037
|
+
startValues = _BPTreeTransaction._multiValueKeys.includes(key) ? this.ensureValues(condition[key]) : [condition[key]];
|
|
2037
2038
|
break;
|
|
2038
2039
|
}
|
|
2039
2040
|
}
|
|
2040
|
-
for (
|
|
2041
|
+
for (let i = 0, len = endCandidates.length; i < len; i++) {
|
|
2042
|
+
const key = endCandidates[i];
|
|
2041
2043
|
if (key in condition) {
|
|
2042
2044
|
endKey = key;
|
|
2043
|
-
endValues = this.ensureValues(condition[key]);
|
|
2045
|
+
endValues = _BPTreeTransaction._multiValueKeys.includes(key) ? this.ensureValues(condition[key]) : [condition[key]];
|
|
2044
2046
|
break;
|
|
2045
2047
|
}
|
|
2046
2048
|
}
|
|
@@ -2070,6 +2072,11 @@ var require_cjs = __commonJS({
|
|
|
2070
2072
|
"primaryOr",
|
|
2071
2073
|
"or"
|
|
2072
2074
|
];
|
|
2075
|
+
// Condition keys that accept multiple values (V[]) rather than a single value (V)
|
|
2076
|
+
static _multiValueKeys = [
|
|
2077
|
+
"or",
|
|
2078
|
+
"primaryOr"
|
|
2079
|
+
];
|
|
2073
2080
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
2074
2081
|
this.rootTx = rootTx === null ? this : rootTx;
|
|
2075
2082
|
this.mvccRoot = mvccRoot;
|
|
@@ -2306,7 +2313,7 @@ var require_cjs = __commonJS({
|
|
|
2306
2313
|
this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2307
2314
|
}
|
|
2308
2315
|
}
|
|
2309
|
-
|
|
2316
|
+
locateLeaf(value) {
|
|
2310
2317
|
let node = this.getNode(this.rootId);
|
|
2311
2318
|
while (!node.leaf) {
|
|
2312
2319
|
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
@@ -2314,7 +2321,7 @@ var require_cjs = __commonJS({
|
|
|
2314
2321
|
}
|
|
2315
2322
|
return node;
|
|
2316
2323
|
}
|
|
2317
|
-
|
|
2324
|
+
findLowerBoundLeaf(value) {
|
|
2318
2325
|
let node = this.getNode(this.rootId);
|
|
2319
2326
|
while (!node.leaf) {
|
|
2320
2327
|
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
@@ -2322,7 +2329,7 @@ var require_cjs = __commonJS({
|
|
|
2322
2329
|
}
|
|
2323
2330
|
return node;
|
|
2324
2331
|
}
|
|
2325
|
-
|
|
2332
|
+
findUpperBoundLeaf(value) {
|
|
2326
2333
|
let node = this.getNode(this.rootId);
|
|
2327
2334
|
while (!node.leaf) {
|
|
2328
2335
|
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
@@ -2330,15 +2337,8 @@ var require_cjs = __commonJS({
|
|
|
2330
2337
|
}
|
|
2331
2338
|
return node;
|
|
2332
2339
|
}
|
|
2333
|
-
|
|
2334
|
-
const
|
|
2335
|
-
if (!node.next) {
|
|
2336
|
-
return null;
|
|
2337
|
-
}
|
|
2338
|
-
return this.getNode(node.next);
|
|
2339
|
-
}
|
|
2340
|
-
insertableEndNode(value, direction) {
|
|
2341
|
-
const insertableNode = direction === -1 ? this.insertableNodeByPrimary(value) : this.insertableRightestNodeByPrimary(value);
|
|
2340
|
+
findOuterBoundaryLeaf(value, direction) {
|
|
2341
|
+
const insertableNode = direction === -1 ? this.findLowerBoundLeaf(value) : this.findUpperBoundLeaf(value);
|
|
2342
2342
|
let key;
|
|
2343
2343
|
switch (direction) {
|
|
2344
2344
|
case -1:
|
|
@@ -2450,7 +2450,7 @@ var require_cjs = __commonJS({
|
|
|
2450
2450
|
}
|
|
2451
2451
|
}
|
|
2452
2452
|
exists(key, value) {
|
|
2453
|
-
const node = this.
|
|
2453
|
+
const node = this.locateLeaf(value);
|
|
2454
2454
|
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2455
2455
|
if (found) {
|
|
2456
2456
|
const keys = node.keys[index];
|
|
@@ -2547,7 +2547,7 @@ var require_cjs = __commonJS({
|
|
|
2547
2547
|
return map;
|
|
2548
2548
|
}
|
|
2549
2549
|
insert(key, value) {
|
|
2550
|
-
let before = this.
|
|
2550
|
+
let before = this.locateLeaf(value);
|
|
2551
2551
|
before = this._insertAtLeaf(before, key, value);
|
|
2552
2552
|
if (before.values.length === this.order) {
|
|
2553
2553
|
let after = this._createNode(
|
|
@@ -2575,7 +2575,7 @@ var require_cjs = __commonJS({
|
|
|
2575
2575
|
let currentLeaf = null;
|
|
2576
2576
|
let modified = false;
|
|
2577
2577
|
for (const [key, value] of sorted) {
|
|
2578
|
-
const targetLeaf = this.
|
|
2578
|
+
const targetLeaf = this.locateLeaf(value);
|
|
2579
2579
|
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
2580
2580
|
} else {
|
|
2581
2581
|
if (currentLeaf !== null && modified) {
|
|
@@ -2817,7 +2817,7 @@ var require_cjs = __commonJS({
|
|
|
2817
2817
|
if (value === void 0) {
|
|
2818
2818
|
return;
|
|
2819
2819
|
}
|
|
2820
|
-
let node = this.
|
|
2820
|
+
let node = this.findLowerBoundLeaf(value);
|
|
2821
2821
|
let found = false;
|
|
2822
2822
|
while (true) {
|
|
2823
2823
|
let i = node.values.length;
|
|
@@ -3399,7 +3399,7 @@ var require_cjs = __commonJS({
|
|
|
3399
3399
|
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
3400
3400
|
}
|
|
3401
3401
|
}
|
|
3402
|
-
async
|
|
3402
|
+
async locateLeaf(value) {
|
|
3403
3403
|
let node = await this.getNode(this.rootId);
|
|
3404
3404
|
while (!node.leaf) {
|
|
3405
3405
|
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
@@ -3407,7 +3407,7 @@ var require_cjs = __commonJS({
|
|
|
3407
3407
|
}
|
|
3408
3408
|
return node;
|
|
3409
3409
|
}
|
|
3410
|
-
async
|
|
3410
|
+
async findLowerBoundLeaf(value) {
|
|
3411
3411
|
let node = await this.getNode(this.rootId);
|
|
3412
3412
|
while (!node.leaf) {
|
|
3413
3413
|
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
@@ -3415,7 +3415,7 @@ var require_cjs = __commonJS({
|
|
|
3415
3415
|
}
|
|
3416
3416
|
return node;
|
|
3417
3417
|
}
|
|
3418
|
-
async
|
|
3418
|
+
async findUpperBoundLeaf(value) {
|
|
3419
3419
|
let node = await this.getNode(this.rootId);
|
|
3420
3420
|
while (!node.leaf) {
|
|
3421
3421
|
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
@@ -3423,15 +3423,8 @@ var require_cjs = __commonJS({
|
|
|
3423
3423
|
}
|
|
3424
3424
|
return node;
|
|
3425
3425
|
}
|
|
3426
|
-
async
|
|
3427
|
-
const
|
|
3428
|
-
if (!node.next) {
|
|
3429
|
-
return null;
|
|
3430
|
-
}
|
|
3431
|
-
return await this.getNode(node.next);
|
|
3432
|
-
}
|
|
3433
|
-
async insertableEndNode(value, direction) {
|
|
3434
|
-
const insertableNode = direction === -1 ? await this.insertableNodeByPrimary(value) : await this.insertableRightestNodeByPrimary(value);
|
|
3426
|
+
async findOuterBoundaryLeaf(value, direction) {
|
|
3427
|
+
const insertableNode = direction === -1 ? await this.findLowerBoundLeaf(value) : await this.findUpperBoundLeaf(value);
|
|
3435
3428
|
let key;
|
|
3436
3429
|
switch (direction) {
|
|
3437
3430
|
case -1:
|
|
@@ -3552,7 +3545,7 @@ var require_cjs = __commonJS({
|
|
|
3552
3545
|
}
|
|
3553
3546
|
}
|
|
3554
3547
|
async exists(key, value) {
|
|
3555
|
-
const node = await this.
|
|
3548
|
+
const node = await this.locateLeaf(value);
|
|
3556
3549
|
const { index, found } = this._binarySearchValues(node.values, value);
|
|
3557
3550
|
if (found) {
|
|
3558
3551
|
const keys = node.keys[index];
|
|
@@ -3650,7 +3643,7 @@ var require_cjs = __commonJS({
|
|
|
3650
3643
|
}
|
|
3651
3644
|
async insert(key, value) {
|
|
3652
3645
|
return this.writeLock(0, async () => {
|
|
3653
|
-
let before = await this.
|
|
3646
|
+
let before = await this.locateLeaf(value);
|
|
3654
3647
|
before = await this._insertAtLeaf(before, key, value);
|
|
3655
3648
|
if (before.values.length === this.order) {
|
|
3656
3649
|
let after = await this._createNode(
|
|
@@ -3680,7 +3673,7 @@ var require_cjs = __commonJS({
|
|
|
3680
3673
|
let currentLeaf = null;
|
|
3681
3674
|
let modified = false;
|
|
3682
3675
|
for (const [key, value] of sorted) {
|
|
3683
|
-
const targetLeaf = await this.
|
|
3676
|
+
const targetLeaf = await this.locateLeaf(value);
|
|
3684
3677
|
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
3685
3678
|
} else {
|
|
3686
3679
|
if (currentLeaf !== null && modified) {
|
|
@@ -3924,7 +3917,7 @@ var require_cjs = __commonJS({
|
|
|
3924
3917
|
if (value === void 0) {
|
|
3925
3918
|
return;
|
|
3926
3919
|
}
|
|
3927
|
-
let node = await this.
|
|
3920
|
+
let node = await this.findLowerBoundLeaf(value);
|
|
3928
3921
|
let found = false;
|
|
3929
3922
|
while (true) {
|
|
3930
3923
|
let i = node.values.length;
|
|
@@ -6519,7 +6512,7 @@ var require_cjs = __commonJS({
|
|
|
6519
6512
|
const threshold = mean + stddev * logN;
|
|
6520
6513
|
return Math.max(threshold, baseGap * 5, 20);
|
|
6521
6514
|
}
|
|
6522
|
-
function clusterNumbers(numbers,
|
|
6515
|
+
function clusterNumbers(numbers, maxGap) {
|
|
6523
6516
|
const n = numbers.length;
|
|
6524
6517
|
if (n === 0) return [];
|
|
6525
6518
|
if (n === 1) return [new Float64Array([numbers[0]])];
|
|
@@ -6530,10 +6523,8 @@ var require_cjs = __commonJS({
|
|
|
6530
6523
|
}
|
|
6531
6524
|
const sortedGaps = gaps.slice().sort();
|
|
6532
6525
|
let threshold;
|
|
6533
|
-
if (
|
|
6534
|
-
|
|
6535
|
-
const iqr = q3 - sortedGaps[Math.floor((n - 1) * 0.25)];
|
|
6536
|
-
threshold = q3 + iqr * gapMultiplier;
|
|
6526
|
+
if (maxGap !== void 0) {
|
|
6527
|
+
threshold = maxGap;
|
|
6537
6528
|
} else {
|
|
6538
6529
|
threshold = calcThreshold(sortedGaps, n);
|
|
6539
6530
|
}
|
|
@@ -9486,9 +9477,12 @@ var require_cjs = __commonJS({
|
|
|
9486
9477
|
for (let i = 0, len = pks.length; i < len; i++) {
|
|
9487
9478
|
pkIndexMap.set(pks[i], i);
|
|
9488
9479
|
}
|
|
9489
|
-
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);
|
|
9490
9484
|
const btx = await this.getBPTreeTransaction(tx);
|
|
9491
|
-
const clusters = clusterNumbers(pks);
|
|
9485
|
+
const clusters = clusterNumbers(pks, this.order / 2);
|
|
9492
9486
|
for (let i = 0, len = clusters.length; i < len; i++) {
|
|
9493
9487
|
const cluster = clusters[i];
|
|
9494
9488
|
const minPk = cluster[0];
|
|
@@ -9499,7 +9493,9 @@ var require_cjs = __commonJS({
|
|
|
9499
9493
|
const rid = keys.values().next().value;
|
|
9500
9494
|
const index = pkIndexMap.get(minPk);
|
|
9501
9495
|
if (index !== void 0) {
|
|
9502
|
-
|
|
9496
|
+
pkArray[index] = minPk;
|
|
9497
|
+
ridArray[index] = rid;
|
|
9498
|
+
indexArray[index] = index;
|
|
9503
9499
|
}
|
|
9504
9500
|
}
|
|
9505
9501
|
continue;
|
|
@@ -9508,11 +9504,13 @@ var require_cjs = __commonJS({
|
|
|
9508
9504
|
for await (const [rid, pk] of stream) {
|
|
9509
9505
|
const index = pkIndexMap.get(pk);
|
|
9510
9506
|
if (index !== void 0) {
|
|
9511
|
-
|
|
9507
|
+
pkArray[index] = pk;
|
|
9508
|
+
ridArray[index] = rid;
|
|
9509
|
+
indexArray[index] = index;
|
|
9512
9510
|
}
|
|
9513
9511
|
}
|
|
9514
9512
|
}
|
|
9515
|
-
return this.fetchRowsByRids(
|
|
9513
|
+
return this.fetchRowsByRids(validCount, pkArray, ridArray, indexArray, tx);
|
|
9516
9514
|
}
|
|
9517
9515
|
/**
|
|
9518
9516
|
* Fetches multiple rows by their RID and PK combinations, grouping by page ID to minimize I/O.
|
|
@@ -9520,19 +9518,21 @@ var require_cjs = __commonJS({
|
|
|
9520
9518
|
* @param tx Transaction
|
|
9521
9519
|
* @returns Array of row data in the same order as input PKs
|
|
9522
9520
|
*/
|
|
9523
|
-
async fetchRowsByRids(
|
|
9524
|
-
const result = new Array(
|
|
9525
|
-
if (
|
|
9521
|
+
async fetchRowsByRids(validCount, pkArray, ridArray, indexArray, tx) {
|
|
9522
|
+
const result = new Array(validCount).fill(null);
|
|
9523
|
+
if (validCount === 0) return result;
|
|
9526
9524
|
const pageGroupMap = /* @__PURE__ */ new Map();
|
|
9527
|
-
for (
|
|
9528
|
-
|
|
9529
|
-
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;
|
|
9530
9530
|
const slotIndex = rid % 65536;
|
|
9531
9531
|
const pageId = Math.floor(rid / 65536);
|
|
9532
9532
|
if (!pageGroupMap.has(pageId)) {
|
|
9533
9533
|
pageGroupMap.set(pageId, []);
|
|
9534
9534
|
}
|
|
9535
|
-
pageGroupMap.get(pageId).push({ pk
|
|
9535
|
+
pageGroupMap.get(pageId).push({ pk, slotIndex, index });
|
|
9536
9536
|
}
|
|
9537
9537
|
const sortedPageIds = Array.from(pageGroupMap.keys()).sort((a, b) => a - b);
|
|
9538
9538
|
await Promise.all(sortedPageIds.map(async (pageId) => {
|
|
@@ -9542,7 +9542,8 @@ var require_cjs = __commonJS({
|
|
|
9542
9542
|
throw new Error(`Page ${pageId} is not a data page`);
|
|
9543
9543
|
}
|
|
9544
9544
|
const manager = this.factory.getManager(page);
|
|
9545
|
-
for (
|
|
9545
|
+
for (let i = 0, len = items.length; i < len; i++) {
|
|
9546
|
+
const item = items[i];
|
|
9546
9547
|
const row = manager.getRow(page, item.slotIndex);
|
|
9547
9548
|
if (this.rowManager.getDeletedFlag(row)) {
|
|
9548
9549
|
result[item.index] = null;
|
|
@@ -11195,6 +11196,191 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11195
11196
|
}
|
|
11196
11197
|
return result;
|
|
11197
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
|
+
}
|
|
11198
11384
|
/**
|
|
11199
11385
|
* Choose the best index (driver) for the given query.
|
|
11200
11386
|
* Scores each index based on field coverage and condition type.
|
|
@@ -11210,161 +11396,26 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11210
11396
|
const tree = this.trees.get(indexName);
|
|
11211
11397
|
if (!tree) continue;
|
|
11212
11398
|
if (config.type === "btree") {
|
|
11213
|
-
const primaryField = config.fields[0];
|
|
11214
|
-
if (!queryFields.has(primaryField)) continue;
|
|
11215
11399
|
const treeTx = await tree.createTransaction();
|
|
11216
|
-
const
|
|
11217
|
-
let score = 0;
|
|
11218
|
-
let isConsecutive = true;
|
|
11219
|
-
const coveredFields = [];
|
|
11220
|
-
const compositeVerifyFields = [];
|
|
11221
|
-
const startValues = [];
|
|
11222
|
-
const endValues = [];
|
|
11223
|
-
let startOperator = null;
|
|
11224
|
-
let endOperator = null;
|
|
11225
|
-
for (let i = 0, len = config.fields.length; i < len; i++) {
|
|
11226
|
-
const field = config.fields[i];
|
|
11227
|
-
if (!queryFields.has(field)) {
|
|
11228
|
-
isConsecutive = false;
|
|
11229
|
-
continue;
|
|
11230
|
-
}
|
|
11231
|
-
coveredFields.push(field);
|
|
11232
|
-
if (field !== primaryField) {
|
|
11233
|
-
compositeVerifyFields.push(field);
|
|
11234
|
-
}
|
|
11235
|
-
score += 1;
|
|
11236
|
-
if (isConsecutive) {
|
|
11237
|
-
const cond = query[field];
|
|
11238
|
-
if (cond !== void 0) {
|
|
11239
|
-
if (typeof cond !== "object" || cond === null) {
|
|
11240
|
-
score += 100;
|
|
11241
|
-
startValues.push(cond);
|
|
11242
|
-
endValues.push(cond);
|
|
11243
|
-
startOperator = "primaryGte";
|
|
11244
|
-
endOperator = "primaryLte";
|
|
11245
|
-
} else if ("primaryEqual" in cond || "equal" in cond) {
|
|
11246
|
-
const val = cond.primaryEqual?.v ?? cond.equal?.v ?? cond.primaryEqual ?? cond.equal;
|
|
11247
|
-
score += 100;
|
|
11248
|
-
startValues.push(val);
|
|
11249
|
-
endValues.push(val);
|
|
11250
|
-
startOperator = "primaryGte";
|
|
11251
|
-
endOperator = "primaryLte";
|
|
11252
|
-
} else if ("primaryGte" in cond || "gte" in cond) {
|
|
11253
|
-
const val = cond.primaryGte?.v ?? cond.gte?.v ?? cond.primaryGte ?? cond.gte;
|
|
11254
|
-
score += 50;
|
|
11255
|
-
isConsecutive = false;
|
|
11256
|
-
startValues.push(val);
|
|
11257
|
-
startOperator = "primaryGte";
|
|
11258
|
-
if (endValues.length > 0) {
|
|
11259
|
-
endOperator = "primaryLte";
|
|
11260
|
-
}
|
|
11261
|
-
} else if ("primaryGt" in cond || "gt" in cond) {
|
|
11262
|
-
const val = cond.primaryGt?.v ?? cond.gt?.v ?? cond.primaryGt ?? cond.gt;
|
|
11263
|
-
score += 50;
|
|
11264
|
-
isConsecutive = false;
|
|
11265
|
-
startValues.push(val);
|
|
11266
|
-
startOperator = "primaryGt";
|
|
11267
|
-
if (endValues.length > 0) {
|
|
11268
|
-
endOperator = "primaryLte";
|
|
11269
|
-
}
|
|
11270
|
-
} else if ("primaryLte" in cond || "lte" in cond) {
|
|
11271
|
-
const val = cond.primaryLte?.v ?? cond.lte?.v ?? cond.primaryLte ?? cond.lte;
|
|
11272
|
-
score += 50;
|
|
11273
|
-
isConsecutive = false;
|
|
11274
|
-
endValues.push(val);
|
|
11275
|
-
endOperator = "primaryLte";
|
|
11276
|
-
if (startValues.length > 0) {
|
|
11277
|
-
startOperator = "primaryGte";
|
|
11278
|
-
}
|
|
11279
|
-
} else if ("primaryLt" in cond || "lt" in cond) {
|
|
11280
|
-
const val = cond.primaryLt?.v ?? cond.lt?.v ?? cond.primaryLt ?? cond.lt;
|
|
11281
|
-
score += 50;
|
|
11282
|
-
isConsecutive = false;
|
|
11283
|
-
endValues.push(val);
|
|
11284
|
-
endOperator = "primaryLt";
|
|
11285
|
-
if (startValues.length > 0) {
|
|
11286
|
-
startOperator = "primaryGte";
|
|
11287
|
-
}
|
|
11288
|
-
} else if ("primaryOr" in cond || "or" in cond) {
|
|
11289
|
-
score += 20;
|
|
11290
|
-
isConsecutive = false;
|
|
11291
|
-
} else if ("like" in cond) {
|
|
11292
|
-
score += 15;
|
|
11293
|
-
isConsecutive = false;
|
|
11294
|
-
} else {
|
|
11295
|
-
score += 10;
|
|
11296
|
-
isConsecutive = false;
|
|
11297
|
-
}
|
|
11298
|
-
}
|
|
11299
|
-
}
|
|
11300
|
-
}
|
|
11301
|
-
if (coveredFields.length === 1 && config.fields.length === 1) {
|
|
11302
|
-
Object.assign(builtCondition, query[primaryField]);
|
|
11303
|
-
} else {
|
|
11304
|
-
if (startOperator && startValues.length > 0) {
|
|
11305
|
-
builtCondition[startOperator] = { v: startValues.length === 1 ? startValues[0] : startValues };
|
|
11306
|
-
}
|
|
11307
|
-
if (endOperator && endValues.length > 0) {
|
|
11308
|
-
if (startOperator && startValues.length === endValues.length && startValues.every((val, i) => val === endValues[i])) {
|
|
11309
|
-
delete builtCondition[startOperator];
|
|
11310
|
-
builtCondition["primaryEqual"] = { v: startValues.length === 1 ? startValues[0] : startValues };
|
|
11311
|
-
} else {
|
|
11312
|
-
builtCondition[endOperator] = { v: endValues.length === 1 ? endValues[0] : endValues };
|
|
11313
|
-
}
|
|
11314
|
-
}
|
|
11315
|
-
if (Object.keys(builtCondition).length === 0) {
|
|
11316
|
-
Object.assign(builtCondition, query[primaryField] || {});
|
|
11317
|
-
}
|
|
11318
|
-
}
|
|
11319
|
-
let isIndexOrderSupported = false;
|
|
11320
|
-
if (orderByField) {
|
|
11321
|
-
for (let i = 0, len = config.fields.length; i < len; i++) {
|
|
11322
|
-
const field = config.fields[i];
|
|
11323
|
-
if (field === orderByField) {
|
|
11324
|
-
isIndexOrderSupported = true;
|
|
11325
|
-
break;
|
|
11326
|
-
}
|
|
11327
|
-
const cond = query[field];
|
|
11328
|
-
let isExactMatch = false;
|
|
11329
|
-
if (cond !== void 0) {
|
|
11330
|
-
if (typeof cond !== "object" || cond === null) isExactMatch = true;
|
|
11331
|
-
else if ("primaryEqual" in cond || "equal" in cond) isExactMatch = true;
|
|
11332
|
-
}
|
|
11333
|
-
if (!isExactMatch) break;
|
|
11334
|
-
}
|
|
11335
|
-
if (isIndexOrderSupported) {
|
|
11336
|
-
score += 200;
|
|
11337
|
-
}
|
|
11338
|
-
}
|
|
11339
|
-
candidates.push({
|
|
11340
|
-
tree: treeTx,
|
|
11341
|
-
condition: builtCondition,
|
|
11342
|
-
field: primaryField,
|
|
11400
|
+
const candidate = this.evaluateBTreeCandidate(
|
|
11343
11401
|
indexName,
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11402
|
+
config,
|
|
11403
|
+
query,
|
|
11404
|
+
queryFields,
|
|
11405
|
+
treeTx,
|
|
11406
|
+
orderByField
|
|
11407
|
+
);
|
|
11408
|
+
if (candidate) candidates.push(candidate);
|
|
11349
11409
|
} else if (config.type === "fts") {
|
|
11350
|
-
const field = config.fields;
|
|
11351
|
-
if (!queryFields.has(field)) continue;
|
|
11352
|
-
const condition = query[field];
|
|
11353
|
-
if (!condition || typeof condition !== "object" || !("match" in condition)) continue;
|
|
11354
11410
|
const treeTx = await tree.createTransaction();
|
|
11355
|
-
const
|
|
11356
|
-
const matchTokens = ftsConfig ? tokenize(condition.match, ftsConfig) : [];
|
|
11357
|
-
candidates.push({
|
|
11358
|
-
tree: treeTx,
|
|
11359
|
-
condition,
|
|
11360
|
-
field,
|
|
11411
|
+
const candidate = this.evaluateFTSCandidate(
|
|
11361
11412
|
indexName,
|
|
11362
|
-
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11413
|
+
config,
|
|
11414
|
+
query,
|
|
11415
|
+
queryFields,
|
|
11416
|
+
treeTx
|
|
11417
|
+
);
|
|
11418
|
+
if (candidate) candidates.push(candidate);
|
|
11368
11419
|
}
|
|
11369
11420
|
}
|
|
11370
11421
|
const rollback = () => {
|
|
@@ -11385,7 +11436,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11385
11436
|
return aFieldCount - bFieldCount;
|
|
11386
11437
|
});
|
|
11387
11438
|
const driver = candidates[0];
|
|
11388
|
-
const
|
|
11439
|
+
const driverCoveredFields = new Set(driver.coveredFields);
|
|
11440
|
+
const others = candidates.slice(1).filter((c) => !driverCoveredFields.has(c.field));
|
|
11389
11441
|
const compositeVerifyConditions = [];
|
|
11390
11442
|
for (let i = 0, len = driver.compositeVerifyFields.length; i < len; i++) {
|
|
11391
11443
|
const field = driver.compositeVerifyFields[i];
|
|
@@ -11858,12 +11910,13 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11858
11910
|
* Prefetch 방식으로 키 스트림을 청크 단위로 조회하여 문서를 순회합니다.
|
|
11859
11911
|
* FTS 검증, 복합 인덱스 검증, others 후보에 대한 tree.verify() 검증을 통과한 문서만 yield 합니다.
|
|
11860
11912
|
*/
|
|
11861
|
-
async *processChunkedKeysWithVerify(keysStream, startIdx, initialChunkSize, ftsConditions, compositeVerifyConditions, others, tx) {
|
|
11913
|
+
async *processChunkedKeysWithVerify(keysStream, startIdx, initialChunkSize, limit, ftsConditions, compositeVerifyConditions, others, tx) {
|
|
11862
11914
|
const verifyOthers = others.filter((o) => !o.isFtsMatch);
|
|
11863
11915
|
const isFts = ftsConditions.length > 0;
|
|
11864
11916
|
const isCompositeVerify = compositeVerifyConditions.length > 0;
|
|
11865
11917
|
const isVerifyOthers = verifyOthers.length > 0;
|
|
11866
|
-
|
|
11918
|
+
const isInfiniteLimit = isFinite(limit);
|
|
11919
|
+
let currentChunkSize = isInfiniteLimit ? initialChunkSize : limit;
|
|
11867
11920
|
let chunk = [];
|
|
11868
11921
|
let chunkSize = 0;
|
|
11869
11922
|
let dropped = 0;
|
|
@@ -11898,7 +11951,9 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11898
11951
|
}
|
|
11899
11952
|
docs.push(doc);
|
|
11900
11953
|
}
|
|
11901
|
-
|
|
11954
|
+
if (isInfiniteLimit) {
|
|
11955
|
+
currentChunkSize = this.adjustChunkSize(currentChunkSize, chunkTotalSize);
|
|
11956
|
+
}
|
|
11902
11957
|
return docs;
|
|
11903
11958
|
};
|
|
11904
11959
|
for await (const pk of keysStream) {
|
|
@@ -11966,6 +12021,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11966
12021
|
const driverResult = await self.getDriverKeys(query, orderByField, sortOrder);
|
|
11967
12022
|
if (!driverResult) return;
|
|
11968
12023
|
const { keysStream, others, compositeVerifyConditions, isDriverOrderByField, rollback } = driverResult;
|
|
12024
|
+
const initialChunkSize = self.options.pageSize;
|
|
11969
12025
|
try {
|
|
11970
12026
|
if (!isDriverOrderByField && orderByField) {
|
|
11971
12027
|
const topK = limit === Infinity ? Infinity : offset + limit;
|
|
@@ -11982,7 +12038,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11982
12038
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
11983
12039
|
keysStream,
|
|
11984
12040
|
0,
|
|
11985
|
-
|
|
12041
|
+
initialChunkSize,
|
|
12042
|
+
limit,
|
|
11986
12043
|
ftsConditions,
|
|
11987
12044
|
compositeVerifyConditions,
|
|
11988
12045
|
others,
|
|
@@ -12023,7 +12080,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
12023
12080
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
12024
12081
|
keysStream,
|
|
12025
12082
|
startIdx,
|
|
12026
|
-
|
|
12083
|
+
initialChunkSize,
|
|
12084
|
+
limit,
|
|
12027
12085
|
ftsConditions,
|
|
12028
12086
|
compositeVerifyConditions,
|
|
12029
12087
|
others,
|
|
@@ -110,6 +110,31 @@ export declare class DocumentDataplyAPI<T extends DocumentJSON> extends DataplyA
|
|
|
110
110
|
* @returns The verbose query object
|
|
111
111
|
*/
|
|
112
112
|
verboseQuery<U extends Partial<DocumentDataplyQuery<T>>, V extends DataplyTreeValue<U>>(query: Partial<DocumentDataplyQuery<U>>): Partial<DocumentDataplyQuery<V>>;
|
|
113
|
+
/**
|
|
114
|
+
* B-Tree 타입 인덱스의 선택도를 평가하고 트리에 부여할 조건을 산출합니다.
|
|
115
|
+
* 필드 매칭 여부를 검사하고, 연속된(Prefix) 조건에 대해 점수를 부여하며 Start/End 바운드를 구성합니다.
|
|
116
|
+
*
|
|
117
|
+
* @param indexName 평가할 인덱스의 이름 (예: idx_nickname_createdat)
|
|
118
|
+
* @param config 등록된 인덱스의 설정 객체
|
|
119
|
+
* @param query 쿼리 객체
|
|
120
|
+
* @param queryFields 쿼리에 포함된 필드 목록 집합
|
|
121
|
+
* @param treeTx 조회를 수행할 B-Tree 트랜잭션 객체
|
|
122
|
+
* @param orderByField 정렬에 사용할 필드명 (옵션)
|
|
123
|
+
* @returns B-Tree 인덱스 후보 정보 (조건, 점수, 커버된 필드 등), 적합하지 않으면 null
|
|
124
|
+
*/
|
|
125
|
+
private evaluateBTreeCandidate;
|
|
126
|
+
/**
|
|
127
|
+
* FTS (Full Text Search) 타입 인덱스의 선택도를 평가합니다.
|
|
128
|
+
* 'match' 연산자가 쿼리에 존재하는지 확인하고, 검색용 토큰으로 분해(tokenize)하여 점수를 매깁니다.
|
|
129
|
+
*
|
|
130
|
+
* @param indexName 평가할 인덱스의 이름
|
|
131
|
+
* @param config 등록된 인덱스의 설정 객체
|
|
132
|
+
* @param query 쿼리 객체
|
|
133
|
+
* @param queryFields 쿼리에 포함된 필드 목록 집합
|
|
134
|
+
* @param treeTx 조회를 수행할 B-Tree 트랜잭션 객체
|
|
135
|
+
* @returns FTS 인덱스 후보 정보 (조건, 점수, 분석된 토큰 등), 적합하지 않으면 null
|
|
136
|
+
*/
|
|
137
|
+
private evaluateFTSCandidate;
|
|
113
138
|
/**
|
|
114
139
|
* Choose the best index (driver) for the given query.
|
|
115
140
|
* Scores each index based on field coverage and condition type.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-dataply",
|
|
3
|
-
"version": "0.0.9-alpha.
|
|
3
|
+
"version": "0.0.9-alpha.15",
|
|
4
4
|
"description": "Simple and powerful JSON document database supporting complex queries and flexible indexing policies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "izure <admin@izure.org>",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"dataply"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"dataply": "^0.0.24-alpha.
|
|
45
|
+
"dataply": "^0.0.24-alpha.13"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/jest": "^30.0.0",
|