document-dataply 0.0.9-alpha.4 → 0.0.9-alpha.5
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 +150 -99
- 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
|
@@ -10572,8 +10572,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10572
10572
|
if (metadata.lastId === 0) {
|
|
10573
10573
|
return 0;
|
|
10574
10574
|
}
|
|
10575
|
-
|
|
10576
|
-
const indexEntryMap = /* @__PURE__ */ new Map();
|
|
10575
|
+
let indexTxMap = {};
|
|
10577
10576
|
for (const indexName of backfillTargets) {
|
|
10578
10577
|
const tree = this.trees.get(indexName);
|
|
10579
10578
|
if (tree && indexName !== "_id") {
|
|
@@ -10581,6 +10580,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10581
10580
|
}
|
|
10582
10581
|
}
|
|
10583
10582
|
let backfilledCount = 0;
|
|
10583
|
+
let chunkCount = 0;
|
|
10584
|
+
const CHUNK_SIZE = 1e3;
|
|
10584
10585
|
const idTree = this.trees.get("_id");
|
|
10585
10586
|
if (!idTree) {
|
|
10586
10587
|
throw new Error("ID tree not found");
|
|
@@ -10609,10 +10610,6 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10609
10610
|
const keyToInsert = this.getTokenKey(k, token);
|
|
10610
10611
|
const entry = { k, v: token };
|
|
10611
10612
|
batchInsertData.push([keyToInsert, entry]);
|
|
10612
|
-
if (!indexEntryMap.has(btx)) {
|
|
10613
|
-
indexEntryMap.set(btx, []);
|
|
10614
|
-
}
|
|
10615
|
-
indexEntryMap.get(btx).push({ k: keyToInsert, v: entry });
|
|
10616
10613
|
}
|
|
10617
10614
|
await btx.batchInsert(batchInsertData);
|
|
10618
10615
|
} else {
|
|
@@ -10620,34 +10617,42 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10620
10617
|
if (indexVal === void 0) continue;
|
|
10621
10618
|
const entry = { k, v: indexVal };
|
|
10622
10619
|
const batchInsertData = [[k, entry]];
|
|
10623
|
-
if (!indexEntryMap.has(btx)) {
|
|
10624
|
-
indexEntryMap.set(btx, []);
|
|
10625
|
-
}
|
|
10626
|
-
indexEntryMap.get(btx).push(entry);
|
|
10627
10620
|
await btx.batchInsert(batchInsertData);
|
|
10628
10621
|
}
|
|
10629
10622
|
}
|
|
10630
10623
|
backfilledCount++;
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
|
|
10624
|
+
chunkCount++;
|
|
10625
|
+
if (chunkCount >= CHUNK_SIZE) {
|
|
10626
|
+
try {
|
|
10627
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10628
|
+
await btx.commit();
|
|
10629
|
+
}
|
|
10630
|
+
} catch (err) {
|
|
10631
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10632
|
+
await btx.rollback();
|
|
10633
|
+
}
|
|
10634
|
+
throw err;
|
|
10635
|
+
}
|
|
10636
|
+
for (const indexName of backfillTargets) {
|
|
10637
|
+
const tree = this.trees.get(indexName);
|
|
10638
|
+
if (tree && indexName !== "_id") {
|
|
10639
|
+
indexTxMap[indexName] = await tree.createTransaction();
|
|
10640
|
+
}
|
|
10641
|
+
}
|
|
10642
|
+
chunkCount = 0;
|
|
10642
10643
|
}
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
for (const
|
|
10647
|
-
await btx.
|
|
10644
|
+
}
|
|
10645
|
+
if (chunkCount > 0) {
|
|
10646
|
+
try {
|
|
10647
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10648
|
+
await btx.commit();
|
|
10648
10649
|
}
|
|
10650
|
+
} catch (err) {
|
|
10651
|
+
for (const btx of Object.values(indexTxMap)) {
|
|
10652
|
+
await btx.rollback();
|
|
10653
|
+
}
|
|
10654
|
+
throw err;
|
|
10649
10655
|
}
|
|
10650
|
-
throw err;
|
|
10651
10656
|
}
|
|
10652
10657
|
this.pendingBackfillFields = [];
|
|
10653
10658
|
return backfilledCount;
|
|
@@ -10805,27 +10810,61 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10805
10810
|
const condition = query[primaryField];
|
|
10806
10811
|
const treeTx = await tree.createTransaction();
|
|
10807
10812
|
let score = 0;
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
}
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
}
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10813
|
+
let isConsecutive = true;
|
|
10814
|
+
const coveredFields = [];
|
|
10815
|
+
const compositeVerifyFields = [];
|
|
10816
|
+
for (const field of config.fields) {
|
|
10817
|
+
if (!queryFields.has(field)) {
|
|
10818
|
+
isConsecutive = false;
|
|
10819
|
+
continue;
|
|
10820
|
+
}
|
|
10821
|
+
coveredFields.push(field);
|
|
10822
|
+
if (field !== primaryField) {
|
|
10823
|
+
compositeVerifyFields.push(field);
|
|
10824
|
+
}
|
|
10825
|
+
score += 1;
|
|
10826
|
+
if (isConsecutive) {
|
|
10827
|
+
const cond = query[field];
|
|
10828
|
+
if (cond !== void 0) {
|
|
10829
|
+
if (typeof cond !== "object" || cond === null) {
|
|
10830
|
+
score += 100;
|
|
10831
|
+
} else if ("primaryEqual" in cond || "equal" in cond) {
|
|
10832
|
+
score += 100;
|
|
10833
|
+
} 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) {
|
|
10834
|
+
score += 50;
|
|
10835
|
+
isConsecutive = false;
|
|
10836
|
+
} else if ("primaryOr" in cond || "or" in cond) {
|
|
10837
|
+
score += 20;
|
|
10838
|
+
isConsecutive = false;
|
|
10839
|
+
} else if ("like" in cond) {
|
|
10840
|
+
score += 15;
|
|
10841
|
+
isConsecutive = false;
|
|
10842
|
+
} else {
|
|
10843
|
+
score += 10;
|
|
10844
|
+
isConsecutive = false;
|
|
10845
|
+
}
|
|
10846
|
+
}
|
|
10823
10847
|
}
|
|
10824
10848
|
}
|
|
10825
|
-
|
|
10826
|
-
|
|
10849
|
+
let isIndexOrderSupported = false;
|
|
10850
|
+
if (orderByField) {
|
|
10851
|
+
for (const field of config.fields) {
|
|
10852
|
+
if (field === orderByField) {
|
|
10853
|
+
isIndexOrderSupported = true;
|
|
10854
|
+
break;
|
|
10855
|
+
}
|
|
10856
|
+
const cond = query[field];
|
|
10857
|
+
let isExactMatch = false;
|
|
10858
|
+
if (cond !== void 0) {
|
|
10859
|
+
if (typeof cond !== "object" || cond === null) isExactMatch = true;
|
|
10860
|
+
else if ("primaryEqual" in cond || "equal" in cond) isExactMatch = true;
|
|
10861
|
+
}
|
|
10862
|
+
if (!isExactMatch) break;
|
|
10863
|
+
}
|
|
10864
|
+
if (isIndexOrderSupported) {
|
|
10865
|
+
score += 200;
|
|
10866
|
+
}
|
|
10827
10867
|
}
|
|
10828
|
-
const compositeVerifyFields = coveredFields.filter((f) => f !== primaryField);
|
|
10829
10868
|
candidates.push({
|
|
10830
10869
|
tree: treeTx,
|
|
10831
10870
|
condition,
|
|
@@ -10833,7 +10872,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10833
10872
|
indexName,
|
|
10834
10873
|
isFtsMatch: false,
|
|
10835
10874
|
score,
|
|
10836
|
-
compositeVerifyFields
|
|
10875
|
+
compositeVerifyFields,
|
|
10876
|
+
isIndexOrderSupported
|
|
10837
10877
|
});
|
|
10838
10878
|
} else if (config.type === "fts") {
|
|
10839
10879
|
const field = config.fields;
|
|
@@ -10851,7 +10891,8 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10851
10891
|
isFtsMatch: true,
|
|
10852
10892
|
matchTokens,
|
|
10853
10893
|
score: 90,
|
|
10854
|
-
compositeVerifyFields: []
|
|
10894
|
+
compositeVerifyFields: [],
|
|
10895
|
+
isIndexOrderSupported: false
|
|
10855
10896
|
});
|
|
10856
10897
|
}
|
|
10857
10898
|
}
|
|
@@ -10894,33 +10935,30 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10894
10935
|
getTokenKey(pk, token) {
|
|
10895
10936
|
return pk + ":" + token;
|
|
10896
10937
|
}
|
|
10897
|
-
async
|
|
10938
|
+
async *applyCandidateByFTSStream(candidate, matchedTokens, filterValues, order) {
|
|
10898
10939
|
const keys = /* @__PURE__ */ new Set();
|
|
10899
10940
|
for (let i = 0, len = matchedTokens.length; i < len; i++) {
|
|
10900
10941
|
const token = matchedTokens[i];
|
|
10901
|
-
const
|
|
10942
|
+
for await (const pair of candidate.tree.whereStream(
|
|
10902
10943
|
{ primaryEqual: { v: token } },
|
|
10903
|
-
{
|
|
10904
|
-
|
|
10944
|
+
{ order }
|
|
10945
|
+
)) {
|
|
10946
|
+
const pk = pair[1].k;
|
|
10947
|
+
if (filterValues && !filterValues.has(pk)) continue;
|
|
10948
|
+
if (!keys.has(pk)) {
|
|
10949
|
+
keys.add(pk);
|
|
10950
|
+
yield pk;
|
|
10905
10951
|
}
|
|
10906
|
-
);
|
|
10907
|
-
for (const pair of pairs.values()) {
|
|
10908
|
-
if (filterValues && !filterValues.has(pair.k)) continue;
|
|
10909
|
-
keys.add(pair.k);
|
|
10910
10952
|
}
|
|
10911
10953
|
}
|
|
10912
|
-
return keys;
|
|
10913
10954
|
}
|
|
10914
10955
|
/**
|
|
10915
10956
|
* 특정 인덱스 후보를 조회하여 PK 집합을 필터링합니다.
|
|
10916
10957
|
*/
|
|
10917
|
-
|
|
10918
|
-
return
|
|
10958
|
+
applyCandidateStream(candidate, filterValues, order) {
|
|
10959
|
+
return candidate.tree.keysStream(
|
|
10919
10960
|
candidate.condition,
|
|
10920
|
-
{
|
|
10921
|
-
filterValues,
|
|
10922
|
-
order
|
|
10923
|
-
}
|
|
10961
|
+
{ filterValues, order }
|
|
10924
10962
|
);
|
|
10925
10963
|
}
|
|
10926
10964
|
/**
|
|
@@ -10936,30 +10974,34 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10936
10974
|
);
|
|
10937
10975
|
if (!selectivity) return new Float64Array(0);
|
|
10938
10976
|
const { driver, others, rollback } = selectivity;
|
|
10939
|
-
const useIndexOrder = orderBy === void 0 || driver.
|
|
10977
|
+
const useIndexOrder = orderBy === void 0 || driver.isIndexOrderSupported;
|
|
10940
10978
|
const candidates = [driver, ...others];
|
|
10941
10979
|
let keys = void 0;
|
|
10942
10980
|
for (let i = 0, len = candidates.length; i < len; i++) {
|
|
10943
10981
|
const candidate = candidates[i];
|
|
10944
10982
|
const currentOrder = useIndexOrder ? sortOrder : void 0;
|
|
10945
10983
|
if (candidate.isFtsMatch && candidate.matchTokens && candidate.matchTokens.length > 0) {
|
|
10946
|
-
|
|
10984
|
+
const stream = this.applyCandidateByFTSStream(
|
|
10947
10985
|
candidate,
|
|
10948
10986
|
candidate.matchTokens,
|
|
10949
10987
|
keys,
|
|
10950
10988
|
currentOrder
|
|
10951
10989
|
);
|
|
10990
|
+
keys = /* @__PURE__ */ new Set();
|
|
10991
|
+
for await (const pk of stream) keys.add(pk);
|
|
10952
10992
|
} else {
|
|
10953
|
-
|
|
10993
|
+
const stream = this.applyCandidateStream(candidate, keys, currentOrder);
|
|
10994
|
+
keys = /* @__PURE__ */ new Set();
|
|
10995
|
+
for await (const pk of stream) keys.add(pk);
|
|
10954
10996
|
}
|
|
10955
10997
|
}
|
|
10956
10998
|
rollback();
|
|
10957
10999
|
return new Float64Array(Array.from(keys || []));
|
|
10958
11000
|
}
|
|
10959
11001
|
/**
|
|
10960
|
-
* 드라이버 인덱스만으로 PK
|
|
11002
|
+
* 드라이버 인덱스만으로 PK 스트림을 가져옵니다. (교집합 없이)
|
|
10961
11003
|
* selectDocuments에서 사용하며, 나머지 조건(others)은 스트리밍 중 tree.verify()로 검증합니다.
|
|
10962
|
-
* @returns 드라이버 키
|
|
11004
|
+
* @returns 드라이버 키 스트림, others 후보 목록, rollback 함수. 또는 null.
|
|
10963
11005
|
*/
|
|
10964
11006
|
async getDriverKeys(query, orderBy, sortOrder = "asc") {
|
|
10965
11007
|
const isQueryEmpty = Object.keys(query).length === 0;
|
|
@@ -10970,21 +11012,21 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
10970
11012
|
);
|
|
10971
11013
|
if (!selectivity) return null;
|
|
10972
11014
|
const { driver, others, compositeVerifyConditions, rollback } = selectivity;
|
|
10973
|
-
const useIndexOrder = orderBy === void 0 || driver.
|
|
11015
|
+
const useIndexOrder = orderBy === void 0 || driver.isIndexOrderSupported;
|
|
10974
11016
|
const currentOrder = useIndexOrder ? sortOrder : void 0;
|
|
10975
|
-
let
|
|
11017
|
+
let keysStream;
|
|
10976
11018
|
if (driver.isFtsMatch && driver.matchTokens && driver.matchTokens.length > 0) {
|
|
10977
|
-
|
|
11019
|
+
keysStream = this.applyCandidateByFTSStream(
|
|
10978
11020
|
driver,
|
|
10979
11021
|
driver.matchTokens,
|
|
10980
11022
|
void 0,
|
|
10981
11023
|
currentOrder
|
|
10982
11024
|
);
|
|
10983
11025
|
} else {
|
|
10984
|
-
|
|
11026
|
+
keysStream = this.applyCandidateStream(driver, void 0, currentOrder);
|
|
10985
11027
|
}
|
|
10986
11028
|
return {
|
|
10987
|
-
|
|
11029
|
+
keysStream,
|
|
10988
11030
|
others,
|
|
10989
11031
|
compositeVerifyConditions,
|
|
10990
11032
|
isDriverOrderByField: useIndexOrder,
|
|
@@ -11334,28 +11376,17 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11334
11376
|
return currentChunkSize;
|
|
11335
11377
|
}
|
|
11336
11378
|
/**
|
|
11337
|
-
* Prefetch 방식으로 키
|
|
11379
|
+
* Prefetch 방식으로 키 스트림을 청크 단위로 조회하여 문서를 순회합니다.
|
|
11338
11380
|
* FTS 검증, 복합 인덱스 검증, others 후보에 대한 tree.verify() 검증을 통과한 문서만 yield 합니다.
|
|
11339
11381
|
*/
|
|
11340
|
-
async *processChunkedKeysWithVerify(
|
|
11382
|
+
async *processChunkedKeysWithVerify(keysStream, startIdx, initialChunkSize, ftsConditions, compositeVerifyConditions, others, tx) {
|
|
11341
11383
|
const verifyOthers = others.filter((o) => !o.isFtsMatch);
|
|
11342
|
-
let i = startIdx;
|
|
11343
|
-
const totalKeys = keys.length;
|
|
11344
11384
|
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
|
-
}
|
|
11385
|
+
let chunk = [];
|
|
11386
|
+
let dropped = 0;
|
|
11387
|
+
const processChunk = async (pks) => {
|
|
11388
|
+
const docs = [];
|
|
11389
|
+
const rawResults = await this.selectMany(new Float64Array(pks), false, tx);
|
|
11359
11390
|
let chunkTotalSize = 0;
|
|
11360
11391
|
for (let j = 0, len = rawResults.length; j < len; j++) {
|
|
11361
11392
|
const s = rawResults[j];
|
|
@@ -11382,9 +11413,26 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11382
11413
|
}
|
|
11383
11414
|
if (!passed) continue;
|
|
11384
11415
|
}
|
|
11385
|
-
|
|
11416
|
+
docs.push(doc);
|
|
11386
11417
|
}
|
|
11387
11418
|
currentChunkSize = this.adjustChunkSize(currentChunkSize, chunkTotalSize);
|
|
11419
|
+
return docs;
|
|
11420
|
+
};
|
|
11421
|
+
for await (const pk of keysStream) {
|
|
11422
|
+
if (dropped < startIdx) {
|
|
11423
|
+
dropped++;
|
|
11424
|
+
continue;
|
|
11425
|
+
}
|
|
11426
|
+
chunk.push(pk);
|
|
11427
|
+
if (chunk.length >= currentChunkSize) {
|
|
11428
|
+
const docs = await processChunk(chunk);
|
|
11429
|
+
for (let j = 0; j < docs.length; j++) yield docs[j];
|
|
11430
|
+
chunk = [];
|
|
11431
|
+
}
|
|
11432
|
+
}
|
|
11433
|
+
if (chunk.length > 0) {
|
|
11434
|
+
const docs = await processChunk(chunk);
|
|
11435
|
+
for (let j = 0; j < docs.length; j++) yield docs[j];
|
|
11388
11436
|
}
|
|
11389
11437
|
}
|
|
11390
11438
|
/**
|
|
@@ -11432,11 +11480,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11432
11480
|
}
|
|
11433
11481
|
const driverResult = await self.getDriverKeys(query, orderByField, sortOrder);
|
|
11434
11482
|
if (!driverResult) return;
|
|
11435
|
-
const {
|
|
11436
|
-
if (keys.length === 0) {
|
|
11437
|
-
rollback();
|
|
11438
|
-
return;
|
|
11439
|
-
}
|
|
11483
|
+
const { keysStream, others, compositeVerifyConditions, isDriverOrderByField, rollback } = driverResult;
|
|
11440
11484
|
try {
|
|
11441
11485
|
if (!isDriverOrderByField && orderByField) {
|
|
11442
11486
|
const topK = limit === Infinity ? Infinity : offset + limit;
|
|
@@ -11451,7 +11495,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11451
11495
|
}
|
|
11452
11496
|
const results = [];
|
|
11453
11497
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
11454
|
-
|
|
11498
|
+
keysStream,
|
|
11455
11499
|
0,
|
|
11456
11500
|
self.options.pageSize,
|
|
11457
11501
|
ftsConditions,
|
|
@@ -11487,16 +11531,23 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
11487
11531
|
yield limitedResults[j];
|
|
11488
11532
|
}
|
|
11489
11533
|
} else {
|
|
11534
|
+
const hasFilters = ftsConditions.length > 0 || compositeVerifyConditions.length > 0 || others.length > 0;
|
|
11535
|
+
const startIdx = hasFilters ? 0 : offset;
|
|
11490
11536
|
let yieldedCount = 0;
|
|
11537
|
+
let skippedCount = hasFilters ? 0 : offset;
|
|
11491
11538
|
for await (const doc of self.processChunkedKeysWithVerify(
|
|
11492
|
-
|
|
11493
|
-
|
|
11539
|
+
keysStream,
|
|
11540
|
+
startIdx,
|
|
11494
11541
|
self.options.pageSize,
|
|
11495
11542
|
ftsConditions,
|
|
11496
11543
|
compositeVerifyConditions,
|
|
11497
11544
|
others,
|
|
11498
11545
|
tx2
|
|
11499
11546
|
)) {
|
|
11547
|
+
if (skippedCount < offset) {
|
|
11548
|
+
skippedCount++;
|
|
11549
|
+
continue;
|
|
11550
|
+
}
|
|
11500
11551
|
if (yieldedCount >= limit) break;
|
|
11501
11552
|
yield doc;
|
|
11502
11553
|
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.5",
|
|
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.1"
|
|
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',
|