cry-search 1.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.
Files changed (64) hide show
  1. package/CLAUDE.md +285 -0
  2. package/LICENSE.md +67 -0
  3. package/README.md +283 -0
  4. package/UNIVERSE.md +818 -0
  5. package/dist/common/SearchUniverse.d.ts +210 -0
  6. package/dist/common/SearchUniverse.d.ts.map +1 -0
  7. package/dist/common/findInArray.d.ts +37 -0
  8. package/dist/common/findInArray.d.ts.map +1 -0
  9. package/dist/common/findInArrayReturnDataAndMeta.d.ts +52 -0
  10. package/dist/common/findInArrayReturnDataAndMeta.d.ts.map +1 -0
  11. package/dist/common/findInLinkedArrays.d.ts +66 -0
  12. package/dist/common/findInLinkedArrays.d.ts.map +1 -0
  13. package/dist/common/numeric/createSearchArrayMetadata.d.ts +65 -0
  14. package/dist/common/numeric/createSearchArrayMetadata.d.ts.map +1 -0
  15. package/dist/common/numeric/createSearchLinkedMetadata.d.ts +46 -0
  16. package/dist/common/numeric/createSearchLinkedMetadata.d.ts.map +1 -0
  17. package/dist/common/numeric/findInLinkedArrays.d.ts +32 -0
  18. package/dist/common/numeric/findInLinkedArrays.d.ts.map +1 -0
  19. package/dist/common/numeric/index.d.ts +9 -0
  20. package/dist/common/numeric/index.d.ts.map +1 -0
  21. package/dist/common/numeric/searchInData.d.ts +31 -0
  22. package/dist/common/numeric/searchInData.d.ts.map +1 -0
  23. package/dist/common/numeric/updateSearchMetadata.d.ts +60 -0
  24. package/dist/common/numeric/updateSearchMetadata.d.ts.map +1 -0
  25. package/dist/common/string/createSearchArrayMetadata.d.ts +117 -0
  26. package/dist/common/string/createSearchArrayMetadata.d.ts.map +1 -0
  27. package/dist/common/string/createSearchLinkedMetadata.d.ts +36 -0
  28. package/dist/common/string/createSearchLinkedMetadata.d.ts.map +1 -0
  29. package/dist/common/string/index.d.ts +10 -0
  30. package/dist/common/string/index.d.ts.map +1 -0
  31. package/dist/common/string/updateSearchMetadata.d.ts +103 -0
  32. package/dist/common/string/updateSearchMetadata.d.ts.map +1 -0
  33. package/dist/common/syncSearchArrayMetadata.d.ts +64 -0
  34. package/dist/common/syncSearchArrayMetadata.d.ts.map +1 -0
  35. package/dist/common/updateSearchLinkedMetadata.d.ts +129 -0
  36. package/dist/common/updateSearchLinkedMetadata.d.ts.map +1 -0
  37. package/dist/index.cjs +1827 -0
  38. package/dist/index.d.cts +32 -0
  39. package/dist/index.d.ts +32 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +1795 -0
  42. package/dist/types/index.d.ts +300 -0
  43. package/dist/types/index.d.ts.map +1 -0
  44. package/dist/types.d.ts +6 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/utils/matchToken.d.ts +65 -0
  47. package/dist/utils/matchToken.d.ts.map +1 -0
  48. package/dist/utils/matchTokenNumeric.d.ts +94 -0
  49. package/dist/utils/matchTokenNumeric.d.ts.map +1 -0
  50. package/dist/utils/normalizeDates.d.ts +39 -0
  51. package/dist/utils/normalizeDates.d.ts.map +1 -0
  52. package/dist/utils/prepareStringForSearch.d.ts +28 -0
  53. package/dist/utils/prepareStringForSearch.d.ts.map +1 -0
  54. package/dist/utils/prepareStringForSearchNumeric.d.ts +42 -0
  55. package/dist/utils/prepareStringForSearchNumeric.d.ts.map +1 -0
  56. package/dist/utils/preprocessString.d.ts +26 -0
  57. package/dist/utils/preprocessString.d.ts.map +1 -0
  58. package/dist/utils/sanitiseString.d.ts +26 -0
  59. package/dist/utils/sanitiseString.d.ts.map +1 -0
  60. package/dist/utils/tokenRegistry.d.ts +70 -0
  61. package/dist/utils/tokenRegistry.d.ts.map +1 -0
  62. package/dist/utils/tokenize.d.ts +46 -0
  63. package/dist/utils/tokenize.d.ts.map +1 -0
  64. package/package.json +67 -0
package/dist/index.js ADDED
@@ -0,0 +1,1795 @@
1
+ // src/types/index.ts
2
+ var DEFAULT_SEARCH_OPTS = {
3
+ matchWords: "start",
4
+ matchNumbers: "startEnd"
5
+ };
6
+ function arrayToSearchableData(items) {
7
+ const map = new Map;
8
+ for (const item of items) {
9
+ map.set(item._id, item);
10
+ }
11
+ return map;
12
+ }
13
+ function searchableDataToArray(data) {
14
+ return Array.from(data.values());
15
+ }
16
+ // src/utils/normalizeDates.ts
17
+ var MONTH_NAMES = {
18
+ jan: "01",
19
+ feb: "02",
20
+ mar: "03",
21
+ apr: "04",
22
+ maj: "05",
23
+ jun: "06",
24
+ jul: "07",
25
+ avg: "08",
26
+ sep: "09",
27
+ okt: "10",
28
+ nov: "11",
29
+ dec: "12",
30
+ januar: "01",
31
+ februar: "02",
32
+ marec: "03",
33
+ april: "04",
34
+ junij: "06",
35
+ julij: "07",
36
+ avgust: "08",
37
+ september: "09",
38
+ oktober: "10",
39
+ november: "11",
40
+ december: "12",
41
+ january: "01",
42
+ february: "02",
43
+ march: "03",
44
+ may: "05",
45
+ june: "06",
46
+ july: "07",
47
+ august: "08",
48
+ october: "10"
49
+ };
50
+ var RE_DATE_ISO = /\b(\d{4})-(\d{2})-(\d{2})(?:T[\d:.]+Z?)?\b/g;
51
+ var RE_DATE_ISO_YM = /\b(\d{4})-(\d{2})\b/g;
52
+ var RE_DATE_DMY = /\b(\d{1,2})\.(\d{1,2})\.(\d{4})\b/g;
53
+ var RE_DATE_DMY_SHORT = /\b(\d{1,2})\.(\d{1,2})\.(\d{2})\b/g;
54
+ var RE_DATE_MY = /\b(\d{1,2})\.(\d{4})\b/g;
55
+ var RE_DATE_MY_SLASH_DASH = /\b(\d{1,2})[-/](\d{4})\b/g;
56
+ var RE_DATE_MY_SLASH_SHORT = /\b(\d{1,2})\/(\d{2})\b/g;
57
+ var RE_DATE_MMYYYY = /\b(0[1-9]|1[0-2])(20\d{2})\b/g;
58
+ var RE_DATE_DDMMYYYY = /\b(0[1-9]|[12]\d|3[01])(0[1-9]|1[0-2])(20\d{2})\b/g;
59
+ var RE_DATE_MONTH_YEAR = new RegExp(`\\b(${Object.keys(MONTH_NAMES).join("|")})\\s*(\\d{4})\\b`, "gi");
60
+ function pad(num, length) {
61
+ return num.padStart(length, "0");
62
+ }
63
+ function normalizeDates(input) {
64
+ let result = input;
65
+ result = result.replace(RE_DATE_ISO, (_match, year, month, day) => {
66
+ return `${year}${month}${day}`;
67
+ });
68
+ result = result.replace(RE_DATE_ISO_YM, (_match, year, month) => {
69
+ return `${year}${month}`;
70
+ });
71
+ result = result.replace(RE_DATE_DMY, (_match, day, month, year) => {
72
+ return `${year}${pad(month, 2)}${pad(day, 2)}`;
73
+ });
74
+ result = result.replace(RE_DATE_DMY_SHORT, (_match, day, month, year) => {
75
+ return `20${year}${pad(month, 2)}${pad(day, 2)}`;
76
+ });
77
+ result = result.replace(RE_DATE_MY, (_match, month, year) => {
78
+ return `${year}${pad(month, 2)}`;
79
+ });
80
+ result = result.replace(RE_DATE_MY_SLASH_DASH, (_match, month, year) => {
81
+ const y = parseInt(year, 10);
82
+ if (y > 2000 && y < 2100) {
83
+ return `${year}${pad(month, 2)}`;
84
+ }
85
+ return _match;
86
+ });
87
+ result = result.replace(RE_DATE_MY_SLASH_SHORT, (_match, month, year) => {
88
+ const m = parseInt(month, 10);
89
+ if (m >= 1 && m <= 12) {
90
+ return `20${year}${pad(month, 2)}`;
91
+ }
92
+ return _match;
93
+ });
94
+ result = result.replace(RE_DATE_DDMMYYYY, (_match, day, month, year) => {
95
+ return `${year}${month}${day}`;
96
+ });
97
+ result = result.replace(RE_DATE_MMYYYY, (_match, month, year) => {
98
+ return `${year}${month}`;
99
+ });
100
+ result = result.replace(RE_DATE_MONTH_YEAR, (_match, monthName, year) => {
101
+ const monthNum = MONTH_NAMES[monthName.toLowerCase()];
102
+ if (monthNum) {
103
+ return `${year}${monthNum}`;
104
+ }
105
+ return _match;
106
+ });
107
+ return result;
108
+ }
109
+
110
+ // src/utils/preprocessString.ts
111
+ var RE_LEADING_ZEROS = /\b0+(\d)/g;
112
+ var RE_DECIMAL_COMMA = /(\d),(\d)/g;
113
+ var RE_STANDALONE_COMMA = /(?<!\d),(\d)/g;
114
+ var RE_ZERO_DECIMAL = /\b0+\./g;
115
+ var RE_DIGIT_DASH = /(\d)\s*-\s*(\d)/g;
116
+ var RE_LETTERS_DIGITS = /(^|\s)([a-zA-Z]+)(\d+)(?=\s|$)/g;
117
+ var RE_DIGITS_LETTERS = /(^|\s)(\d+)([a-zA-Z]+)(?=\s|$)/g;
118
+ function preprocessString(input) {
119
+ let result = input;
120
+ result = result.replace(RE_LEADING_ZEROS, "$1");
121
+ result = result.replace(RE_DECIMAL_COMMA, "$1.$2");
122
+ result = result.replace(RE_STANDALONE_COMMA, ".$1");
123
+ result = result.replace(RE_ZERO_DECIMAL, ".");
124
+ result = result.replace(RE_DIGIT_DASH, "$1-$2");
125
+ result = result.replace(RE_LETTERS_DIGITS, "$1$2 $3");
126
+ result = result.replace(RE_DIGITS_LETTERS, "$1$2 $3");
127
+ return result;
128
+ }
129
+
130
+ // src/utils/sanitiseString.ts
131
+ var RE_DIACRITICS = /[\u0300-\u036f]/g;
132
+ var RE_INVALID_CHARS = /[^a-z0-9.\- ]/g;
133
+ function sanitiseString(input) {
134
+ let result = input;
135
+ result = result.toLowerCase();
136
+ result = result.normalize("NFD").replace(RE_DIACRITICS, "");
137
+ result = result.replace(RE_INVALID_CHARS, " ");
138
+ return result;
139
+ }
140
+
141
+ // src/utils/tokenize.ts
142
+ var DEFAULT_REPLACE_TOKENS = new Map([
143
+ ["zdravilo", "zdr"],
144
+ ["izdelek", "izd"],
145
+ ["material", "mat"],
146
+ ["pes", "ps"],
147
+ ["psi", "ps"],
148
+ ["dog", "ps"],
149
+ ["cat", "mk"],
150
+ ["macka", "mk"],
151
+ ["macke", "mk"],
152
+ ["ulica", "ul"],
153
+ ["cesta", "ces"],
154
+ ["mesanec", "mes"],
155
+ ["nova", "nv"]
156
+ ]);
157
+ var DEFAULT_REMOVE_TOKENS = new Set([
158
+ "s",
159
+ "z",
160
+ "-",
161
+ "in",
162
+ "na",
163
+ "v",
164
+ "po",
165
+ "za",
166
+ "se"
167
+ ]);
168
+ var DEFAULT_TOKENIZE_CONFIG = {
169
+ replaceTokens: DEFAULT_REPLACE_TOKENS,
170
+ removeTokens: DEFAULT_REMOVE_TOKENS
171
+ };
172
+ function tokenize(input, config) {
173
+ let tokens = input.split(" ").map((token) => token.trim()).filter((token) => token.length > 0);
174
+ if (config?.replaceTokens) {
175
+ tokens = tokens.map((token) => {
176
+ if (token.startsWith("--") && token.length > 2) {
177
+ const withoutPrefix = token.slice(2);
178
+ const replaced = config.replaceTokens.get(withoutPrefix);
179
+ return replaced ? "--" + replaced : token;
180
+ }
181
+ return config.replaceTokens.get(token) ?? token;
182
+ });
183
+ }
184
+ if (config?.removeTokens) {
185
+ tokens = tokens.filter((token) => !config.removeTokens.has(token));
186
+ }
187
+ return tokens;
188
+ }
189
+
190
+ // src/utils/prepareStringForSearch.ts
191
+ function prepareStringForSearch(input) {
192
+ const datesNormalized = normalizeDates(input);
193
+ const preprocessed = preprocessString(datesNormalized);
194
+ const sanitised = sanitiseString(preprocessed);
195
+ const tokens = tokenize(sanitised, DEFAULT_TOKENIZE_CONFIG);
196
+ return tokens.sort();
197
+ }
198
+ // src/utils/tokenRegistry.ts
199
+ var INITIAL_CAPACITY = 10 * 1000;
200
+ var tokens = new Array(INITIAL_CAPACITY);
201
+ var tokenCount = 0;
202
+ function getTokenCount() {
203
+ return tokenCount;
204
+ }
205
+ function getTokenById(id) {
206
+ return tokens[id];
207
+ }
208
+ function findTokenId(token) {
209
+ for (let i = 0;i < tokenCount; i++) {
210
+ if (tokens[i] === token) {
211
+ return i;
212
+ }
213
+ }
214
+ return -1;
215
+ }
216
+ function registerToken(token) {
217
+ const id = tokenCount;
218
+ tokens[id] = token;
219
+ tokenCount++;
220
+ return id;
221
+ }
222
+ function getOrCreateTokenId(token, tokensMap) {
223
+ const existing = tokensMap.get(token);
224
+ if (existing !== undefined) {
225
+ return existing;
226
+ }
227
+ const id = registerToken(token);
228
+ tokensMap.set(token, id);
229
+ return id;
230
+ }
231
+ function createTokensMap() {
232
+ const map = new Map;
233
+ for (let i = 0;i < tokenCount; i++) {
234
+ map.set(tokens[i], i);
235
+ }
236
+ return map;
237
+ }
238
+ function clearTokensMap(tokensMap) {
239
+ tokensMap.clear();
240
+ }
241
+ function resetTokenRegistry() {
242
+ tokenCount = 0;
243
+ tokens.length = INITIAL_CAPACITY;
244
+ tokens.fill(undefined, 0, INITIAL_CAPACITY);
245
+ }
246
+ // src/utils/prepareStringForSearchNumeric.ts
247
+ function prepareStringForSearchNumeric(input, tokensMap) {
248
+ const datesNormalized = normalizeDates(input);
249
+ const preprocessed = preprocessString(datesNormalized);
250
+ const sanitised = sanitiseString(preprocessed);
251
+ const stringTokens = tokenize(sanitised, DEFAULT_TOKENIZE_CONFIG);
252
+ const numericTokens = new Array(stringTokens.length);
253
+ for (let i = 0;i < stringTokens.length; i++) {
254
+ numericTokens[i] = getOrCreateTokenId(stringTokens[i], tokensMap);
255
+ }
256
+ numericTokens.sort((a, b) => a - b);
257
+ return new Uint32Array(numericTokens);
258
+ }
259
+
260
+ // src/common/string/createSearchArrayMetadata.ts
261
+ var MATCH_MODE_PREFIXES = {
262
+ start: "<",
263
+ end: ">",
264
+ startEnd: "+",
265
+ anywhere: "*",
266
+ whole: "!"
267
+ };
268
+ var PREFIX_TO_MATCH_MODE = {
269
+ "<": "start",
270
+ ">": "end",
271
+ "+": "startEnd",
272
+ "*": "anywhere",
273
+ "!": "whole",
274
+ "=": "whole",
275
+ "?": "anywhere"
276
+ };
277
+ var DEFAULT_EXCLUDED_FIELDS = new Set(["_id", "_deleted", "_blocked"]);
278
+ function getValueByPath(obj, path) {
279
+ const parts = path.split(".");
280
+ let current = obj;
281
+ for (let i = 0;i < parts.length; i++) {
282
+ if (current == null)
283
+ return;
284
+ const part = parts[i];
285
+ if (Array.isArray(current)) {
286
+ const remainingPath = parts.slice(i).join(".");
287
+ const results = [];
288
+ for (const item of current) {
289
+ const value = getValueByPath(item, remainingPath);
290
+ if (value !== undefined) {
291
+ if (Array.isArray(value)) {
292
+ results.push(...value);
293
+ } else {
294
+ results.push(value);
295
+ }
296
+ }
297
+ }
298
+ return results.length > 0 ? results : undefined;
299
+ }
300
+ if (typeof current === "object") {
301
+ current = current[part];
302
+ } else {
303
+ return;
304
+ }
305
+ }
306
+ return current;
307
+ }
308
+ function isDotNotation(field) {
309
+ return field.includes(".");
310
+ }
311
+ function getRootField(field) {
312
+ const dotIndex = field.indexOf(".");
313
+ return dotIndex === -1 ? field : field.slice(0, dotIndex);
314
+ }
315
+ function extractStringsFromValue(value, results) {
316
+ if (value == null)
317
+ return;
318
+ if (typeof value === "string") {
319
+ results.push(value);
320
+ } else if (typeof value === "number") {
321
+ results.push(String(value));
322
+ } else if (value instanceof Date) {
323
+ results.push(value.toISOString());
324
+ } else if (Array.isArray(value)) {
325
+ for (const item of value) {
326
+ extractStringsFromValue(item, results);
327
+ }
328
+ } else if (typeof value === "object") {
329
+ for (const v of Object.values(value)) {
330
+ extractStringsFromValue(v, results);
331
+ }
332
+ }
333
+ }
334
+ function isDeletedOrBlocked(obj) {
335
+ return obj._deleted != null || obj._blocked != null;
336
+ }
337
+ function extractSearchableStringDefault(obj, spec) {
338
+ if (isDeletedOrBlocked(obj)) {
339
+ return;
340
+ }
341
+ if (spec?.enrichSearchObjectFn) {
342
+ spec.enrichSearchObjectFn(obj, spec.searchContext);
343
+ }
344
+ const parts = [];
345
+ const fieldsToSearch = spec?.searchInFields ?? Object.keys(obj);
346
+ const fieldsToExclude = new Set(spec?.dontSearchInFields ?? []);
347
+ for (const key of fieldsToSearch) {
348
+ const keyStr = key;
349
+ if (!spec?.searchInFields && DEFAULT_EXCLUDED_FIELDS.has(keyStr))
350
+ continue;
351
+ if (fieldsToExclude.has(key))
352
+ continue;
353
+ const value = isDotNotation(keyStr) ? getValueByPath(obj, keyStr) : obj[key];
354
+ extractStringsFromValue(value, parts);
355
+ }
356
+ return parts.join(" ");
357
+ }
358
+ function prepareObjectForSearch(obj, spec) {
359
+ if (isDeletedOrBlocked(obj)) {
360
+ return;
361
+ }
362
+ if (spec?.extractSearchableStringFn) {
363
+ const searchableString = spec.extractSearchableStringFn(obj);
364
+ if (searchableString === undefined) {
365
+ return;
366
+ }
367
+ return prepareStringForSearch(searchableString);
368
+ }
369
+ return prepareObjectFieldsForSearch(obj, spec);
370
+ }
371
+ function prepareObjectFieldsForSearch(obj, spec) {
372
+ if (spec?.enrichSearchObjectFn) {
373
+ spec.enrichSearchObjectFn(obj, spec.searchContext);
374
+ }
375
+ const allTokens = [];
376
+ const fieldMatchModes = spec?.fieldMatchModes;
377
+ const fieldsToSearch = spec?.searchInFields ?? Object.keys(obj);
378
+ const fieldsToExclude = new Set(spec?.dontSearchInFields ?? []);
379
+ const processedRootFields = new Set;
380
+ for (const key of fieldsToSearch) {
381
+ const keyStr = key;
382
+ if (!spec?.searchInFields && DEFAULT_EXCLUDED_FIELDS.has(keyStr))
383
+ continue;
384
+ if (fieldsToExclude.has(key))
385
+ continue;
386
+ const isDot = isDotNotation(keyStr);
387
+ const rootField = getRootField(keyStr);
388
+ let value;
389
+ if (isDot) {
390
+ value = getValueByPath(obj, keyStr);
391
+ } else {
392
+ value = obj[key];
393
+ processedRootFields.add(rootField);
394
+ }
395
+ if (value == null)
396
+ continue;
397
+ const matchMode = fieldMatchModes?.[key];
398
+ const prefix = matchMode ? MATCH_MODE_PREFIXES[matchMode] : "";
399
+ const fieldStrings = [];
400
+ extractStringsFromValue(value, fieldStrings);
401
+ if (fieldStrings.length > 0) {
402
+ const fieldText = fieldStrings.join(" ");
403
+ const tokens2 = prepareStringForSearch(fieldText);
404
+ for (const token of tokens2) {
405
+ allTokens.push(prefix + token);
406
+ }
407
+ }
408
+ }
409
+ return [...new Set(allTokens)].sort();
410
+ }
411
+ function createSearchArrayMetadata(data, spec) {
412
+ const metadata = new Map;
413
+ for (const [id, item] of data) {
414
+ const tokens2 = prepareObjectForSearch(item, spec);
415
+ if (tokens2 !== undefined) {
416
+ metadata.set(id, tokens2);
417
+ }
418
+ }
419
+ return metadata;
420
+ }
421
+ function wrapMetadataLegacy(metadata) {
422
+ return { items: metadata };
423
+ }
424
+ function unwrapMetadataLegacy(legacy) {
425
+ return legacy.items;
426
+ }
427
+
428
+ // src/common/numeric/createSearchArrayMetadata.ts
429
+ var MATCH_MODE_BITS = {
430
+ start: 0,
431
+ end: 1,
432
+ startEnd: 2,
433
+ anywhere: 3,
434
+ whole: 4
435
+ };
436
+ var MODE_SHIFT = 29;
437
+ var TOKEN_ID_MASK = (1 << MODE_SHIFT) - 1;
438
+ function encodeTokenWithMode(tokenId, mode) {
439
+ return tokenId | MATCH_MODE_BITS[mode] << MODE_SHIFT;
440
+ }
441
+ function decodeTokenId(encoded) {
442
+ return encoded & TOKEN_ID_MASK;
443
+ }
444
+ function decodeMatchMode(encoded) {
445
+ const modeBits = encoded >>> MODE_SHIFT;
446
+ switch (modeBits) {
447
+ case 1:
448
+ return "end";
449
+ case 2:
450
+ return "startEnd";
451
+ case 3:
452
+ return "anywhere";
453
+ case 4:
454
+ return "whole";
455
+ default:
456
+ return "start";
457
+ }
458
+ }
459
+ var DEFAULT_EXCLUDED_FIELDS2 = new Set(["_id", "_deleted", "_blocked"]);
460
+ function getValueByPath2(obj, path) {
461
+ const parts = path.split(".");
462
+ let current = obj;
463
+ for (let i = 0;i < parts.length; i++) {
464
+ if (current == null)
465
+ return;
466
+ const part = parts[i];
467
+ if (Array.isArray(current)) {
468
+ const remainingPath = parts.slice(i).join(".");
469
+ const results = [];
470
+ for (const item of current) {
471
+ const value = getValueByPath2(item, remainingPath);
472
+ if (value !== undefined) {
473
+ if (Array.isArray(value)) {
474
+ results.push(...value);
475
+ } else {
476
+ results.push(value);
477
+ }
478
+ }
479
+ }
480
+ return results.length > 0 ? results : undefined;
481
+ }
482
+ if (typeof current === "object") {
483
+ current = current[part];
484
+ } else {
485
+ return;
486
+ }
487
+ }
488
+ return current;
489
+ }
490
+ function isDotNotation2(field) {
491
+ return field.includes(".");
492
+ }
493
+ function extractStringsFromValue2(value, results) {
494
+ if (value == null)
495
+ return;
496
+ if (typeof value === "string") {
497
+ results.push(value);
498
+ } else if (typeof value === "number") {
499
+ results.push(String(value));
500
+ } else if (value instanceof Date) {
501
+ results.push(value.toISOString());
502
+ } else if (Array.isArray(value)) {
503
+ for (const item of value) {
504
+ extractStringsFromValue2(item, results);
505
+ }
506
+ } else if (typeof value === "object") {
507
+ for (const v of Object.values(value)) {
508
+ extractStringsFromValue2(v, results);
509
+ }
510
+ }
511
+ }
512
+ function prepareObjectForSearchNumeric(obj, spec, tokensMap) {
513
+ if (isDeletedOrBlocked(obj)) {
514
+ return;
515
+ }
516
+ if (spec?.extractSearchableStringFn) {
517
+ const searchableString = spec.extractSearchableStringFn(obj);
518
+ if (searchableString === undefined) {
519
+ return;
520
+ }
521
+ return prepareStringForSearchNumeric(searchableString, tokensMap);
522
+ }
523
+ return prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap);
524
+ }
525
+ function prepareObjectFieldsForSearchNumeric(obj, spec, tokensMap) {
526
+ if (spec?.enrichSearchObjectFn) {
527
+ spec.enrichSearchObjectFn(obj, spec.searchContext);
528
+ }
529
+ const allTokens = [];
530
+ const fieldMatchModes = spec?.fieldMatchModes;
531
+ const fieldsToSearch = spec?.searchInFields ?? Object.keys(obj);
532
+ const fieldsToExclude = new Set(spec?.dontSearchInFields ?? []);
533
+ for (const key of fieldsToSearch) {
534
+ const keyStr = key;
535
+ if (!spec?.searchInFields && DEFAULT_EXCLUDED_FIELDS2.has(keyStr))
536
+ continue;
537
+ if (fieldsToExclude.has(key))
538
+ continue;
539
+ const isDot = isDotNotation2(keyStr);
540
+ const value = isDot ? getValueByPath2(obj, keyStr) : obj[key];
541
+ if (value == null)
542
+ continue;
543
+ const matchMode = fieldMatchModes?.[key];
544
+ const fieldStrings = [];
545
+ extractStringsFromValue2(value, fieldStrings);
546
+ if (fieldStrings.length > 0) {
547
+ const fieldText = fieldStrings.join(" ");
548
+ const datesNormalized = normalizeDates(fieldText);
549
+ const preprocessed = preprocessString(datesNormalized);
550
+ const sanitised = sanitiseString(preprocessed);
551
+ const stringTokens = tokenize(sanitised, DEFAULT_TOKENIZE_CONFIG);
552
+ const effectiveMode = matchMode ?? (keyStr === "_id" ? "whole" : undefined);
553
+ for (const token of stringTokens) {
554
+ const tokenId = getOrCreateTokenId(token, tokensMap);
555
+ if (effectiveMode) {
556
+ allTokens.push(encodeTokenWithMode(tokenId, effectiveMode));
557
+ } else {
558
+ allTokens.push(tokenId);
559
+ }
560
+ }
561
+ }
562
+ }
563
+ const uniqueTokens = [...new Set(allTokens)].sort((a, b) => a - b);
564
+ return new Uint32Array(uniqueTokens);
565
+ }
566
+ function createSearchArrayMetadataNumeric(data, spec) {
567
+ const tokensMap = createTokensMap();
568
+ try {
569
+ const metadata = new Map;
570
+ for (const [id, item] of data) {
571
+ const tokens2 = prepareObjectForSearchNumeric(item, spec, tokensMap);
572
+ if (tokens2 !== undefined) {
573
+ metadata.set(id, tokens2);
574
+ }
575
+ }
576
+ return metadata;
577
+ } finally {
578
+ clearTokensMap(tokensMap);
579
+ }
580
+ }
581
+ // src/common/numeric/createSearchLinkedMetadata.ts
582
+ function createSearchLinkedMetadataNumeric(primaryData, primaryMetadata, linkedData, linkedMetadata, foreignKeyGetter) {
583
+ const primaryToLinked = new Map;
584
+ for (const [linkedId, linkedItem] of linkedData) {
585
+ const primaryId = foreignKeyGetter(linkedItem);
586
+ if (primaryId) {
587
+ const list = primaryToLinked.get(primaryId) || [];
588
+ list.push(linkedId);
589
+ primaryToLinked.set(primaryId, list);
590
+ }
591
+ }
592
+ return {
593
+ primaryMeta: primaryMetadata,
594
+ linkedMeta: linkedMetadata,
595
+ primaryToLinked,
596
+ primaryData,
597
+ linkedData
598
+ };
599
+ }
600
+ // src/common/numeric/updateSearchMetadata.ts
601
+ function updateSearchMetadataNumeric(metadata, objectId, obj, spec, tokensMap) {
602
+ const tokens2 = obj != null ? prepareObjectForSearchNumeric(obj, spec, tokensMap) : undefined;
603
+ if (tokens2 === undefined) {
604
+ metadata.delete(objectId);
605
+ return false;
606
+ } else {
607
+ metadata.set(objectId, tokens2);
608
+ return true;
609
+ }
610
+ }
611
+ function updateSearchMetadataBatchNumeric(metadata, batch, spec) {
612
+ if (batch.length === 0) {
613
+ return { updated: 0, removed: 0 };
614
+ }
615
+ const tokensMap = createTokensMap();
616
+ try {
617
+ let updated = 0;
618
+ let removed = 0;
619
+ for (const { objectId, obj } of batch) {
620
+ const wasUpdated = updateSearchMetadataNumeric(metadata, objectId, obj, spec, tokensMap);
621
+ if (wasUpdated) {
622
+ updated++;
623
+ } else {
624
+ removed++;
625
+ }
626
+ }
627
+ return { updated, removed };
628
+ } finally {
629
+ clearTokensMap(tokensMap);
630
+ }
631
+ }
632
+ function removeFromSearchMetadataNumeric(metadata, objectId) {
633
+ return metadata.delete(objectId);
634
+ }
635
+ function removeFromSearchMetadataBatchNumeric(metadata, objectIds) {
636
+ if (objectIds.length === 0) {
637
+ return 0;
638
+ }
639
+ let removed = 0;
640
+ for (const id of objectIds) {
641
+ if (metadata.delete(id)) {
642
+ removed++;
643
+ }
644
+ }
645
+ return removed;
646
+ }
647
+ // src/utils/matchTokenNumeric.ts
648
+ var RE_NUMERIC = /^[\d.\-]+$/;
649
+ function prepareQueryTokens(queryTokenStrs) {
650
+ return queryTokenStrs.map((str) => {
651
+ let overrideMode;
652
+ let negated = false;
653
+ let cleanStr = str;
654
+ if (str.length > 2 && str.startsWith("--")) {
655
+ negated = true;
656
+ cleanStr = str.slice(2);
657
+ } else if (str.length > 1 && str.startsWith("~")) {
658
+ negated = true;
659
+ cleanStr = str.slice(1);
660
+ } else if (str.length > 3 && str.startsWith("...")) {
661
+ overrideMode = "end";
662
+ cleanStr = str.slice(3);
663
+ } else if (str.length > 2 && str.startsWith("..")) {
664
+ overrideMode = "end";
665
+ cleanStr = str.slice(2);
666
+ } else if (str.length > 3 && str.endsWith("...")) {
667
+ overrideMode = "start";
668
+ cleanStr = str.slice(0, -3);
669
+ } else if (str.length > 2 && str.endsWith("..")) {
670
+ overrideMode = "start";
671
+ cleanStr = str.slice(0, -2);
672
+ } else if (str.length > 1) {
673
+ const firstChar = str[0];
674
+ if (firstChar && PREFIX_TO_MATCH_MODE[firstChar]) {
675
+ overrideMode = PREFIX_TO_MATCH_MODE[firstChar];
676
+ cleanStr = str.slice(1);
677
+ }
678
+ }
679
+ return {
680
+ str: cleanStr,
681
+ id: findTokenId(cleanStr),
682
+ isNumeric: RE_NUMERIC.test(cleanStr),
683
+ overrideMode,
684
+ negated: negated || undefined
685
+ };
686
+ });
687
+ }
688
+ function matchWithModeNumeric(searchTokenId, searchTokenStr, targetTokenEncoded, opts, overrideMode) {
689
+ const targetTokenId = decodeTokenId(targetTokenEncoded);
690
+ const targetTokenStr = tokens[targetTokenId];
691
+ if (!targetTokenStr)
692
+ return false;
693
+ const hasExplicitMode = targetTokenEncoded !== targetTokenId;
694
+ let mode;
695
+ if (overrideMode) {
696
+ mode = overrideMode;
697
+ } else if (hasExplicitMode) {
698
+ mode = decodeMatchMode(targetTokenEncoded);
699
+ } else {
700
+ const isNumeric = RE_NUMERIC.test(searchTokenStr);
701
+ mode = isNumeric ? opts?.matchNumbers ?? DEFAULT_SEARCH_OPTS.matchNumbers : opts?.matchWords ?? DEFAULT_SEARCH_OPTS.matchWords;
702
+ }
703
+ switch (mode) {
704
+ case "start":
705
+ return targetTokenStr.startsWith(searchTokenStr);
706
+ case "end":
707
+ return targetTokenStr.endsWith(searchTokenStr);
708
+ case "startEnd":
709
+ return targetTokenStr.startsWith(searchTokenStr) || targetTokenStr.endsWith(searchTokenStr);
710
+ case "anywhere":
711
+ return targetTokenStr.includes(searchTokenStr);
712
+ case "whole":
713
+ if (!hasExplicitMode && !overrideMode) {
714
+ return searchTokenId === targetTokenId;
715
+ }
716
+ return targetTokenStr === searchTokenStr;
717
+ }
718
+ }
719
+ function binarySearchUint32(arr, target) {
720
+ let left = 0;
721
+ let right = arr.length - 1;
722
+ while (left <= right) {
723
+ const mid = left + right >>> 1;
724
+ const val = arr[mid];
725
+ if (val === target)
726
+ return true;
727
+ if (val < target) {
728
+ left = mid + 1;
729
+ } else {
730
+ right = mid - 1;
731
+ }
732
+ }
733
+ return false;
734
+ }
735
+ function matchPreparedTokenInSortedList(preparedToken, targetTokens, opts) {
736
+ const { str: searchTokenStr, id: searchTokenId, isNumeric, overrideMode } = preparedToken;
737
+ const effectiveMode = overrideMode ?? (isNumeric ? opts?.matchNumbers ?? DEFAULT_SEARCH_OPTS.matchNumbers : opts?.matchWords ?? DEFAULT_SEARCH_OPTS.matchWords);
738
+ if (effectiveMode === "whole" && searchTokenId !== -1) {
739
+ let hasEncodedTokens = false;
740
+ for (let i = 0;i < targetTokens.length; i++) {
741
+ if (targetTokens[i] > TOKEN_ID_MASK) {
742
+ hasEncodedTokens = true;
743
+ break;
744
+ }
745
+ }
746
+ if (!hasEncodedTokens) {
747
+ return binarySearchUint32(targetTokens, searchTokenId);
748
+ }
749
+ }
750
+ for (let i = 0;i < targetTokens.length; i++) {
751
+ const targetEncoded = targetTokens[i];
752
+ if (matchWithModeNumeric(searchTokenId, searchTokenStr, targetEncoded, opts, overrideMode)) {
753
+ return true;
754
+ }
755
+ }
756
+ return false;
757
+ }
758
+ function matchTokenInSortedListNumeric(searchTokenStr, targetTokens, opts) {
759
+ let overrideMode;
760
+ let negated = false;
761
+ let cleanStr = searchTokenStr;
762
+ if (searchTokenStr.length > 2 && searchTokenStr.startsWith("--")) {
763
+ negated = true;
764
+ cleanStr = searchTokenStr.slice(2);
765
+ } else if (searchTokenStr.length > 1 && searchTokenStr.startsWith("~")) {
766
+ negated = true;
767
+ cleanStr = searchTokenStr.slice(1);
768
+ } else if (searchTokenStr.length > 3 && searchTokenStr.startsWith("...")) {
769
+ overrideMode = "end";
770
+ cleanStr = searchTokenStr.slice(3);
771
+ } else if (searchTokenStr.length > 2 && searchTokenStr.startsWith("..")) {
772
+ overrideMode = "end";
773
+ cleanStr = searchTokenStr.slice(2);
774
+ } else if (searchTokenStr.length > 3 && searchTokenStr.endsWith("...")) {
775
+ overrideMode = "start";
776
+ cleanStr = searchTokenStr.slice(0, -3);
777
+ } else if (searchTokenStr.length > 2 && searchTokenStr.endsWith("..")) {
778
+ overrideMode = "start";
779
+ cleanStr = searchTokenStr.slice(0, -2);
780
+ } else if (searchTokenStr.length > 1) {
781
+ const firstChar = searchTokenStr[0];
782
+ if (firstChar && PREFIX_TO_MATCH_MODE[firstChar]) {
783
+ overrideMode = PREFIX_TO_MATCH_MODE[firstChar];
784
+ cleanStr = searchTokenStr.slice(1);
785
+ }
786
+ }
787
+ const preparedToken = {
788
+ str: cleanStr,
789
+ id: findTokenId(cleanStr),
790
+ isNumeric: RE_NUMERIC.test(cleanStr),
791
+ overrideMode,
792
+ negated: negated || undefined
793
+ };
794
+ const matches = matchPreparedTokenInSortedList(preparedToken, targetTokens, opts);
795
+ return negated ? !matches : matches;
796
+ }
797
+ function allPreparedTokensMatch(preparedTokens, targetTokens, opts) {
798
+ for (const preparedToken of preparedTokens) {
799
+ const matches = matchPreparedTokenInSortedList(preparedToken, targetTokens, opts);
800
+ if (preparedToken.negated) {
801
+ if (matches)
802
+ return false;
803
+ } else {
804
+ if (!matches)
805
+ return false;
806
+ }
807
+ }
808
+ return true;
809
+ }
810
+ function allTokensMatchNumeric(searchTokenStrs, targetTokens, opts) {
811
+ const preparedTokens = prepareQueryTokens(searchTokenStrs);
812
+ return allPreparedTokensMatch(preparedTokens, targetTokens, opts);
813
+ }
814
+
815
+ // src/common/numeric/searchInData.ts
816
+ function searchInDataReturnIdsNumeric(query, metadata, opts) {
817
+ const queryTokenStrs = prepareStringForSearch(query);
818
+ if (queryTokenStrs.length === 0) {
819
+ return [];
820
+ }
821
+ const preparedTokens = prepareQueryTokens(queryTokenStrs);
822
+ const results = [];
823
+ for (const [id, targetTokens] of metadata) {
824
+ if (allPreparedTokensMatch(preparedTokens, targetTokens, opts)) {
825
+ results.push(id);
826
+ }
827
+ }
828
+ return results;
829
+ }
830
+ function searchInDataReturnObjectsNumeric(query, metadata, data, opts) {
831
+ const ids = searchInDataReturnIdsNumeric(query, metadata, opts);
832
+ const results = new Map;
833
+ for (const id of ids) {
834
+ const obj = data.get(id);
835
+ if (obj) {
836
+ results.set(id, obj);
837
+ }
838
+ }
839
+ return results;
840
+ }
841
+ function searchInDataReturnIdsWithLimitNumeric(query, metadata, limit, opts) {
842
+ const queryTokenStrs = prepareStringForSearch(query);
843
+ if (queryTokenStrs.length === 0) {
844
+ return [];
845
+ }
846
+ const preparedTokens = prepareQueryTokens(queryTokenStrs);
847
+ const results = [];
848
+ for (const [id, targetTokens] of metadata) {
849
+ if (allPreparedTokensMatch(preparedTokens, targetTokens, opts)) {
850
+ results.push(id);
851
+ if (results.length >= limit) {
852
+ break;
853
+ }
854
+ }
855
+ }
856
+ return results;
857
+ }
858
+ // src/common/numeric/findInLinkedArrays.ts
859
+ function findInLinkedArraysNumeric(query, linked, limit = 10, opts) {
860
+ const queryTokenStrs = prepareStringForSearch(query);
861
+ if (queryTokenStrs.length === 0) {
862
+ return { queryTokens: queryTokenStrs, results: [] };
863
+ }
864
+ const preparedTokens = prepareQueryTokens(queryTokenStrs);
865
+ const positiveTokens = preparedTokens.filter((t) => !t.negated);
866
+ const negatedTokens = preparedTokens.filter((t) => t.negated);
867
+ const results = [];
868
+ for (const [primaryId, primary] of linked.primaryData) {
869
+ if (results.length >= limit)
870
+ break;
871
+ const primaryTokens = linked.primaryMeta.get(primaryId);
872
+ if (!primaryTokens)
873
+ continue;
874
+ const linkedIds = linked.primaryToLinked.get(primaryId) || [];
875
+ let negatedMatchesInPrimary = false;
876
+ for (const negatedToken of negatedTokens) {
877
+ if (matchPreparedTokenInSortedList(negatedToken, primaryTokens, opts)) {
878
+ negatedMatchesInPrimary = true;
879
+ break;
880
+ }
881
+ }
882
+ if (negatedMatchesInPrimary) {
883
+ continue;
884
+ }
885
+ let totalLength = primaryTokens.length;
886
+ for (const linkedId of linkedIds) {
887
+ const linkedTokens = linked.linkedMeta.get(linkedId);
888
+ if (linkedTokens) {
889
+ totalLength += linkedTokens.length;
890
+ }
891
+ }
892
+ const allTokens = new Uint32Array(totalLength);
893
+ let offset = 0;
894
+ allTokens.set(primaryTokens, offset);
895
+ offset += primaryTokens.length;
896
+ for (const linkedId of linkedIds) {
897
+ const linkedTokens = linked.linkedMeta.get(linkedId);
898
+ if (linkedTokens) {
899
+ allTokens.set(linkedTokens, offset);
900
+ offset += linkedTokens.length;
901
+ }
902
+ }
903
+ allTokens.sort();
904
+ let allPositiveMatch = true;
905
+ for (const token of positiveTokens) {
906
+ if (!matchPreparedTokenInSortedList(token, allTokens, opts)) {
907
+ allPositiveMatch = false;
908
+ break;
909
+ }
910
+ }
911
+ if (allPositiveMatch) {
912
+ let anyMatchInPrimary = false;
913
+ let anyMatchInLinked = false;
914
+ const matchingLinkedIds = new Set;
915
+ const tokensMatchingPrimary = new Set;
916
+ for (const preparedToken of positiveTokens) {
917
+ if (matchPreparedTokenInSortedList(preparedToken, primaryTokens, opts)) {
918
+ anyMatchInPrimary = true;
919
+ tokensMatchingPrimary.add(preparedToken);
920
+ }
921
+ }
922
+ const tokensForLinkedMatching = positiveTokens.filter((t) => !tokensMatchingPrimary.has(t));
923
+ if (tokensForLinkedMatching.length > 0 || negatedTokens.length > 0) {
924
+ for (const linkedId of linkedIds) {
925
+ const linkedTokens = linked.linkedMeta.get(linkedId);
926
+ if (linkedTokens) {
927
+ let matchesNegatedToken = false;
928
+ for (const negatedToken of negatedTokens) {
929
+ if (matchPreparedTokenInSortedList(negatedToken, linkedTokens, opts)) {
930
+ matchesNegatedToken = true;
931
+ break;
932
+ }
933
+ }
934
+ if (matchesNegatedToken) {
935
+ continue;
936
+ }
937
+ if (tokensForLinkedMatching.length > 0) {
938
+ const matchesAllNonPrimaryTokens = tokensForLinkedMatching.every((preparedToken) => matchPreparedTokenInSortedList(preparedToken, linkedTokens, opts));
939
+ if (matchesAllNonPrimaryTokens) {
940
+ anyMatchInLinked = true;
941
+ matchingLinkedIds.add(linkedId);
942
+ }
943
+ } else {
944
+ matchingLinkedIds.add(linkedId);
945
+ }
946
+ }
947
+ }
948
+ }
949
+ if (tokensForLinkedMatching.length > 0 && matchingLinkedIds.size === 0) {
950
+ continue;
951
+ }
952
+ const matchedLinked = Array.from(matchingLinkedIds).map((id) => linked.linkedData.get(id)).filter((item) => item !== undefined);
953
+ results.push({
954
+ primary,
955
+ linked: matchedLinked,
956
+ matchedIn: anyMatchInPrimary && anyMatchInLinked ? "both" : anyMatchInPrimary ? "primary" : "linked"
957
+ });
958
+ }
959
+ }
960
+ return { queryTokens: queryTokenStrs, results };
961
+ }
962
+ function findInLinkedArraysSimpleNumeric(query, linked, limit = 10, opts) {
963
+ return findInLinkedArraysNumeric(query, linked, limit, opts).results;
964
+ }
965
+ // src/common/string/createSearchLinkedMetadata.ts
966
+ function createSearchLinkedMetadata(primaryData, primaryMetadata, linkedData, linkedMetadata, foreignKeyGetter) {
967
+ const primaryToLinked = new Map;
968
+ for (const [linkedId, linkedItem] of linkedData) {
969
+ const primaryId = foreignKeyGetter(linkedItem);
970
+ if (primaryId) {
971
+ const list = primaryToLinked.get(primaryId) || [];
972
+ list.push(linkedId);
973
+ primaryToLinked.set(primaryId, list);
974
+ }
975
+ }
976
+ return {
977
+ primaryMeta: primaryMetadata,
978
+ linkedMeta: linkedMetadata,
979
+ primaryToLinked,
980
+ primaryData,
981
+ linkedData
982
+ };
983
+ }
984
+ // src/common/string/updateSearchMetadata.ts
985
+ function updateSearchMetadata(metadata, objectId, obj, spec) {
986
+ const tokens2 = obj != null ? prepareObjectForSearch(obj, spec) : undefined;
987
+ if (tokens2 === undefined) {
988
+ metadata.delete(objectId);
989
+ return false;
990
+ } else {
991
+ metadata.set(objectId, tokens2);
992
+ return true;
993
+ }
994
+ }
995
+ function updateSearchMetadataBatch(metadata, batch, spec) {
996
+ if (batch.length === 0) {
997
+ return { updated: 0, removed: 0 };
998
+ }
999
+ let updated = 0;
1000
+ let removed = 0;
1001
+ for (const { objectId, obj } of batch) {
1002
+ const wasUpdated = updateSearchMetadata(metadata, objectId, obj, spec);
1003
+ if (wasUpdated) {
1004
+ updated++;
1005
+ } else {
1006
+ removed++;
1007
+ }
1008
+ }
1009
+ return { updated, removed };
1010
+ }
1011
+ function removeFromSearchMetadata(metadata, objectId) {
1012
+ return metadata.delete(objectId);
1013
+ }
1014
+ function removeFromSearchMetadataBatch(metadata, objectIds) {
1015
+ if (objectIds.length === 0) {
1016
+ return 0;
1017
+ }
1018
+ let removed = 0;
1019
+ for (const id of objectIds) {
1020
+ if (metadata.delete(id)) {
1021
+ removed++;
1022
+ }
1023
+ }
1024
+ return removed;
1025
+ }
1026
+ // src/utils/matchToken.ts
1027
+ var RE_NUMERIC2 = /^[\d.\-]+$/;
1028
+ var PREFIX_TO_MODE = {
1029
+ "<": "start",
1030
+ ">": "end",
1031
+ "+": "startEnd",
1032
+ "*": "anywhere",
1033
+ "!": "whole"
1034
+ };
1035
+ function matchWithMode(searchToken, targetToken, mode) {
1036
+ switch (mode) {
1037
+ case "start":
1038
+ return targetToken.startsWith(searchToken);
1039
+ case "end":
1040
+ return targetToken.endsWith(searchToken);
1041
+ case "startEnd":
1042
+ return targetToken.startsWith(searchToken) || targetToken.endsWith(searchToken);
1043
+ case "anywhere":
1044
+ return targetToken.includes(searchToken);
1045
+ case "whole":
1046
+ return targetToken === searchToken;
1047
+ }
1048
+ }
1049
+ function matchToken(searchToken, targetToken, opts) {
1050
+ const firstChar = targetToken[0];
1051
+ const prefixMode = firstChar ? PREFIX_TO_MODE[firstChar] : undefined;
1052
+ if (prefixMode) {
1053
+ const actualTarget = targetToken.slice(1);
1054
+ return matchWithMode(searchToken, actualTarget, prefixMode);
1055
+ }
1056
+ const matchWords = opts?.matchWords ?? DEFAULT_SEARCH_OPTS.matchWords;
1057
+ const matchNumbers = opts?.matchNumbers ?? DEFAULT_SEARCH_OPTS.matchNumbers;
1058
+ const isNumeric = RE_NUMERIC2.test(searchToken);
1059
+ return matchWithMode(searchToken, targetToken, isNumeric ? matchNumbers : matchWords);
1060
+ }
1061
+ function matchTokenInSortedList(searchToken, targetTokens, opts) {
1062
+ const isNumeric = RE_NUMERIC2.test(searchToken);
1063
+ const effectiveMode = isNumeric ? opts?.matchNumbers ?? DEFAULT_SEARCH_OPTS.matchNumbers : opts?.matchWords ?? DEFAULT_SEARCH_OPTS.matchWords;
1064
+ const canEarlyExit = effectiveMode === "start";
1065
+ for (const targetToken of targetTokens) {
1066
+ const firstChar = targetToken[0];
1067
+ const hasPrefix = firstChar ? PREFIX_TO_MODE[firstChar] !== undefined : false;
1068
+ if (hasPrefix) {
1069
+ if (matchToken(searchToken, targetToken, opts)) {
1070
+ return true;
1071
+ }
1072
+ } else {
1073
+ if (canEarlyExit) {
1074
+ if (targetToken.startsWith(searchToken)) {
1075
+ return true;
1076
+ }
1077
+ if (targetToken > searchToken && targetToken[0] !== searchToken[0]) {
1078
+ return false;
1079
+ }
1080
+ } else {
1081
+ if (matchToken(searchToken, targetToken, opts)) {
1082
+ return true;
1083
+ }
1084
+ }
1085
+ }
1086
+ }
1087
+ return false;
1088
+ }
1089
+ function allTokensMatch(searchTokens, targetTokens, opts) {
1090
+ for (const searchToken of searchTokens) {
1091
+ if (!matchTokenInSortedList(searchToken, targetTokens, opts)) {
1092
+ return false;
1093
+ }
1094
+ }
1095
+ return true;
1096
+ }
1097
+
1098
+ // src/common/findInArrayReturnDataAndMeta.ts
1099
+ function findInArrayReturnDataAndMeta(query, data, metadata, limit = 10, opts) {
1100
+ const queryTokens = prepareStringForSearch(query);
1101
+ if (queryTokens.length === 0) {
1102
+ return {
1103
+ queryTokens,
1104
+ results: []
1105
+ };
1106
+ }
1107
+ const results = [];
1108
+ for (const [id, itemTokens] of metadata) {
1109
+ if (results.length >= limit) {
1110
+ break;
1111
+ }
1112
+ if (allTokensMatch(queryTokens, itemTokens, opts)) {
1113
+ const item = data.get(id);
1114
+ if (item) {
1115
+ results.push({
1116
+ item,
1117
+ tokens: itemTokens
1118
+ });
1119
+ }
1120
+ }
1121
+ }
1122
+ return {
1123
+ queryTokens,
1124
+ results
1125
+ };
1126
+ }
1127
+ function findInArrayReturnIds(query, metadata, limit = 10, opts) {
1128
+ const queryTokens = prepareStringForSearch(query);
1129
+ if (queryTokens.length === 0) {
1130
+ return [];
1131
+ }
1132
+ const results = [];
1133
+ for (const [id, itemTokens] of metadata) {
1134
+ if (results.length >= limit) {
1135
+ break;
1136
+ }
1137
+ if (allTokensMatch(queryTokens, itemTokens, opts)) {
1138
+ results.push(id);
1139
+ }
1140
+ }
1141
+ return results;
1142
+ }
1143
+
1144
+ // src/common/findInArray.ts
1145
+ function findInArray(query, data, metadata, limit = 10, opts) {
1146
+ const result = findInArrayReturnDataAndMeta(query, data, metadata, limit, opts);
1147
+ return result.results.map((r) => r.item);
1148
+ }
1149
+ // src/common/findInLinkedArrays.ts
1150
+ function findInLinkedArrays(query, linked, limit = 10, opts) {
1151
+ const queryTokens = prepareStringForSearch(query);
1152
+ if (queryTokens.length === 0) {
1153
+ return { queryTokens, results: [] };
1154
+ }
1155
+ const results = [];
1156
+ for (const [primaryId, primary] of linked.primaryData) {
1157
+ if (results.length >= limit)
1158
+ break;
1159
+ const primaryTokens = linked.primaryMeta.get(primaryId);
1160
+ if (!primaryTokens)
1161
+ continue;
1162
+ const linkedIds = linked.primaryToLinked.get(primaryId) || [];
1163
+ const allTokens = [...primaryTokens];
1164
+ for (const linkedId of linkedIds) {
1165
+ const linkedTokens = linked.linkedMeta.get(linkedId);
1166
+ if (linkedTokens) {
1167
+ allTokens.push(...linkedTokens);
1168
+ }
1169
+ }
1170
+ allTokens.sort();
1171
+ if (allTokensMatch(queryTokens, allTokens, opts)) {
1172
+ let anyMatchInPrimary = false;
1173
+ let anyMatchInLinked = false;
1174
+ const matchingLinkedIds = new Set;
1175
+ const tokensMatchingPrimary = new Set;
1176
+ for (const queryToken of queryTokens) {
1177
+ if (matchTokenInSortedList(queryToken, primaryTokens, opts)) {
1178
+ anyMatchInPrimary = true;
1179
+ tokensMatchingPrimary.add(queryToken);
1180
+ }
1181
+ }
1182
+ const tokensForLinkedMatching = queryTokens.filter((t) => !tokensMatchingPrimary.has(t));
1183
+ if (tokensForLinkedMatching.length > 0) {
1184
+ for (const linkedId of linkedIds) {
1185
+ const linkedTokens = linked.linkedMeta.get(linkedId);
1186
+ if (linkedTokens) {
1187
+ const matchesAllNonPrimaryTokens = tokensForLinkedMatching.every((queryToken) => matchTokenInSortedList(queryToken, linkedTokens, opts));
1188
+ if (matchesAllNonPrimaryTokens) {
1189
+ anyMatchInLinked = true;
1190
+ matchingLinkedIds.add(linkedId);
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ if (tokensForLinkedMatching.length > 0 && matchingLinkedIds.size === 0) {
1196
+ continue;
1197
+ }
1198
+ const matchedLinked = Array.from(matchingLinkedIds).map((id) => linked.linkedData.get(id)).filter((item) => item !== undefined);
1199
+ results.push({
1200
+ primary,
1201
+ linked: matchedLinked,
1202
+ matchedIn: anyMatchInPrimary && anyMatchInLinked ? "both" : anyMatchInPrimary ? "primary" : "linked"
1203
+ });
1204
+ }
1205
+ }
1206
+ return { queryTokens, results };
1207
+ }
1208
+ function findInLinkedArraysSimple(query, linked, limit = 10, opts) {
1209
+ return findInLinkedArrays(query, linked, limit, opts).results;
1210
+ }
1211
+ // src/common/syncSearchArrayMetadata.ts
1212
+ function tokensEqual(a, b) {
1213
+ if (a.length !== b.length)
1214
+ return false;
1215
+ for (let i = 0;i < a.length; i++) {
1216
+ if (a[i] !== b[i])
1217
+ return false;
1218
+ }
1219
+ return true;
1220
+ }
1221
+ function syncSearchArrayMetadata(metadata, newData, spec) {
1222
+ const result = {
1223
+ added: 0,
1224
+ updated: 0,
1225
+ removed: 0,
1226
+ addedIds: [],
1227
+ updatedIds: [],
1228
+ removedIds: []
1229
+ };
1230
+ for (const id of metadata.keys()) {
1231
+ if (!newData.has(id)) {
1232
+ metadata.delete(id);
1233
+ result.removed++;
1234
+ result.removedIds.push(id);
1235
+ }
1236
+ }
1237
+ for (const [id, item] of newData) {
1238
+ const newTokens = prepareObjectForSearch(item, spec);
1239
+ if (newTokens === undefined) {
1240
+ if (metadata.has(id)) {
1241
+ metadata.delete(id);
1242
+ result.removed++;
1243
+ result.removedIds.push(id);
1244
+ }
1245
+ continue;
1246
+ }
1247
+ const existingTokens = metadata.get(id);
1248
+ if (existingTokens === undefined) {
1249
+ metadata.set(id, newTokens);
1250
+ result.added++;
1251
+ result.addedIds.push(id);
1252
+ } else if (!tokensEqual(existingTokens, newTokens)) {
1253
+ metadata.set(id, newTokens);
1254
+ result.updated++;
1255
+ result.updatedIds.push(id);
1256
+ }
1257
+ }
1258
+ return result;
1259
+ }
1260
+ function syncSearchArrayMetadataWithPrevious(metadata, previousData, newData, options, spec) {
1261
+ const result = {
1262
+ added: 0,
1263
+ updated: 0,
1264
+ removed: 0,
1265
+ addedIds: [],
1266
+ updatedIds: [],
1267
+ removedIds: []
1268
+ };
1269
+ for (const id of previousData.keys()) {
1270
+ if (!newData.has(id)) {
1271
+ metadata.delete(id);
1272
+ result.removed++;
1273
+ result.removedIds.push(id);
1274
+ }
1275
+ }
1276
+ for (const [id, item] of newData) {
1277
+ const wasInPrevious = previousData.has(id);
1278
+ if (!wasInPrevious) {
1279
+ const tokens2 = prepareObjectForSearch(item, spec);
1280
+ if (tokens2 !== undefined) {
1281
+ metadata.set(id, tokens2);
1282
+ result.added++;
1283
+ result.addedIds.push(id);
1284
+ }
1285
+ } else if (!options?.skipUpdateCheck) {
1286
+ const newTokens = prepareObjectForSearch(item, spec);
1287
+ if (newTokens === undefined) {
1288
+ metadata.delete(id);
1289
+ result.removed++;
1290
+ result.removedIds.push(id);
1291
+ } else {
1292
+ const existingTokens = metadata.get(id);
1293
+ if (existingTokens && !tokensEqual(existingTokens, newTokens)) {
1294
+ metadata.set(id, newTokens);
1295
+ result.updated++;
1296
+ result.updatedIds.push(id);
1297
+ }
1298
+ }
1299
+ }
1300
+ }
1301
+ return result;
1302
+ }
1303
+ // src/common/updateSearchLinkedMetadata.ts
1304
+ function tokensEqual2(a, b) {
1305
+ if (a.length !== b.length)
1306
+ return false;
1307
+ for (let i = 0;i < a.length; i++) {
1308
+ if (a[i] !== b[i])
1309
+ return false;
1310
+ }
1311
+ return true;
1312
+ }
1313
+ function upsertPrimaryItem(linked, item, spec) {
1314
+ const id = item._id;
1315
+ const wasAdded = !linked.primaryData.has(id);
1316
+ linked.primaryData.set(id, item);
1317
+ const tokens2 = prepareObjectForSearch(item, spec);
1318
+ if (tokens2 !== undefined) {
1319
+ linked.primaryMeta.set(id, tokens2);
1320
+ } else {
1321
+ linked.primaryMeta.delete(id);
1322
+ }
1323
+ if (wasAdded && !linked.primaryToLinked.has(id)) {
1324
+ linked.primaryToLinked.set(id, []);
1325
+ }
1326
+ return { added: wasAdded };
1327
+ }
1328
+ function removePrimaryItem(linked, primaryId) {
1329
+ if (!linked.primaryData.has(primaryId)) {
1330
+ return false;
1331
+ }
1332
+ linked.primaryData.delete(primaryId);
1333
+ linked.primaryMeta.delete(primaryId);
1334
+ linked.primaryToLinked.delete(primaryId);
1335
+ return true;
1336
+ }
1337
+ function upsertLinkedItem(linked, item, foreignKeyGetter, spec) {
1338
+ const id = item._id;
1339
+ const newPrimaryId = foreignKeyGetter(item);
1340
+ let previousPrimaryId;
1341
+ const existingItem = linked.linkedData.get(id);
1342
+ if (existingItem) {
1343
+ previousPrimaryId = foreignKeyGetter(existingItem);
1344
+ }
1345
+ const wasAdded = !existingItem;
1346
+ linked.linkedData.set(id, item);
1347
+ const tokens2 = prepareObjectForSearch(item, spec);
1348
+ if (tokens2 !== undefined) {
1349
+ linked.linkedMeta.set(id, tokens2);
1350
+ } else {
1351
+ linked.linkedMeta.delete(id);
1352
+ }
1353
+ if (previousPrimaryId !== newPrimaryId) {
1354
+ if (previousPrimaryId) {
1355
+ const oldList = linked.primaryToLinked.get(previousPrimaryId);
1356
+ if (oldList) {
1357
+ const index = oldList.indexOf(id);
1358
+ if (index !== -1) {
1359
+ oldList.splice(index, 1);
1360
+ }
1361
+ }
1362
+ }
1363
+ if (newPrimaryId) {
1364
+ const newList = linked.primaryToLinked.get(newPrimaryId);
1365
+ if (newList) {
1366
+ if (!newList.includes(id)) {
1367
+ newList.push(id);
1368
+ }
1369
+ } else {
1370
+ linked.primaryToLinked.set(newPrimaryId, [id]);
1371
+ }
1372
+ }
1373
+ }
1374
+ return {
1375
+ added: wasAdded,
1376
+ previousPrimaryId: wasAdded ? undefined : previousPrimaryId
1377
+ };
1378
+ }
1379
+ function removeLinkedItem(linked, linkedId, foreignKeyGetter) {
1380
+ const existingItem = linked.linkedData.get(linkedId);
1381
+ if (!existingItem) {
1382
+ return false;
1383
+ }
1384
+ const primaryId = foreignKeyGetter(existingItem);
1385
+ linked.linkedData.delete(linkedId);
1386
+ linked.linkedMeta.delete(linkedId);
1387
+ if (primaryId) {
1388
+ const list = linked.primaryToLinked.get(primaryId);
1389
+ if (list) {
1390
+ const index = list.indexOf(linkedId);
1391
+ if (index !== -1) {
1392
+ list.splice(index, 1);
1393
+ }
1394
+ }
1395
+ }
1396
+ return true;
1397
+ }
1398
+ function syncLinkedItemsForPrimary(linked, primaryId, newLinkedItems, foreignKeyGetter, spec) {
1399
+ const result = {
1400
+ added: 0,
1401
+ updated: 0,
1402
+ removed: 0
1403
+ };
1404
+ const currentLinkedIds = new Set(linked.primaryToLinked.get(primaryId) || []);
1405
+ const newLinkedIds = new Set;
1406
+ for (const [id, item] of newLinkedItems) {
1407
+ if (foreignKeyGetter(item) === primaryId) {
1408
+ newLinkedIds.add(id);
1409
+ }
1410
+ }
1411
+ for (const id of currentLinkedIds) {
1412
+ if (!newLinkedIds.has(id)) {
1413
+ const item = linked.linkedData.get(id);
1414
+ if (item) {
1415
+ linked.linkedData.delete(id);
1416
+ linked.linkedMeta.delete(id);
1417
+ result.removed++;
1418
+ }
1419
+ }
1420
+ }
1421
+ for (const id of newLinkedIds) {
1422
+ const item = newLinkedItems.get(id);
1423
+ const tokens2 = prepareObjectForSearch(item, spec);
1424
+ if (currentLinkedIds.has(id)) {
1425
+ const existingTokens = linked.linkedMeta.get(id);
1426
+ if (tokens2 !== undefined) {
1427
+ if (!existingTokens || !tokensEqual2(existingTokens, tokens2)) {
1428
+ linked.linkedMeta.set(id, tokens2);
1429
+ result.updated++;
1430
+ }
1431
+ }
1432
+ linked.linkedData.set(id, item);
1433
+ } else {
1434
+ linked.linkedData.set(id, item);
1435
+ if (tokens2 !== undefined) {
1436
+ linked.linkedMeta.set(id, tokens2);
1437
+ }
1438
+ result.added++;
1439
+ }
1440
+ }
1441
+ linked.primaryToLinked.set(primaryId, Array.from(newLinkedIds));
1442
+ return result;
1443
+ }
1444
+ // src/common/SearchUniverse.ts
1445
+ class SearchUniverse {
1446
+ collections = new Map;
1447
+ registerCollection(name, config = {}) {
1448
+ if (this.collections.has(name)) {
1449
+ throw new Error(`Collection already registered: ${name}`);
1450
+ }
1451
+ const collection = {
1452
+ data: new Map,
1453
+ metadata: new Map,
1454
+ config
1455
+ };
1456
+ if (config.linkedTo) {
1457
+ collection.primaryToLinked = new Map;
1458
+ }
1459
+ this.collections.set(name, collection);
1460
+ }
1461
+ hasCollection(name) {
1462
+ return this.collections.has(name);
1463
+ }
1464
+ getCollectionNames() {
1465
+ return Array.from(this.collections.keys());
1466
+ }
1467
+ loadCollection(name, items) {
1468
+ const collection = this.getCollectionOrThrow(name);
1469
+ collection.data.clear();
1470
+ collection.metadata.clear();
1471
+ if (collection.primaryToLinked) {
1472
+ collection.primaryToLinked.clear();
1473
+ }
1474
+ for (const item of items) {
1475
+ collection.data.set(item._id, item);
1476
+ }
1477
+ const newMetadata = createSearchArrayMetadataNumeric(collection.data, collection.config.spec);
1478
+ for (const [id, tokens2] of newMetadata) {
1479
+ collection.metadata.set(id, tokens2);
1480
+ }
1481
+ if (collection.config.linkedTo && collection.primaryToLinked) {
1482
+ const { foreignKeyGetter } = collection.config.linkedTo;
1483
+ for (const [id, item] of collection.data) {
1484
+ const primaryId = foreignKeyGetter(item);
1485
+ if (primaryId) {
1486
+ const list = collection.primaryToLinked.get(primaryId) || [];
1487
+ list.push(id);
1488
+ collection.primaryToLinked.set(primaryId, list);
1489
+ }
1490
+ }
1491
+ }
1492
+ }
1493
+ getItem(collectionName, id) {
1494
+ const collection = this.getCollectionOrThrow(collectionName);
1495
+ return collection.data.get(id);
1496
+ }
1497
+ getItems(collectionName) {
1498
+ const collection = this.getCollectionOrThrow(collectionName);
1499
+ return Array.from(collection.data.values());
1500
+ }
1501
+ getCollectionSize(collectionName) {
1502
+ const collection = this.getCollectionOrThrow(collectionName);
1503
+ return collection.data.size;
1504
+ }
1505
+ getMetadata(collectionName) {
1506
+ const collection = this.getCollectionOrThrow(collectionName);
1507
+ return collection.metadata;
1508
+ }
1509
+ getData(collectionName) {
1510
+ const collection = this.getCollectionOrThrow(collectionName);
1511
+ return collection.data;
1512
+ }
1513
+ getLinkedIds(linkedCollectionName, primaryId) {
1514
+ const collection = this.getCollectionOrThrow(linkedCollectionName);
1515
+ if (!collection.primaryToLinked) {
1516
+ throw new Error(`Collection ${linkedCollectionName} is not a linked collection`);
1517
+ }
1518
+ return collection.primaryToLinked.get(primaryId) || [];
1519
+ }
1520
+ getLinkedItems(linkedCollectionName, primaryId) {
1521
+ const collection = this.getCollectionOrThrow(linkedCollectionName);
1522
+ const ids = this.getLinkedIds(linkedCollectionName, primaryId);
1523
+ return ids.map((id) => collection.data.get(id)).filter(Boolean);
1524
+ }
1525
+ updateSearchMetadata(collectionName, id, item) {
1526
+ const collection = this.getCollectionOrThrow(collectionName);
1527
+ const existingItem = collection.data.get(id);
1528
+ const wasAdded = !existingItem;
1529
+ let previousPrimaryId;
1530
+ if (collection.config.linkedTo && collection.primaryToLinked) {
1531
+ const { foreignKeyGetter } = collection.config.linkedTo;
1532
+ const fkGetter = foreignKeyGetter;
1533
+ if (existingItem) {
1534
+ previousPrimaryId = fkGetter(existingItem);
1535
+ }
1536
+ const newPrimaryId = fkGetter(item);
1537
+ if (previousPrimaryId !== newPrimaryId) {
1538
+ if (previousPrimaryId) {
1539
+ const oldList = collection.primaryToLinked.get(previousPrimaryId);
1540
+ if (oldList) {
1541
+ const index = oldList.indexOf(id);
1542
+ if (index !== -1) {
1543
+ oldList.splice(index, 1);
1544
+ if (oldList.length === 0) {
1545
+ collection.primaryToLinked.delete(previousPrimaryId);
1546
+ }
1547
+ }
1548
+ }
1549
+ }
1550
+ if (newPrimaryId && !item._deleted && !item._blocked) {
1551
+ const newList = collection.primaryToLinked.get(newPrimaryId) || [];
1552
+ if (!newList.includes(id)) {
1553
+ newList.push(id);
1554
+ }
1555
+ collection.primaryToLinked.set(newPrimaryId, newList);
1556
+ }
1557
+ } else if (item._deleted || item._blocked) {
1558
+ if (previousPrimaryId) {
1559
+ const list = collection.primaryToLinked.get(previousPrimaryId);
1560
+ if (list) {
1561
+ const index = list.indexOf(id);
1562
+ if (index !== -1) {
1563
+ list.splice(index, 1);
1564
+ if (list.length === 0) {
1565
+ collection.primaryToLinked.delete(previousPrimaryId);
1566
+ }
1567
+ }
1568
+ }
1569
+ }
1570
+ }
1571
+ }
1572
+ collection.data.set(id, item);
1573
+ const tokensMap = createTokensMap();
1574
+ try {
1575
+ const tokens2 = prepareObjectForSearchNumeric(item, collection.config.spec, tokensMap);
1576
+ if (tokens2 !== undefined) {
1577
+ collection.metadata.set(id, tokens2);
1578
+ } else {
1579
+ collection.metadata.delete(id);
1580
+ }
1581
+ } finally {
1582
+ clearTokensMap(tokensMap);
1583
+ }
1584
+ return {
1585
+ added: wasAdded,
1586
+ previousPrimaryId: wasAdded ? undefined : previousPrimaryId
1587
+ };
1588
+ }
1589
+ updateSearchMetadataBatch(collectionName, items) {
1590
+ if (items.length === 0) {
1591
+ return { added: 0, updated: 0, removed: 0 };
1592
+ }
1593
+ const result = {
1594
+ added: 0,
1595
+ updated: 0,
1596
+ removed: 0
1597
+ };
1598
+ for (const item of items) {
1599
+ const updateResult = this.updateSearchMetadata(collectionName, item._id, item);
1600
+ if (item._deleted || item._blocked) {
1601
+ result.removed++;
1602
+ } else if (updateResult.added) {
1603
+ result.added++;
1604
+ } else {
1605
+ result.updated++;
1606
+ }
1607
+ }
1608
+ return result;
1609
+ }
1610
+ removeFromSearchMetadata(collectionName, id) {
1611
+ const collection = this.getCollectionOrThrow(collectionName);
1612
+ const existingItem = collection.data.get(id);
1613
+ if (!existingItem) {
1614
+ return false;
1615
+ }
1616
+ if (collection.config.linkedTo && collection.primaryToLinked) {
1617
+ const { foreignKeyGetter } = collection.config.linkedTo;
1618
+ const primaryId = foreignKeyGetter(existingItem);
1619
+ if (primaryId) {
1620
+ const list = collection.primaryToLinked.get(primaryId);
1621
+ if (list) {
1622
+ const index = list.indexOf(id);
1623
+ if (index !== -1) {
1624
+ list.splice(index, 1);
1625
+ if (list.length === 0) {
1626
+ collection.primaryToLinked.delete(primaryId);
1627
+ }
1628
+ }
1629
+ }
1630
+ }
1631
+ }
1632
+ collection.data.delete(id);
1633
+ collection.metadata.delete(id);
1634
+ return true;
1635
+ }
1636
+ removeFromSearchMetadataBatch(collectionName, ids) {
1637
+ if (ids.length === 0) {
1638
+ return 0;
1639
+ }
1640
+ let removed = 0;
1641
+ for (const id of ids) {
1642
+ if (this.removeFromSearchMetadata(collectionName, id)) {
1643
+ removed++;
1644
+ }
1645
+ }
1646
+ return removed;
1647
+ }
1648
+ getCollectionOrThrow(name) {
1649
+ const collection = this.collections.get(name);
1650
+ if (!collection) {
1651
+ throw new Error(`Collection not found: ${name}`);
1652
+ }
1653
+ return collection;
1654
+ }
1655
+ searchUniversally(query, limit = 10, opts) {
1656
+ const results = {};
1657
+ const { inCollections, ...searchOpts } = opts || {};
1658
+ for (const [name, collection] of this.collections) {
1659
+ if (collection.config.linkedTo) {
1660
+ const linkedKey = `${name}-${collection.config.linkedTo.collectionName}`;
1661
+ if (inCollections && !inCollections.includes(name) && !inCollections.includes(linkedKey)) {
1662
+ continue;
1663
+ }
1664
+ const primaryCollectionName = collection.config.linkedTo.collectionName;
1665
+ const primaryCollection = this.collections.get(primaryCollectionName);
1666
+ if (!primaryCollection)
1667
+ continue;
1668
+ const linkedMetadata = {
1669
+ primaryMeta: primaryCollection.metadata,
1670
+ linkedMeta: collection.metadata,
1671
+ primaryToLinked: collection.primaryToLinked || new Map,
1672
+ primaryData: primaryCollection.data,
1673
+ linkedData: collection.data
1674
+ };
1675
+ const linkedSearchResults = findInLinkedArraysNumeric(query, linkedMetadata, limit, searchOpts);
1676
+ if (linkedSearchResults.results.length > 0) {
1677
+ const combinedResults = [];
1678
+ const hasNegation = query.includes("--");
1679
+ for (const result of linkedSearchResults.results) {
1680
+ let linkedItems = result.linked;
1681
+ if (result.matchedIn === "primary" && !hasNegation) {
1682
+ const primaryId = result.primary._id;
1683
+ const allLinkedIds = collection.primaryToLinked?.get(primaryId) || [];
1684
+ linkedItems = allLinkedIds.map((id) => collection.data.get(id)).filter((item) => item !== undefined);
1685
+ }
1686
+ combinedResults.push({
1687
+ primary: result.primary,
1688
+ linked: linkedItems,
1689
+ matchedIn: result.matchedIn
1690
+ });
1691
+ }
1692
+ results[name] = combinedResults;
1693
+ }
1694
+ } else {
1695
+ if (inCollections && !inCollections.includes(name)) {
1696
+ continue;
1697
+ }
1698
+ const matchingIds = searchInDataReturnIdsWithLimitNumeric(query, collection.metadata, limit, searchOpts);
1699
+ if (matchingIds.length > 0) {
1700
+ const collectionResults = [];
1701
+ for (const id of matchingIds) {
1702
+ const item = collection.data.get(id);
1703
+ if (item) {
1704
+ collectionResults.push(item);
1705
+ }
1706
+ }
1707
+ results[name] = collectionResults;
1708
+ }
1709
+ }
1710
+ }
1711
+ return results;
1712
+ }
1713
+ clear() {
1714
+ for (const collection of this.collections.values()) {
1715
+ collection.data.clear();
1716
+ collection.metadata.clear();
1717
+ if (collection.primaryToLinked) {
1718
+ collection.primaryToLinked.clear();
1719
+ }
1720
+ }
1721
+ this.collections.clear();
1722
+ }
1723
+ }
1724
+ export {
1725
+ wrapMetadataLegacy,
1726
+ upsertPrimaryItem,
1727
+ upsertLinkedItem,
1728
+ updateSearchMetadata as updateSearchMetadataString,
1729
+ updateSearchMetadataBatch as updateSearchMetadataBatchString,
1730
+ updateSearchMetadataBatchNumeric as updateSearchMetadataBatch,
1731
+ updateSearchMetadataNumeric as updateSearchMetadata,
1732
+ unwrapMetadataLegacy,
1733
+ tokens,
1734
+ tokenize,
1735
+ syncSearchArrayMetadataWithPrevious,
1736
+ syncSearchArrayMetadata,
1737
+ syncLinkedItemsForPrimary,
1738
+ searchableDataToArray,
1739
+ searchInDataReturnIdsWithLimitNumeric as searchInDataWithLimit,
1740
+ searchInDataReturnObjectsNumeric as searchInDataReturnObjects,
1741
+ searchInDataReturnIdsNumeric as searchInDataReturnIds,
1742
+ searchInDataReturnIdsNumeric as searchInData,
1743
+ sanitiseString,
1744
+ resetTokenRegistry,
1745
+ removePrimaryItem,
1746
+ removeLinkedItem,
1747
+ removeFromSearchMetadata as removeFromSearchMetadataString,
1748
+ removeFromSearchMetadataBatch as removeFromSearchMetadataBatchString,
1749
+ removeFromSearchMetadataBatchNumeric as removeFromSearchMetadataBatch,
1750
+ removeFromSearchMetadataNumeric as removeFromSearchMetadata,
1751
+ registerToken,
1752
+ preprocessString,
1753
+ prepareStringForSearch,
1754
+ prepareQueryTokens,
1755
+ prepareObjectForSearch as prepareObjectForSearchString,
1756
+ prepareObjectForSearchNumeric as prepareObjectForSearch,
1757
+ normalizeDates,
1758
+ matchTokenInSortedListNumeric,
1759
+ matchTokenInSortedList,
1760
+ matchToken,
1761
+ matchPreparedTokenInSortedList,
1762
+ isDeletedOrBlocked,
1763
+ getTokenCount,
1764
+ getTokenById,
1765
+ getOrCreateTokenId,
1766
+ findTokenId,
1767
+ findInLinkedArraysSimpleNumeric,
1768
+ findInLinkedArraysSimple,
1769
+ findInLinkedArraysNumeric,
1770
+ findInLinkedArrays,
1771
+ findInArrayReturnIds,
1772
+ findInArrayReturnDataAndMeta,
1773
+ findInArray,
1774
+ extractSearchableStringDefault,
1775
+ encodeTokenWithMode,
1776
+ decodeTokenId,
1777
+ decodeMatchMode,
1778
+ createTokensMap,
1779
+ createSearchLinkedMetadata as createSearchLinkedMetadataString,
1780
+ createSearchLinkedMetadataNumeric as createSearchLinkedMetadata,
1781
+ createSearchArrayMetadata as createSearchArrayMetadataString,
1782
+ createSearchArrayMetadataNumeric as createSearchArrayMetadata,
1783
+ clearTokensMap,
1784
+ binarySearchUint32,
1785
+ arrayToSearchableData,
1786
+ allTokensMatchNumeric,
1787
+ allTokensMatch,
1788
+ allPreparedTokensMatch,
1789
+ TOKEN_ID_MASK,
1790
+ SearchUniverse,
1791
+ PREFIX_TO_MATCH_MODE,
1792
+ MATCH_MODE_PREFIXES,
1793
+ MATCH_MODE_BITS,
1794
+ DEFAULT_SEARCH_OPTS
1795
+ };