document-dataply 0.0.9-alpha.4 → 0.0.9-alpha.6
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 +434 -206
- package/dist/types/core/documentAPI.d.ts +9 -5
- package/package.json +2 -2
- package/readme.md +12 -7
package/dist/cjs/index.js
CHANGED
|
@@ -1580,83 +1580,217 @@ var require_cjs = __commonJS({
|
|
|
1580
1580
|
return regexp.test(nodeValue);
|
|
1581
1581
|
}
|
|
1582
1582
|
};
|
|
1583
|
-
|
|
1584
|
-
gt:
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
lte:
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1583
|
+
searchConfigs = {
|
|
1584
|
+
gt: {
|
|
1585
|
+
asc: {
|
|
1586
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1587
|
+
end: () => null,
|
|
1588
|
+
direction: 1,
|
|
1589
|
+
earlyTerminate: false
|
|
1590
|
+
},
|
|
1591
|
+
desc: {
|
|
1592
|
+
start: (tx) => tx.rightestNode(),
|
|
1593
|
+
end: (tx, v) => tx.insertableEndNode(v[0], -1),
|
|
1594
|
+
direction: -1,
|
|
1595
|
+
earlyTerminate: true
|
|
1596
|
+
}
|
|
1597
|
+
},
|
|
1598
|
+
gte: {
|
|
1599
|
+
asc: {
|
|
1600
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1601
|
+
end: () => null,
|
|
1602
|
+
direction: 1,
|
|
1603
|
+
earlyTerminate: false
|
|
1604
|
+
},
|
|
1605
|
+
desc: {
|
|
1606
|
+
start: (tx) => tx.rightestNode(),
|
|
1607
|
+
end: (tx, v) => tx.insertableEndNode(v[0], -1),
|
|
1608
|
+
direction: -1,
|
|
1609
|
+
earlyTerminate: true
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
lt: {
|
|
1613
|
+
asc: {
|
|
1614
|
+
start: (tx) => tx.leftestNode(),
|
|
1615
|
+
end: (tx, v) => tx.insertableEndNode(v[0], 1),
|
|
1616
|
+
direction: 1,
|
|
1617
|
+
earlyTerminate: true
|
|
1618
|
+
},
|
|
1619
|
+
desc: {
|
|
1620
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1621
|
+
end: () => null,
|
|
1622
|
+
direction: -1,
|
|
1623
|
+
earlyTerminate: false
|
|
1624
|
+
}
|
|
1625
|
+
},
|
|
1626
|
+
lte: {
|
|
1627
|
+
asc: {
|
|
1628
|
+
start: (tx) => tx.leftestNode(),
|
|
1629
|
+
end: (tx, v) => tx.insertableEndNode(v[0], 1),
|
|
1630
|
+
direction: 1,
|
|
1631
|
+
earlyTerminate: true
|
|
1632
|
+
},
|
|
1633
|
+
desc: {
|
|
1634
|
+
start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
|
|
1635
|
+
end: () => null,
|
|
1636
|
+
direction: -1,
|
|
1637
|
+
earlyTerminate: false
|
|
1638
|
+
}
|
|
1639
|
+
},
|
|
1640
|
+
equal: {
|
|
1641
|
+
asc: {
|
|
1642
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1643
|
+
end: (tx, v) => tx.insertableEndNode(v[0], 1),
|
|
1644
|
+
direction: 1,
|
|
1645
|
+
earlyTerminate: true
|
|
1646
|
+
},
|
|
1647
|
+
desc: {
|
|
1648
|
+
start: (tx, v) => tx.insertableEndNode(v[0], 1),
|
|
1649
|
+
end: (tx, v) => tx.insertableEndNode(v[0], -1),
|
|
1650
|
+
direction: -1,
|
|
1651
|
+
earlyTerminate: true
|
|
1652
|
+
}
|
|
1653
|
+
},
|
|
1654
|
+
notEqual: {
|
|
1655
|
+
asc: {
|
|
1656
|
+
start: (tx) => tx.leftestNode(),
|
|
1657
|
+
end: () => null,
|
|
1658
|
+
direction: 1,
|
|
1659
|
+
earlyTerminate: false
|
|
1660
|
+
},
|
|
1661
|
+
desc: {
|
|
1662
|
+
start: (tx) => tx.rightestNode(),
|
|
1663
|
+
end: () => null,
|
|
1664
|
+
direction: -1,
|
|
1665
|
+
earlyTerminate: false
|
|
1666
|
+
}
|
|
1667
|
+
},
|
|
1668
|
+
or: {
|
|
1669
|
+
asc: {
|
|
1670
|
+
start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestValue(v)),
|
|
1671
|
+
end: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
|
|
1672
|
+
direction: 1,
|
|
1673
|
+
earlyTerminate: false
|
|
1674
|
+
},
|
|
1675
|
+
desc: {
|
|
1676
|
+
start: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
|
|
1677
|
+
end: (tx, v) => tx.insertableEndNode(tx.lowestValue(v), -1),
|
|
1678
|
+
direction: -1,
|
|
1679
|
+
earlyTerminate: false
|
|
1680
|
+
}
|
|
1681
|
+
},
|
|
1682
|
+
primaryGt: {
|
|
1683
|
+
asc: {
|
|
1684
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1685
|
+
end: () => null,
|
|
1686
|
+
direction: 1,
|
|
1687
|
+
earlyTerminate: false
|
|
1688
|
+
},
|
|
1689
|
+
desc: {
|
|
1690
|
+
start: (tx) => tx.rightestNode(),
|
|
1691
|
+
end: (tx, v) => tx.insertableEndNode(v[0], -1),
|
|
1692
|
+
direction: -1,
|
|
1693
|
+
earlyTerminate: true
|
|
1694
|
+
}
|
|
1695
|
+
},
|
|
1696
|
+
primaryGte: {
|
|
1697
|
+
asc: {
|
|
1698
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1699
|
+
end: () => null,
|
|
1700
|
+
direction: 1,
|
|
1701
|
+
earlyTerminate: false
|
|
1702
|
+
},
|
|
1703
|
+
desc: {
|
|
1704
|
+
start: (tx) => tx.rightestNode(),
|
|
1705
|
+
end: (tx, v) => tx.insertableEndNode(v[0], -1),
|
|
1706
|
+
direction: -1,
|
|
1707
|
+
earlyTerminate: true
|
|
1708
|
+
}
|
|
1709
|
+
},
|
|
1710
|
+
primaryLt: {
|
|
1711
|
+
asc: {
|
|
1712
|
+
start: (tx) => tx.leftestNode(),
|
|
1713
|
+
end: (tx, v) => tx.insertableEndNode(v[0], 1),
|
|
1714
|
+
direction: 1,
|
|
1715
|
+
earlyTerminate: true
|
|
1716
|
+
},
|
|
1717
|
+
desc: {
|
|
1718
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1719
|
+
end: () => null,
|
|
1720
|
+
direction: -1,
|
|
1721
|
+
earlyTerminate: false
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
primaryLte: {
|
|
1725
|
+
asc: {
|
|
1726
|
+
start: (tx) => tx.leftestNode(),
|
|
1727
|
+
end: (tx, v) => tx.insertableEndNode(v[0], 1),
|
|
1728
|
+
direction: 1,
|
|
1729
|
+
earlyTerminate: true
|
|
1730
|
+
},
|
|
1731
|
+
desc: {
|
|
1732
|
+
start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
|
|
1733
|
+
end: () => null,
|
|
1734
|
+
direction: -1,
|
|
1735
|
+
earlyTerminate: false
|
|
1736
|
+
}
|
|
1737
|
+
},
|
|
1738
|
+
primaryEqual: {
|
|
1739
|
+
asc: {
|
|
1740
|
+
start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
|
|
1741
|
+
end: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
|
|
1742
|
+
direction: 1,
|
|
1743
|
+
earlyTerminate: true
|
|
1744
|
+
},
|
|
1745
|
+
desc: {
|
|
1746
|
+
start: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
|
|
1747
|
+
end: (tx, v) => tx.insertableEndNode(v[0], -1),
|
|
1748
|
+
direction: -1,
|
|
1749
|
+
earlyTerminate: true
|
|
1750
|
+
}
|
|
1751
|
+
},
|
|
1752
|
+
primaryNotEqual: {
|
|
1753
|
+
asc: {
|
|
1754
|
+
start: (tx) => tx.leftestNode(),
|
|
1755
|
+
end: () => null,
|
|
1756
|
+
direction: 1,
|
|
1757
|
+
earlyTerminate: false
|
|
1758
|
+
},
|
|
1759
|
+
desc: {
|
|
1760
|
+
start: (tx) => tx.rightestNode(),
|
|
1761
|
+
end: () => null,
|
|
1762
|
+
direction: -1,
|
|
1763
|
+
earlyTerminate: false
|
|
1764
|
+
}
|
|
1765
|
+
},
|
|
1766
|
+
primaryOr: {
|
|
1767
|
+
asc: {
|
|
1768
|
+
start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestPrimaryValue(v)),
|
|
1769
|
+
end: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
|
|
1770
|
+
direction: 1,
|
|
1771
|
+
earlyTerminate: false
|
|
1772
|
+
},
|
|
1773
|
+
desc: {
|
|
1774
|
+
start: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
|
|
1775
|
+
end: (tx, v) => tx.insertableEndNode(tx.lowestPrimaryValue(v), -1),
|
|
1776
|
+
direction: -1,
|
|
1777
|
+
earlyTerminate: false
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
like: {
|
|
1781
|
+
asc: {
|
|
1782
|
+
start: (tx) => tx.leftestNode(),
|
|
1783
|
+
end: () => null,
|
|
1784
|
+
direction: 1,
|
|
1785
|
+
earlyTerminate: false
|
|
1786
|
+
},
|
|
1787
|
+
desc: {
|
|
1788
|
+
start: (tx) => tx.rightestNode(),
|
|
1789
|
+
end: () => null,
|
|
1790
|
+
direction: -1,
|
|
1791
|
+
earlyTerminate: false
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1660
1794
|
};
|
|
1661
1795
|
/**
|
|
1662
1796
|
* Priority map for condition types.
|
|
@@ -2267,16 +2401,20 @@ var require_cjs = __commonJS({
|
|
|
2267
2401
|
const driverKey = this.getDriverKey(condition);
|
|
2268
2402
|
if (!driverKey) return;
|
|
2269
2403
|
const value = condition[driverKey];
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
let
|
|
2404
|
+
const v = this.ensureValues(value);
|
|
2405
|
+
const config = this.searchConfigs[driverKey][order];
|
|
2406
|
+
let startNode = config.start(this, v);
|
|
2407
|
+
let endNode = config.end(this, v);
|
|
2408
|
+
const direction = config.direction;
|
|
2409
|
+
const earlyTerminate = config.earlyTerminate;
|
|
2410
|
+
if (order === "desc" && !startNode) {
|
|
2411
|
+
startNode = this.rightestNode();
|
|
2412
|
+
}
|
|
2413
|
+
if (order === "asc" && !startNode) {
|
|
2414
|
+
startNode = this.leftestNode();
|
|
2415
|
+
}
|
|
2416
|
+
if (!startNode) return;
|
|
2273
2417
|
const comparator = this.verifierMap[driverKey];
|
|
2274
|
-
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
2275
|
-
if (order === "desc") {
|
|
2276
|
-
startNode = endNode ?? this.rightestNode();
|
|
2277
|
-
endNode = null;
|
|
2278
|
-
direction *= -1;
|
|
2279
|
-
}
|
|
2280
2418
|
const generator = this.getPairsGenerator(
|
|
2281
2419
|
value,
|
|
2282
2420
|
startNode,
|
|
@@ -2288,7 +2426,7 @@ var require_cjs = __commonJS({
|
|
|
2288
2426
|
let count = 0;
|
|
2289
2427
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2290
2428
|
for (const pair of generator) {
|
|
2291
|
-
const [k,
|
|
2429
|
+
const [k, v2] = pair;
|
|
2292
2430
|
if (intersection && !intersection.has(k)) {
|
|
2293
2431
|
continue;
|
|
2294
2432
|
}
|
|
@@ -2297,7 +2435,7 @@ var require_cjs = __commonJS({
|
|
|
2297
2435
|
if (key === driverKey) continue;
|
|
2298
2436
|
const verify = this.verifierMap[key];
|
|
2299
2437
|
const condValue = condition[key];
|
|
2300
|
-
if (!verify(
|
|
2438
|
+
if (!verify(v2, condValue)) {
|
|
2301
2439
|
isMatch = false;
|
|
2302
2440
|
break;
|
|
2303
2441
|
}
|
|
@@ -3397,16 +3535,20 @@ var require_cjs = __commonJS({
|
|
|
3397
3535
|
const driverKey = this.getDriverKey(condition);
|
|
3398
3536
|
if (!driverKey) return;
|
|
3399
3537
|
const value = condition[driverKey];
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
let
|
|
3538
|
+
const v = this.ensureValues(value);
|
|
3539
|
+
const config = this.searchConfigs[driverKey][order];
|
|
3540
|
+
let startNode = await config.start(this, v);
|
|
3541
|
+
let endNode = await config.end(this, v);
|
|
3542
|
+
const direction = config.direction;
|
|
3543
|
+
const earlyTerminate = config.earlyTerminate;
|
|
3544
|
+
if (order === "desc" && !startNode) {
|
|
3545
|
+
startNode = await this.rightestNode();
|
|
3546
|
+
}
|
|
3547
|
+
if (order === "asc" && !startNode) {
|
|
3548
|
+
startNode = await this.leftestNode();
|
|
3549
|
+
}
|
|
3550
|
+
if (!startNode) return;
|
|
3403
3551
|
const comparator = this.verifierMap[driverKey];
|
|
3404
|
-
const earlyTerminate = this.verifierEarlyTerminate[driverKey];
|
|
3405
|
-
if (order === "desc") {
|
|
3406
|
-
startNode = endNode ?? await this.rightestNode();
|
|
3407
|
-
endNode = null;
|
|
3408
|
-
direction *= -1;
|
|
3409
|
-
}
|
|
3410
3552
|
const generator = this.getPairsGenerator(
|
|
3411
3553
|
value,
|
|
3412
3554
|
startNode,
|
|
@@ -3418,7 +3560,7 @@ var require_cjs = __commonJS({
|
|
|
3418
3560
|
let count = 0;
|
|
3419
3561
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3420
3562
|
for await (const pair of generator) {
|
|
3421
|
-
const [k,
|
|
3563
|
+
const [k, v2] = pair;
|
|
3422
3564
|
if (intersection && !intersection.has(k)) {
|
|
3423
3565
|
continue;
|
|
3424
3566
|
}
|
|
@@ -3427,7 +3569,7 @@ var require_cjs = __commonJS({
|
|
|
3427
3569
|
if (key === driverKey) continue;
|
|
3428
3570
|
const verify = this.verifierMap[key];
|
|
3429
3571
|
const condValue = condition[key];
|
|
3430
|
-
if (!verify(
|
|
3572
|
+
if (!verify(v2, condValue)) {
|
|
3431
3573
|
isMatch = false;
|
|
3432
3574
|
break;
|
|
3433
3575
|
}
|
|
@@ -8342,7 +8484,7 @@ var require_cjs = __commonJS({
|
|
|
8342
8484
|
/**
|
|
8343
8485
|
* Appends and inserts a new page.
|
|
8344
8486
|
* If a free page is available in the free list, it reuses it.
|
|
8345
|
-
* Otherwise, it
|
|
8487
|
+
* Otherwise, it preallocates `pagePreallocationCount` pages to support sequential reads.
|
|
8346
8488
|
* @returns Created or reused page ID
|
|
8347
8489
|
*/
|
|
8348
8490
|
async appendNewPage(pageType = PageManager.CONSTANT.PAGE_TYPE_EMPTY, tx) {
|
|
@@ -8363,12 +8505,26 @@ var require_cjs = __commonJS({
|
|
|
8363
8505
|
await this.setPage(reusedPageId, newPage2, tx);
|
|
8364
8506
|
return reusedPageId;
|
|
8365
8507
|
}
|
|
8508
|
+
const preallocationCount = this.options.pagePreallocationCount;
|
|
8366
8509
|
const pageCount = metadataManager.getPageCount(metadata);
|
|
8367
8510
|
const newPageIndex = pageCount;
|
|
8368
|
-
const newTotalCount = pageCount +
|
|
8511
|
+
const newTotalCount = pageCount + preallocationCount;
|
|
8369
8512
|
const manager = this.pageFactory.getManagerFromType(pageType);
|
|
8370
8513
|
const newPage = manager.create(this.pageSize, newPageIndex);
|
|
8371
8514
|
await this.setPage(newPageIndex, newPage, tx);
|
|
8515
|
+
const emptyManager = this.pageFactory.getManagerFromType(PageManager.CONSTANT.PAGE_TYPE_EMPTY);
|
|
8516
|
+
const firstFreeIndex = newPageIndex + 1;
|
|
8517
|
+
const lastFreeIndex = newPageIndex + preallocationCount - 1;
|
|
8518
|
+
for (let i = firstFreeIndex; i <= lastFreeIndex; i++) {
|
|
8519
|
+
const emptyPage = emptyManager.create(this.pageSize, i);
|
|
8520
|
+
const nextId = i < lastFreeIndex ? i + 1 : -1;
|
|
8521
|
+
emptyManager.setNextPageId(emptyPage, nextId);
|
|
8522
|
+
await this.setPage(i, emptyPage, tx);
|
|
8523
|
+
await this.updateBitmap(i, true, tx);
|
|
8524
|
+
}
|
|
8525
|
+
if (preallocationCount > 1) {
|
|
8526
|
+
metadataManager.setFreePageId(metadata, firstFreeIndex);
|
|
8527
|
+
}
|
|
8372
8528
|
metadataManager.setPageCount(metadata, newTotalCount);
|
|
8373
8529
|
await this.setPage(0, metadata, tx);
|
|
8374
8530
|
return newPageIndex;
|
|
@@ -8452,7 +8608,8 @@ var require_cjs = __commonJS({
|
|
|
8452
8608
|
}
|
|
8453
8609
|
/**
|
|
8454
8610
|
* Frees the page and marks it as available in the bitmap.
|
|
8455
|
-
*
|
|
8611
|
+
* Inserts the page into the free list in ascending order by page ID
|
|
8612
|
+
* to support HDD sequential reads.
|
|
8456
8613
|
* @param pageId Page ID
|
|
8457
8614
|
* @param tx Transaction
|
|
8458
8615
|
*/
|
|
@@ -8462,13 +8619,30 @@ var require_cjs = __commonJS({
|
|
|
8462
8619
|
await tx.__acquireWriteLock(pageId);
|
|
8463
8620
|
const metadata = await this.getMetadata(tx);
|
|
8464
8621
|
const metadataManager = this.pageFactory.getManager(metadata);
|
|
8465
|
-
const currentHeadFreePageId = metadataManager.getFreePageId(metadata);
|
|
8466
8622
|
const emptyPageManager = this.pageFactory.getManagerFromType(PageManager.CONSTANT.PAGE_TYPE_EMPTY);
|
|
8467
8623
|
const emptyPage = emptyPageManager.create(this.pageSize, pageId);
|
|
8468
|
-
|
|
8469
|
-
|
|
8624
|
+
const headFreePageId = metadataManager.getFreePageId(metadata);
|
|
8625
|
+
if (headFreePageId === -1 || pageId < headFreePageId) {
|
|
8626
|
+
emptyPageManager.setNextPageId(emptyPage, headFreePageId);
|
|
8627
|
+
await this.setPage(pageId, emptyPage, tx);
|
|
8628
|
+
metadataManager.setFreePageId(metadata, pageId);
|
|
8629
|
+
} else {
|
|
8630
|
+
let prevPageId = headFreePageId;
|
|
8631
|
+
let prevPage = await this.get(prevPageId, tx);
|
|
8632
|
+
let prevManager = this.pageFactory.getManager(prevPage);
|
|
8633
|
+
let nextPageId = prevManager.getNextPageId(prevPage);
|
|
8634
|
+
while (nextPageId !== -1 && nextPageId < pageId) {
|
|
8635
|
+
prevPageId = nextPageId;
|
|
8636
|
+
prevPage = await this.get(prevPageId, tx);
|
|
8637
|
+
prevManager = this.pageFactory.getManager(prevPage);
|
|
8638
|
+
nextPageId = prevManager.getNextPageId(prevPage);
|
|
8639
|
+
}
|
|
8640
|
+
emptyPageManager.setNextPageId(emptyPage, nextPageId);
|
|
8641
|
+
await this.setPage(pageId, emptyPage, tx);
|
|
8642
|
+
prevManager.setNextPageId(prevPage, pageId);
|
|
8643
|
+
await this.setPage(prevPageId, prevPage, tx);
|
|
8644
|
+
}
|
|
8470
8645
|
await this.updateBitmap(pageId, true, tx);
|
|
8471
|
-
metadataManager.setFreePageId(metadata, pageId);
|
|
8472
8646
|
await this.setPage(0, metadata, tx);
|
|
8473
8647
|
}
|
|
8474
8648
|
/**
|
|
@@ -9168,7 +9342,9 @@ var require_cjs = __commonJS({
|
|
|
9168
9342
|
}
|
|
9169
9343
|
pageGroupMap.get(pageId).push({ pk: pair.pk, slotIndex, index: pair.index });
|
|
9170
9344
|
}
|
|
9171
|
-
|
|
9345
|
+
const sortedPageIds = Array.from(pageGroupMap.keys()).sort((a, b) => a - b);
|
|
9346
|
+
await Promise.all(sortedPageIds.map(async (pageId) => {
|
|
9347
|
+
const items = pageGroupMap.get(pageId);
|
|
9172
9348
|
const page = await this.pfs.get(pageId, tx);
|
|
9173
9349
|
if (!this.factory.isDataPage(page)) {
|
|
9174
9350
|
throw new Error(`Page ${pageId} is not a data page`);
|
|
@@ -9519,6 +9695,7 @@ var require_cjs = __commonJS({
|
|
|
9519
9695
|
return Object.assign({
|
|
9520
9696
|
pageSize: 8192,
|
|
9521
9697
|
pageCacheCapacity: 1e4,
|
|
9698
|
+
pagePreallocationCount: 1e3,
|
|
9522
9699
|
wal: null,
|
|
9523
9700
|
walCheckpointThreshold: 1e3
|
|
9524
9701
|
}, options);
|
|
@@ -10572,8 +10749,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10572
10749
|
if (metadata.lastId === 0) {
|
|
10573
10750
|
return 0;
|
|
10574
10751
|
}
|
|
10575
|
-
|
|
10576
|
-
const indexEntryMap = /* @__PURE__ */ new Map();
|
|
10752
|
+
let indexTxMap = {};
|
|
10577
10753
|
for (const indexName of backfillTargets) {
|
|
10578
10754
|
const tree = this.trees.get(indexName);
|
|
10579
10755
|
if (tree && indexName !== "_id") {
|
|
@@ -10581,6 +10757,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10581
10757
|
}
|
|
10582
10758
|
}
|
|
10583
10759
|
let backfilledCount = 0;
|
|
10760
|
+
let chunkCount = 0;
|
|
10761
|
+
const CHUNK_SIZE = 1e3;
|
|
10584
10762
|
const idTree = this.trees.get("_id");
|
|
10585
10763
|
if (!idTree) {
|
|
10586
10764
|
throw new Error("ID tree not found");
|
|
@@ -10609,10 +10787,6 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10609
10787
|
const keyToInsert = this.getTokenKey(k, token);
|
|
10610
10788
|
const entry = { k, v: token };
|
|
10611
10789
|
batchInsertData.push([keyToInsert, entry]);
|
|
10612
|
-
if (!indexEntryMap.has(btx)) {
|
|
10613
|
-
indexEntryMap.set(btx, []);
|
|
10614
|
-
}
|
|
10615
|
-
indexEntryMap.get(btx).push({ k: keyToInsert, v: entry });
|
|
10616
10790
|
}
|
|
10617
10791
|
await btx.batchInsert(batchInsertData);
|
|
10618
10792
|
} else {
|
|
@@ -10620,34 +10794,42 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10620
10794
|
if (indexVal === void 0) continue;
|
|
10621
10795
|
const entry = { k, v: indexVal };
|
|
10622
10796
|
const batchInsertData = [[k, entry]];
|
|
10623
|
-
if (!indexEntryMap.has(btx)) {
|
|
10624
|
-
indexEntryMap.set(btx, []);
|
|
10625
|
-
}
|
|
10626
|
-
indexEntryMap.get(btx).push(entry);
|
|
10627
10797
|
await btx.batchInsert(batchInsertData);
|
|
10628
10798
|
}
|
|
10629
10799
|
}
|
|
10630
10800
|
backfilledCount++;
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
|
|
10801
|
+
chunkCount++;
|
|
10802
|
+
if (chunkCount >= CHUNK_SIZE) {
|
|
10803
|
+
try {
|
|
10804
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10805
|
+
await btx.commit();
|
|
10806
|
+
}
|
|
10807
|
+
} catch (err) {
|
|
10808
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10809
|
+
await btx.rollback();
|
|
10810
|
+
}
|
|
10811
|
+
throw err;
|
|
10812
|
+
}
|
|
10813
|
+
for (const indexName of backfillTargets) {
|
|
10814
|
+
const tree = this.trees.get(indexName);
|
|
10815
|
+
if (tree && indexName !== "_id") {
|
|
10816
|
+
indexTxMap[indexName] = await tree.createTransaction();
|
|
10817
|
+
}
|
|
10818
|
+
}
|
|
10819
|
+
chunkCount = 0;
|
|
10642
10820
|
}
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
for (const
|
|
10647
|
-
await btx.
|
|
10821
|
+
}
|
|
10822
|
+
if (chunkCount > 0) {
|
|
10823
|
+
try {
|
|
10824
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10825
|
+
await btx.commit();
|
|
10648
10826
|
}
|
|
10827
|
+
} catch (err) {
|
|
10828
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10829
|
+
await btx.rollback();
|
|
10830
|
+
}
|
|
10831
|
+
throw err;
|
|
10649
10832
|
}
|
|
10650
|
-
throw err;
|
|
10651
10833
|
}
|
|
10652
10834
|
this.pendingBackfillFields = [];
|
|
10653
10835
|
return backfilledCount;
|
|
@@ -10805,27 +10987,61 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10805
10987
|
const condition = query[primaryField];
|
|
10806
10988
|
const treeTx = await tree.createTransaction();
|
|
10807
10989
|
let score = 0;
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
}
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
}
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10990
|
+
let isConsecutive = true;
|
|
10991
|
+
const coveredFields = [];
|
|
10992
|
+
const compositeVerifyFields = [];
|
|
10993
|
+
for (const field of config.fields) {
|
|
10994
|
+
if (!queryFields.has(field)) {
|
|
10995
|
+
isConsecutive = false;
|
|
10996
|
+
continue;
|
|
10997
|
+
}
|
|
10998
|
+
coveredFields.push(field);
|
|
10999
|
+
if (field !== primaryField) {
|
|
11000
|
+
compositeVerifyFields.push(field);
|
|
11001
|
+
}
|
|
11002
|
+
score += 1;
|
|
11003
|
+
if (isConsecutive) {
|
|
11004
|
+
const cond = query[field];
|
|
11005
|
+
if (cond !== void 0) {
|
|
11006
|
+
if (typeof cond !== "object" || cond === null) {
|
|
11007
|
+
score += 100;
|
|
11008
|
+
} else if ("primaryEqual" in cond || "equal" in cond) {
|
|
11009
|
+
score += 100;
|
|
11010
|
+
} 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) {
|
|
11011
|
+
score += 50;
|
|
11012
|
+
isConsecutive = false;
|
|
11013
|
+
} else if ("primaryOr" in cond || "or" in cond) {
|
|
11014
|
+
score += 20;
|
|
11015
|
+
isConsecutive = false;
|
|
11016
|
+
} else if ("like" in cond) {
|
|
11017
|
+
score += 15;
|
|
11018
|
+
isConsecutive = false;
|
|
11019
|
+
} else {
|
|
11020
|
+
score += 10;
|
|
11021
|
+
isConsecutive = false;
|
|
11022
|
+
}
|
|
11023
|
+
}
|
|
10823
11024
|
}
|
|
10824
11025
|
}
|
|
10825
|
-
|
|
10826
|
-
|
|
11026
|
+
let isIndexOrderSupported = false;
|
|
11027
|
+
if (orderByField) {
|
|
11028
|
+
for (const field of config.fields) {
|
|
11029
|
+
if (field === orderByField) {
|
|
11030
|
+
isIndexOrderSupported = true;
|
|
11031
|
+
break;
|
|
11032
|
+
}
|
|
11033
|
+
const cond = query[field];
|
|
11034
|
+
let isExactMatch = false;
|
|
11035
|
+
if (cond !== void 0) {
|
|
11036
|
+
if (typeof cond !== "object" || cond === null) isExactMatch = true;
|
|
11037
|
+
else if ("primaryEqual" in cond || "equal" in cond) isExactMatch = true;
|
|
11038
|
+
}
|
|
11039
|
+
if (!isExactMatch) break;
|
|
11040
|
+
}
|
|
11041
|
+
if (isIndexOrderSupported) {
|
|
11042
|
+
score += 200;
|
|
11043
|
+
}
|
|
10827
11044
|
}
|
|
10828
|
-
const compositeVerifyFields = coveredFields.filter((f) => f !== primaryField);
|
|
10829
11045
|
candidates.push({
|
|
10830
11046
|
tree: treeTx,
|
|
10831
11047
|
condition,
|
|
@@ -10833,7 +11049,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10833
11049
|
indexName,
|
|
10834
11050
|
isFtsMatch: false,
|
|
10835
11051
|
score,
|
|
10836
|
-
compositeVerifyFields
|
|
11052
|
+
compositeVerifyFields,
|
|
11053
|
+
isIndexOrderSupported
|
|
10837
11054
|
});
|
|
10838
11055
|
} else if (config.type === "fts") {
|
|
10839
11056
|
const field = config.fields;
|
|
@@ -10851,7 +11068,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10851
11068
|
isFtsMatch: true,
|
|
10852
11069
|
matchTokens,
|
|
10853
11070
|
score: 90,
|
|
10854
|
-
compositeVerifyFields: []
|
|
11071
|
+
compositeVerifyFields: [],
|
|
11072
|
+
isIndexOrderSupported: false
|
|
10855
11073
|
});
|
|
10856
11074
|
}
|
|
10857
11075
|
}
|
|
@@ -10894,33 +11112,30 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10894
11112
|
getTokenKey(pk, token) {
|
|
10895
11113
|
return pk + ":" + token;
|
|
10896
11114
|
}
|
|
10897
|
-
async
|
|
11115
|
+
async *applyCandidateByFTSStream(candidate, matchedTokens, filterValues, order) {
|
|
10898
11116
|
const keys = /* @__PURE__ */ new Set();
|
|
10899
11117
|
for (let i = 0, len = matchedTokens.length; i < len; i++) {
|
|
10900
11118
|
const token = matchedTokens[i];
|
|
10901
|
-
const
|
|
11119
|
+
for await (const pair of candidate.tree.whereStream(
|
|
10902
11120
|
{ primaryEqual: { v: token } },
|
|
10903
|
-
{
|
|
10904
|
-
|
|
11121
|
+
{ order }
|
|
11122
|
+
)) {
|
|
11123
|
+
const pk = pair[1].k;
|
|
11124
|
+
if (filterValues && !filterValues.has(pk)) continue;
|
|
11125
|
+
if (!keys.has(pk)) {
|
|
11126
|
+
keys.add(pk);
|
|
11127
|
+
yield pk;
|
|
10905
11128
|
}
|
|
10906
|
-
);
|
|
10907
|
-
for (const pair of pairs.values()) {
|
|
10908
|
-
if (filterValues && !filterValues.has(pair.k)) continue;
|
|
10909
|
-
keys.add(pair.k);
|
|
10910
11129
|
}
|
|
10911
11130
|
}
|
|
10912
|
-
return keys;
|
|
10913
11131
|
}
|
|
10914
11132
|
/**
|
|
10915
11133
|
* 특정 인덱스 후보를 조회하여 PK 집합을 필터링합니다.
|
|
10916
11134
|
*/
|
|
10917
|
-
|
|
10918
|
-
return
|
|
11135
|
+
applyCandidateStream(candidate, filterValues, order) {
|
|
11136
|
+
return candidate.tree.keysStream(
|
|
10919
11137
|
candidate.condition,
|
|
10920
|
-
{
|
|
10921
|
-
filterValues,
|
|
10922
|
-
order
|
|
10923
|
-
}
|
|
11138
|
+
{ filterValues, order }
|
|
10924
11139
|
);
|
|
10925
11140
|
}
|
|
10926
11141
|
/**
|
|
@@ -10936,30 +11151,34 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10936
11151
|
);
|
|
10937
11152
|
if (!selectivity) return new Float64Array(0);
|
|
10938
11153
|
const { driver, others, rollback } = selectivity;
|
|
10939
|
-
const useIndexOrder = orderBy === void 0 || driver.
|
|
11154
|
+
const useIndexOrder = orderBy === void 0 || driver.isIndexOrderSupported;
|
|
10940
11155
|
const candidates = [driver, ...others];
|
|
10941
11156
|
let keys = void 0;
|
|
10942
11157
|
for (let i = 0, len = candidates.length; i < len; i++) {
|
|
10943
11158
|
const candidate = candidates[i];
|
|
10944
11159
|
const currentOrder = useIndexOrder ? sortOrder : void 0;
|
|
10945
11160
|
if (candidate.isFtsMatch && candidate.matchTokens && candidate.matchTokens.length > 0) {
|
|
10946
|
-
|
|
11161
|
+
const stream = this.applyCandidateByFTSStream(
|
|
10947
11162
|
candidate,
|
|
10948
11163
|
candidate.matchTokens,
|
|
10949
11164
|
keys,
|
|
10950
11165
|
currentOrder
|
|
10951
11166
|
);
|
|
11167
|
+
keys = /* @__PURE__ */ new Set();
|
|
11168
|
+
for await (const pk of stream) keys.add(pk);
|
|
10952
11169
|
} else {
|
|
10953
|
-
|
|
11170
|
+
const stream = this.applyCandidateStream(candidate, keys, currentOrder);
|
|
11171
|
+
keys = /* @__PURE__ */ new Set();
|
|
11172
|
+
for await (const pk of stream) keys.add(pk);
|
|
10954
11173
|
}
|
|
10955
11174
|
}
|
|
10956
11175
|
rollback();
|
|
10957
11176
|
return new Float64Array(Array.from(keys || []));
|
|
10958
11177
|
}
|
|
10959
11178
|
/**
|
|
10960
|
-
* 드라이버 인덱스만으로 PK
|
|
11179
|
+
* 드라이버 인덱스만으로 PK 스트림을 가져옵니다. (교집합 없이)
|
|
10961
11180
|
* selectDocuments에서 사용하며, 나머지 조건(others)은 스트리밍 중 tree.verify()로 검증합니다.
|
|
10962
|
-
* @returns 드라이버 키
|
|
11181
|
+
* @returns 드라이버 키 스트림, others 후보 목록, rollback 함수. 또는 null.
|
|
10963
11182
|
*/
|
|
10964
11183
|
async getDriverKeys(query, orderBy, sortOrder = "asc") {
|
|
10965
11184
|
const isQueryEmpty = Object.keys(query).length === 0;
|
|
@@ -10970,21 +11189,21 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10970
11189
|
);
|
|
10971
11190
|
if (!selectivity) return null;
|
|
10972
11191
|
const { driver, others, compositeVerifyConditions, rollback } = selectivity;
|
|
10973
|
-
const useIndexOrder = orderBy === void 0 || driver.
|
|
11192
|
+
const useIndexOrder = orderBy === void 0 || driver.isIndexOrderSupported;
|
|
10974
11193
|
const currentOrder = useIndexOrder ? sortOrder : void 0;
|
|
10975
|
-
let
|
|
11194
|
+
let keysStream;
|
|
10976
11195
|
if (driver.isFtsMatch && driver.matchTokens && driver.matchTokens.length > 0) {
|
|
10977
|
-
|
|
11196
|
+
keysStream = this.applyCandidateByFTSStream(
|
|
10978
11197
|
driver,
|
|
10979
11198
|
driver.matchTokens,
|
|
10980
11199
|
void 0,
|
|
10981
11200
|
currentOrder
|
|
10982
11201
|
);
|
|
10983
11202
|
} else {
|
|
10984
|
-
|
|
11203
|
+
keysStream = this.applyCandidateStream(driver, void 0, currentOrder);
|
|
10985
11204
|
}
|
|
10986
11205
|
return {
|
|
10987
|
-
|
|
11206
|
+
keysStream,
|
|
10988
11207
|
others,
|
|
10989
11208
|
compositeVerifyConditions,
|
|
10990
11209
|
isDriverOrderByField: useIndexOrder,
|
|
@@ -11334,28 +11553,17 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11334
11553
|
return currentChunkSize;
|
|
11335
11554
|
}
|
|
11336
11555
|
/**
|
|
11337
|
-
* Prefetch 방식으로 키
|
|
11556
|
+
* Prefetch 방식으로 키 스트림을 청크 단위로 조회하여 문서를 순회합니다.
|
|
11338
11557
|
* FTS 검증, 복합 인덱스 검증, others 후보에 대한 tree.verify() 검증을 통과한 문서만 yield 합니다.
|
|
11339
11558
|
*/
|
|
11340
|
-
async *processChunkedKeysWithVerify(
|
|
11559
|
+
async *processChunkedKeysWithVerify(keysStream, startIdx, initialChunkSize, ftsConditions, compositeVerifyConditions, others, tx) {
|
|
11341
11560
|
const verifyOthers = others.filter((o) => !o.isFtsMatch);
|
|
11342
|
-
let i = startIdx;
|
|
11343
|
-
const totalKeys = keys.length;
|
|
11344
11561
|
let currentChunkSize = initialChunkSize;
|
|
11345
|
-
let
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
}
|
|
11351
|
-
while (nextChunkPromise) {
|
|
11352
|
-
const rawResults = await nextChunkPromise;
|
|
11353
|
-
nextChunkPromise = null;
|
|
11354
|
-
if (i < totalKeys) {
|
|
11355
|
-
const endIdx = Math.min(i + currentChunkSize, totalKeys);
|
|
11356
|
-
nextChunkPromise = this.selectMany(keys.subarray(i, endIdx), false, tx);
|
|
11357
|
-
i = endIdx;
|
|
11358
|
-
}
|
|
11562
|
+
let chunk = [];
|
|
11563
|
+
let dropped = 0;
|
|
11564
|
+
const processChunk = async (pks) => {
|
|
11565
|
+
const docs = [];
|
|
11566
|
+
const rawResults = await this.selectMany(new Float64Array(pks), false, tx);
|
|
11359
11567
|
let chunkTotalSize = 0;
|
|
11360
11568
|
for (let j = 0, len = rawResults.length; j < len; j++) {
|
|
11361
11569
|
const s = rawResults[j];
|
|
@@ -11382,9 +11590,26 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11382
11590
|
}
|
|
11383
11591
|
if (!passed) continue;
|
|
11384
11592
|
}
|
|
11385
|
-
|
|
11593
|
+
docs.push(doc);
|
|
11386
11594
|
}
|
|
11387
11595
|
currentChunkSize = this.adjustChunkSize(currentChunkSize, chunkTotalSize);
|
|
11596
|
+
return docs;
|
|
11597
|
+
};
|
|
11598
|
+
for await (const pk of keysStream) {
|
|
11599
|
+
if (dropped < startIdx) {
|
|
11600
|
+
dropped++;
|
|
11601
|
+
continue;
|
|
11602
|
+
}
|
|
11603
|
+
chunk.push(pk);
|
|
11604
|
+
if (chunk.length >= currentChunkSize) {
|
|
11605
|
+
const docs = await processChunk(chunk);
|
|
11606
|
+
for (let j = 0; j < docs.length; j++) yield docs[j];
|
|
11607
|
+
chunk = [];
|
|
11608
|
+
}
|
|
11609
|
+
}
|
|
11610
|
+
if (chunk.length > 0) {
|
|
11611
|
+
const docs = await processChunk(chunk);
|
|
11612
|
+
for (let j = 0; j < docs.length; j++) yield docs[j];
|
|
11388
11613
|
}
|
|
11389
11614
|
}
|
|
11390
11615
|
/**
|
|
@@ -11432,11 +11657,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11432
11657
|
}
|
|
11433
11658
|
const driverResult = await self.getDriverKeys(query, orderByField, sortOrder);
|
|
11434
11659
|
if (!driverResult) return;
|
|
11435
|
-
const {
|
|
11436
|
-
if (keys.length === 0) {
|
|
11437
|
-
rollback();
|
|
11438
|
-
return;
|
|
11439
|
-
}
|
|
11660
|
+
const { keysStream, others, compositeVerifyConditions, isDriverOrderByField, rollback } = driverResult;
|
|
11440
11661
|
try {
|
|
11441
11662
|
if (!isDriverOrderByField && orderByField) {
|
|
11442
11663
|
const topK = limit === Infinity ? Infinity : offset + limit;
|
|
@@ -11451,7 +11672,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11451
11672
|
}
|
|
11452
11673
|
const results = [];
|
|
11453
11674
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
11454
|
-
|
|
11675
|
+
keysStream,
|
|
11455
11676
|
0,
|
|
11456
11677
|
self.options.pageSize,
|
|
11457
11678
|
ftsConditions,
|
|
@@ -11487,16 +11708,23 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11487
11708
|
yield limitedResults[j];
|
|
11488
11709
|
}
|
|
11489
11710
|
} else {
|
|
11711
|
+
const hasFilters = ftsConditions.length > 0 || compositeVerifyConditions.length > 0 || others.length > 0;
|
|
11712
|
+
const startIdx = hasFilters ? 0 : offset;
|
|
11490
11713
|
let yieldedCount = 0;
|
|
11714
|
+
let skippedCount = hasFilters ? 0 : offset;
|
|
11491
11715
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
11492
|
-
|
|
11493
|
-
|
|
11716
|
+
keysStream,
|
|
11717
|
+
startIdx,
|
|
11494
11718
|
self.options.pageSize,
|
|
11495
11719
|
ftsConditions,
|
|
11496
11720
|
compositeVerifyConditions,
|
|
11497
11721
|
others,
|
|
11498
11722
|
tx2
|
|
11499
11723
|
)) {
|
|
11724
|
+
if (skippedCount < offset) {
|
|
11725
|
+
skippedCount++;
|
|
11726
|
+
continue;
|
|
11727
|
+
}
|
|
11500
11728
|
if (yieldedCount >= limit) break;
|
|
11501
11729
|
yield doc;
|
|
11502
11730
|
yieldedCount++;
|
|
@@ -127,6 +127,7 @@ export declare class DocumentDataplyAPI<T extends DocumentJSON> extends DataplyA
|
|
|
127
127
|
field: string;
|
|
128
128
|
indexName: string;
|
|
129
129
|
isFtsMatch: false;
|
|
130
|
+
isIndexOrderSupported: boolean;
|
|
130
131
|
} | {
|
|
131
132
|
tree: BPTreeAsync<string, V>;
|
|
132
133
|
condition: Partial<DocumentDataplyCondition<U>>;
|
|
@@ -134,6 +135,7 @@ export declare class DocumentDataplyAPI<T extends DocumentJSON> extends DataplyA
|
|
|
134
135
|
indexName: string;
|
|
135
136
|
isFtsMatch: true;
|
|
136
137
|
matchTokens: string[];
|
|
138
|
+
isIndexOrderSupported: boolean;
|
|
137
139
|
});
|
|
138
140
|
others: ({
|
|
139
141
|
tree: BPTreeAsync<number, V>;
|
|
@@ -141,6 +143,7 @@ export declare class DocumentDataplyAPI<T extends DocumentJSON> extends DataplyA
|
|
|
141
143
|
field: string;
|
|
142
144
|
indexName: string;
|
|
143
145
|
isFtsMatch: false;
|
|
146
|
+
isIndexOrderSupported: boolean;
|
|
144
147
|
} | {
|
|
145
148
|
tree: BPTreeAsync<string, V>;
|
|
146
149
|
condition: Partial<DocumentDataplyCondition<U>>;
|
|
@@ -148,6 +151,7 @@ export declare class DocumentDataplyAPI<T extends DocumentJSON> extends DataplyA
|
|
|
148
151
|
indexName: string;
|
|
149
152
|
isFtsMatch: true;
|
|
150
153
|
matchTokens: string[];
|
|
154
|
+
isIndexOrderSupported: boolean;
|
|
151
155
|
})[];
|
|
152
156
|
compositeVerifyConditions: {
|
|
153
157
|
field: string;
|
|
@@ -164,20 +168,20 @@ export declare class DocumentDataplyAPI<T extends DocumentJSON> extends DataplyA
|
|
|
164
168
|
smallChunkSize: number;
|
|
165
169
|
};
|
|
166
170
|
private getTokenKey;
|
|
167
|
-
private
|
|
171
|
+
private applyCandidateByFTSStream;
|
|
168
172
|
/**
|
|
169
173
|
* 특정 인덱스 후보를 조회하여 PK 집합을 필터링합니다.
|
|
170
174
|
*/
|
|
171
|
-
private
|
|
175
|
+
private applyCandidateStream;
|
|
172
176
|
/**
|
|
173
177
|
* 쿼리와 인덱스 선택을 기반으로 기본 키(Primary Keys)를 가져옵니다.
|
|
174
178
|
* 쿼리 최적화를 통합하기 위한 내부 공통 메서드입니다.
|
|
175
179
|
*/
|
|
176
180
|
getKeys(query: Partial<DocumentDataplyQuery<T>>, orderBy?: string, sortOrder?: 'asc' | 'desc'): Promise<Float64Array>;
|
|
177
181
|
/**
|
|
178
|
-
* 드라이버 인덱스만으로 PK
|
|
182
|
+
* 드라이버 인덱스만으로 PK 스트림을 가져옵니다. (교집합 없이)
|
|
179
183
|
* selectDocuments에서 사용하며, 나머지 조건(others)은 스트리밍 중 tree.verify()로 검증합니다.
|
|
180
|
-
* @returns 드라이버 키
|
|
184
|
+
* @returns 드라이버 키 스트림, others 후보 목록, rollback 함수. 또는 null.
|
|
181
185
|
*/
|
|
182
186
|
private getDriverKeys;
|
|
183
187
|
private insertDocumentInternal;
|
|
@@ -250,7 +254,7 @@ export declare class DocumentDataplyAPI<T extends DocumentJSON> extends DataplyA
|
|
|
250
254
|
*/
|
|
251
255
|
private adjustChunkSize;
|
|
252
256
|
/**
|
|
253
|
-
* Prefetch 방식으로 키
|
|
257
|
+
* Prefetch 방식으로 키 스트림을 청크 단위로 조회하여 문서를 순회합니다.
|
|
254
258
|
* FTS 검증, 복합 인덱스 검증, others 후보에 대한 tree.verify() 검증을 통과한 문서만 yield 합니다.
|
|
255
259
|
*/
|
|
256
260
|
private processChunkedKeysWithVerify;
|
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.6",
|
|
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.2"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/jest": "^30.0.0",
|
package/readme.md
CHANGED
|
@@ -54,16 +54,21 @@ async function main() {
|
|
|
54
54
|
.Options({ wal: 'my-database.wal' })
|
|
55
55
|
.Open('my-database.db');
|
|
56
56
|
|
|
57
|
-
// Register indices before init (Recommended)
|
|
58
|
-
await db.createIndex('name', { type: 'btree', fields: ['name'] });
|
|
59
|
-
await db.createIndex('tags_0', { type: 'btree', fields: ['tags.0'] });
|
|
60
|
-
|
|
61
|
-
// Composite Index support
|
|
62
|
-
await db.createIndex('idx_name_age', { type: 'btree', fields: ['name', 'age'] });
|
|
63
|
-
|
|
64
57
|
// Initialize database
|
|
65
58
|
await db.init();
|
|
66
59
|
|
|
60
|
+
// Register indices
|
|
61
|
+
// use transaction to ensure atomicity
|
|
62
|
+
await db.migration(1, async (tx) => {
|
|
63
|
+
await db.createIndex('name', { type: 'btree', fields: ['name'] }, tx);
|
|
64
|
+
await db.createIndex('tags_0', { type: 'btree', fields: ['tags.0'] }, tx);
|
|
65
|
+
|
|
66
|
+
// Composite Index support
|
|
67
|
+
await db.createIndex('idx_name_age', { type: 'btree', fields: ['name', 'age'] }, tx);
|
|
68
|
+
|
|
69
|
+
console.log('Migration completed successfully');
|
|
70
|
+
});
|
|
71
|
+
|
|
67
72
|
// Insert document
|
|
68
73
|
const id = await db.insert({
|
|
69
74
|
name: 'John Doe',
|