cry-search 1.0.6 → 1.0.8
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 +79 -78
- package/README.md +93 -17
- package/UNIVERSE.md +29 -20
- package/dist/common/SearchUniverse.d.ts +28 -13
- 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 +48 -0
- package/dist/common/numeric/searchAndRank.d.ts.map +1 -0
- 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 +646 -312
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +646 -312
- 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.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/types/index.ts
|
|
2
|
+
var DEFAULT_FIRST_TOKENS_N = 8;
|
|
2
3
|
var DEFAULT_SEARCH_OPTS = {
|
|
3
4
|
matchWords: "start",
|
|
4
5
|
matchNumbers: "startEnd",
|
|
@@ -268,11 +269,23 @@ function prepareStringForSearchNumeric(input, tokensMap) {
|
|
|
268
269
|
for (let i = 0;i < stringTokens.length; i++) {
|
|
269
270
|
numericTokens[i] = getOrCreateTokenId(stringTokens[i], tokensMap);
|
|
270
271
|
}
|
|
271
|
-
|
|
272
|
-
|
|
272
|
+
const unsorted = Uint32Array.from(numericTokens);
|
|
273
|
+
const sortedArr = numericTokens.slice().sort((a, b) => a - b);
|
|
274
|
+
const sorted = Uint32Array.from(sortedArr);
|
|
275
|
+
return { sorted, unsorted };
|
|
273
276
|
}
|
|
274
277
|
|
|
275
|
-
// src/common/
|
|
278
|
+
// src/common/numeric/createSearchArrayMetadata.ts
|
|
279
|
+
function isDeletedOrBlocked(obj) {
|
|
280
|
+
return obj._deleted != null || obj._blocked != null;
|
|
281
|
+
}
|
|
282
|
+
var MATCH_MODE_PREFIXES = {
|
|
283
|
+
start: "<",
|
|
284
|
+
end: ">",
|
|
285
|
+
startEnd: "+",
|
|
286
|
+
anywhere: "*",
|
|
287
|
+
whole: "!"
|
|
288
|
+
};
|
|
276
289
|
var PREFIX_TO_MATCH_MODE = {
|
|
277
290
|
"<": "start",
|
|
278
291
|
">": "end",
|
|
@@ -282,12 +295,6 @@ var PREFIX_TO_MATCH_MODE = {
|
|
|
282
295
|
"=": "whole",
|
|
283
296
|
"?": "anywhere"
|
|
284
297
|
};
|
|
285
|
-
var DEFAULT_EXCLUDED_FIELDS = new Set(["_id", "_deleted", "_blocked"]);
|
|
286
|
-
function isDeletedOrBlocked(obj) {
|
|
287
|
-
return obj._deleted != null || obj._blocked != null;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// src/common/numeric/createSearchArrayMetadata.ts
|
|
291
298
|
var MATCH_MODE_BITS = {
|
|
292
299
|
start: 0,
|
|
293
300
|
end: 1,
|
|
@@ -318,7 +325,7 @@ function decodeMatchMode(encoded) {
|
|
|
318
325
|
return "start";
|
|
319
326
|
}
|
|
320
327
|
}
|
|
321
|
-
var
|
|
328
|
+
var DEFAULT_EXCLUDED_FIELDS = new Set(["_id", "_deleted", "_blocked"]);
|
|
322
329
|
function getValueByPath(obj, path) {
|
|
323
330
|
const parts = path.split(".");
|
|
324
331
|
let current = obj;
|
|
@@ -375,26 +382,29 @@ function prepareObjectForSearchNumeric(obj, spec, tokensMap) {
|
|
|
375
382
|
if (isDeletedOrBlocked(obj)) {
|
|
376
383
|
return;
|
|
377
384
|
}
|
|
378
|
-
if (spec?.extractSearchableStringFn) {
|
|
379
|
-
const searchableString = spec.extractSearchableStringFn(obj);
|
|
380
|
-
if (searchableString === undefined) {
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
return prepareStringForSearchNumeric(searchableString, tokensMap);
|
|
384
|
-
}
|
|
385
|
-
return prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap);
|
|
386
|
-
}
|
|
387
|
-
function prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap) {
|
|
388
385
|
if (spec?.enrichSearchObjectFn) {
|
|
389
386
|
spec.enrichSearchObjectFn(obj, spec.searchContext);
|
|
390
387
|
}
|
|
388
|
+
const sorted = spec?.extractSearchableStringFn ? buildSortedFromExtractFn(obj, spec.extractSearchableStringFn, tokensMap) : buildSortedFromFields(obj, spec, tokensMap);
|
|
389
|
+
if (sorted === undefined)
|
|
390
|
+
return;
|
|
391
|
+
const firstN = spec?.keyFields && spec.keyFields.length > 0 ? buildFirstNFromKeyFields(obj, spec.keyFields, spec.firstTokensN ?? DEFAULT_FIRST_TOKENS_N, tokensMap) : undefined;
|
|
392
|
+
return { sorted, firstN };
|
|
393
|
+
}
|
|
394
|
+
function buildSortedFromExtractFn(obj, extractFn, tokensMap) {
|
|
395
|
+
const str = extractFn(obj);
|
|
396
|
+
if (str === undefined)
|
|
397
|
+
return;
|
|
398
|
+
return prepareStringForSearchNumeric(str, tokensMap).sorted;
|
|
399
|
+
}
|
|
400
|
+
function buildSortedFromFields(obj, spec, tokensMap) {
|
|
391
401
|
const allTokens = [];
|
|
392
402
|
const fieldMatchModes = spec?.fieldMatchModes;
|
|
393
403
|
const fieldsToSearch = spec?.searchInFields ?? Object.keys(obj);
|
|
394
404
|
const fieldsToExclude = new Set(spec?.dontSearchInFields ?? []);
|
|
395
405
|
for (const key of fieldsToSearch) {
|
|
396
406
|
const keyStr = key;
|
|
397
|
-
if (!spec?.searchInFields &&
|
|
407
|
+
if (!spec?.searchInFields && DEFAULT_EXCLUDED_FIELDS.has(keyStr))
|
|
398
408
|
continue;
|
|
399
409
|
if (fieldsToExclude.has(key))
|
|
400
410
|
continue;
|
|
@@ -425,14 +435,42 @@ function prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap) {
|
|
|
425
435
|
const uniqueTokens = [...new Set(allTokens)].sort((a, b) => a - b);
|
|
426
436
|
return new Uint32Array(uniqueTokens);
|
|
427
437
|
}
|
|
438
|
+
function buildFirstNFromKeyFields(obj, keyFields, n, tokensMap) {
|
|
439
|
+
const strings = [];
|
|
440
|
+
for (const field of keyFields) {
|
|
441
|
+
const keyStr = field;
|
|
442
|
+
const value = isDotNotation(keyStr) ? getValueByPath(obj, keyStr) : obj[field];
|
|
443
|
+
if (value == null)
|
|
444
|
+
continue;
|
|
445
|
+
extractStringsFromValue(value, strings);
|
|
446
|
+
}
|
|
447
|
+
if (strings.length === 0)
|
|
448
|
+
return;
|
|
449
|
+
const text = strings.join(" ");
|
|
450
|
+
const datesNormalized = normalizeDates(text);
|
|
451
|
+
const preprocessed = preprocessString(datesNormalized);
|
|
452
|
+
const sanitised = sanitiseString(preprocessed);
|
|
453
|
+
const stringTokens = tokenize(sanitised, DEFAULT_TOKENIZE_CONFIG);
|
|
454
|
+
if (stringTokens.length === 0)
|
|
455
|
+
return;
|
|
456
|
+
const sliced = stringTokens.slice(0, n);
|
|
457
|
+
const out = new Uint32Array(sliced.length);
|
|
458
|
+
for (let i = 0;i < sliced.length; i++) {
|
|
459
|
+
out[i] = getOrCreateTokenId(sliced[i], tokensMap);
|
|
460
|
+
}
|
|
461
|
+
return out;
|
|
462
|
+
}
|
|
428
463
|
function createSearchArrayMetadataNumeric(data, spec) {
|
|
429
464
|
const tokensMap = createTokensMap();
|
|
430
465
|
try {
|
|
431
|
-
const metadata =
|
|
466
|
+
const metadata = emptyNumericSearchMetadata();
|
|
432
467
|
for (const [id, item] of data) {
|
|
433
|
-
const
|
|
434
|
-
if (
|
|
435
|
-
metadata.set(id,
|
|
468
|
+
const result = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
469
|
+
if (result !== undefined) {
|
|
470
|
+
metadata.sorted.set(id, result.sorted);
|
|
471
|
+
if (result.firstN !== undefined) {
|
|
472
|
+
metadata.unsorted.set(id, result.firstN);
|
|
473
|
+
}
|
|
436
474
|
}
|
|
437
475
|
}
|
|
438
476
|
return metadata;
|
|
@@ -440,6 +478,9 @@ function createSearchArrayMetadataNumeric(data, spec) {
|
|
|
440
478
|
clearTokensMap(tokensMap);
|
|
441
479
|
}
|
|
442
480
|
}
|
|
481
|
+
function emptyNumericSearchMetadata() {
|
|
482
|
+
return { sorted: new Map, unsorted: new Map };
|
|
483
|
+
}
|
|
443
484
|
// src/common/numeric/createSearchLinkedMetadata.ts
|
|
444
485
|
function createSearchLinkedMetadataNumeric(primaryData, primaryMetadata, linkedData, linkedMetadata, foreignKeyGetter) {
|
|
445
486
|
const primaryToLinked = new Map;
|
|
@@ -461,14 +502,19 @@ function createSearchLinkedMetadataNumeric(primaryData, primaryMetadata, linkedD
|
|
|
461
502
|
}
|
|
462
503
|
// src/common/numeric/updateSearchMetadata.ts
|
|
463
504
|
function updateSearchMetadataNumeric(metadata, objectId, obj, spec, tokensMap) {
|
|
464
|
-
const
|
|
465
|
-
if (
|
|
466
|
-
metadata.delete(objectId);
|
|
505
|
+
const result = obj != null ? prepareObjectForSearchNumeric(obj, spec, tokensMap) : undefined;
|
|
506
|
+
if (result === undefined) {
|
|
507
|
+
metadata.sorted.delete(objectId);
|
|
508
|
+
metadata.unsorted.delete(objectId);
|
|
467
509
|
return false;
|
|
510
|
+
}
|
|
511
|
+
metadata.sorted.set(objectId, result.sorted);
|
|
512
|
+
if (result.firstN !== undefined) {
|
|
513
|
+
metadata.unsorted.set(objectId, result.firstN);
|
|
468
514
|
} else {
|
|
469
|
-
metadata.
|
|
470
|
-
return true;
|
|
515
|
+
metadata.unsorted.delete(objectId);
|
|
471
516
|
}
|
|
517
|
+
return true;
|
|
472
518
|
}
|
|
473
519
|
function updateSearchMetadataBatchNumeric(metadata, batch, spec) {
|
|
474
520
|
if (batch.length === 0) {
|
|
@@ -492,7 +538,9 @@ function updateSearchMetadataBatchNumeric(metadata, batch, spec) {
|
|
|
492
538
|
}
|
|
493
539
|
}
|
|
494
540
|
function removeFromSearchMetadataNumeric(metadata, objectId) {
|
|
495
|
-
|
|
541
|
+
const had = metadata.sorted.delete(objectId);
|
|
542
|
+
metadata.unsorted.delete(objectId);
|
|
543
|
+
return had;
|
|
496
544
|
}
|
|
497
545
|
function removeFromSearchMetadataBatchNumeric(metadata, objectIds) {
|
|
498
546
|
if (objectIds.length === 0) {
|
|
@@ -500,9 +548,10 @@ function removeFromSearchMetadataBatchNumeric(metadata, objectIds) {
|
|
|
500
548
|
}
|
|
501
549
|
let removed = 0;
|
|
502
550
|
for (const id of objectIds) {
|
|
503
|
-
|
|
551
|
+
const had = metadata.sorted.delete(id);
|
|
552
|
+
metadata.unsorted.delete(id);
|
|
553
|
+
if (had)
|
|
504
554
|
removed++;
|
|
505
|
-
}
|
|
506
555
|
}
|
|
507
556
|
return removed;
|
|
508
557
|
}
|
|
@@ -692,6 +741,106 @@ function allTokensMatchNumeric(searchTokenStrs, targetTokens, opts) {
|
|
|
692
741
|
return allPreparedTokensMatch(preparedTokens, targetTokens, opts);
|
|
693
742
|
}
|
|
694
743
|
|
|
744
|
+
// src/common/numeric/scoring.ts
|
|
745
|
+
function orderedTokenize(input) {
|
|
746
|
+
return tokenize(sanitiseString(preprocessString(normalizeDates(input))), DEFAULT_TOKENIZE_CONFIG);
|
|
747
|
+
}
|
|
748
|
+
function scoreOne(query, qTokens, itemTokens, exactKeys) {
|
|
749
|
+
if (exactKeys && exactKeys.length > 0) {
|
|
750
|
+
for (let i = 0;i < exactKeys.length; i++) {
|
|
751
|
+
if (exactKeys[i] === query)
|
|
752
|
+
return 1e5;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
if (qTokens.length === 0)
|
|
756
|
+
return 0;
|
|
757
|
+
if (itemTokens.length === 0)
|
|
758
|
+
return 1;
|
|
759
|
+
let qi = 0;
|
|
760
|
+
const positions = [];
|
|
761
|
+
for (let i = 0;i < itemTokens.length; i++) {
|
|
762
|
+
if (qi < qTokens.length && itemTokens[i].startsWith(qTokens[qi])) {
|
|
763
|
+
positions.push(i);
|
|
764
|
+
qi++;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
if (qi === 0)
|
|
768
|
+
return 1;
|
|
769
|
+
let score = 50;
|
|
770
|
+
if (qi === qTokens.length)
|
|
771
|
+
score += 100;
|
|
772
|
+
if (positions[0] === 0)
|
|
773
|
+
score += 50;
|
|
774
|
+
let perfect = qi === qTokens.length;
|
|
775
|
+
if (perfect) {
|
|
776
|
+
for (let i = 0;i < positions.length; i++) {
|
|
777
|
+
if (positions[i] !== i) {
|
|
778
|
+
perfect = false;
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (perfect)
|
|
784
|
+
score += 80;
|
|
785
|
+
if (positions.length >= 2) {
|
|
786
|
+
const span = positions[positions.length - 1] - positions[0] + 1;
|
|
787
|
+
score += positions.length / span * 30;
|
|
788
|
+
}
|
|
789
|
+
let totalLen = 0;
|
|
790
|
+
for (const t of itemTokens)
|
|
791
|
+
totalLen += t.length + 1;
|
|
792
|
+
score -= totalLen * 0.1;
|
|
793
|
+
return score;
|
|
794
|
+
}
|
|
795
|
+
function scoreBag(qTokens, itemTokens, perTokenWeight = 30) {
|
|
796
|
+
if (qTokens.length === 0 || itemTokens.length === 0)
|
|
797
|
+
return 0;
|
|
798
|
+
const usedItemIdx = new Set;
|
|
799
|
+
let score = 0;
|
|
800
|
+
for (const qt of qTokens) {
|
|
801
|
+
for (let i = 0;i < itemTokens.length; i++) {
|
|
802
|
+
if (usedItemIdx.has(i))
|
|
803
|
+
continue;
|
|
804
|
+
if (itemTokens[i].startsWith(qt)) {
|
|
805
|
+
score += perTokenWeight;
|
|
806
|
+
usedItemIdx.add(i);
|
|
807
|
+
break;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return score;
|
|
812
|
+
}
|
|
813
|
+
function scoreOrderAndPresence(qTokens, itemTokens, weights) {
|
|
814
|
+
const orderedWeight = weights?.ordered ?? 30;
|
|
815
|
+
const presenceWeight = weights?.presence ?? 10;
|
|
816
|
+
if (qTokens.length === 0 || itemTokens.length === 0)
|
|
817
|
+
return 0;
|
|
818
|
+
const matchedQueryIndices = new Set;
|
|
819
|
+
let qi = 0;
|
|
820
|
+
let score = 0;
|
|
821
|
+
for (let i = 0;i < itemTokens.length && qi < qTokens.length; i++) {
|
|
822
|
+
if (itemTokens[i].startsWith(qTokens[qi])) {
|
|
823
|
+
score += orderedWeight;
|
|
824
|
+
matchedQueryIndices.add(qi);
|
|
825
|
+
qi++;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (matchedQueryIndices.size < qTokens.length) {
|
|
829
|
+
for (let qj = 0;qj < qTokens.length; qj++) {
|
|
830
|
+
if (matchedQueryIndices.has(qj))
|
|
831
|
+
continue;
|
|
832
|
+
const qt = qTokens[qj];
|
|
833
|
+
for (let i = 0;i < itemTokens.length; i++) {
|
|
834
|
+
if (itemTokens[i].startsWith(qt)) {
|
|
835
|
+
score += presenceWeight;
|
|
836
|
+
break;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return score;
|
|
842
|
+
}
|
|
843
|
+
|
|
695
844
|
// src/common/numeric/searchInData.ts
|
|
696
845
|
function searchInDataReturnIdsNumeric(query, metadata, opts) {
|
|
697
846
|
return searchInDataReturnIdsWithLimitNumeric(query, metadata, Infinity, opts);
|
|
@@ -709,20 +858,48 @@ function searchInDataReturnObjectsNumeric(query, metadata, data, opts) {
|
|
|
709
858
|
}
|
|
710
859
|
function searchInDataReturnIdsWithLimitNumeric(query, metadata, limit, opts) {
|
|
711
860
|
const queryTokenStrs = prepareStringForSearch(query);
|
|
712
|
-
if (queryTokenStrs.length === 0)
|
|
861
|
+
if (queryTokenStrs.length === 0)
|
|
713
862
|
return [];
|
|
714
|
-
}
|
|
715
863
|
const preparedTokens = prepareQueryTokens(queryTokenStrs);
|
|
716
|
-
const
|
|
717
|
-
for (const [id, targetTokens] of metadata) {
|
|
864
|
+
const candidates = [];
|
|
865
|
+
for (const [id, targetTokens] of metadata.sorted) {
|
|
718
866
|
if (allPreparedTokensMatch(preparedTokens, targetTokens, opts)) {
|
|
719
|
-
|
|
720
|
-
if (results.length >= limit) {
|
|
721
|
-
break;
|
|
722
|
-
}
|
|
867
|
+
candidates.push(id);
|
|
723
868
|
}
|
|
724
869
|
}
|
|
725
|
-
|
|
870
|
+
if (candidates.length === 0)
|
|
871
|
+
return [];
|
|
872
|
+
const qTokens = orderedTokenize(query);
|
|
873
|
+
const hasUnsorted = metadata.unsorted.size > 0;
|
|
874
|
+
if (!hasUnsorted) {
|
|
875
|
+
if (limit === Infinity || limit >= candidates.length)
|
|
876
|
+
return candidates;
|
|
877
|
+
return candidates.slice(0, limit);
|
|
878
|
+
}
|
|
879
|
+
const scored = new Array(candidates.length);
|
|
880
|
+
for (let i = 0;i < candidates.length; i++) {
|
|
881
|
+
const id = candidates[i];
|
|
882
|
+
const unsortedIds = metadata.unsorted.get(id);
|
|
883
|
+
if (unsortedIds === undefined) {
|
|
884
|
+
scored[i] = { id, score: 0, order: i };
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
const itemTokens = new Array(unsortedIds.length);
|
|
888
|
+
for (let j = 0;j < unsortedIds.length; j++) {
|
|
889
|
+
itemTokens[j] = tokens[unsortedIds[j]] ?? "";
|
|
890
|
+
}
|
|
891
|
+
scored[i] = { id, score: scoreOne(query, qTokens, itemTokens), order: i };
|
|
892
|
+
}
|
|
893
|
+
scored.sort((a, b) => {
|
|
894
|
+
if (a.score !== b.score)
|
|
895
|
+
return b.score - a.score;
|
|
896
|
+
return a.order - b.order;
|
|
897
|
+
});
|
|
898
|
+
const out = [];
|
|
899
|
+
const max = limit === Infinity ? scored.length : Math.min(limit, scored.length);
|
|
900
|
+
for (let i = 0;i < max; i++)
|
|
901
|
+
out.push(scored[i].id);
|
|
902
|
+
return out;
|
|
726
903
|
}
|
|
727
904
|
// src/common/numeric/findInLinkedArrays.ts
|
|
728
905
|
function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
@@ -733,11 +910,10 @@ function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
|
733
910
|
const preparedTokens = prepareQueryTokens(queryTokenStrs);
|
|
734
911
|
const positiveTokens = preparedTokens.filter((t) => !t.negated);
|
|
735
912
|
const negatedTokens = preparedTokens.filter((t) => t.negated);
|
|
736
|
-
const
|
|
913
|
+
const scored = [];
|
|
914
|
+
let orderCounter = 0;
|
|
737
915
|
for (const [primaryId, primary] of linked.primaryData) {
|
|
738
|
-
|
|
739
|
-
break;
|
|
740
|
-
const primaryTokens = linked.primaryMeta.get(primaryId);
|
|
916
|
+
const primaryTokens = linked.primaryMeta.sorted.get(primaryId);
|
|
741
917
|
if (!primaryTokens)
|
|
742
918
|
continue;
|
|
743
919
|
const linkedIds = linked.primaryToLinked.get(primaryId) || [];
|
|
@@ -748,22 +924,20 @@ function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
|
748
924
|
break;
|
|
749
925
|
}
|
|
750
926
|
}
|
|
751
|
-
if (negatedMatchesInPrimary)
|
|
927
|
+
if (negatedMatchesInPrimary)
|
|
752
928
|
continue;
|
|
753
|
-
}
|
|
754
929
|
let totalLength = primaryTokens.length;
|
|
755
930
|
for (const linkedId of linkedIds) {
|
|
756
|
-
const linkedTokens = linked.linkedMeta.get(linkedId);
|
|
757
|
-
if (linkedTokens)
|
|
931
|
+
const linkedTokens = linked.linkedMeta.sorted.get(linkedId);
|
|
932
|
+
if (linkedTokens)
|
|
758
933
|
totalLength += linkedTokens.length;
|
|
759
|
-
}
|
|
760
934
|
}
|
|
761
935
|
const allTokens = new Uint32Array(totalLength);
|
|
762
936
|
let offset = 0;
|
|
763
937
|
allTokens.set(primaryTokens, offset);
|
|
764
938
|
offset += primaryTokens.length;
|
|
765
939
|
for (const linkedId of linkedIds) {
|
|
766
|
-
const linkedTokens = linked.linkedMeta.get(linkedId);
|
|
940
|
+
const linkedTokens = linked.linkedMeta.sorted.get(linkedId);
|
|
767
941
|
if (linkedTokens) {
|
|
768
942
|
allTokens.set(linkedTokens, offset);
|
|
769
943
|
offset += linkedTokens.length;
|
|
@@ -777,230 +951,289 @@ function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
|
|
|
777
951
|
break;
|
|
778
952
|
}
|
|
779
953
|
}
|
|
780
|
-
if (allPositiveMatch)
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
954
|
+
if (!allPositiveMatch)
|
|
955
|
+
continue;
|
|
956
|
+
let anyMatchInPrimary = false;
|
|
957
|
+
let anyMatchInLinked = false;
|
|
958
|
+
const matchingLinkedIds = new Set;
|
|
959
|
+
const tokensMatchingPrimary = new Set;
|
|
960
|
+
for (const preparedToken of positiveTokens) {
|
|
961
|
+
if (matchPreparedTokenInSortedList(preparedToken, primaryTokens, opts)) {
|
|
962
|
+
anyMatchInPrimary = true;
|
|
963
|
+
tokensMatchingPrimary.add(preparedToken);
|
|
790
964
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (matchesNegatedToken) {
|
|
804
|
-
continue;
|
|
805
|
-
}
|
|
806
|
-
if (tokensForLinkedMatching.length > 0) {
|
|
807
|
-
const matchesAllNonPrimaryTokens = tokensForLinkedMatching.every((preparedToken) => matchPreparedTokenInSortedList(preparedToken, linkedTokens, opts));
|
|
808
|
-
if (matchesAllNonPrimaryTokens) {
|
|
809
|
-
anyMatchInLinked = true;
|
|
810
|
-
matchingLinkedIds.add(linkedId);
|
|
811
|
-
}
|
|
812
|
-
} else {
|
|
813
|
-
matchingLinkedIds.add(linkedId);
|
|
814
|
-
}
|
|
965
|
+
}
|
|
966
|
+
const tokensForLinkedMatching = positiveTokens.filter((t) => !tokensMatchingPrimary.has(t));
|
|
967
|
+
if (tokensForLinkedMatching.length > 0 || negatedTokens.length > 0) {
|
|
968
|
+
for (const linkedId of linkedIds) {
|
|
969
|
+
const linkedTokens = linked.linkedMeta.sorted.get(linkedId);
|
|
970
|
+
if (!linkedTokens)
|
|
971
|
+
continue;
|
|
972
|
+
let matchesNegatedToken = false;
|
|
973
|
+
for (const negatedToken of negatedTokens) {
|
|
974
|
+
if (matchPreparedTokenInSortedList(negatedToken, linkedTokens, opts)) {
|
|
975
|
+
matchesNegatedToken = true;
|
|
976
|
+
break;
|
|
815
977
|
}
|
|
816
978
|
}
|
|
979
|
+
if (matchesNegatedToken)
|
|
980
|
+
continue;
|
|
981
|
+
if (tokensForLinkedMatching.length > 0) {
|
|
982
|
+
const matchesAllNonPrimaryTokens = tokensForLinkedMatching.every((preparedToken) => matchPreparedTokenInSortedList(preparedToken, linkedTokens, opts));
|
|
983
|
+
if (matchesAllNonPrimaryTokens) {
|
|
984
|
+
anyMatchInLinked = true;
|
|
985
|
+
matchingLinkedIds.add(linkedId);
|
|
986
|
+
}
|
|
987
|
+
} else {
|
|
988
|
+
matchingLinkedIds.add(linkedId);
|
|
989
|
+
}
|
|
817
990
|
}
|
|
818
|
-
|
|
991
|
+
}
|
|
992
|
+
if (tokensForLinkedMatching.length > 0 && matchingLinkedIds.size === 0) {
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
const matchedLinked = Array.from(matchingLinkedIds).map((id) => linked.linkedData.get(id)).filter((item) => item !== undefined);
|
|
996
|
+
const result = {
|
|
997
|
+
primary,
|
|
998
|
+
linked: matchedLinked,
|
|
999
|
+
matchedIn: anyMatchInPrimary && anyMatchInLinked ? "both" : anyMatchInPrimary ? "primary" : "linked"
|
|
1000
|
+
};
|
|
1001
|
+
scored.push({
|
|
1002
|
+
result,
|
|
1003
|
+
score: 0,
|
|
1004
|
+
order: orderCounter++,
|
|
1005
|
+
primaryId,
|
|
1006
|
+
matchedLinkedIds: Array.from(matchingLinkedIds)
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
if (scored.length === 0) {
|
|
1010
|
+
return { queryTokens: queryTokenStrs, results: [], hasNegation: negatedTokens.length > 0 };
|
|
1011
|
+
}
|
|
1012
|
+
const qTokens = orderedTokenize(query);
|
|
1013
|
+
const hasUnsorted = linked.primaryMeta.unsorted.size > 0 || linked.linkedMeta.unsorted.size > 0;
|
|
1014
|
+
if (hasUnsorted) {
|
|
1015
|
+
for (const s of scored) {
|
|
1016
|
+
const itemTokenIds = [];
|
|
1017
|
+
const pu = linked.primaryMeta.unsorted.get(s.primaryId);
|
|
1018
|
+
if (pu)
|
|
1019
|
+
for (const tid of pu)
|
|
1020
|
+
itemTokenIds.push(tid);
|
|
1021
|
+
for (const lid of s.matchedLinkedIds) {
|
|
1022
|
+
const lu = linked.linkedMeta.unsorted.get(lid);
|
|
1023
|
+
if (lu)
|
|
1024
|
+
for (const tid of lu)
|
|
1025
|
+
itemTokenIds.push(tid);
|
|
1026
|
+
}
|
|
1027
|
+
if (itemTokenIds.length === 0) {
|
|
1028
|
+
s.score = 0;
|
|
819
1029
|
continue;
|
|
820
1030
|
}
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
});
|
|
1031
|
+
const itemTokens = new Array(itemTokenIds.length);
|
|
1032
|
+
for (let i = 0;i < itemTokenIds.length; i++) {
|
|
1033
|
+
itemTokens[i] = tokens[itemTokenIds[i]] ?? "";
|
|
1034
|
+
}
|
|
1035
|
+
s.score = scoreOne(query, qTokens, itemTokens);
|
|
827
1036
|
}
|
|
828
1037
|
}
|
|
1038
|
+
scored.sort((a, b) => {
|
|
1039
|
+
if (a.score !== b.score)
|
|
1040
|
+
return b.score - a.score;
|
|
1041
|
+
return a.order - b.order;
|
|
1042
|
+
});
|
|
1043
|
+
const max = Math.min(limit, scored.length);
|
|
1044
|
+
const results = new Array(max);
|
|
1045
|
+
for (let i = 0;i < max; i++)
|
|
1046
|
+
results[i] = scored[i].result;
|
|
829
1047
|
return { queryTokens: queryTokenStrs, results, hasNegation: negatedTokens.length > 0 };
|
|
830
1048
|
}
|
|
831
1049
|
function findInLinkedArraysSimpleNumeric(query, linked, limit = 10, opts) {
|
|
832
1050
|
return findInLinkedArraysNumeric(query, linked, limit, opts).results;
|
|
833
1051
|
}
|
|
834
1052
|
// src/common/numeric/AugmentedMetadata.ts
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
if (
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
if (tokens2 && tokens2.length > 0) {
|
|
855
|
-
this.augmentedTokens.set(id, tokens2);
|
|
1053
|
+
function mergeSortedTokenArrays(a, b) {
|
|
1054
|
+
const merged = new Uint32Array(a.length + b.length);
|
|
1055
|
+
let i = 0, j = 0, k = 0;
|
|
1056
|
+
let lastToken = -1;
|
|
1057
|
+
while (i < a.length && j < b.length) {
|
|
1058
|
+
const tokenA = a[i];
|
|
1059
|
+
const tokenB = b[j];
|
|
1060
|
+
if (tokenA < tokenB) {
|
|
1061
|
+
if (tokenA !== lastToken) {
|
|
1062
|
+
merged[k++] = tokenA;
|
|
1063
|
+
lastToken = tokenA;
|
|
1064
|
+
}
|
|
1065
|
+
i++;
|
|
1066
|
+
} else if (tokenA > tokenB) {
|
|
1067
|
+
if (tokenB !== lastToken) {
|
|
1068
|
+
merged[k++] = tokenB;
|
|
1069
|
+
lastToken = tokenB;
|
|
1070
|
+
}
|
|
1071
|
+
j++;
|
|
856
1072
|
} else {
|
|
857
|
-
|
|
1073
|
+
if (tokenA !== lastToken) {
|
|
1074
|
+
merged[k++] = tokenA;
|
|
1075
|
+
lastToken = tokenA;
|
|
1076
|
+
}
|
|
1077
|
+
i++;
|
|
1078
|
+
j++;
|
|
858
1079
|
}
|
|
859
|
-
clearTokensMap(tokensMap);
|
|
860
1080
|
}
|
|
861
|
-
|
|
862
|
-
const
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
continue;
|
|
867
|
-
}
|
|
868
|
-
const tokens2 = prepareObjectForSearchNumeric(augmentedData, this.spec, tokensMap);
|
|
869
|
-
if (tokens2 && tokens2.length > 0) {
|
|
870
|
-
this.augmentedTokens.set(id, tokens2);
|
|
871
|
-
} else {
|
|
872
|
-
this.augmentedTokens.delete(id);
|
|
873
|
-
}
|
|
1081
|
+
while (i < a.length) {
|
|
1082
|
+
const tokenA = a[i];
|
|
1083
|
+
if (tokenA !== lastToken) {
|
|
1084
|
+
merged[k++] = tokenA;
|
|
1085
|
+
lastToken = tokenA;
|
|
874
1086
|
}
|
|
875
|
-
|
|
1087
|
+
i++;
|
|
876
1088
|
}
|
|
877
|
-
|
|
878
|
-
|
|
1089
|
+
while (j < b.length) {
|
|
1090
|
+
const tokenB = b[j];
|
|
1091
|
+
if (tokenB !== lastToken) {
|
|
1092
|
+
merged[k++] = tokenB;
|
|
1093
|
+
lastToken = tokenB;
|
|
1094
|
+
}
|
|
1095
|
+
j++;
|
|
879
1096
|
}
|
|
880
|
-
|
|
881
|
-
|
|
1097
|
+
return merged.slice(0, k);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
class AugmentedSortedMap extends Map {
|
|
1101
|
+
base;
|
|
1102
|
+
augTokens;
|
|
1103
|
+
constructor(base, augTokens) {
|
|
1104
|
+
super();
|
|
1105
|
+
this.base = base;
|
|
1106
|
+
this.augTokens = augTokens;
|
|
882
1107
|
}
|
|
883
1108
|
get(id) {
|
|
884
|
-
const baseTokens = this.
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
if (
|
|
1109
|
+
const baseTokens = this.base.get(id);
|
|
1110
|
+
const augTokens = this.augTokens.get(id);
|
|
1111
|
+
if (baseTokens === undefined)
|
|
1112
|
+
return augTokens;
|
|
1113
|
+
if (augTokens === undefined)
|
|
889
1114
|
return baseTokens;
|
|
890
|
-
return
|
|
1115
|
+
return mergeSortedTokenArrays(baseTokens, augTokens);
|
|
891
1116
|
}
|
|
892
1117
|
has(id) {
|
|
893
|
-
return this.
|
|
1118
|
+
return this.base.has(id) || this.augTokens.has(id);
|
|
894
1119
|
}
|
|
895
1120
|
get size() {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
if (baseResult.done) {
|
|
905
|
-
return { done: true, value: undefined };
|
|
906
|
-
}
|
|
907
|
-
const [id, baseTokens] = baseResult.value;
|
|
908
|
-
const augTokens = self.augmentedTokens.get(id);
|
|
909
|
-
const tokens2 = augTokens ? self.mergeSortedTokenArrays(baseTokens, augTokens) : baseTokens;
|
|
910
|
-
return { done: false, value: [id, tokens2] };
|
|
911
|
-
},
|
|
912
|
-
[Symbol.iterator]() {
|
|
913
|
-
return this;
|
|
914
|
-
},
|
|
915
|
-
[Symbol.dispose]() {}
|
|
916
|
-
};
|
|
1121
|
+
if (this.augTokens.size === 0)
|
|
1122
|
+
return this.base.size;
|
|
1123
|
+
let count = this.base.size;
|
|
1124
|
+
for (const id of this.augTokens.keys()) {
|
|
1125
|
+
if (!this.base.has(id))
|
|
1126
|
+
count++;
|
|
1127
|
+
}
|
|
1128
|
+
return count;
|
|
917
1129
|
}
|
|
918
1130
|
keys() {
|
|
919
|
-
return this.
|
|
1131
|
+
return this.unionIdIterator();
|
|
920
1132
|
}
|
|
921
1133
|
values() {
|
|
922
1134
|
const self = this;
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
return tokens2 ? { done: false, value: tokens2 } : { done: true, value: undefined };
|
|
932
|
-
},
|
|
933
|
-
[Symbol.iterator]() {
|
|
934
|
-
return this;
|
|
935
|
-
},
|
|
936
|
-
[Symbol.dispose]() {}
|
|
937
|
-
};
|
|
1135
|
+
function* gen() {
|
|
1136
|
+
for (const id of self.unionIdIterator()) {
|
|
1137
|
+
const tokens2 = self.get(id);
|
|
1138
|
+
if (tokens2 !== undefined)
|
|
1139
|
+
yield tokens2;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
return gen();
|
|
938
1143
|
}
|
|
939
1144
|
entries() {
|
|
940
|
-
|
|
1145
|
+
const self = this;
|
|
1146
|
+
function* gen() {
|
|
1147
|
+
for (const id of self.unionIdIterator()) {
|
|
1148
|
+
const tokens2 = self.get(id);
|
|
1149
|
+
if (tokens2 !== undefined)
|
|
1150
|
+
yield [id, tokens2];
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return gen();
|
|
1154
|
+
}
|
|
1155
|
+
[Symbol.iterator]() {
|
|
1156
|
+
return this.entries();
|
|
941
1157
|
}
|
|
942
1158
|
forEach(callbackfn) {
|
|
943
|
-
for (const [id, tokens2] of this) {
|
|
1159
|
+
for (const [id, tokens2] of this.entries()) {
|
|
944
1160
|
callbackfn(tokens2, id, this);
|
|
945
1161
|
}
|
|
946
1162
|
}
|
|
947
1163
|
set(_key, _value) {
|
|
948
|
-
throw new Error("AugmentedMetadata.
|
|
1164
|
+
throw new Error("AugmentedMetadata.sorted is read-only. Use updateAugmented() instead.");
|
|
949
1165
|
}
|
|
950
1166
|
delete(_key) {
|
|
951
|
-
throw new Error("AugmentedMetadata.
|
|
1167
|
+
throw new Error("AugmentedMetadata.sorted is read-only. Use clearAugmented() instead.");
|
|
952
1168
|
}
|
|
953
1169
|
clear() {
|
|
954
|
-
throw new Error("AugmentedMetadata.
|
|
1170
|
+
throw new Error("AugmentedMetadata.sorted is read-only. Use clearAllAugmented() instead.");
|
|
955
1171
|
}
|
|
956
1172
|
get [Symbol.toStringTag]() {
|
|
957
|
-
return "
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const tokenA = a[i];
|
|
965
|
-
const tokenB = b[j];
|
|
966
|
-
if (tokenA < tokenB) {
|
|
967
|
-
if (tokenA !== lastToken) {
|
|
968
|
-
merged[k++] = tokenA;
|
|
969
|
-
lastToken = tokenA;
|
|
970
|
-
}
|
|
971
|
-
i++;
|
|
972
|
-
} else if (tokenA > tokenB) {
|
|
973
|
-
if (tokenB !== lastToken) {
|
|
974
|
-
merged[k++] = tokenB;
|
|
975
|
-
lastToken = tokenB;
|
|
976
|
-
}
|
|
977
|
-
j++;
|
|
978
|
-
} else {
|
|
979
|
-
if (tokenA !== lastToken) {
|
|
980
|
-
merged[k++] = tokenA;
|
|
981
|
-
lastToken = tokenA;
|
|
982
|
-
}
|
|
983
|
-
i++;
|
|
984
|
-
j++;
|
|
985
|
-
}
|
|
1173
|
+
return "AugmentedSortedMap";
|
|
1174
|
+
}
|
|
1175
|
+
*unionIdIterator() {
|
|
1176
|
+
const seen = new Set;
|
|
1177
|
+
for (const id of this.base.keys()) {
|
|
1178
|
+
seen.add(id);
|
|
1179
|
+
yield id;
|
|
986
1180
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
merged[k++] = tokenA;
|
|
991
|
-
lastToken = tokenA;
|
|
992
|
-
}
|
|
993
|
-
i++;
|
|
1181
|
+
for (const id of this.augTokens.keys()) {
|
|
1182
|
+
if (!seen.has(id))
|
|
1183
|
+
yield id;
|
|
994
1184
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
class AugmentedMetadata {
|
|
1189
|
+
sorted;
|
|
1190
|
+
unsorted;
|
|
1191
|
+
augmentedTokens;
|
|
1192
|
+
spec;
|
|
1193
|
+
constructor(baseMetadata, spec, augmentedDataMap) {
|
|
1194
|
+
this.augmentedTokens = new Map;
|
|
1195
|
+
this.spec = spec;
|
|
1196
|
+
this.sorted = new AugmentedSortedMap(baseMetadata.sorted, this.augmentedTokens);
|
|
1197
|
+
this.unsorted = baseMetadata.unsorted;
|
|
1198
|
+
if (augmentedDataMap && augmentedDataMap.size > 0) {
|
|
1199
|
+
this.updateAugmentedBatch(augmentedDataMap);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
updateAugmented(id, augmentedData) {
|
|
1203
|
+
if (augmentedData == null) {
|
|
1204
|
+
this.augmentedTokens.delete(id);
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
const tokensMap = createTokensMap();
|
|
1208
|
+
const prepared = prepareObjectForSearchNumeric(augmentedData, this.spec, tokensMap);
|
|
1209
|
+
clearTokensMap(tokensMap);
|
|
1210
|
+
if (prepared !== undefined && prepared.sorted.length > 0) {
|
|
1211
|
+
this.augmentedTokens.set(id, prepared.sorted);
|
|
1212
|
+
} else {
|
|
1213
|
+
this.augmentedTokens.delete(id);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
updateAugmentedBatch(augmentedDataMap) {
|
|
1217
|
+
const tokensMap = createTokensMap();
|
|
1218
|
+
for (const [id, augmentedData] of augmentedDataMap) {
|
|
1219
|
+
if (augmentedData == null) {
|
|
1220
|
+
this.augmentedTokens.delete(id);
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
const prepared = prepareObjectForSearchNumeric(augmentedData, this.spec, tokensMap);
|
|
1224
|
+
if (prepared !== undefined && prepared.sorted.length > 0) {
|
|
1225
|
+
this.augmentedTokens.set(id, prepared.sorted);
|
|
1226
|
+
} else {
|
|
1227
|
+
this.augmentedTokens.delete(id);
|
|
1000
1228
|
}
|
|
1001
|
-
j++;
|
|
1002
1229
|
}
|
|
1003
|
-
|
|
1230
|
+
clearTokensMap(tokensMap);
|
|
1231
|
+
}
|
|
1232
|
+
clearAugmented(id) {
|
|
1233
|
+
this.augmentedTokens.delete(id);
|
|
1234
|
+
}
|
|
1235
|
+
clearAllAugmented() {
|
|
1236
|
+
this.augmentedTokens.clear();
|
|
1004
1237
|
}
|
|
1005
1238
|
}
|
|
1006
1239
|
// src/common/numeric/syncSearchArrayMetadata.ts
|
|
@@ -1013,6 +1246,25 @@ function tokensEqual(a, b) {
|
|
|
1013
1246
|
}
|
|
1014
1247
|
return true;
|
|
1015
1248
|
}
|
|
1249
|
+
function firstNEqual(a, b) {
|
|
1250
|
+
if (a === undefined && b === undefined)
|
|
1251
|
+
return true;
|
|
1252
|
+
if (a === undefined || b === undefined)
|
|
1253
|
+
return false;
|
|
1254
|
+
return tokensEqual(a, b);
|
|
1255
|
+
}
|
|
1256
|
+
function applyPreparedTokens(metadata, id, result) {
|
|
1257
|
+
metadata.sorted.set(id, result.sorted);
|
|
1258
|
+
if (result.firstN !== undefined) {
|
|
1259
|
+
metadata.unsorted.set(id, result.firstN);
|
|
1260
|
+
} else {
|
|
1261
|
+
metadata.unsorted.delete(id);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
function deletePreparedTokens(metadata, id) {
|
|
1265
|
+
metadata.sorted.delete(id);
|
|
1266
|
+
metadata.unsorted.delete(id);
|
|
1267
|
+
}
|
|
1016
1268
|
function syncSearchArrayMetadataNumeric(metadata, newData, spec) {
|
|
1017
1269
|
const result = {
|
|
1018
1270
|
added: 0,
|
|
@@ -1023,30 +1275,31 @@ function syncSearchArrayMetadataNumeric(metadata, newData, spec) {
|
|
|
1023
1275
|
removedIds: []
|
|
1024
1276
|
};
|
|
1025
1277
|
const tokensMap = createTokensMap();
|
|
1026
|
-
for (const id of metadata.keys()) {
|
|
1278
|
+
for (const id of metadata.sorted.keys()) {
|
|
1027
1279
|
if (!newData.has(id)) {
|
|
1028
|
-
metadata
|
|
1280
|
+
deletePreparedTokens(metadata, id);
|
|
1029
1281
|
result.removed++;
|
|
1030
1282
|
result.removedIds.push(id);
|
|
1031
1283
|
}
|
|
1032
1284
|
}
|
|
1033
1285
|
for (const [id, item] of newData) {
|
|
1034
|
-
const
|
|
1035
|
-
if (
|
|
1036
|
-
if (metadata.has(id)) {
|
|
1037
|
-
metadata
|
|
1286
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1287
|
+
if (prepared === undefined) {
|
|
1288
|
+
if (metadata.sorted.has(id)) {
|
|
1289
|
+
deletePreparedTokens(metadata, id);
|
|
1038
1290
|
result.removed++;
|
|
1039
1291
|
result.removedIds.push(id);
|
|
1040
1292
|
}
|
|
1041
1293
|
continue;
|
|
1042
1294
|
}
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
|
|
1295
|
+
const existingSorted = metadata.sorted.get(id);
|
|
1296
|
+
const existingFirstN = metadata.unsorted.get(id);
|
|
1297
|
+
if (existingSorted === undefined) {
|
|
1298
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1046
1299
|
result.added++;
|
|
1047
1300
|
result.addedIds.push(id);
|
|
1048
|
-
} else if (!tokensEqual(
|
|
1049
|
-
metadata
|
|
1301
|
+
} else if (!tokensEqual(existingSorted, prepared.sorted) || !firstNEqual(existingFirstN, prepared.firstN)) {
|
|
1302
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1050
1303
|
result.updated++;
|
|
1051
1304
|
result.updatedIds.push(id);
|
|
1052
1305
|
}
|
|
@@ -1066,7 +1319,7 @@ function syncSearchArrayMetadataNumericWithPrevious(metadata, previousData, newD
|
|
|
1066
1319
|
const tokensMap = createTokensMap();
|
|
1067
1320
|
for (const id of previousData.keys()) {
|
|
1068
1321
|
if (!newData.has(id)) {
|
|
1069
|
-
metadata
|
|
1322
|
+
deletePreparedTokens(metadata, id);
|
|
1070
1323
|
result.removed++;
|
|
1071
1324
|
result.removedIds.push(id);
|
|
1072
1325
|
}
|
|
@@ -1074,22 +1327,23 @@ function syncSearchArrayMetadataNumericWithPrevious(metadata, previousData, newD
|
|
|
1074
1327
|
for (const [id, item] of newData) {
|
|
1075
1328
|
const wasInPrevious = previousData.has(id);
|
|
1076
1329
|
if (!wasInPrevious) {
|
|
1077
|
-
const
|
|
1078
|
-
if (
|
|
1079
|
-
metadata
|
|
1330
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1331
|
+
if (prepared !== undefined) {
|
|
1332
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1080
1333
|
result.added++;
|
|
1081
1334
|
result.addedIds.push(id);
|
|
1082
1335
|
}
|
|
1083
1336
|
} else if (!options?.skipUpdateCheck) {
|
|
1084
|
-
const
|
|
1085
|
-
if (
|
|
1086
|
-
metadata
|
|
1337
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1338
|
+
if (prepared === undefined) {
|
|
1339
|
+
deletePreparedTokens(metadata, id);
|
|
1087
1340
|
result.removed++;
|
|
1088
1341
|
result.removedIds.push(id);
|
|
1089
1342
|
} else {
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1343
|
+
const existingSorted = metadata.sorted.get(id);
|
|
1344
|
+
const existingFirstN = metadata.unsorted.get(id);
|
|
1345
|
+
if (existingSorted && (!tokensEqual(existingSorted, prepared.sorted) || !firstNEqual(existingFirstN, prepared.firstN))) {
|
|
1346
|
+
applyPreparedTokens(metadata, id, prepared);
|
|
1093
1347
|
result.updated++;
|
|
1094
1348
|
result.updatedIds.push(id);
|
|
1095
1349
|
}
|
|
@@ -1109,29 +1363,48 @@ function tokensEqual2(a, b) {
|
|
|
1109
1363
|
}
|
|
1110
1364
|
return true;
|
|
1111
1365
|
}
|
|
1366
|
+
function firstNEqual2(a, b) {
|
|
1367
|
+
if (a === undefined && b === undefined)
|
|
1368
|
+
return true;
|
|
1369
|
+
if (a === undefined || b === undefined)
|
|
1370
|
+
return false;
|
|
1371
|
+
return tokensEqual2(a, b);
|
|
1372
|
+
}
|
|
1373
|
+
function applyOrClear(meta, id, prepared) {
|
|
1374
|
+
if (prepared === undefined) {
|
|
1375
|
+
meta.sorted.delete(id);
|
|
1376
|
+
meta.unsorted.delete(id);
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
meta.sorted.set(id, prepared.sorted);
|
|
1380
|
+
if (prepared.firstN !== undefined) {
|
|
1381
|
+
meta.unsorted.set(id, prepared.firstN);
|
|
1382
|
+
} else {
|
|
1383
|
+
meta.unsorted.delete(id);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
function clearTokens(meta, id) {
|
|
1387
|
+
meta.sorted.delete(id);
|
|
1388
|
+
meta.unsorted.delete(id);
|
|
1389
|
+
}
|
|
1112
1390
|
function upsertPrimaryItemNumeric(linked, item, spec) {
|
|
1113
1391
|
const id = item._id;
|
|
1114
1392
|
const wasAdded = !linked.primaryData.has(id);
|
|
1115
1393
|
linked.primaryData.set(id, item);
|
|
1116
1394
|
const tokensMap = createTokensMap();
|
|
1117
|
-
const
|
|
1395
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1118
1396
|
clearTokensMap(tokensMap);
|
|
1119
|
-
|
|
1120
|
-
linked.primaryMeta.set(id, tokens2);
|
|
1121
|
-
} else {
|
|
1122
|
-
linked.primaryMeta.delete(id);
|
|
1123
|
-
}
|
|
1397
|
+
applyOrClear(linked.primaryMeta, id, prepared);
|
|
1124
1398
|
if (wasAdded && !linked.primaryToLinked.has(id)) {
|
|
1125
1399
|
linked.primaryToLinked.set(id, []);
|
|
1126
1400
|
}
|
|
1127
1401
|
return { added: wasAdded };
|
|
1128
1402
|
}
|
|
1129
1403
|
function removePrimaryItemNumeric(linked, primaryId) {
|
|
1130
|
-
if (!linked.primaryData.has(primaryId))
|
|
1404
|
+
if (!linked.primaryData.has(primaryId))
|
|
1131
1405
|
return false;
|
|
1132
|
-
}
|
|
1133
1406
|
linked.primaryData.delete(primaryId);
|
|
1134
|
-
linked.primaryMeta
|
|
1407
|
+
clearTokens(linked.primaryMeta, primaryId);
|
|
1135
1408
|
linked.primaryToLinked.delete(primaryId);
|
|
1136
1409
|
return true;
|
|
1137
1410
|
}
|
|
@@ -1140,35 +1413,28 @@ function upsertLinkedItemNumeric(linked, item, foreignKeyGetter, spec) {
|
|
|
1140
1413
|
const newPrimaryId = foreignKeyGetter(item);
|
|
1141
1414
|
let previousPrimaryId;
|
|
1142
1415
|
const existingItem = linked.linkedData.get(id);
|
|
1143
|
-
if (existingItem)
|
|
1416
|
+
if (existingItem)
|
|
1144
1417
|
previousPrimaryId = foreignKeyGetter(existingItem);
|
|
1145
|
-
}
|
|
1146
1418
|
const wasAdded = !existingItem;
|
|
1147
1419
|
linked.linkedData.set(id, item);
|
|
1148
1420
|
const tokensMap = createTokensMap();
|
|
1149
|
-
const
|
|
1421
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1150
1422
|
clearTokensMap(tokensMap);
|
|
1151
|
-
|
|
1152
|
-
linked.linkedMeta.set(id, tokens2);
|
|
1153
|
-
} else {
|
|
1154
|
-
linked.linkedMeta.delete(id);
|
|
1155
|
-
}
|
|
1423
|
+
applyOrClear(linked.linkedMeta, id, prepared);
|
|
1156
1424
|
if (previousPrimaryId !== newPrimaryId) {
|
|
1157
1425
|
if (previousPrimaryId) {
|
|
1158
1426
|
const oldList = linked.primaryToLinked.get(previousPrimaryId);
|
|
1159
1427
|
if (oldList) {
|
|
1160
1428
|
const index = oldList.indexOf(id);
|
|
1161
|
-
if (index !== -1)
|
|
1429
|
+
if (index !== -1)
|
|
1162
1430
|
oldList.splice(index, 1);
|
|
1163
|
-
}
|
|
1164
1431
|
}
|
|
1165
1432
|
}
|
|
1166
1433
|
if (newPrimaryId) {
|
|
1167
1434
|
const newList = linked.primaryToLinked.get(newPrimaryId);
|
|
1168
1435
|
if (newList) {
|
|
1169
|
-
if (!newList.includes(id))
|
|
1436
|
+
if (!newList.includes(id))
|
|
1170
1437
|
newList.push(id);
|
|
1171
|
-
}
|
|
1172
1438
|
} else {
|
|
1173
1439
|
linked.primaryToLinked.set(newPrimaryId, [id]);
|
|
1174
1440
|
}
|
|
@@ -1181,64 +1447,57 @@ function upsertLinkedItemNumeric(linked, item, foreignKeyGetter, spec) {
|
|
|
1181
1447
|
}
|
|
1182
1448
|
function removeLinkedItemNumeric(linked, linkedId, foreignKeyGetter) {
|
|
1183
1449
|
const existingItem = linked.linkedData.get(linkedId);
|
|
1184
|
-
if (!existingItem)
|
|
1450
|
+
if (!existingItem)
|
|
1185
1451
|
return false;
|
|
1186
|
-
}
|
|
1187
1452
|
const primaryId = foreignKeyGetter(existingItem);
|
|
1188
1453
|
linked.linkedData.delete(linkedId);
|
|
1189
|
-
linked.linkedMeta
|
|
1454
|
+
clearTokens(linked.linkedMeta, linkedId);
|
|
1190
1455
|
if (primaryId) {
|
|
1191
1456
|
const list = linked.primaryToLinked.get(primaryId);
|
|
1192
1457
|
if (list) {
|
|
1193
1458
|
const index = list.indexOf(linkedId);
|
|
1194
|
-
if (index !== -1)
|
|
1459
|
+
if (index !== -1)
|
|
1195
1460
|
list.splice(index, 1);
|
|
1196
|
-
}
|
|
1197
1461
|
}
|
|
1198
1462
|
}
|
|
1199
1463
|
return true;
|
|
1200
1464
|
}
|
|
1201
1465
|
function syncLinkedItemsForPrimaryNumeric(linked, primaryId, newLinkedItems, foreignKeyGetter, spec) {
|
|
1202
|
-
const result = {
|
|
1203
|
-
added: 0,
|
|
1204
|
-
updated: 0,
|
|
1205
|
-
removed: 0
|
|
1206
|
-
};
|
|
1466
|
+
const result = { added: 0, updated: 0, removed: 0 };
|
|
1207
1467
|
const tokensMap = createTokensMap();
|
|
1208
1468
|
const currentLinkedIds = new Set(linked.primaryToLinked.get(primaryId) || []);
|
|
1209
1469
|
const newLinkedIds = new Set;
|
|
1210
1470
|
for (const [id, item] of newLinkedItems) {
|
|
1211
|
-
if (foreignKeyGetter(item) === primaryId)
|
|
1471
|
+
if (foreignKeyGetter(item) === primaryId)
|
|
1212
1472
|
newLinkedIds.add(id);
|
|
1213
|
-
}
|
|
1214
1473
|
}
|
|
1215
1474
|
for (const id of currentLinkedIds) {
|
|
1216
1475
|
if (!newLinkedIds.has(id)) {
|
|
1217
|
-
|
|
1218
|
-
if (item) {
|
|
1476
|
+
if (linked.linkedData.has(id)) {
|
|
1219
1477
|
linked.linkedData.delete(id);
|
|
1220
|
-
linked.linkedMeta
|
|
1478
|
+
clearTokens(linked.linkedMeta, id);
|
|
1221
1479
|
result.removed++;
|
|
1222
1480
|
}
|
|
1223
1481
|
}
|
|
1224
1482
|
}
|
|
1225
1483
|
for (const id of newLinkedIds) {
|
|
1226
1484
|
const item = newLinkedItems.get(id);
|
|
1227
|
-
const
|
|
1485
|
+
const prepared = prepareObjectForSearchNumeric(item, spec, tokensMap);
|
|
1228
1486
|
if (currentLinkedIds.has(id)) {
|
|
1229
|
-
const
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1487
|
+
const existingSorted = linked.linkedMeta.sorted.get(id);
|
|
1488
|
+
const existingFirstN = linked.linkedMeta.unsorted.get(id);
|
|
1489
|
+
if (prepared !== undefined) {
|
|
1490
|
+
if (!existingSorted || !tokensEqual2(existingSorted, prepared.sorted) || !firstNEqual2(existingFirstN, prepared.firstN)) {
|
|
1491
|
+
applyOrClear(linked.linkedMeta, id, prepared);
|
|
1233
1492
|
result.updated++;
|
|
1234
1493
|
}
|
|
1494
|
+
} else {
|
|
1495
|
+
clearTokens(linked.linkedMeta, id);
|
|
1235
1496
|
}
|
|
1236
1497
|
linked.linkedData.set(id, item);
|
|
1237
1498
|
} else {
|
|
1238
1499
|
linked.linkedData.set(id, item);
|
|
1239
|
-
|
|
1240
|
-
linked.linkedMeta.set(id, tokens2);
|
|
1241
|
-
}
|
|
1500
|
+
applyOrClear(linked.linkedMeta, id, prepared);
|
|
1242
1501
|
result.added++;
|
|
1243
1502
|
}
|
|
1244
1503
|
}
|
|
@@ -1246,6 +1505,43 @@ function syncLinkedItemsForPrimaryNumeric(linked, primaryId, newLinkedItems, for
|
|
|
1246
1505
|
clearTokensMap(tokensMap);
|
|
1247
1506
|
return result;
|
|
1248
1507
|
}
|
|
1508
|
+
// src/common/numeric/searchAndRank.ts
|
|
1509
|
+
function tokenIdsToStrings(tokenIds) {
|
|
1510
|
+
if (tokenIds === undefined)
|
|
1511
|
+
return;
|
|
1512
|
+
const out = new Array(tokenIds.length);
|
|
1513
|
+
for (let i = 0;i < tokenIds.length; i++) {
|
|
1514
|
+
out[i] = tokens[tokenIds[i]] ?? "";
|
|
1515
|
+
}
|
|
1516
|
+
return out;
|
|
1517
|
+
}
|
|
1518
|
+
function searchAndRankNumeric(query, data, metadata, options) {
|
|
1519
|
+
const { primaryTextFn, exactKeysFn, limit, opts } = options;
|
|
1520
|
+
const ids = searchInDataReturnIdsNumeric(query, metadata, opts);
|
|
1521
|
+
if (ids.length === 0)
|
|
1522
|
+
return [];
|
|
1523
|
+
const qTokens = orderedTokenize(query);
|
|
1524
|
+
const scored = [];
|
|
1525
|
+
for (const id of ids) {
|
|
1526
|
+
const item = data.get(id);
|
|
1527
|
+
if (!item)
|
|
1528
|
+
continue;
|
|
1529
|
+
const itemTokens = tokenIdsToStrings(metadata.unsorted.get(id)) ?? orderedTokenize(primaryTextFn(item) || "");
|
|
1530
|
+
const exactKeys = exactKeysFn?.(item);
|
|
1531
|
+
const score = scoreOne(query, qTokens, itemTokens, exactKeys);
|
|
1532
|
+
scored.push({ id, item, score });
|
|
1533
|
+
}
|
|
1534
|
+
scored.sort((x, y) => {
|
|
1535
|
+
if (y.score !== x.score)
|
|
1536
|
+
return y.score - x.score;
|
|
1537
|
+
const xText = primaryTextFn(x.item) || "";
|
|
1538
|
+
const yText = primaryTextFn(y.item) || "";
|
|
1539
|
+
return xText.localeCompare(yText);
|
|
1540
|
+
});
|
|
1541
|
+
if (limit === undefined || limit === Infinity || limit >= scored.length)
|
|
1542
|
+
return scored;
|
|
1543
|
+
return scored.slice(0, limit);
|
|
1544
|
+
}
|
|
1249
1545
|
// src/common/SearchUniverse.ts
|
|
1250
1546
|
function tokensEqual3(a, b) {
|
|
1251
1547
|
if (a.length !== b.length)
|
|
@@ -1256,6 +1552,13 @@ function tokensEqual3(a, b) {
|
|
|
1256
1552
|
}
|
|
1257
1553
|
return true;
|
|
1258
1554
|
}
|
|
1555
|
+
function firstNEqual3(a, b) {
|
|
1556
|
+
if (a === undefined && b === undefined)
|
|
1557
|
+
return true;
|
|
1558
|
+
if (a === undefined || b === undefined)
|
|
1559
|
+
return false;
|
|
1560
|
+
return tokensEqual3(a, b);
|
|
1561
|
+
}
|
|
1259
1562
|
|
|
1260
1563
|
class SearchUniverse {
|
|
1261
1564
|
collections = new Map;
|
|
@@ -1265,7 +1568,7 @@ class SearchUniverse {
|
|
|
1265
1568
|
}
|
|
1266
1569
|
const collection = {
|
|
1267
1570
|
data: new Map,
|
|
1268
|
-
metadata:
|
|
1571
|
+
metadata: emptyNumericSearchMetadata(),
|
|
1269
1572
|
config
|
|
1270
1573
|
};
|
|
1271
1574
|
if (config.linkedTo) {
|
|
@@ -1282,7 +1585,8 @@ class SearchUniverse {
|
|
|
1282
1585
|
loadCollection(name, items) {
|
|
1283
1586
|
const collection = this.getCollectionOrThrow(name);
|
|
1284
1587
|
collection.data.clear();
|
|
1285
|
-
collection.metadata.clear();
|
|
1588
|
+
collection.metadata.sorted.clear();
|
|
1589
|
+
collection.metadata.unsorted.clear();
|
|
1286
1590
|
if (collection.primaryToLinked) {
|
|
1287
1591
|
collection.primaryToLinked.clear();
|
|
1288
1592
|
}
|
|
@@ -1290,8 +1594,11 @@ class SearchUniverse {
|
|
|
1290
1594
|
collection.data.set(item._id, item);
|
|
1291
1595
|
}
|
|
1292
1596
|
const newMetadata = createSearchArrayMetadataNumeric(collection.data, collection.config.spec);
|
|
1293
|
-
for (const [id, tokens2] of newMetadata) {
|
|
1294
|
-
collection.metadata.set(id, tokens2);
|
|
1597
|
+
for (const [id, tokens2] of newMetadata.sorted) {
|
|
1598
|
+
collection.metadata.sorted.set(id, tokens2);
|
|
1599
|
+
}
|
|
1600
|
+
for (const [id, tokens2] of newMetadata.unsorted) {
|
|
1601
|
+
collection.metadata.unsorted.set(id, tokens2);
|
|
1295
1602
|
}
|
|
1296
1603
|
if (collection.config.linkedTo && collection.primaryToLinked) {
|
|
1297
1604
|
const { foreignKeyGetter } = collection.config.linkedTo;
|
|
@@ -1387,11 +1694,17 @@ class SearchUniverse {
|
|
|
1387
1694
|
collection.data.set(id, item);
|
|
1388
1695
|
const tokensMap = createTokensMap();
|
|
1389
1696
|
try {
|
|
1390
|
-
const
|
|
1391
|
-
if (
|
|
1392
|
-
collection.metadata.set(id,
|
|
1697
|
+
const prepared = prepareObjectForSearchNumeric(item, collection.config.spec, tokensMap);
|
|
1698
|
+
if (prepared !== undefined) {
|
|
1699
|
+
collection.metadata.sorted.set(id, prepared.sorted);
|
|
1700
|
+
if (prepared.firstN !== undefined) {
|
|
1701
|
+
collection.metadata.unsorted.set(id, prepared.firstN);
|
|
1702
|
+
} else {
|
|
1703
|
+
collection.metadata.unsorted.delete(id);
|
|
1704
|
+
}
|
|
1393
1705
|
} else {
|
|
1394
|
-
collection.metadata.delete(id);
|
|
1706
|
+
collection.metadata.sorted.delete(id);
|
|
1707
|
+
collection.metadata.unsorted.delete(id);
|
|
1395
1708
|
}
|
|
1396
1709
|
} finally {
|
|
1397
1710
|
clearTokensMap(tokensMap);
|
|
@@ -1445,7 +1758,8 @@ class SearchUniverse {
|
|
|
1445
1758
|
}
|
|
1446
1759
|
}
|
|
1447
1760
|
collection.data.delete(id);
|
|
1448
|
-
collection.metadata.delete(id);
|
|
1761
|
+
collection.metadata.sorted.delete(id);
|
|
1762
|
+
collection.metadata.unsorted.delete(id);
|
|
1449
1763
|
return true;
|
|
1450
1764
|
}
|
|
1451
1765
|
removeFromSearchMetadataBatch(collectionName, ids) {
|
|
@@ -1496,9 +1810,10 @@ class SearchUniverse {
|
|
|
1496
1810
|
}
|
|
1497
1811
|
}
|
|
1498
1812
|
}
|
|
1499
|
-
const hadMetadata = collection.metadata.has(id);
|
|
1813
|
+
const hadMetadata = collection.metadata.sorted.has(id);
|
|
1500
1814
|
collection.data.delete(id);
|
|
1501
|
-
collection.metadata.delete(id);
|
|
1815
|
+
collection.metadata.sorted.delete(id);
|
|
1816
|
+
collection.metadata.unsorted.delete(id);
|
|
1502
1817
|
if (hadMetadata) {
|
|
1503
1818
|
result.removed++;
|
|
1504
1819
|
result.removedIds.push(id);
|
|
@@ -1509,11 +1824,11 @@ class SearchUniverse {
|
|
|
1509
1824
|
for (const item of newItems) {
|
|
1510
1825
|
const id = item._id;
|
|
1511
1826
|
const existing = collection.data.get(id);
|
|
1512
|
-
const hadMetadata = collection.metadata.has(id);
|
|
1827
|
+
const hadMetadata = collection.metadata.sorted.has(id);
|
|
1513
1828
|
const shouldTokenize = !existing || !skipUpdateCheck;
|
|
1514
|
-
let
|
|
1829
|
+
let prepared;
|
|
1515
1830
|
if (shouldTokenize) {
|
|
1516
|
-
|
|
1831
|
+
prepared = prepareObjectForSearchNumeric(item, collection.config.spec, tokensMap);
|
|
1517
1832
|
}
|
|
1518
1833
|
if (fkGetter && collection.primaryToLinked) {
|
|
1519
1834
|
const newFk = fkGetter(item);
|
|
@@ -1543,20 +1858,30 @@ class SearchUniverse {
|
|
|
1543
1858
|
collection.data.set(id, item);
|
|
1544
1859
|
if (!shouldTokenize)
|
|
1545
1860
|
continue;
|
|
1546
|
-
if (
|
|
1861
|
+
if (prepared === undefined) {
|
|
1547
1862
|
if (hadMetadata) {
|
|
1548
|
-
collection.metadata.delete(id);
|
|
1863
|
+
collection.metadata.sorted.delete(id);
|
|
1864
|
+
collection.metadata.unsorted.delete(id);
|
|
1549
1865
|
result.removed++;
|
|
1550
1866
|
result.removedIds.push(id);
|
|
1551
1867
|
}
|
|
1552
1868
|
} else if (!hadMetadata) {
|
|
1553
|
-
collection.metadata.set(id,
|
|
1869
|
+
collection.metadata.sorted.set(id, prepared.sorted);
|
|
1870
|
+
if (prepared.firstN !== undefined) {
|
|
1871
|
+
collection.metadata.unsorted.set(id, prepared.firstN);
|
|
1872
|
+
}
|
|
1554
1873
|
result.added++;
|
|
1555
1874
|
result.addedIds.push(id);
|
|
1556
1875
|
} else {
|
|
1557
|
-
const
|
|
1558
|
-
|
|
1559
|
-
|
|
1876
|
+
const existingSorted = collection.metadata.sorted.get(id);
|
|
1877
|
+
const existingFirstN = collection.metadata.unsorted.get(id);
|
|
1878
|
+
if (!tokensEqual3(existingSorted, prepared.sorted) || !firstNEqual3(existingFirstN, prepared.firstN)) {
|
|
1879
|
+
collection.metadata.sorted.set(id, prepared.sorted);
|
|
1880
|
+
if (prepared.firstN !== undefined) {
|
|
1881
|
+
collection.metadata.unsorted.set(id, prepared.firstN);
|
|
1882
|
+
} else {
|
|
1883
|
+
collection.metadata.unsorted.delete(id);
|
|
1884
|
+
}
|
|
1560
1885
|
result.updated++;
|
|
1561
1886
|
result.updatedIds.push(id);
|
|
1562
1887
|
}
|
|
@@ -1635,7 +1960,8 @@ class SearchUniverse {
|
|
|
1635
1960
|
clear() {
|
|
1636
1961
|
for (const collection of this.collections.values()) {
|
|
1637
1962
|
collection.data.clear();
|
|
1638
|
-
collection.metadata.clear();
|
|
1963
|
+
collection.metadata.sorted.clear();
|
|
1964
|
+
collection.metadata.unsorted.clear();
|
|
1639
1965
|
if (collection.primaryToLinked) {
|
|
1640
1966
|
collection.primaryToLinked.clear();
|
|
1641
1967
|
}
|
|
@@ -1658,6 +1984,11 @@ export {
|
|
|
1658
1984
|
searchInDataReturnObjectsNumeric as searchInDataReturnObjects,
|
|
1659
1985
|
searchInDataReturnIdsNumeric as searchInDataReturnIds,
|
|
1660
1986
|
searchInDataReturnIdsNumeric as searchInData,
|
|
1987
|
+
searchAndRankNumeric,
|
|
1988
|
+
searchAndRankNumeric as searchAndRank,
|
|
1989
|
+
scoreOrderAndPresence,
|
|
1990
|
+
scoreOne,
|
|
1991
|
+
scoreBag,
|
|
1661
1992
|
sanitiseString,
|
|
1662
1993
|
resetTokenRegistry,
|
|
1663
1994
|
removePrimaryItemNumeric as removePrimaryItem,
|
|
@@ -1669,6 +2000,7 @@ export {
|
|
|
1669
2000
|
prepareStringForSearch,
|
|
1670
2001
|
prepareQueryTokens,
|
|
1671
2002
|
prepareObjectForSearchNumeric as prepareObjectForSearch,
|
|
2003
|
+
orderedTokenize,
|
|
1672
2004
|
normalizeDates,
|
|
1673
2005
|
matchTokenInSortedListNumeric,
|
|
1674
2006
|
matchPreparedTokenInSortedList,
|
|
@@ -1692,6 +2024,8 @@ export {
|
|
|
1692
2024
|
allPreparedTokensMatch,
|
|
1693
2025
|
TOKEN_ID_MASK,
|
|
1694
2026
|
SearchUniverse,
|
|
2027
|
+
PREFIX_TO_MATCH_MODE,
|
|
2028
|
+
MATCH_MODE_PREFIXES,
|
|
1695
2029
|
MATCH_MODE_BITS,
|
|
1696
2030
|
DEFAULT_SEARCH_OPTS,
|
|
1697
2031
|
AugmentedMetadata
|