cry-search 1.0.7 → 2.0.0
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/CLAUDE.md +73 -98
- package/README.md +39 -28
- package/UNIVERSE.md +11 -18
- package/dist/common/SearchUniverse.d.ts.map +1 -1
- package/dist/common/numeric/AugmentedMetadata.d.ts +27 -92
- package/dist/common/numeric/AugmentedMetadata.d.ts.map +1 -1
- package/dist/common/numeric/createSearchArrayMetadata.d.ts +47 -7
- package/dist/common/numeric/createSearchArrayMetadata.d.ts.map +1 -1
- package/dist/common/numeric/findInLinkedArrays.d.ts +7 -4
- package/dist/common/numeric/findInLinkedArrays.d.ts.map +1 -1
- package/dist/common/numeric/scoring.d.ts +95 -0
- package/dist/common/numeric/scoring.d.ts.map +1 -0
- package/dist/common/numeric/searchAndRank.d.ts +18 -60
- package/dist/common/numeric/searchAndRank.d.ts.map +1 -1
- package/dist/common/numeric/searchInData.d.ts +17 -9
- package/dist/common/numeric/searchInData.d.ts.map +1 -1
- package/dist/common/numeric/syncSearchArrayMetadata.d.ts +7 -50
- package/dist/common/numeric/syncSearchArrayMetadata.d.ts.map +1 -1
- package/dist/common/numeric/updateSearchLinkedMetadata.d.ts +11 -110
- package/dist/common/numeric/updateSearchLinkedMetadata.d.ts.map +1 -1
- package/dist/common/numeric/updateSearchMetadata.d.ts.map +1 -1
- package/dist/index.cjs +614 -360
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +614 -360
- package/dist/types/index.d.ts +35 -50
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/matchTokenNumeric.d.ts.map +1 -1
- package/dist/utils/prepareStringForSearchNumeric.d.ts +24 -29
- package/dist/utils/prepareStringForSearchNumeric.d.ts.map +1 -1
- package/package.json +4 -14
- package/dist/common/findInArray.d.ts +0 -37
- package/dist/common/findInArray.d.ts.map +0 -1
- package/dist/common/findInArrayReturnDataAndMeta.d.ts +0 -52
- package/dist/common/findInArrayReturnDataAndMeta.d.ts.map +0 -1
- package/dist/common/findInLinkedArrays.d.ts +0 -66
- package/dist/common/findInLinkedArrays.d.ts.map +0 -1
- package/dist/common/string/createSearchArrayMetadata.d.ts +0 -117
- package/dist/common/string/createSearchArrayMetadata.d.ts.map +0 -1
- package/dist/common/string/createSearchLinkedMetadata.d.ts +0 -36
- package/dist/common/string/createSearchLinkedMetadata.d.ts.map +0 -1
- package/dist/common/string/index.d.ts +0 -10
- package/dist/common/string/index.d.ts.map +0 -1
- package/dist/common/string/updateSearchMetadata.d.ts +0 -103
- package/dist/common/string/updateSearchMetadata.d.ts.map +0 -1
- package/dist/common/syncSearchArrayMetadata.d.ts +0 -68
- package/dist/common/syncSearchArrayMetadata.d.ts.map +0 -1
- package/dist/common/updateSearchLinkedMetadata.d.ts +0 -139
- package/dist/common/updateSearchLinkedMetadata.d.ts.map +0 -1
- package/dist/string.cjs +0 -930
- package/dist/string.d.cts +0 -26
- package/dist/string.d.ts +0 -26
- package/dist/string.d.ts.map +0 -1
- package/dist/string.js +0 -898
- package/dist/utils/matchToken.d.ts +0 -65
- package/dist/utils/matchToken.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -45,7 +45,9 @@ __export(exports_src, {
|
|
|
45
45
|
searchInData: () => searchInDataReturnIdsNumeric,
|
|
46
46
|
searchAndRankNumeric: () => searchAndRankNumeric,
|
|
47
47
|
searchAndRank: () => searchAndRankNumeric,
|
|
48
|
+
scoreOrderAndPresence: () => scoreOrderAndPresence,
|
|
48
49
|
scoreOne: () => scoreOne,
|
|
50
|
+
scoreBag: () => scoreBag,
|
|
49
51
|
sanitiseString: () => sanitiseString,
|
|
50
52
|
resetTokenRegistry: () => resetTokenRegistry,
|
|
51
53
|
removePrimaryItem: () => removePrimaryItemNumeric,
|
|
@@ -81,6 +83,8 @@ __export(exports_src, {
|
|
|
81
83
|
allPreparedTokensMatch: () => allPreparedTokensMatch,
|
|
82
84
|
TOKEN_ID_MASK: () => TOKEN_ID_MASK,
|
|
83
85
|
SearchUniverse: () => SearchUniverse,
|
|
86
|
+
PREFIX_TO_MATCH_MODE: () => PREFIX_TO_MATCH_MODE,
|
|
87
|
+
MATCH_MODE_PREFIXES: () => MATCH_MODE_PREFIXES,
|
|
84
88
|
MATCH_MODE_BITS: () => MATCH_MODE_BITS,
|
|
85
89
|
DEFAULT_SEARCH_OPTS: () => DEFAULT_SEARCH_OPTS,
|
|
86
90
|
AugmentedMetadata: () => AugmentedMetadata
|
|
@@ -88,6 +92,7 @@ __export(exports_src, {
|
|
|
88
92
|
module.exports = __toCommonJS(exports_src);
|
|
89
93
|
|
|
90
94
|
// src/types/index.ts
|
|
95
|
+
var DEFAULT_FIRST_TOKENS_N = 8;
|
|
91
96
|
var DEFAULT_SEARCH_OPTS = {
|
|
92
97
|
matchWords: "start",
|
|
93
98
|
matchNumbers: "startEnd",
|
|
@@ -357,11 +362,23 @@ function prepareStringForSearchNumeric(input, tokensMap) {
|
|
|
357
362
|
for (let i = 0;i < stringTokens.length; i++) {
|
|
358
363
|
numericTokens[i] = getOrCreateTokenId(stringTokens[i], tokensMap);
|
|
359
364
|
}
|
|
360
|
-
|
|
361
|
-
|
|
365
|
+
const unsorted = Uint32Array.from(numericTokens);
|
|
366
|
+
const sortedArr = numericTokens.slice().sort((a, b) => a - b);
|
|
367
|
+
const sorted = Uint32Array.from(sortedArr);
|
|
368
|
+
return { sorted, unsorted };
|
|
362
369
|
}
|
|
363
370
|
|
|
364
|
-
// src/common/
|
|
371
|
+
// src/common/numeric/createSearchArrayMetadata.ts
|
|
372
|
+
function isDeletedOrBlocked(obj) {
|
|
373
|
+
return obj._deleted != null || obj._blocked != null;
|
|
374
|
+
}
|
|
375
|
+
var MATCH_MODE_PREFIXES = {
|
|
376
|
+
start: "<",
|
|
377
|
+
end: ">",
|
|
378
|
+
startEnd: "+",
|
|
379
|
+
anywhere: "*",
|
|
380
|
+
whole: "!"
|
|
381
|
+
};
|
|
365
382
|
var PREFIX_TO_MATCH_MODE = {
|
|
366
383
|
"<": "start",
|
|
367
384
|
">": "end",
|
|
@@ -371,12 +388,6 @@ var PREFIX_TO_MATCH_MODE = {
|
|
|
371
388
|
"=": "whole",
|
|
372
389
|
"?": "anywhere"
|
|
373
390
|
};
|
|
374
|
-
var DEFAULT_EXCLUDED_FIELDS = new Set(["_id", "_deleted", "_blocked"]);
|
|
375
|
-
function isDeletedOrBlocked(obj) {
|
|
376
|
-
return obj._deleted != null || obj._blocked != null;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// src/common/numeric/createSearchArrayMetadata.ts
|
|
380
391
|
var MATCH_MODE_BITS = {
|
|
381
392
|
start: 0,
|
|
382
393
|
end: 1,
|
|
@@ -407,7 +418,7 @@ function decodeMatchMode(encoded) {
|
|
|
407
418
|
return "start";
|
|
408
419
|
}
|
|
409
420
|
}
|
|
410
|
-
var
|
|
421
|
+
var DEFAULT_EXCLUDED_FIELDS = new Set(["_id", "_deleted", "_blocked"]);
|
|
411
422
|
function getValueByPath(obj, path) {
|
|
412
423
|
const parts = path.split(".");
|
|
413
424
|
let current = obj;
|
|
@@ -464,26 +475,29 @@ function prepareObjectForSearchNumeric(obj, spec, tokensMap) {
|
|
|
464
475
|
if (isDeletedOrBlocked(obj)) {
|
|
465
476
|
return;
|
|
466
477
|
}
|
|
467
|
-
if (spec?.extractSearchableStringFn) {
|
|
468
|
-
const searchableString = spec.extractSearchableStringFn(obj);
|
|
469
|
-
if (searchableString === undefined) {
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
return prepareStringForSearchNumeric(searchableString, tokensMap);
|
|
473
|
-
}
|
|
474
|
-
return prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap);
|
|
475
|
-
}
|
|
476
|
-
function prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap) {
|
|
477
478
|
if (spec?.enrichSearchObjectFn) {
|
|
478
479
|
spec.enrichSearchObjectFn(obj, spec.searchContext);
|
|
479
480
|
}
|
|
481
|
+
const sorted = spec?.extractSearchableStringFn ? buildSortedFromExtractFn(obj, spec.extractSearchableStringFn, tokensMap) : buildSortedFromFields(obj, spec, tokensMap);
|
|
482
|
+
if (sorted === undefined)
|
|
483
|
+
return;
|
|
484
|
+
const firstN = spec?.keyFields && spec.keyFields.length > 0 ? buildFirstNFromKeyFields(obj, spec.keyFields, spec.firstTokensN ?? DEFAULT_FIRST_TOKENS_N, tokensMap) : undefined;
|
|
485
|
+
return { sorted, firstN };
|
|
486
|
+
}
|
|
487
|
+
function buildSortedFromExtractFn(obj, extractFn, tokensMap) {
|
|
488
|
+
const str = extractFn(obj);
|
|
489
|
+
if (str === undefined)
|
|
490
|
+
return;
|
|
491
|
+
return prepareStringForSearchNumeric(str, tokensMap).sorted;
|
|
492
|
+
}
|
|
493
|
+
function buildSortedFromFields(obj, spec, tokensMap) {
|
|
480
494
|
const allTokens = [];
|
|
481
495
|
const fieldMatchModes = spec?.fieldMatchModes;
|
|
482
496
|
const fieldsToSearch = spec?.searchInFields ?? Object.keys(obj);
|
|
483
497
|
const fieldsToExclude = new Set(spec?.dontSearchInFields ?? []);
|
|
484
498
|
for (const key of fieldsToSearch) {
|
|
485
499
|
const keyStr = key;
|
|
486
|
-
if (!spec?.searchInFields &&
|
|
500
|
+
if (!spec?.searchInFields && DEFAULT_EXCLUDED_FIELDS.has(keyStr))
|
|
487
501
|
continue;
|
|
488
502
|
if (fieldsToExclude.has(key))
|
|
489
503
|
continue;
|
|
@@ -514,14 +528,42 @@ function prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap) {
|
|
|
514
528
|
const uniqueTokens = [...new Set(allTokens)].sort((a, b) => a - b);
|
|
515
529
|
return new Uint32Array(uniqueTokens);
|
|
516
530
|
}
|
|
531
|
+
function buildFirstNFromKeyFields(obj, keyFields, n, tokensMap) {
|
|
532
|
+
const strings = [];
|
|
533
|
+
for (const field of keyFields) {
|
|
534
|
+
const keyStr = field;
|
|
535
|
+
const value = isDotNotation(keyStr) ? getValueByPath(obj, keyStr) : obj[field];
|
|
536
|
+
if (value == null)
|
|
537
|
+
continue;
|
|
538
|
+
extractStringsFromValue(value, strings);
|
|
539
|
+
}
|
|
540
|
+
if (strings.length === 0)
|
|
541
|
+
return;
|
|
542
|
+
const text = strings.join(" ");
|
|
543
|
+
const datesNormalized = normalizeDates(text);
|
|
544
|
+
const preprocessed = preprocessString(datesNormalized);
|
|
545
|
+
const sanitised = sanitiseString(preprocessed);
|
|
546
|
+
const stringTokens = tokenize(sanitised, DEFAULT_TOKENIZE_CONFIG);
|
|
547
|
+
if (stringTokens.length === 0)
|
|
548
|
+
return;
|
|
549
|
+
const sliced = stringTokens.slice(0, n);
|
|
550
|
+
const out = new Uint32Array(sliced.length);
|
|
551
|
+
for (let i = 0;i < sliced.length; i++) {
|
|
552
|
+
out[i] = getOrCreateTokenId(sliced[i], tokensMap);
|
|
553
|
+
}
|
|
554
|
+
return out;
|
|
555
|
+
}
|
|
517
556
|
function createSearchArrayMetadataNumeric(data, spec) {
|
|
518
557
|
const tokensMap = createTokensMap();
|
|
519
558
|
try {
|
|
520
|
-
const metadata =
|
|
559
|
+
const metadata = emptyNumericSearchMetadata();
|
|
521
560
|
for (const [id, item] of data) {
|
|
522
|
-
const
|
|
523
|
-
if (
|
|
524
|
-
metadata.set(id,
|
|
561
|
+
const result = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
562
|
+
if (result !== undefined) {
|
|
563
|
+
metadata.sorted.set(id, result.sorted);
|
|
564
|
+
if (result.firstN !== undefined) {
|
|
565
|
+
metadata.unsorted.set(id, result.firstN);
|
|
566
|
+
}
|
|
525
567
|
}
|
|
526
568
|
}
|
|
527
569
|
return metadata;
|
|
@@ -529,6 +571,9 @@ function createSearchArrayMetadataNumeric(data, spec) {
|
|
|
529
571
|
clearTokensMap(tokensMap);
|
|
530
572
|
}
|
|
531
573
|
}
|
|
574
|
+
function emptyNumericSearchMetadata() {
|
|
575
|
+
return { sorted: new Map, unsorted: new Map };
|
|
576
|
+
}
|
|
532
577
|
// src/common/numeric/createSearchLinkedMetadata.ts
|
|
533
578
|
function createSearchLinkedMetadataNumeric(primaryData, primaryMetadata, linkedData, linkedMetadata, foreignKeyGetter) {
|
|
534
579
|
const primaryToLinked = new Map;
|
|
@@ -550,14 +595,19 @@ function createSearchLinkedMetadataNumeric(primaryData, primaryMetadata, linkedD
|
|
|
550
595
|
}
|
|
551
596
|
// src/common/numeric/updateSearchMetadata.ts
|
|
552
597
|
function updateSearchMetadataNumeric(metadata, objectId, obj, spec, tokensMap) {
|
|
553
|
-
const
|
|
554
|
-
if (
|
|
555
|
-
metadata.delete(objectId);
|
|
598
|
+
const result = obj != null ? prepareObjectForSearchNumeric(obj, spec, tokensMap) : undefined;
|
|
599
|
+
if (result === undefined) {
|
|
600
|
+
metadata.sorted.delete(objectId);
|
|
601
|
+
metadata.unsorted.delete(objectId);
|
|
556
602
|
return false;
|
|
603
|
+
}
|
|
604
|
+
metadata.sorted.set(objectId, result.sorted);
|
|
605
|
+
if (result.firstN !== undefined) {
|
|
606
|
+
metadata.unsorted.set(objectId, result.firstN);
|
|
557
607
|
} else {
|
|
558
|
-
metadata.
|
|
559
|
-
return true;
|
|
608
|
+
metadata.unsorted.delete(objectId);
|
|
560
609
|
}
|
|
610
|
+
return true;
|
|
561
611
|
}
|
|
562
612
|
function updateSearchMetadataBatchNumeric(metadata, batch, spec) {
|
|
563
613
|
if (batch.length === 0) {
|
|
@@ -581,7 +631,9 @@ function updateSearchMetadataBatchNumeric(metadata, batch, spec) {
|
|
|
581
631
|
}
|
|
582
632
|
}
|
|
583
633
|
function removeFromSearchMetadataNumeric(metadata, objectId) {
|
|
584
|
-
|
|
634
|
+
const had = metadata.sorted.delete(objectId);
|
|
635
|
+
metadata.unsorted.delete(objectId);
|
|
636
|
+
return had;
|
|
585
637
|
}
|
|
586
638
|
function removeFromSearchMetadataBatchNumeric(metadata, objectIds) {
|
|
587
639
|
if (objectIds.length === 0) {
|
|
@@ -589,9 +641,10 @@ function removeFromSearchMetadataBatchNumeric(metadata, objectIds) {
|
|
|
589
641
|
}
|
|
590
642
|
let removed = 0;
|
|
591
643
|
for (const id of objectIds) {
|
|
592
|
-
|
|
644
|
+
const had = metadata.sorted.delete(id);
|
|
645
|
+
metadata.unsorted.delete(id);
|
|
646
|
+
if (had)
|
|
593
647
|
removed++;
|
|
594
|
-
}
|
|
595
648
|
}
|
|
596
649
|
return removed;
|
|
597
650
|
}
|
|
@@ -781,6 +834,106 @@ function allTokensMatchNumeric(searchTokenStrs, targetTokens, opts) {
|
|
|
781
834
|
return allPreparedTokensMatch(preparedTokens, targetTokens, opts);
|
|
782
835
|
}
|
|
783
836
|
|
|
837
|
+
// src/common/numeric/scoring.ts
|
|
838
|
+
function orderedTokenize(input) {
|
|
839
|
+
return tokenize(sanitiseString(preprocessString(normalizeDates(input))), DEFAULT_TOKENIZE_CONFIG);
|
|
840
|
+
}
|
|
841
|
+
function scoreOne(query, qTokens, itemTokens, exactKeys) {
|
|
842
|
+
if (exactKeys && exactKeys.length > 0) {
|
|
843
|
+
for (let i = 0;i < exactKeys.length; i++) {
|
|
844
|
+
if (exactKeys[i] === query)
|
|
845
|
+
return 1e5;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
if (qTokens.length === 0)
|
|
849
|
+
return 0;
|
|
850
|
+
if (itemTokens.length === 0)
|
|
851
|
+
return 1;
|
|
852
|
+
let qi = 0;
|
|
853
|
+
const positions = [];
|
|
854
|
+
for (let i = 0;i < itemTokens.length; i++) {
|
|
855
|
+
if (qi < qTokens.length && itemTokens[i].startsWith(qTokens[qi])) {
|
|
856
|
+
positions.push(i);
|
|
857
|
+
qi++;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
if (qi === 0)
|
|
861
|
+
return 1;
|
|
862
|
+
let score = 50;
|
|
863
|
+
if (qi === qTokens.length)
|
|
864
|
+
score += 100;
|
|
865
|
+
if (positions[0] === 0)
|
|
866
|
+
score += 50;
|
|
867
|
+
let perfect = qi === qTokens.length;
|
|
868
|
+
if (perfect) {
|
|
869
|
+
for (let i = 0;i < positions.length; i++) {
|
|
870
|
+
if (positions[i] !== i) {
|
|
871
|
+
perfect = false;
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
if (perfect)
|
|
877
|
+
score += 80;
|
|
878
|
+
if (positions.length >= 2) {
|
|
879
|
+
const span = positions[positions.length - 1] - positions[0] + 1;
|
|
880
|
+
score += positions.length / span * 30;
|
|
881
|
+
}
|
|
882
|
+
let totalLen = 0;
|
|
883
|
+
for (const t of itemTokens)
|
|
884
|
+
totalLen += t.length + 1;
|
|
885
|
+
score -= totalLen * 0.1;
|
|
886
|
+
return score;
|
|
887
|
+
}
|
|
888
|
+
function scoreBag(qTokens, itemTokens, perTokenWeight = 30) {
|
|
889
|
+
if (qTokens.length === 0 || itemTokens.length === 0)
|
|
890
|
+
return 0;
|
|
891
|
+
const usedItemIdx = new Set;
|
|
892
|
+
let score = 0;
|
|
893
|
+
for (const qt of qTokens) {
|
|
894
|
+
for (let i = 0;i < itemTokens.length; i++) {
|
|
895
|
+
if (usedItemIdx.has(i))
|
|
896
|
+
continue;
|
|
897
|
+
if (itemTokens[i].startsWith(qt)) {
|
|
898
|
+
score += perTokenWeight;
|
|
899
|
+
usedItemIdx.add(i);
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return score;
|
|
905
|
+
}
|
|
906
|
+
function scoreOrderAndPresence(qTokens, itemTokens, weights) {
|
|
907
|
+
const orderedWeight = weights?.ordered ?? 30;
|
|
908
|
+
const presenceWeight = weights?.presence ?? 10;
|
|
909
|
+
if (qTokens.length === 0 || itemTokens.length === 0)
|
|
910
|
+
return 0;
|
|
911
|
+
const matchedQueryIndices = new Set;
|
|
912
|
+
let qi = 0;
|
|
913
|
+
let score = 0;
|
|
914
|
+
for (let i = 0;i < itemTokens.length && qi < qTokens.length; i++) {
|
|
915
|
+
if (itemTokens[i].startsWith(qTokens[qi])) {
|
|
916
|
+
score += orderedWeight;
|
|
917
|
+
matchedQueryIndices.add(qi);
|
|
918
|
+
qi++;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if (matchedQueryIndices.size < qTokens.length) {
|
|
922
|
+
for (let qj = 0;qj < qTokens.length; qj++) {
|
|
923
|
+
if (matchedQueryIndices.has(qj))
|
|
924
|
+
continue;
|
|
925
|
+
const qt = qTokens[qj];
|
|
926
|
+
for (let i = 0;i < itemTokens.length; i++) {
|
|
927
|
+
if (itemTokens[i].startsWith(qt)) {
|
|
928
|
+
score += presenceWeight;
|
|
929
|
+
break;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return score;
|
|
935
|
+
}
|
|
936
|
+
|
|
784
937
|
// src/common/numeric/searchInData.ts
|
|
785
938
|
function searchInDataReturnIdsNumeric(query, metadata, opts) {
|
|
786
939
|
return searchInDataReturnIdsWithLimitNumeric(query, metadata, Infinity, opts);
|
|
@@ -798,20 +951,48 @@ function searchInDataReturnObjectsNumeric(query, metadata, data, opts) {
|
|
|
798
951
|
}
|
|
799
952
|
function searchInDataReturnIdsWithLimitNumeric(query, metadata, limit, opts) {
|
|
800
953
|
const queryTokenStrs = prepareStringForSearch(query);
|
|
801
|
-
if (queryTokenStrs.length === 0)
|
|
954
|
+
if (queryTokenStrs.length === 0)
|
|
802
955
|
return [];
|
|
803
|
-
}
|
|
804
956
|
const preparedTokens = prepareQueryTokens(queryTokenStrs);
|
|
805
|
-
const
|
|
806
|
-
for (const [id, targetTokens] of metadata) {
|
|
957
|
+
const candidates = [];
|
|
958
|
+
for (const [id, targetTokens] of metadata.sorted) {
|
|
807
959
|
if (allPreparedTokensMatch(preparedTokens, targetTokens, opts)) {
|
|
808
|
-
|
|
809
|
-
if (results.length >= limit) {
|
|
810
|
-
break;
|
|
811
|
-
}
|
|
960
|
+
candidates.push(id);
|
|
812
961
|
}
|
|
813
962
|
}
|
|
814
|
-
|
|
963
|
+
if (candidates.length === 0)
|
|
964
|
+
return [];
|
|
965
|
+
const qTokens = orderedTokenize(query);
|
|
966
|
+
const hasUnsorted = metadata.unsorted.size > 0;
|
|
967
|
+
if (!hasUnsorted) {
|
|
968
|
+
if (limit === Infinity || limit >= candidates.length)
|
|
969
|
+
return candidates;
|
|
970
|
+
return candidates.slice(0, limit);
|
|
971
|
+
}
|
|
972
|
+
const scored = new Array(candidates.length);
|
|
973
|
+
for (let i = 0;i < candidates.length; i++) {
|
|
974
|
+
const id = candidates[i];
|
|
975
|
+
const unsortedIds = metadata.unsorted.get(id);
|
|
976
|
+
if (unsortedIds === undefined) {
|
|
977
|
+
scored[i] = { id, score: 0, order: i };
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
const itemTokens = new Array(unsortedIds.length);
|
|
981
|
+
for (let j = 0;j < unsortedIds.length; j++) {
|
|
982
|
+
itemTokens[j] = tokens[unsortedIds[j]] ?? "";
|
|
983
|
+
}
|
|
984
|
+
scored[i] = { id, score: scoreOne(query, qTokens, itemTokens), order: i };
|
|
985
|
+
}
|
|
986
|
+
scored.sort((a, b) => {
|
|
987
|
+
if (a.score !== b.score)
|
|
988
|
+
return b.score - a.score;
|
|
989
|
+
return a.order - b.order;
|
|
990
|
+
});
|
|
991
|
+
const out = [];
|
|
992
|
+
const max = limit === Infinity ? scored.length : Math.min(limit, scored.length);
|
|
993
|
+
for (let i = 0;i < max; i++)
|
|
994
|
+
out.push(scored[i].id);
|
|
995
|
+
return out;
|
|
815
996
|
}
|
|
816
997
|
// src/common/numeric/findInLinkedArrays.ts
|
|
817
998
|
function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
@@ -822,11 +1003,10 @@ function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
|
822
1003
|
const preparedTokens = prepareQueryTokens(queryTokenStrs);
|
|
823
1004
|
const positiveTokens = preparedTokens.filter((t) => !t.negated);
|
|
824
1005
|
const negatedTokens = preparedTokens.filter((t) => t.negated);
|
|
825
|
-
const
|
|
1006
|
+
const scored = [];
|
|
1007
|
+
let orderCounter = 0;
|
|
826
1008
|
for (const [primaryId, primary] of linked.primaryData) {
|
|
827
|
-
|
|
828
|
-
break;
|
|
829
|
-
const primaryTokens = linked.primaryMeta.get(primaryId);
|
|
1009
|
+
const primaryTokens = linked.primaryMeta.sorted.get(primaryId);
|
|
830
1010
|
if (!primaryTokens)
|
|
831
1011
|
continue;
|
|
832
1012
|
const linkedIds = linked.primaryToLinked.get(primaryId) || [];
|
|
@@ -837,22 +1017,20 @@ function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
|
837
1017
|
break;
|
|
838
1018
|
}
|
|
839
1019
|
}
|
|
840
|
-
if (negatedMatchesInPrimary)
|
|
1020
|
+
if (negatedMatchesInPrimary)
|
|
841
1021
|
continue;
|
|
842
|
-
}
|
|
843
1022
|
let totalLength = primaryTokens.length;
|
|
844
1023
|
for (const linkedId of linkedIds) {
|
|
845
|
-
const linkedTokens = linked.linkedMeta.get(linkedId);
|
|
846
|
-
if (linkedTokens)
|
|
1024
|
+
const linkedTokens = linked.linkedMeta.sorted.get(linkedId);
|
|
1025
|
+
if (linkedTokens)
|
|
847
1026
|
totalLength += linkedTokens.length;
|
|
848
|
-
}
|
|
849
1027
|
}
|
|
850
1028
|
const allTokens = new Uint32Array(totalLength);
|
|
851
1029
|
let offset = 0;
|
|
852
1030
|
allTokens.set(primaryTokens, offset);
|
|
853
1031
|
offset += primaryTokens.length;
|
|
854
1032
|
for (const linkedId of linkedIds) {
|
|
855
|
-
const linkedTokens = linked.linkedMeta.get(linkedId);
|
|
1033
|
+
const linkedTokens = linked.linkedMeta.sorted.get(linkedId);
|
|
856
1034
|
if (linkedTokens) {
|
|
857
1035
|
allTokens.set(linkedTokens, offset);
|
|
858
1036
|
offset += linkedTokens.length;
|
|
@@ -866,230 +1044,289 @@ function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
|
866
1044
|
break;
|
|
867
1045
|
}
|
|
868
1046
|
}
|
|
869
|
-
if (allPositiveMatch)
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1047
|
+
if (!allPositiveMatch)
|
|
1048
|
+
continue;
|
|
1049
|
+
let anyMatchInPrimary = false;
|
|
1050
|
+
let anyMatchInLinked = false;
|
|
1051
|
+
const matchingLinkedIds = new Set;
|
|
1052
|
+
const tokensMatchingPrimary = new Set;
|
|
1053
|
+
for (const preparedToken of positiveTokens) {
|
|
1054
|
+
if (matchPreparedTokenInSortedList(preparedToken, primaryTokens, opts)) {
|
|
1055
|
+
anyMatchInPrimary = true;
|
|
1056
|
+
tokensMatchingPrimary.add(preparedToken);
|
|
879
1057
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
if (matchesNegatedToken) {
|
|
893
|
-
continue;
|
|
894
|
-
}
|
|
895
|
-
if (tokensForLinkedMatching.length > 0) {
|
|
896
|
-
const matchesAllNonPrimaryTokens = tokensForLinkedMatching.every((preparedToken) => matchPreparedTokenInSortedList(preparedToken, linkedTokens, opts));
|
|
897
|
-
if (matchesAllNonPrimaryTokens) {
|
|
898
|
-
anyMatchInLinked = true;
|
|
899
|
-
matchingLinkedIds.add(linkedId);
|
|
900
|
-
}
|
|
901
|
-
} else {
|
|
902
|
-
matchingLinkedIds.add(linkedId);
|
|
903
|
-
}
|
|
1058
|
+
}
|
|
1059
|
+
const tokensForLinkedMatching = positiveTokens.filter((t) => !tokensMatchingPrimary.has(t));
|
|
1060
|
+
if (tokensForLinkedMatching.length > 0 || negatedTokens.length > 0) {
|
|
1061
|
+
for (const linkedId of linkedIds) {
|
|
1062
|
+
const linkedTokens = linked.linkedMeta.sorted.get(linkedId);
|
|
1063
|
+
if (!linkedTokens)
|
|
1064
|
+
continue;
|
|
1065
|
+
let matchesNegatedToken = false;
|
|
1066
|
+
for (const negatedToken of negatedTokens) {
|
|
1067
|
+
if (matchPreparedTokenInSortedList(negatedToken, linkedTokens, opts)) {
|
|
1068
|
+
matchesNegatedToken = true;
|
|
1069
|
+
break;
|
|
904
1070
|
}
|
|
905
1071
|
}
|
|
1072
|
+
if (matchesNegatedToken)
|
|
1073
|
+
continue;
|
|
1074
|
+
if (tokensForLinkedMatching.length > 0) {
|
|
1075
|
+
const matchesAllNonPrimaryTokens = tokensForLinkedMatching.every((preparedToken) => matchPreparedTokenInSortedList(preparedToken, linkedTokens, opts));
|
|
1076
|
+
if (matchesAllNonPrimaryTokens) {
|
|
1077
|
+
anyMatchInLinked = true;
|
|
1078
|
+
matchingLinkedIds.add(linkedId);
|
|
1079
|
+
}
|
|
1080
|
+
} else {
|
|
1081
|
+
matchingLinkedIds.add(linkedId);
|
|
1082
|
+
}
|
|
906
1083
|
}
|
|
907
|
-
|
|
1084
|
+
}
|
|
1085
|
+
if (tokensForLinkedMatching.length > 0 && matchingLinkedIds.size === 0) {
|
|
1086
|
+
continue;
|
|
1087
|
+
}
|
|
1088
|
+
const matchedLinked = Array.from(matchingLinkedIds).map((id) => linked.linkedData.get(id)).filter((item) => item !== undefined);
|
|
1089
|
+
const result = {
|
|
1090
|
+
primary,
|
|
1091
|
+
linked: matchedLinked,
|
|
1092
|
+
matchedIn: anyMatchInPrimary && anyMatchInLinked ? "both" : anyMatchInPrimary ? "primary" : "linked"
|
|
1093
|
+
};
|
|
1094
|
+
scored.push({
|
|
1095
|
+
result,
|
|
1096
|
+
score: 0,
|
|
1097
|
+
order: orderCounter++,
|
|
1098
|
+
primaryId,
|
|
1099
|
+
matchedLinkedIds: Array.from(matchingLinkedIds)
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
if (scored.length === 0) {
|
|
1103
|
+
return { queryTokens: queryTokenStrs, results: [], hasNegation: negatedTokens.length > 0 };
|
|
1104
|
+
}
|
|
1105
|
+
const qTokens = orderedTokenize(query);
|
|
1106
|
+
const hasUnsorted = linked.primaryMeta.unsorted.size > 0 || linked.linkedMeta.unsorted.size > 0;
|
|
1107
|
+
if (hasUnsorted) {
|
|
1108
|
+
for (const s of scored) {
|
|
1109
|
+
const itemTokenIds = [];
|
|
1110
|
+
const pu = linked.primaryMeta.unsorted.get(s.primaryId);
|
|
1111
|
+
if (pu)
|
|
1112
|
+
for (const tid of pu)
|
|
1113
|
+
itemTokenIds.push(tid);
|
|
1114
|
+
for (const lid of s.matchedLinkedIds) {
|
|
1115
|
+
const lu = linked.linkedMeta.unsorted.get(lid);
|
|
1116
|
+
if (lu)
|
|
1117
|
+
for (const tid of lu)
|
|
1118
|
+
itemTokenIds.push(tid);
|
|
1119
|
+
}
|
|
1120
|
+
if (itemTokenIds.length === 0) {
|
|
1121
|
+
s.score = 0;
|
|
908
1122
|
continue;
|
|
909
1123
|
}
|
|
910
|
-
const
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
});
|
|
1124
|
+
const itemTokens = new Array(itemTokenIds.length);
|
|
1125
|
+
for (let i = 0;i < itemTokenIds.length; i++) {
|
|
1126
|
+
itemTokens[i] = tokens[itemTokenIds[i]] ?? "";
|
|
1127
|
+
}
|
|
1128
|
+
s.score = scoreOne(query, qTokens, itemTokens);
|
|
916
1129
|
}
|
|
917
1130
|
}
|
|
1131
|
+
scored.sort((a, b) => {
|
|
1132
|
+
if (a.score !== b.score)
|
|
1133
|
+
return b.score - a.score;
|
|
1134
|
+
return a.order - b.order;
|
|
1135
|
+
});
|
|
1136
|
+
const max = Math.min(limit, scored.length);
|
|
1137
|
+
const results = new Array(max);
|
|
1138
|
+
for (let i = 0;i < max; i++)
|
|
1139
|
+
results[i] = scored[i].result;
|
|
918
1140
|
return { queryTokens: queryTokenStrs, results, hasNegation: negatedTokens.length > 0 };
|
|
919
1141
|
}
|
|
920
1142
|
function findInLinkedArraysSimpleNumeric(query, linked, limit = 10, opts) {
|
|
921
1143
|
return findInLinkedArraysNumeric(query, linked, limit, opts).results;
|
|
922
1144
|
}
|
|
923
1145
|
// src/common/numeric/AugmentedMetadata.ts
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
if (
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
if (tokens2 && tokens2.length > 0) {
|
|
944
|
-
this.augmentedTokens.set(id, tokens2);
|
|
1146
|
+
function mergeSortedTokenArrays(a, b) {
|
|
1147
|
+
const merged = new Uint32Array(a.length + b.length);
|
|
1148
|
+
let i = 0, j = 0, k = 0;
|
|
1149
|
+
let lastToken = -1;
|
|
1150
|
+
while (i < a.length && j < b.length) {
|
|
1151
|
+
const tokenA = a[i];
|
|
1152
|
+
const tokenB = b[j];
|
|
1153
|
+
if (tokenA < tokenB) {
|
|
1154
|
+
if (tokenA !== lastToken) {
|
|
1155
|
+
merged[k++] = tokenA;
|
|
1156
|
+
lastToken = tokenA;
|
|
1157
|
+
}
|
|
1158
|
+
i++;
|
|
1159
|
+
} else if (tokenA > tokenB) {
|
|
1160
|
+
if (tokenB !== lastToken) {
|
|
1161
|
+
merged[k++] = tokenB;
|
|
1162
|
+
lastToken = tokenB;
|
|
1163
|
+
}
|
|
1164
|
+
j++;
|
|
945
1165
|
} else {
|
|
946
|
-
|
|
1166
|
+
if (tokenA !== lastToken) {
|
|
1167
|
+
merged[k++] = tokenA;
|
|
1168
|
+
lastToken = tokenA;
|
|
1169
|
+
}
|
|
1170
|
+
i++;
|
|
1171
|
+
j++;
|
|
947
1172
|
}
|
|
948
|
-
clearTokensMap(tokensMap);
|
|
949
1173
|
}
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
continue;
|
|
956
|
-
}
|
|
957
|
-
const tokens2 = prepareObjectForSearchNumeric(augmentedData, this.spec, tokensMap);
|
|
958
|
-
if (tokens2 && tokens2.length > 0) {
|
|
959
|
-
this.augmentedTokens.set(id, tokens2);
|
|
960
|
-
} else {
|
|
961
|
-
this.augmentedTokens.delete(id);
|
|
962
|
-
}
|
|
1174
|
+
while (i < a.length) {
|
|
1175
|
+
const tokenA = a[i];
|
|
1176
|
+
if (tokenA !== lastToken) {
|
|
1177
|
+
merged[k++] = tokenA;
|
|
1178
|
+
lastToken = tokenA;
|
|
963
1179
|
}
|
|
964
|
-
|
|
1180
|
+
i++;
|
|
965
1181
|
}
|
|
966
|
-
|
|
967
|
-
|
|
1182
|
+
while (j < b.length) {
|
|
1183
|
+
const tokenB = b[j];
|
|
1184
|
+
if (tokenB !== lastToken) {
|
|
1185
|
+
merged[k++] = tokenB;
|
|
1186
|
+
lastToken = tokenB;
|
|
1187
|
+
}
|
|
1188
|
+
j++;
|
|
968
1189
|
}
|
|
969
|
-
|
|
970
|
-
|
|
1190
|
+
return merged.slice(0, k);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
class AugmentedSortedMap extends Map {
|
|
1194
|
+
base;
|
|
1195
|
+
augTokens;
|
|
1196
|
+
constructor(base, augTokens) {
|
|
1197
|
+
super();
|
|
1198
|
+
this.base = base;
|
|
1199
|
+
this.augTokens = augTokens;
|
|
971
1200
|
}
|
|
972
1201
|
get(id) {
|
|
973
|
-
const baseTokens = this.
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
if (
|
|
1202
|
+
const baseTokens = this.base.get(id);
|
|
1203
|
+
const augTokens = this.augTokens.get(id);
|
|
1204
|
+
if (baseTokens === undefined)
|
|
1205
|
+
return augTokens;
|
|
1206
|
+
if (augTokens === undefined)
|
|
978
1207
|
return baseTokens;
|
|
979
|
-
return
|
|
1208
|
+
return mergeSortedTokenArrays(baseTokens, augTokens);
|
|
980
1209
|
}
|
|
981
1210
|
has(id) {
|
|
982
|
-
return this.
|
|
1211
|
+
return this.base.has(id) || this.augTokens.has(id);
|
|
983
1212
|
}
|
|
984
1213
|
get size() {
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
const
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
if (baseResult.done) {
|
|
994
|
-
return { done: true, value: undefined };
|
|
995
|
-
}
|
|
996
|
-
const [id, baseTokens] = baseResult.value;
|
|
997
|
-
const augTokens = self.augmentedTokens.get(id);
|
|
998
|
-
const tokens2 = augTokens ? self.mergeSortedTokenArrays(baseTokens, augTokens) : baseTokens;
|
|
999
|
-
return { done: false, value: [id, tokens2] };
|
|
1000
|
-
},
|
|
1001
|
-
[Symbol.iterator]() {
|
|
1002
|
-
return this;
|
|
1003
|
-
},
|
|
1004
|
-
[Symbol.dispose]() {}
|
|
1005
|
-
};
|
|
1214
|
+
if (this.augTokens.size === 0)
|
|
1215
|
+
return this.base.size;
|
|
1216
|
+
let count = this.base.size;
|
|
1217
|
+
for (const id of this.augTokens.keys()) {
|
|
1218
|
+
if (!this.base.has(id))
|
|
1219
|
+
count++;
|
|
1220
|
+
}
|
|
1221
|
+
return count;
|
|
1006
1222
|
}
|
|
1007
1223
|
keys() {
|
|
1008
|
-
return this.
|
|
1224
|
+
return this.unionIdIterator();
|
|
1009
1225
|
}
|
|
1010
1226
|
values() {
|
|
1011
1227
|
const self = this;
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
return tokens2 ? { done: false, value: tokens2 } : { done: true, value: undefined };
|
|
1021
|
-
},
|
|
1022
|
-
[Symbol.iterator]() {
|
|
1023
|
-
return this;
|
|
1024
|
-
},
|
|
1025
|
-
[Symbol.dispose]() {}
|
|
1026
|
-
};
|
|
1228
|
+
function* gen() {
|
|
1229
|
+
for (const id of self.unionIdIterator()) {
|
|
1230
|
+
const tokens2 = self.get(id);
|
|
1231
|
+
if (tokens2 !== undefined)
|
|
1232
|
+
yield tokens2;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
return gen();
|
|
1027
1236
|
}
|
|
1028
1237
|
entries() {
|
|
1029
|
-
|
|
1238
|
+
const self = this;
|
|
1239
|
+
function* gen() {
|
|
1240
|
+
for (const id of self.unionIdIterator()) {
|
|
1241
|
+
const tokens2 = self.get(id);
|
|
1242
|
+
if (tokens2 !== undefined)
|
|
1243
|
+
yield [id, tokens2];
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
return gen();
|
|
1247
|
+
}
|
|
1248
|
+
[Symbol.iterator]() {
|
|
1249
|
+
return this.entries();
|
|
1030
1250
|
}
|
|
1031
1251
|
forEach(callbackfn) {
|
|
1032
|
-
for (const [id, tokens2] of this) {
|
|
1252
|
+
for (const [id, tokens2] of this.entries()) {
|
|
1033
1253
|
callbackfn(tokens2, id, this);
|
|
1034
1254
|
}
|
|
1035
1255
|
}
|
|
1036
1256
|
set(_key, _value) {
|
|
1037
|
-
throw new Error("AugmentedMetadata.
|
|
1257
|
+
throw new Error("AugmentedMetadata.sorted is read-only. Use updateAugmented() instead.");
|
|
1038
1258
|
}
|
|
1039
1259
|
delete(_key) {
|
|
1040
|
-
throw new Error("AugmentedMetadata.
|
|
1260
|
+
throw new Error("AugmentedMetadata.sorted is read-only. Use clearAugmented() instead.");
|
|
1041
1261
|
}
|
|
1042
1262
|
clear() {
|
|
1043
|
-
throw new Error("AugmentedMetadata.
|
|
1263
|
+
throw new Error("AugmentedMetadata.sorted is read-only. Use clearAllAugmented() instead.");
|
|
1044
1264
|
}
|
|
1045
1265
|
get [Symbol.toStringTag]() {
|
|
1046
|
-
return "
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
const tokenA = a[i];
|
|
1054
|
-
const tokenB = b[j];
|
|
1055
|
-
if (tokenA < tokenB) {
|
|
1056
|
-
if (tokenA !== lastToken) {
|
|
1057
|
-
merged[k++] = tokenA;
|
|
1058
|
-
lastToken = tokenA;
|
|
1059
|
-
}
|
|
1060
|
-
i++;
|
|
1061
|
-
} else if (tokenA > tokenB) {
|
|
1062
|
-
if (tokenB !== lastToken) {
|
|
1063
|
-
merged[k++] = tokenB;
|
|
1064
|
-
lastToken = tokenB;
|
|
1065
|
-
}
|
|
1066
|
-
j++;
|
|
1067
|
-
} else {
|
|
1068
|
-
if (tokenA !== lastToken) {
|
|
1069
|
-
merged[k++] = tokenA;
|
|
1070
|
-
lastToken = tokenA;
|
|
1071
|
-
}
|
|
1072
|
-
i++;
|
|
1073
|
-
j++;
|
|
1074
|
-
}
|
|
1266
|
+
return "AugmentedSortedMap";
|
|
1267
|
+
}
|
|
1268
|
+
*unionIdIterator() {
|
|
1269
|
+
const seen = new Set;
|
|
1270
|
+
for (const id of this.base.keys()) {
|
|
1271
|
+
seen.add(id);
|
|
1272
|
+
yield id;
|
|
1075
1273
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
merged[k++] = tokenA;
|
|
1080
|
-
lastToken = tokenA;
|
|
1081
|
-
}
|
|
1082
|
-
i++;
|
|
1274
|
+
for (const id of this.augTokens.keys()) {
|
|
1275
|
+
if (!seen.has(id))
|
|
1276
|
+
yield id;
|
|
1083
1277
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
class AugmentedMetadata {
|
|
1282
|
+
sorted;
|
|
1283
|
+
unsorted;
|
|
1284
|
+
augmentedTokens;
|
|
1285
|
+
spec;
|
|
1286
|
+
constructor(baseMetadata, spec, augmentedDataMap) {
|
|
1287
|
+
this.augmentedTokens = new Map;
|
|
1288
|
+
this.spec = spec;
|
|
1289
|
+
this.sorted = new AugmentedSortedMap(baseMetadata.sorted, this.augmentedTokens);
|
|
1290
|
+
this.unsorted = baseMetadata.unsorted;
|
|
1291
|
+
if (augmentedDataMap && augmentedDataMap.size > 0) {
|
|
1292
|
+
this.updateAugmentedBatch(augmentedDataMap);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
updateAugmented(id, augmentedData) {
|
|
1296
|
+
if (augmentedData == null) {
|
|
1297
|
+
this.augmentedTokens.delete(id);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
const tokensMap = createTokensMap();
|
|
1301
|
+
const prepared = prepareObjectForSearchNumeric(augmentedData, this.spec, tokensMap);
|
|
1302
|
+
clearTokensMap(tokensMap);
|
|
1303
|
+
if (prepared !== undefined && prepared.sorted.length > 0) {
|
|
1304
|
+
this.augmentedTokens.set(id, prepared.sorted);
|
|
1305
|
+
} else {
|
|
1306
|
+
this.augmentedTokens.delete(id);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
updateAugmentedBatch(augmentedDataMap) {
|
|
1310
|
+
const tokensMap = createTokensMap();
|
|
1311
|
+
for (const [id, augmentedData] of augmentedDataMap) {
|
|
1312
|
+
if (augmentedData == null) {
|
|
1313
|
+
this.augmentedTokens.delete(id);
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
const prepared = prepareObjectForSearchNumeric(augmentedData, this.spec, tokensMap);
|
|
1317
|
+
if (prepared !== undefined && prepared.sorted.length > 0) {
|
|
1318
|
+
this.augmentedTokens.set(id, prepared.sorted);
|
|
1319
|
+
} else {
|
|
1320
|
+
this.augmentedTokens.delete(id);
|
|
1089
1321
|
}
|
|
1090
|
-
j++;
|
|
1091
1322
|
}
|
|
1092
|
-
|
|
1323
|
+
clearTokensMap(tokensMap);
|
|
1324
|
+
}
|
|
1325
|
+
clearAugmented(id) {
|
|
1326
|
+
this.augmentedTokens.delete(id);
|
|
1327
|
+
}
|
|
1328
|
+
clearAllAugmented() {
|
|
1329
|
+
this.augmentedTokens.clear();
|
|
1093
1330
|
}
|
|
1094
1331
|
}
|
|
1095
1332
|
// src/common/numeric/syncSearchArrayMetadata.ts
|
|
@@ -1102,6 +1339,25 @@ function tokensEqual(a, b) {
|
|
|
1102
1339
|
}
|
|
1103
1340
|
return true;
|
|
1104
1341
|
}
|
|
1342
|
+
function firstNEqual(a, b) {
|
|
1343
|
+
if (a === undefined && b === undefined)
|
|
1344
|
+
return true;
|
|
1345
|
+
if (a === undefined || b === undefined)
|
|
1346
|
+
return false;
|
|
1347
|
+
return tokensEqual(a, b);
|
|
1348
|
+
}
|
|
1349
|
+
function applyPreparedTokens(metadata, id, result) {
|
|
1350
|
+
metadata.sorted.set(id, result.sorted);
|
|
1351
|
+
if (result.firstN !== undefined) {
|
|
1352
|
+
metadata.unsorted.set(id, result.firstN);
|
|
1353
|
+
} else {
|
|
1354
|
+
metadata.unsorted.delete(id);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
function deletePreparedTokens(metadata, id) {
|
|
1358
|
+
metadata.sorted.delete(id);
|
|
1359
|
+
metadata.unsorted.delete(id);
|
|
1360
|
+
}
|
|
1105
1361
|
function syncSearchArrayMetadataNumeric(metadata, newData, spec) {
|
|
1106
1362
|
const result = {
|
|
1107
1363
|
added: 0,
|
|
@@ -1112,30 +1368,31 @@ function syncSearchArrayMetadataNumeric(metadata, newData, spec) {
|
|
|
1112
1368
|
removedIds: []
|
|
1113
1369
|
};
|
|
1114
1370
|
const tokensMap = createTokensMap();
|
|
1115
|
-
for (const id of metadata.keys()) {
|
|
1371
|
+
for (const id of metadata.sorted.keys()) {
|
|
1116
1372
|
if (!newData.has(id)) {
|
|
1117
|
-
metadata
|
|
1373
|
+
deletePreparedTokens(metadata, id);
|
|
1118
1374
|
result.removed++;
|
|
1119
1375
|
result.removedIds.push(id);
|
|
1120
1376
|
}
|
|
1121
1377
|
}
|
|
1122
1378
|
for (const [id, item] of newData) {
|
|
1123
|
-
const
|
|
1124
|
-
if (
|
|
1125
|
-
if (metadata.has(id)) {
|
|
1126
|
-
metadata
|
|
1379
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1380
|
+
if (prepared === undefined) {
|
|
1381
|
+
if (metadata.sorted.has(id)) {
|
|
1382
|
+
deletePreparedTokens(metadata, id);
|
|
1127
1383
|
result.removed++;
|
|
1128
1384
|
result.removedIds.push(id);
|
|
1129
1385
|
}
|
|
1130
1386
|
continue;
|
|
1131
1387
|
}
|
|
1132
|
-
const
|
|
1133
|
-
|
|
1134
|
-
|
|
1388
|
+
const existingSorted = metadata.sorted.get(id);
|
|
1389
|
+
const existingFirstN = metadata.unsorted.get(id);
|
|
1390
|
+
if (existingSorted === undefined) {
|
|
1391
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1135
1392
|
result.added++;
|
|
1136
1393
|
result.addedIds.push(id);
|
|
1137
|
-
} else if (!tokensEqual(
|
|
1138
|
-
metadata
|
|
1394
|
+
} else if (!tokensEqual(existingSorted, prepared.sorted) || !firstNEqual(existingFirstN, prepared.firstN)) {
|
|
1395
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1139
1396
|
result.updated++;
|
|
1140
1397
|
result.updatedIds.push(id);
|
|
1141
1398
|
}
|
|
@@ -1155,7 +1412,7 @@ function syncSearchArrayMetadataNumericWithPrevious(metadata, previousData, newD
|
|
|
1155
1412
|
const tokensMap = createTokensMap();
|
|
1156
1413
|
for (const id of previousData.keys()) {
|
|
1157
1414
|
if (!newData.has(id)) {
|
|
1158
|
-
metadata
|
|
1415
|
+
deletePreparedTokens(metadata, id);
|
|
1159
1416
|
result.removed++;
|
|
1160
1417
|
result.removedIds.push(id);
|
|
1161
1418
|
}
|
|
@@ -1163,22 +1420,23 @@ function syncSearchArrayMetadataNumericWithPrevious(metadata, previousData, newD
|
|
|
1163
1420
|
for (const [id, item] of newData) {
|
|
1164
1421
|
const wasInPrevious = previousData.has(id);
|
|
1165
1422
|
if (!wasInPrevious) {
|
|
1166
|
-
const
|
|
1167
|
-
if (
|
|
1168
|
-
metadata
|
|
1423
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1424
|
+
if (prepared !== undefined) {
|
|
1425
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1169
1426
|
result.added++;
|
|
1170
1427
|
result.addedIds.push(id);
|
|
1171
1428
|
}
|
|
1172
1429
|
} else if (!options?.skipUpdateCheck) {
|
|
1173
|
-
const
|
|
1174
|
-
if (
|
|
1175
|
-
metadata
|
|
1430
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1431
|
+
if (prepared === undefined) {
|
|
1432
|
+
deletePreparedTokens(metadata, id);
|
|
1176
1433
|
result.removed++;
|
|
1177
1434
|
result.removedIds.push(id);
|
|
1178
1435
|
} else {
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
|
|
1436
|
+
const existingSorted = metadata.sorted.get(id);
|
|
1437
|
+
const existingFirstN = metadata.unsorted.get(id);
|
|
1438
|
+
if (existingSorted && (!tokensEqual(existingSorted, prepared.sorted) || !firstNEqual(existingFirstN, prepared.firstN))) {
|
|
1439
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1182
1440
|
result.updated++;
|
|
1183
1441
|
result.updatedIds.push(id);
|
|
1184
1442
|
}
|
|
@@ -1198,29 +1456,48 @@ function tokensEqual2(a, b) {
|
|
|
1198
1456
|
}
|
|
1199
1457
|
return true;
|
|
1200
1458
|
}
|
|
1459
|
+
function firstNEqual2(a, b) {
|
|
1460
|
+
if (a === undefined && b === undefined)
|
|
1461
|
+
return true;
|
|
1462
|
+
if (a === undefined || b === undefined)
|
|
1463
|
+
return false;
|
|
1464
|
+
return tokensEqual2(a, b);
|
|
1465
|
+
}
|
|
1466
|
+
function applyOrClear(meta, id, prepared) {
|
|
1467
|
+
if (prepared === undefined) {
|
|
1468
|
+
meta.sorted.delete(id);
|
|
1469
|
+
meta.unsorted.delete(id);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
meta.sorted.set(id, prepared.sorted);
|
|
1473
|
+
if (prepared.firstN !== undefined) {
|
|
1474
|
+
meta.unsorted.set(id, prepared.firstN);
|
|
1475
|
+
} else {
|
|
1476
|
+
meta.unsorted.delete(id);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function clearTokens(meta, id) {
|
|
1480
|
+
meta.sorted.delete(id);
|
|
1481
|
+
meta.unsorted.delete(id);
|
|
1482
|
+
}
|
|
1201
1483
|
function upsertPrimaryItemNumeric(linked, item, spec) {
|
|
1202
1484
|
const id = item._id;
|
|
1203
1485
|
const wasAdded = !linked.primaryData.has(id);
|
|
1204
1486
|
linked.primaryData.set(id, item);
|
|
1205
1487
|
const tokensMap = createTokensMap();
|
|
1206
|
-
const
|
|
1488
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1207
1489
|
clearTokensMap(tokensMap);
|
|
1208
|
-
|
|
1209
|
-
linked.primaryMeta.set(id, tokens2);
|
|
1210
|
-
} else {
|
|
1211
|
-
linked.primaryMeta.delete(id);
|
|
1212
|
-
}
|
|
1490
|
+
applyOrClear(linked.primaryMeta, id, prepared);
|
|
1213
1491
|
if (wasAdded && !linked.primaryToLinked.has(id)) {
|
|
1214
1492
|
linked.primaryToLinked.set(id, []);
|
|
1215
1493
|
}
|
|
1216
1494
|
return { added: wasAdded };
|
|
1217
1495
|
}
|
|
1218
1496
|
function removePrimaryItemNumeric(linked, primaryId) {
|
|
1219
|
-
if (!linked.primaryData.has(primaryId))
|
|
1497
|
+
if (!linked.primaryData.has(primaryId))
|
|
1220
1498
|
return false;
|
|
1221
|
-
}
|
|
1222
1499
|
linked.primaryData.delete(primaryId);
|
|
1223
|
-
linked.primaryMeta
|
|
1500
|
+
clearTokens(linked.primaryMeta, primaryId);
|
|
1224
1501
|
linked.primaryToLinked.delete(primaryId);
|
|
1225
1502
|
return true;
|
|
1226
1503
|
}
|
|
@@ -1229,35 +1506,28 @@ function upsertLinkedItemNumeric(linked, item, foreignKeyGetter, spec) {
|
|
|
1229
1506
|
const newPrimaryId = foreignKeyGetter(item);
|
|
1230
1507
|
let previousPrimaryId;
|
|
1231
1508
|
const existingItem = linked.linkedData.get(id);
|
|
1232
|
-
if (existingItem)
|
|
1509
|
+
if (existingItem)
|
|
1233
1510
|
previousPrimaryId = foreignKeyGetter(existingItem);
|
|
1234
|
-
}
|
|
1235
1511
|
const wasAdded = !existingItem;
|
|
1236
1512
|
linked.linkedData.set(id, item);
|
|
1237
1513
|
const tokensMap = createTokensMap();
|
|
1238
|
-
const
|
|
1514
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1239
1515
|
clearTokensMap(tokensMap);
|
|
1240
|
-
|
|
1241
|
-
linked.linkedMeta.set(id, tokens2);
|
|
1242
|
-
} else {
|
|
1243
|
-
linked.linkedMeta.delete(id);
|
|
1244
|
-
}
|
|
1516
|
+
applyOrClear(linked.linkedMeta, id, prepared);
|
|
1245
1517
|
if (previousPrimaryId !== newPrimaryId) {
|
|
1246
1518
|
if (previousPrimaryId) {
|
|
1247
1519
|
const oldList = linked.primaryToLinked.get(previousPrimaryId);
|
|
1248
1520
|
if (oldList) {
|
|
1249
1521
|
const index = oldList.indexOf(id);
|
|
1250
|
-
if (index !== -1)
|
|
1522
|
+
if (index !== -1)
|
|
1251
1523
|
oldList.splice(index, 1);
|
|
1252
|
-
}
|
|
1253
1524
|
}
|
|
1254
1525
|
}
|
|
1255
1526
|
if (newPrimaryId) {
|
|
1256
1527
|
const newList = linked.primaryToLinked.get(newPrimaryId);
|
|
1257
1528
|
if (newList) {
|
|
1258
|
-
if (!newList.includes(id))
|
|
1529
|
+
if (!newList.includes(id))
|
|
1259
1530
|
newList.push(id);
|
|
1260
|
-
}
|
|
1261
1531
|
} else {
|
|
1262
1532
|
linked.primaryToLinked.set(newPrimaryId, [id]);
|
|
1263
1533
|
}
|
|
@@ -1270,64 +1540,57 @@ function upsertLinkedItemNumeric(linked, item, foreignKeyGetter, spec) {
|
|
|
1270
1540
|
}
|
|
1271
1541
|
function removeLinkedItemNumeric(linked, linkedId, foreignKeyGetter) {
|
|
1272
1542
|
const existingItem = linked.linkedData.get(linkedId);
|
|
1273
|
-
if (!existingItem)
|
|
1543
|
+
if (!existingItem)
|
|
1274
1544
|
return false;
|
|
1275
|
-
}
|
|
1276
1545
|
const primaryId = foreignKeyGetter(existingItem);
|
|
1277
1546
|
linked.linkedData.delete(linkedId);
|
|
1278
|
-
linked.linkedMeta
|
|
1547
|
+
clearTokens(linked.linkedMeta, linkedId);
|
|
1279
1548
|
if (primaryId) {
|
|
1280
1549
|
const list = linked.primaryToLinked.get(primaryId);
|
|
1281
1550
|
if (list) {
|
|
1282
1551
|
const index = list.indexOf(linkedId);
|
|
1283
|
-
if (index !== -1)
|
|
1552
|
+
if (index !== -1)
|
|
1284
1553
|
list.splice(index, 1);
|
|
1285
|
-
}
|
|
1286
1554
|
}
|
|
1287
1555
|
}
|
|
1288
1556
|
return true;
|
|
1289
1557
|
}
|
|
1290
1558
|
function syncLinkedItemsForPrimaryNumeric(linked, primaryId, newLinkedItems, foreignKeyGetter, spec) {
|
|
1291
|
-
const result = {
|
|
1292
|
-
added: 0,
|
|
1293
|
-
updated: 0,
|
|
1294
|
-
removed: 0
|
|
1295
|
-
};
|
|
1559
|
+
const result = { added: 0, updated: 0, removed: 0 };
|
|
1296
1560
|
const tokensMap = createTokensMap();
|
|
1297
1561
|
const currentLinkedIds = new Set(linked.primaryToLinked.get(primaryId) || []);
|
|
1298
1562
|
const newLinkedIds = new Set;
|
|
1299
1563
|
for (const [id, item] of newLinkedItems) {
|
|
1300
|
-
if (foreignKeyGetter(item) === primaryId)
|
|
1564
|
+
if (foreignKeyGetter(item) === primaryId)
|
|
1301
1565
|
newLinkedIds.add(id);
|
|
1302
|
-
}
|
|
1303
1566
|
}
|
|
1304
1567
|
for (const id of currentLinkedIds) {
|
|
1305
1568
|
if (!newLinkedIds.has(id)) {
|
|
1306
|
-
|
|
1307
|
-
if (item) {
|
|
1569
|
+
if (linked.linkedData.has(id)) {
|
|
1308
1570
|
linked.linkedData.delete(id);
|
|
1309
|
-
linked.linkedMeta
|
|
1571
|
+
clearTokens(linked.linkedMeta, id);
|
|
1310
1572
|
result.removed++;
|
|
1311
1573
|
}
|
|
1312
1574
|
}
|
|
1313
1575
|
}
|
|
1314
1576
|
for (const id of newLinkedIds) {
|
|
1315
1577
|
const item = newLinkedItems.get(id);
|
|
1316
|
-
const
|
|
1578
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1317
1579
|
if (currentLinkedIds.has(id)) {
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1580
|
+
const existingSorted = linked.linkedMeta.sorted.get(id);
|
|
1581
|
+
const existingFirstN = linked.linkedMeta.unsorted.get(id);
|
|
1582
|
+
if (prepared !== undefined) {
|
|
1583
|
+
if (!existingSorted || !tokensEqual2(existingSorted, prepared.sorted) || !firstNEqual2(existingFirstN, prepared.firstN)) {
|
|
1584
|
+
applyOrClear(linked.linkedMeta, id, prepared);
|
|
1322
1585
|
result.updated++;
|
|
1323
1586
|
}
|
|
1587
|
+
} else {
|
|
1588
|
+
clearTokens(linked.linkedMeta, id);
|
|
1324
1589
|
}
|
|
1325
1590
|
linked.linkedData.set(id, item);
|
|
1326
1591
|
} else {
|
|
1327
1592
|
linked.linkedData.set(id, item);
|
|
1328
|
-
|
|
1329
|
-
linked.linkedMeta.set(id, tokens2);
|
|
1330
|
-
}
|
|
1593
|
+
applyOrClear(linked.linkedMeta, id, prepared);
|
|
1331
1594
|
result.added++;
|
|
1332
1595
|
}
|
|
1333
1596
|
}
|
|
@@ -1336,54 +1599,14 @@ function syncLinkedItemsForPrimaryNumeric(linked, primaryId, newLinkedItems, for
|
|
|
1336
1599
|
return result;
|
|
1337
1600
|
}
|
|
1338
1601
|
// src/common/numeric/searchAndRank.ts
|
|
1339
|
-
function
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
if (exactKeys[i] === query)
|
|
1346
|
-
return 1e5;
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
if (qTokens.length === 0)
|
|
1350
|
-
return 0;
|
|
1351
|
-
const primaryText = primaryTextFn(item) || "";
|
|
1352
|
-
const itemTokens = orderedTokenize(primaryText);
|
|
1353
|
-
if (itemTokens.length === 0)
|
|
1354
|
-
return 1;
|
|
1355
|
-
let qi = 0;
|
|
1356
|
-
const positions = [];
|
|
1357
|
-
for (let i = 0;i < itemTokens.length; i++) {
|
|
1358
|
-
if (qi < qTokens.length && itemTokens[i].startsWith(qTokens[qi])) {
|
|
1359
|
-
positions.push(i);
|
|
1360
|
-
qi++;
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
if (qi === 0)
|
|
1364
|
-
return 1;
|
|
1365
|
-
let score = 50;
|
|
1366
|
-
if (qi === qTokens.length)
|
|
1367
|
-
score += 100;
|
|
1368
|
-
if (positions[0] === 0)
|
|
1369
|
-
score += 50;
|
|
1370
|
-
let perfect = qi === qTokens.length;
|
|
1371
|
-
if (perfect) {
|
|
1372
|
-
for (let i = 0;i < positions.length; i++) {
|
|
1373
|
-
if (positions[i] !== i) {
|
|
1374
|
-
perfect = false;
|
|
1375
|
-
break;
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
if (perfect)
|
|
1380
|
-
score += 80;
|
|
1381
|
-
if (positions.length >= 2) {
|
|
1382
|
-
const span = positions[positions.length - 1] - positions[0] + 1;
|
|
1383
|
-
score += positions.length / span * 30;
|
|
1602
|
+
function tokenIdsToStrings(tokenIds) {
|
|
1603
|
+
if (tokenIds === undefined)
|
|
1604
|
+
return;
|
|
1605
|
+
const out = new Array(tokenIds.length);
|
|
1606
|
+
for (let i = 0;i < tokenIds.length; i++) {
|
|
1607
|
+
out[i] = tokens[tokenIds[i]] ?? "";
|
|
1384
1608
|
}
|
|
1385
|
-
|
|
1386
|
-
return score;
|
|
1609
|
+
return out;
|
|
1387
1610
|
}
|
|
1388
1611
|
function searchAndRankNumeric(query, data, metadata, options) {
|
|
1389
1612
|
const { primaryTextFn, exactKeysFn, limit, opts } = options;
|
|
@@ -1396,8 +1619,9 @@ function searchAndRankNumeric(query, data, metadata, options) {
|
|
|
1396
1619
|
const item = data.get(id);
|
|
1397
1620
|
if (!item)
|
|
1398
1621
|
continue;
|
|
1622
|
+
const itemTokens = tokenIdsToStrings(metadata.unsorted.get(id)) ?? orderedTokenize(primaryTextFn(item) || "");
|
|
1399
1623
|
const exactKeys = exactKeysFn?.(item);
|
|
1400
|
-
const score = scoreOne(
|
|
1624
|
+
const score = scoreOne(query, qTokens, itemTokens, exactKeys);
|
|
1401
1625
|
scored.push({ id, item, score });
|
|
1402
1626
|
}
|
|
1403
1627
|
scored.sort((x, y) => {
|
|
@@ -1421,6 +1645,13 @@ function tokensEqual3(a, b) {
|
|
|
1421
1645
|
}
|
|
1422
1646
|
return true;
|
|
1423
1647
|
}
|
|
1648
|
+
function firstNEqual3(a, b) {
|
|
1649
|
+
if (a === undefined && b === undefined)
|
|
1650
|
+
return true;
|
|
1651
|
+
if (a === undefined || b === undefined)
|
|
1652
|
+
return false;
|
|
1653
|
+
return tokensEqual3(a, b);
|
|
1654
|
+
}
|
|
1424
1655
|
|
|
1425
1656
|
class SearchUniverse {
|
|
1426
1657
|
collections = new Map;
|
|
@@ -1430,7 +1661,7 @@ class SearchUniverse {
|
|
|
1430
1661
|
}
|
|
1431
1662
|
const collection = {
|
|
1432
1663
|
data: new Map,
|
|
1433
|
-
metadata:
|
|
1664
|
+
metadata: emptyNumericSearchMetadata(),
|
|
1434
1665
|
config
|
|
1435
1666
|
};
|
|
1436
1667
|
if (config.linkedTo) {
|
|
@@ -1447,7 +1678,8 @@ class SearchUniverse {
|
|
|
1447
1678
|
loadCollection(name, items) {
|
|
1448
1679
|
const collection = this.getCollectionOrThrow(name);
|
|
1449
1680
|
collection.data.clear();
|
|
1450
|
-
collection.metadata.clear();
|
|
1681
|
+
collection.metadata.sorted.clear();
|
|
1682
|
+
collection.metadata.unsorted.clear();
|
|
1451
1683
|
if (collection.primaryToLinked) {
|
|
1452
1684
|
collection.primaryToLinked.clear();
|
|
1453
1685
|
}
|
|
@@ -1455,8 +1687,11 @@ class SearchUniverse {
|
|
|
1455
1687
|
collection.data.set(item._id, item);
|
|
1456
1688
|
}
|
|
1457
1689
|
const newMetadata = createSearchArrayMetadataNumeric(collection.data, collection.config.spec);
|
|
1458
|
-
for (const [id, tokens2] of newMetadata) {
|
|
1459
|
-
collection.metadata.set(id, tokens2);
|
|
1690
|
+
for (const [id, tokens2] of newMetadata.sorted) {
|
|
1691
|
+
collection.metadata.sorted.set(id, tokens2);
|
|
1692
|
+
}
|
|
1693
|
+
for (const [id, tokens2] of newMetadata.unsorted) {
|
|
1694
|
+
collection.metadata.unsorted.set(id, tokens2);
|
|
1460
1695
|
}
|
|
1461
1696
|
if (collection.config.linkedTo && collection.primaryToLinked) {
|
|
1462
1697
|
const { foreignKeyGetter } = collection.config.linkedTo;
|
|
@@ -1552,11 +1787,17 @@ class SearchUniverse {
|
|
|
1552
1787
|
collection.data.set(id, item);
|
|
1553
1788
|
const tokensMap = createTokensMap();
|
|
1554
1789
|
try {
|
|
1555
|
-
const
|
|
1556
|
-
if (
|
|
1557
|
-
collection.metadata.set(id,
|
|
1790
|
+
const prepared = prepareObjectForSearchNumeric(item, collection.config.spec, tokensMap);
|
|
1791
|
+
if (prepared !== undefined) {
|
|
1792
|
+
collection.metadata.sorted.set(id, prepared.sorted);
|
|
1793
|
+
if (prepared.firstN !== undefined) {
|
|
1794
|
+
collection.metadata.unsorted.set(id, prepared.firstN);
|
|
1795
|
+
} else {
|
|
1796
|
+
collection.metadata.unsorted.delete(id);
|
|
1797
|
+
}
|
|
1558
1798
|
} else {
|
|
1559
|
-
collection.metadata.delete(id);
|
|
1799
|
+
collection.metadata.sorted.delete(id);
|
|
1800
|
+
collection.metadata.unsorted.delete(id);
|
|
1560
1801
|
}
|
|
1561
1802
|
} finally {
|
|
1562
1803
|
clearTokensMap(tokensMap);
|
|
@@ -1610,7 +1851,8 @@ class SearchUniverse {
|
|
|
1610
1851
|
}
|
|
1611
1852
|
}
|
|
1612
1853
|
collection.data.delete(id);
|
|
1613
|
-
collection.metadata.delete(id);
|
|
1854
|
+
collection.metadata.sorted.delete(id);
|
|
1855
|
+
collection.metadata.unsorted.delete(id);
|
|
1614
1856
|
return true;
|
|
1615
1857
|
}
|
|
1616
1858
|
removeFromSearchMetadataBatch(collectionName, ids) {
|
|
@@ -1661,9 +1903,10 @@ class SearchUniverse {
|
|
|
1661
1903
|
}
|
|
1662
1904
|
}
|
|
1663
1905
|
}
|
|
1664
|
-
const hadMetadata = collection.metadata.has(id);
|
|
1906
|
+
const hadMetadata = collection.metadata.sorted.has(id);
|
|
1665
1907
|
collection.data.delete(id);
|
|
1666
|
-
collection.metadata.delete(id);
|
|
1908
|
+
collection.metadata.sorted.delete(id);
|
|
1909
|
+
collection.metadata.unsorted.delete(id);
|
|
1667
1910
|
if (hadMetadata) {
|
|
1668
1911
|
result.removed++;
|
|
1669
1912
|
result.removedIds.push(id);
|
|
@@ -1674,11 +1917,11 @@ class SearchUniverse {
|
|
|
1674
1917
|
for (const item of newItems) {
|
|
1675
1918
|
const id = item._id;
|
|
1676
1919
|
const existing = collection.data.get(id);
|
|
1677
|
-
const hadMetadata = collection.metadata.has(id);
|
|
1920
|
+
const hadMetadata = collection.metadata.sorted.has(id);
|
|
1678
1921
|
const shouldTokenize = !existing || !skipUpdateCheck;
|
|
1679
|
-
let
|
|
1922
|
+
let prepared;
|
|
1680
1923
|
if (shouldTokenize) {
|
|
1681
|
-
|
|
1924
|
+
prepared = prepareObjectForSearchNumeric(item, collection.config.spec, tokensMap);
|
|
1682
1925
|
}
|
|
1683
1926
|
if (fkGetter && collection.primaryToLinked) {
|
|
1684
1927
|
const newFk = fkGetter(item);
|
|
@@ -1708,20 +1951,30 @@ class SearchUniverse {
|
|
|
1708
1951
|
collection.data.set(id, item);
|
|
1709
1952
|
if (!shouldTokenize)
|
|
1710
1953
|
continue;
|
|
1711
|
-
if (
|
|
1954
|
+
if (prepared === undefined) {
|
|
1712
1955
|
if (hadMetadata) {
|
|
1713
|
-
collection.metadata.delete(id);
|
|
1956
|
+
collection.metadata.sorted.delete(id);
|
|
1957
|
+
collection.metadata.unsorted.delete(id);
|
|
1714
1958
|
result.removed++;
|
|
1715
1959
|
result.removedIds.push(id);
|
|
1716
1960
|
}
|
|
1717
1961
|
} else if (!hadMetadata) {
|
|
1718
|
-
collection.metadata.set(id,
|
|
1962
|
+
collection.metadata.sorted.set(id, prepared.sorted);
|
|
1963
|
+
if (prepared.firstN !== undefined) {
|
|
1964
|
+
collection.metadata.unsorted.set(id, prepared.firstN);
|
|
1965
|
+
}
|
|
1719
1966
|
result.added++;
|
|
1720
1967
|
result.addedIds.push(id);
|
|
1721
1968
|
} else {
|
|
1722
|
-
const
|
|
1723
|
-
|
|
1724
|
-
|
|
1969
|
+
const existingSorted = collection.metadata.sorted.get(id);
|
|
1970
|
+
const existingFirstN = collection.metadata.unsorted.get(id);
|
|
1971
|
+
if (!tokensEqual3(existingSorted, prepared.sorted) || !firstNEqual3(existingFirstN, prepared.firstN)) {
|
|
1972
|
+
collection.metadata.sorted.set(id, prepared.sorted);
|
|
1973
|
+
if (prepared.firstN !== undefined) {
|
|
1974
|
+
collection.metadata.unsorted.set(id, prepared.firstN);
|
|
1975
|
+
} else {
|
|
1976
|
+
collection.metadata.unsorted.delete(id);
|
|
1977
|
+
}
|
|
1725
1978
|
result.updated++;
|
|
1726
1979
|
result.updatedIds.push(id);
|
|
1727
1980
|
}
|
|
@@ -1800,7 +2053,8 @@ class SearchUniverse {
|
|
|
1800
2053
|
clear() {
|
|
1801
2054
|
for (const collection of this.collections.values()) {
|
|
1802
2055
|
collection.data.clear();
|
|
1803
|
-
collection.metadata.clear();
|
|
2056
|
+
collection.metadata.sorted.clear();
|
|
2057
|
+
collection.metadata.unsorted.clear();
|
|
1804
2058
|
if (collection.primaryToLinked) {
|
|
1805
2059
|
collection.primaryToLinked.clear();
|
|
1806
2060
|
}
|