cry-search 1.0.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +73 -98
- package/README.md +39 -28
- package/UNIVERSE.md +11 -18
- package/dist/common/SearchUniverse.d.ts.map +1 -1
- package/dist/common/numeric/AugmentedMetadata.d.ts +27 -92
- package/dist/common/numeric/AugmentedMetadata.d.ts.map +1 -1
- package/dist/common/numeric/createSearchArrayMetadata.d.ts +47 -7
- package/dist/common/numeric/createSearchArrayMetadata.d.ts.map +1 -1
- package/dist/common/numeric/findInLinkedArrays.d.ts +7 -4
- package/dist/common/numeric/findInLinkedArrays.d.ts.map +1 -1
- package/dist/common/numeric/scoring.d.ts +95 -0
- package/dist/common/numeric/scoring.d.ts.map +1 -0
- package/dist/common/numeric/searchAndRank.d.ts +18 -60
- package/dist/common/numeric/searchAndRank.d.ts.map +1 -1
- package/dist/common/numeric/searchInData.d.ts +17 -9
- package/dist/common/numeric/searchInData.d.ts.map +1 -1
- package/dist/common/numeric/syncSearchArrayMetadata.d.ts +7 -50
- package/dist/common/numeric/syncSearchArrayMetadata.d.ts.map +1 -1
- package/dist/common/numeric/updateSearchLinkedMetadata.d.ts +11 -110
- package/dist/common/numeric/updateSearchLinkedMetadata.d.ts.map +1 -1
- package/dist/common/numeric/updateSearchMetadata.d.ts.map +1 -1
- package/dist/index.cjs +614 -360
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +614 -360
- package/dist/types/index.d.ts +35 -50
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/matchTokenNumeric.d.ts.map +1 -1
- package/dist/utils/prepareStringForSearchNumeric.d.ts +24 -29
- package/dist/utils/prepareStringForSearchNumeric.d.ts.map +1 -1
- package/package.json +4 -14
- package/dist/common/findInArray.d.ts +0 -37
- package/dist/common/findInArray.d.ts.map +0 -1
- package/dist/common/findInArrayReturnDataAndMeta.d.ts +0 -52
- package/dist/common/findInArrayReturnDataAndMeta.d.ts.map +0 -1
- package/dist/common/findInLinkedArrays.d.ts +0 -66
- package/dist/common/findInLinkedArrays.d.ts.map +0 -1
- package/dist/common/string/createSearchArrayMetadata.d.ts +0 -117
- package/dist/common/string/createSearchArrayMetadata.d.ts.map +0 -1
- package/dist/common/string/createSearchLinkedMetadata.d.ts +0 -36
- package/dist/common/string/createSearchLinkedMetadata.d.ts.map +0 -1
- package/dist/common/string/index.d.ts +0 -10
- package/dist/common/string/index.d.ts.map +0 -1
- package/dist/common/string/updateSearchMetadata.d.ts +0 -103
- package/dist/common/string/updateSearchMetadata.d.ts.map +0 -1
- package/dist/common/syncSearchArrayMetadata.d.ts +0 -68
- package/dist/common/syncSearchArrayMetadata.d.ts.map +0 -1
- package/dist/common/updateSearchLinkedMetadata.d.ts +0 -139
- package/dist/common/updateSearchLinkedMetadata.d.ts.map +0 -1
- package/dist/string.cjs +0 -930
- package/dist/string.d.cts +0 -26
- package/dist/string.d.ts +0 -26
- package/dist/string.d.ts.map +0 -1
- package/dist/string.js +0 -898
- package/dist/utils/matchToken.d.ts +0 -65
- package/dist/utils/matchToken.d.ts.map +0 -1
package/dist/string.js
DELETED
|
@@ -1,898 +0,0 @@
|
|
|
1
|
-
// src/utils/normalizeDates.ts
|
|
2
|
-
var MONTH_NAMES = {
|
|
3
|
-
jan: "01",
|
|
4
|
-
feb: "02",
|
|
5
|
-
mar: "03",
|
|
6
|
-
apr: "04",
|
|
7
|
-
maj: "05",
|
|
8
|
-
jun: "06",
|
|
9
|
-
jul: "07",
|
|
10
|
-
avg: "08",
|
|
11
|
-
sep: "09",
|
|
12
|
-
okt: "10",
|
|
13
|
-
nov: "11",
|
|
14
|
-
dec: "12",
|
|
15
|
-
januar: "01",
|
|
16
|
-
februar: "02",
|
|
17
|
-
marec: "03",
|
|
18
|
-
april: "04",
|
|
19
|
-
junij: "06",
|
|
20
|
-
julij: "07",
|
|
21
|
-
avgust: "08",
|
|
22
|
-
september: "09",
|
|
23
|
-
oktober: "10",
|
|
24
|
-
november: "11",
|
|
25
|
-
december: "12",
|
|
26
|
-
january: "01",
|
|
27
|
-
february: "02",
|
|
28
|
-
march: "03",
|
|
29
|
-
may: "05",
|
|
30
|
-
june: "06",
|
|
31
|
-
july: "07",
|
|
32
|
-
august: "08",
|
|
33
|
-
october: "10"
|
|
34
|
-
};
|
|
35
|
-
var RE_DATE_ISO = /\b(\d{4})-(\d{2})-(\d{2})(?:T[\d:.]+Z?)?\b/g;
|
|
36
|
-
var RE_DATE_ISO_YM = /\b(\d{4})-(\d{2})\b/g;
|
|
37
|
-
var RE_DATE_DMY = /\b(\d{1,2})\.(\d{1,2})\.(\d{4})\b/g;
|
|
38
|
-
var RE_DATE_DMY_SHORT = /\b(\d{1,2})\.(\d{1,2})\.(\d{2})\b/g;
|
|
39
|
-
var RE_DATE_MY = /\b(\d{1,2})\.(\d{4})\b/g;
|
|
40
|
-
var RE_DATE_MY_SLASH_DASH = /\b(\d{1,2})[-/](\d{4})\b/g;
|
|
41
|
-
var RE_DATE_MY_SLASH_SHORT = /\b(\d{1,2})\/(\d{2})\b/g;
|
|
42
|
-
var RE_DATE_MMYYYY = /\b(0[1-9]|1[0-2])(20\d{2})\b/g;
|
|
43
|
-
var RE_DATE_DDMMYYYY = /\b(0[1-9]|[12]\d|3[01])(0[1-9]|1[0-2])(20\d{2})\b/g;
|
|
44
|
-
var RE_DATE_MONTH_YEAR = new RegExp(`\\b(${Object.keys(MONTH_NAMES).join("|")})\\s*(\\d{4})\\b`, "gi");
|
|
45
|
-
function pad(num, length) {
|
|
46
|
-
return num.padStart(length, "0");
|
|
47
|
-
}
|
|
48
|
-
function normalizeDates(input) {
|
|
49
|
-
let result = input;
|
|
50
|
-
result = result.replace(RE_DATE_ISO, (_match, year, month, day) => {
|
|
51
|
-
return `${year}${month}${day}`;
|
|
52
|
-
});
|
|
53
|
-
result = result.replace(RE_DATE_ISO_YM, (_match, year, month) => {
|
|
54
|
-
return `${year}${month}`;
|
|
55
|
-
});
|
|
56
|
-
result = result.replace(RE_DATE_DMY, (_match, day, month, year) => {
|
|
57
|
-
return `${year}${pad(month, 2)}${pad(day, 2)}`;
|
|
58
|
-
});
|
|
59
|
-
result = result.replace(RE_DATE_DMY_SHORT, (_match, day, month, year) => {
|
|
60
|
-
return `20${year}${pad(month, 2)}${pad(day, 2)}`;
|
|
61
|
-
});
|
|
62
|
-
result = result.replace(RE_DATE_MY, (_match, month, year) => {
|
|
63
|
-
return `${year}${pad(month, 2)}`;
|
|
64
|
-
});
|
|
65
|
-
result = result.replace(RE_DATE_MY_SLASH_DASH, (_match, month, year) => {
|
|
66
|
-
const y = parseInt(year, 10);
|
|
67
|
-
if (y > 2000 && y < 2100) {
|
|
68
|
-
return `${year}${pad(month, 2)}`;
|
|
69
|
-
}
|
|
70
|
-
return _match;
|
|
71
|
-
});
|
|
72
|
-
result = result.replace(RE_DATE_MY_SLASH_SHORT, (_match, month, year) => {
|
|
73
|
-
const m = parseInt(month, 10);
|
|
74
|
-
if (m >= 1 && m <= 12) {
|
|
75
|
-
return `20${year}${pad(month, 2)}`;
|
|
76
|
-
}
|
|
77
|
-
return _match;
|
|
78
|
-
});
|
|
79
|
-
result = result.replace(RE_DATE_DDMMYYYY, (_match, day, month, year) => {
|
|
80
|
-
return `${year}${month}${day}`;
|
|
81
|
-
});
|
|
82
|
-
result = result.replace(RE_DATE_MMYYYY, (_match, month, year) => {
|
|
83
|
-
return `${year}${month}`;
|
|
84
|
-
});
|
|
85
|
-
result = result.replace(RE_DATE_MONTH_YEAR, (_match, monthName, year) => {
|
|
86
|
-
const monthNum = MONTH_NAMES[monthName.toLowerCase()];
|
|
87
|
-
if (monthNum) {
|
|
88
|
-
return `${year}${monthNum}`;
|
|
89
|
-
}
|
|
90
|
-
return _match;
|
|
91
|
-
});
|
|
92
|
-
return result;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// src/utils/preprocessString.ts
|
|
96
|
-
var RE_LEADING_ZEROS = /\b0+(\d)/g;
|
|
97
|
-
var RE_DECIMAL_COMMA = /(\d),(\d)/g;
|
|
98
|
-
var RE_STANDALONE_COMMA = /(?<!\d),(\d)/g;
|
|
99
|
-
var RE_ZERO_DECIMAL = /\b0+\./g;
|
|
100
|
-
var RE_PURE_DECIMAL = /(?<![a-zčćšžđñ\d.])(\d+)\.(\d+)(?![a-zčćšžđñ.\d])/gi;
|
|
101
|
-
var RE_DIGIT_DASH = /(\d)\s*-\s*(\d)/g;
|
|
102
|
-
var RE_LETTER_DASH_DIGIT = /([a-zčćšžđñ])-(\d)/gi;
|
|
103
|
-
var RE_DIGIT_DASH_LETTER = /(\d)-([a-zčćšžđñ])/gi;
|
|
104
|
-
var RE_LETTER_DASH_LETTER = /(?<=[a-zčćšžđñ])-(?=[a-zčćšžđñ])/gi;
|
|
105
|
-
var RE_LETTERS_DIGITS = /(^|\s)([a-zčćšžđñ]+)(\d+)(?=\s|$)/gi;
|
|
106
|
-
var RE_DIGITS_LETTERS = /(^|\s)(\d+)([a-zčćšžđñ]+)(?=\s|$)/gi;
|
|
107
|
-
function preprocessString(input) {
|
|
108
|
-
let result = input;
|
|
109
|
-
result = result.replace(RE_LEADING_ZEROS, "$1");
|
|
110
|
-
result = result.replace(RE_DECIMAL_COMMA, "$1.$2");
|
|
111
|
-
result = result.replace(RE_STANDALONE_COMMA, ".$1");
|
|
112
|
-
result = result.replace(RE_ZERO_DECIMAL, ".");
|
|
113
|
-
result = result.replace(RE_PURE_DECIMAL, "$1$2");
|
|
114
|
-
result = result.replace(RE_DIGIT_DASH, "$1-$2");
|
|
115
|
-
result = result.replace(RE_LETTER_DASH_DIGIT, "$1 $2");
|
|
116
|
-
result = result.replace(RE_DIGIT_DASH_LETTER, "$1 $2");
|
|
117
|
-
result = result.replace(RE_LETTER_DASH_LETTER, " ");
|
|
118
|
-
result = result.replace(RE_LETTERS_DIGITS, "$1$2 $3");
|
|
119
|
-
result = result.replace(RE_DIGITS_LETTERS, "$1$2 $3");
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// src/utils/sanitiseString.ts
|
|
124
|
-
var RE_DIACRITICS = /[\u0300-\u036f]/g;
|
|
125
|
-
var RE_INVALID_CHARS = /[^a-z0-9.\-~<>+*!=? ]/g;
|
|
126
|
-
function sanitiseString(input) {
|
|
127
|
-
let result = input;
|
|
128
|
-
result = result.toLowerCase();
|
|
129
|
-
result = result.normalize("NFD").replace(RE_DIACRITICS, "");
|
|
130
|
-
result = result.replace(RE_INVALID_CHARS, " ");
|
|
131
|
-
return result;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// src/utils/tokenize.ts
|
|
135
|
-
var DEFAULT_REPLACE_TOKENS = new Map([
|
|
136
|
-
["zdravilo", "zdr"],
|
|
137
|
-
["izdelek", "izd"],
|
|
138
|
-
["material", "mat"],
|
|
139
|
-
["pes", "ps"],
|
|
140
|
-
["psi", "ps"],
|
|
141
|
-
["dog", "ps"],
|
|
142
|
-
["cat", "mk"],
|
|
143
|
-
["macka", "mk"],
|
|
144
|
-
["macke", "mk"],
|
|
145
|
-
["ulica", "ul"],
|
|
146
|
-
["cesta", "ces"],
|
|
147
|
-
["mesanec", "mes"],
|
|
148
|
-
["nova", "nv"]
|
|
149
|
-
]);
|
|
150
|
-
var DEFAULT_REMOVE_TOKENS = new Set([
|
|
151
|
-
"s",
|
|
152
|
-
"z",
|
|
153
|
-
"-",
|
|
154
|
-
"in",
|
|
155
|
-
"na",
|
|
156
|
-
"v",
|
|
157
|
-
"po",
|
|
158
|
-
"za",
|
|
159
|
-
"se"
|
|
160
|
-
]);
|
|
161
|
-
var DEFAULT_TOKENIZE_CONFIG = {
|
|
162
|
-
replaceTokens: DEFAULT_REPLACE_TOKENS,
|
|
163
|
-
removeTokens: DEFAULT_REMOVE_TOKENS
|
|
164
|
-
};
|
|
165
|
-
function tokenize(input, config) {
|
|
166
|
-
let tokens = input.split(" ").map((token) => token.trim()).filter((token) => token.length > 0);
|
|
167
|
-
if (config?.replaceTokens) {
|
|
168
|
-
tokens = tokens.map((token) => {
|
|
169
|
-
if (token.length > 2 && token.startsWith("--")) {
|
|
170
|
-
const withoutPrefix = token.slice(2);
|
|
171
|
-
const replaced = config.replaceTokens.get(withoutPrefix);
|
|
172
|
-
return replaced ? "--" + replaced : token;
|
|
173
|
-
}
|
|
174
|
-
if (token.length > 1 && token[0] === "-" && /^[a-zčćšžđñ]/i.test(token[1])) {
|
|
175
|
-
const withoutPrefix = token.slice(1);
|
|
176
|
-
const replaced = config.replaceTokens.get(withoutPrefix);
|
|
177
|
-
return replaced ? "-" + replaced : token;
|
|
178
|
-
}
|
|
179
|
-
return config.replaceTokens.get(token) ?? token;
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
if (config?.removeTokens) {
|
|
183
|
-
tokens = tokens.filter((token) => !config.removeTokens.has(token));
|
|
184
|
-
}
|
|
185
|
-
return tokens;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// src/utils/prepareStringForSearch.ts
|
|
189
|
-
function prepareStringForSearch(input) {
|
|
190
|
-
const datesNormalized = normalizeDates(input);
|
|
191
|
-
const preprocessed = preprocessString(datesNormalized);
|
|
192
|
-
const sanitised = sanitiseString(preprocessed);
|
|
193
|
-
const tokens = tokenize(sanitised, DEFAULT_TOKENIZE_CONFIG);
|
|
194
|
-
return tokens.sort();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// src/common/string/createSearchArrayMetadata.ts
|
|
198
|
-
var MATCH_MODE_PREFIXES = {
|
|
199
|
-
start: "<",
|
|
200
|
-
end: ">",
|
|
201
|
-
startEnd: "+",
|
|
202
|
-
anywhere: "*",
|
|
203
|
-
whole: "!"
|
|
204
|
-
};
|
|
205
|
-
var PREFIX_TO_MATCH_MODE = {
|
|
206
|
-
"<": "start",
|
|
207
|
-
">": "end",
|
|
208
|
-
"+": "startEnd",
|
|
209
|
-
"*": "anywhere",
|
|
210
|
-
"!": "whole",
|
|
211
|
-
"=": "whole",
|
|
212
|
-
"?": "anywhere"
|
|
213
|
-
};
|
|
214
|
-
var DEFAULT_EXCLUDED_FIELDS = new Set(["_id", "_deleted", "_blocked"]);
|
|
215
|
-
function getValueByPath(obj, path) {
|
|
216
|
-
const parts = path.split(".");
|
|
217
|
-
let current = obj;
|
|
218
|
-
for (let i = 0;i < parts.length; i++) {
|
|
219
|
-
if (current == null)
|
|
220
|
-
return;
|
|
221
|
-
const part = parts[i];
|
|
222
|
-
if (Array.isArray(current)) {
|
|
223
|
-
const remainingPath = parts.slice(i).join(".");
|
|
224
|
-
const results = [];
|
|
225
|
-
for (const item of current) {
|
|
226
|
-
const value = getValueByPath(item, remainingPath);
|
|
227
|
-
if (value !== undefined) {
|
|
228
|
-
if (Array.isArray(value)) {
|
|
229
|
-
results.push(...value);
|
|
230
|
-
} else {
|
|
231
|
-
results.push(value);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return results.length > 0 ? results : undefined;
|
|
236
|
-
}
|
|
237
|
-
if (typeof current === "object") {
|
|
238
|
-
current = current[part];
|
|
239
|
-
} else {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return current;
|
|
244
|
-
}
|
|
245
|
-
function isDotNotation(field) {
|
|
246
|
-
return field.includes(".");
|
|
247
|
-
}
|
|
248
|
-
function getRootField(field) {
|
|
249
|
-
const dotIndex = field.indexOf(".");
|
|
250
|
-
return dotIndex === -1 ? field : field.slice(0, dotIndex);
|
|
251
|
-
}
|
|
252
|
-
function extractStringsFromValue(value, results) {
|
|
253
|
-
if (value == null)
|
|
254
|
-
return;
|
|
255
|
-
if (typeof value === "string") {
|
|
256
|
-
results.push(value);
|
|
257
|
-
} else if (typeof value === "number") {
|
|
258
|
-
results.push(String(value));
|
|
259
|
-
} else if (value instanceof Date) {
|
|
260
|
-
results.push(value.toISOString());
|
|
261
|
-
} else if (Array.isArray(value)) {
|
|
262
|
-
for (const item of value) {
|
|
263
|
-
extractStringsFromValue(item, results);
|
|
264
|
-
}
|
|
265
|
-
} else if (typeof value === "object") {
|
|
266
|
-
for (const v of Object.values(value)) {
|
|
267
|
-
extractStringsFromValue(v, results);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
function isDeletedOrBlocked(obj) {
|
|
272
|
-
return obj._deleted != null || obj._blocked != null;
|
|
273
|
-
}
|
|
274
|
-
function extractSearchableStringDefault(obj, spec) {
|
|
275
|
-
if (isDeletedOrBlocked(obj)) {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
if (spec?.enrichSearchObjectFn) {
|
|
279
|
-
spec.enrichSearchObjectFn(obj, spec.searchContext);
|
|
280
|
-
}
|
|
281
|
-
const parts = [];
|
|
282
|
-
const fieldsToSearch = spec?.searchInFields ?? Object.keys(obj);
|
|
283
|
-
const fieldsToExclude = new Set(spec?.dontSearchInFields ?? []);
|
|
284
|
-
for (const key of fieldsToSearch) {
|
|
285
|
-
const keyStr = key;
|
|
286
|
-
if (!spec?.searchInFields && DEFAULT_EXCLUDED_FIELDS.has(keyStr))
|
|
287
|
-
continue;
|
|
288
|
-
if (fieldsToExclude.has(key))
|
|
289
|
-
continue;
|
|
290
|
-
const value = isDotNotation(keyStr) ? getValueByPath(obj, keyStr) : obj[key];
|
|
291
|
-
extractStringsFromValue(value, parts);
|
|
292
|
-
}
|
|
293
|
-
return parts.join(" ");
|
|
294
|
-
}
|
|
295
|
-
function prepareObjectForSearch(obj, spec) {
|
|
296
|
-
if (isDeletedOrBlocked(obj)) {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
if (spec?.extractSearchableStringFn) {
|
|
300
|
-
const searchableString = spec.extractSearchableStringFn(obj);
|
|
301
|
-
if (searchableString === undefined) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
return prepareStringForSearch(searchableString);
|
|
305
|
-
}
|
|
306
|
-
return prepareObjectFieldsForSearch(obj, spec);
|
|
307
|
-
}
|
|
308
|
-
function prepareObjectFieldsForSearch(obj, spec) {
|
|
309
|
-
if (spec?.enrichSearchObjectFn) {
|
|
310
|
-
spec.enrichSearchObjectFn(obj, spec.searchContext);
|
|
311
|
-
}
|
|
312
|
-
const allTokens = [];
|
|
313
|
-
const fieldMatchModes = spec?.fieldMatchModes;
|
|
314
|
-
const fieldsToSearch = spec?.searchInFields ?? Object.keys(obj);
|
|
315
|
-
const fieldsToExclude = new Set(spec?.dontSearchInFields ?? []);
|
|
316
|
-
const processedRootFields = new Set;
|
|
317
|
-
for (const key of fieldsToSearch) {
|
|
318
|
-
const keyStr = key;
|
|
319
|
-
if (!spec?.searchInFields && DEFAULT_EXCLUDED_FIELDS.has(keyStr))
|
|
320
|
-
continue;
|
|
321
|
-
if (fieldsToExclude.has(key))
|
|
322
|
-
continue;
|
|
323
|
-
const isDot = isDotNotation(keyStr);
|
|
324
|
-
const rootField = getRootField(keyStr);
|
|
325
|
-
let value;
|
|
326
|
-
if (isDot) {
|
|
327
|
-
value = getValueByPath(obj, keyStr);
|
|
328
|
-
} else {
|
|
329
|
-
value = obj[key];
|
|
330
|
-
processedRootFields.add(rootField);
|
|
331
|
-
}
|
|
332
|
-
if (value == null)
|
|
333
|
-
continue;
|
|
334
|
-
const matchMode = fieldMatchModes?.[key];
|
|
335
|
-
const prefix = matchMode ? MATCH_MODE_PREFIXES[matchMode] : "";
|
|
336
|
-
const fieldStrings = [];
|
|
337
|
-
extractStringsFromValue(value, fieldStrings);
|
|
338
|
-
if (fieldStrings.length > 0) {
|
|
339
|
-
const fieldText = fieldStrings.join(" ");
|
|
340
|
-
const tokens = prepareStringForSearch(fieldText);
|
|
341
|
-
for (const token of tokens) {
|
|
342
|
-
allTokens.push(prefix + token);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
return [...new Set(allTokens)].sort();
|
|
347
|
-
}
|
|
348
|
-
function createSearchArrayMetadata(data, spec) {
|
|
349
|
-
const metadata = new Map;
|
|
350
|
-
for (const [id, item] of data) {
|
|
351
|
-
const tokens = prepareObjectForSearch(item, spec);
|
|
352
|
-
if (tokens !== undefined) {
|
|
353
|
-
metadata.set(id, tokens);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
return metadata;
|
|
357
|
-
}
|
|
358
|
-
function wrapMetadataLegacy(metadata) {
|
|
359
|
-
return { items: metadata };
|
|
360
|
-
}
|
|
361
|
-
function unwrapMetadataLegacy(legacy) {
|
|
362
|
-
return legacy.items;
|
|
363
|
-
}
|
|
364
|
-
// src/common/string/createSearchLinkedMetadata.ts
|
|
365
|
-
function createSearchLinkedMetadata(primaryData, primaryMetadata, linkedData, linkedMetadata, foreignKeyGetter) {
|
|
366
|
-
const primaryToLinked = new Map;
|
|
367
|
-
for (const [linkedId, linkedItem] of linkedData) {
|
|
368
|
-
const primaryId = foreignKeyGetter(linkedItem);
|
|
369
|
-
if (primaryId) {
|
|
370
|
-
const list = primaryToLinked.get(primaryId) || [];
|
|
371
|
-
list.push(linkedId);
|
|
372
|
-
primaryToLinked.set(primaryId, list);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
return {
|
|
376
|
-
primaryMeta: primaryMetadata,
|
|
377
|
-
linkedMeta: linkedMetadata,
|
|
378
|
-
primaryToLinked,
|
|
379
|
-
primaryData,
|
|
380
|
-
linkedData
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
// src/common/string/updateSearchMetadata.ts
|
|
384
|
-
function updateSearchMetadata(metadata, objectId, obj, spec) {
|
|
385
|
-
const tokens = obj != null ? prepareObjectForSearch(obj, spec) : undefined;
|
|
386
|
-
if (tokens === undefined) {
|
|
387
|
-
metadata.delete(objectId);
|
|
388
|
-
return false;
|
|
389
|
-
} else {
|
|
390
|
-
metadata.set(objectId, tokens);
|
|
391
|
-
return true;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
function updateSearchMetadataBatch(metadata, batch, spec) {
|
|
395
|
-
if (batch.length === 0) {
|
|
396
|
-
return { updated: 0, removed: 0 };
|
|
397
|
-
}
|
|
398
|
-
let updated = 0;
|
|
399
|
-
let removed = 0;
|
|
400
|
-
for (const { objectId, obj } of batch) {
|
|
401
|
-
const wasUpdated = updateSearchMetadata(metadata, objectId, obj, spec);
|
|
402
|
-
if (wasUpdated) {
|
|
403
|
-
updated++;
|
|
404
|
-
} else {
|
|
405
|
-
removed++;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
return { updated, removed };
|
|
409
|
-
}
|
|
410
|
-
function removeFromSearchMetadata(metadata, objectId) {
|
|
411
|
-
return metadata.delete(objectId);
|
|
412
|
-
}
|
|
413
|
-
function removeFromSearchMetadataBatch(metadata, objectIds) {
|
|
414
|
-
if (objectIds.length === 0) {
|
|
415
|
-
return 0;
|
|
416
|
-
}
|
|
417
|
-
let removed = 0;
|
|
418
|
-
for (const id of objectIds) {
|
|
419
|
-
if (metadata.delete(id)) {
|
|
420
|
-
removed++;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return removed;
|
|
424
|
-
}
|
|
425
|
-
// src/types/index.ts
|
|
426
|
-
var DEFAULT_SEARCH_OPTS = {
|
|
427
|
-
matchWords: "start",
|
|
428
|
-
matchNumbers: "startEnd",
|
|
429
|
-
matchNumbersShort: "start",
|
|
430
|
-
matchNumbersThreshold: 6
|
|
431
|
-
};
|
|
432
|
-
function arrayToSearchableData(items) {
|
|
433
|
-
const map = new Map;
|
|
434
|
-
for (const item of items) {
|
|
435
|
-
map.set(item._id, item);
|
|
436
|
-
}
|
|
437
|
-
return map;
|
|
438
|
-
}
|
|
439
|
-
function searchableDataToArray(data) {
|
|
440
|
-
return Array.from(data.values());
|
|
441
|
-
}
|
|
442
|
-
// src/utils/matchToken.ts
|
|
443
|
-
var RE_NUMERIC = /^[\d.\-]+$/;
|
|
444
|
-
var PREFIX_TO_MODE = {
|
|
445
|
-
"<": "start",
|
|
446
|
-
">": "end",
|
|
447
|
-
"+": "startEnd",
|
|
448
|
-
"*": "anywhere",
|
|
449
|
-
"!": "whole"
|
|
450
|
-
};
|
|
451
|
-
function matchWithMode(searchToken, targetToken, mode) {
|
|
452
|
-
switch (mode) {
|
|
453
|
-
case "start":
|
|
454
|
-
return targetToken.startsWith(searchToken);
|
|
455
|
-
case "end":
|
|
456
|
-
return targetToken.endsWith(searchToken);
|
|
457
|
-
case "startEnd":
|
|
458
|
-
return targetToken.startsWith(searchToken) || targetToken.endsWith(searchToken);
|
|
459
|
-
case "anywhere":
|
|
460
|
-
return targetToken.includes(searchToken);
|
|
461
|
-
case "whole":
|
|
462
|
-
return targetToken === searchToken;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
function matchToken(searchToken, targetToken, opts) {
|
|
466
|
-
const firstChar = targetToken[0];
|
|
467
|
-
const prefixMode = firstChar ? PREFIX_TO_MODE[firstChar] : undefined;
|
|
468
|
-
if (prefixMode) {
|
|
469
|
-
const actualTarget = targetToken.slice(1);
|
|
470
|
-
return matchWithMode(searchToken, actualTarget, prefixMode);
|
|
471
|
-
}
|
|
472
|
-
const matchWords = opts?.matchWords ?? DEFAULT_SEARCH_OPTS.matchWords;
|
|
473
|
-
const matchNumbers = opts?.matchNumbers ?? DEFAULT_SEARCH_OPTS.matchNumbers;
|
|
474
|
-
const isNumeric = RE_NUMERIC.test(searchToken);
|
|
475
|
-
return matchWithMode(searchToken, targetToken, isNumeric ? matchNumbers : matchWords);
|
|
476
|
-
}
|
|
477
|
-
function matchTokenInSortedList(searchToken, targetTokens, opts) {
|
|
478
|
-
const isNumeric = RE_NUMERIC.test(searchToken);
|
|
479
|
-
const effectiveMode = isNumeric ? opts?.matchNumbers ?? DEFAULT_SEARCH_OPTS.matchNumbers : opts?.matchWords ?? DEFAULT_SEARCH_OPTS.matchWords;
|
|
480
|
-
const canEarlyExit = effectiveMode === "start";
|
|
481
|
-
for (const targetToken of targetTokens) {
|
|
482
|
-
const firstChar = targetToken[0];
|
|
483
|
-
const hasPrefix = firstChar ? PREFIX_TO_MODE[firstChar] !== undefined : false;
|
|
484
|
-
if (hasPrefix) {
|
|
485
|
-
if (matchToken(searchToken, targetToken, opts)) {
|
|
486
|
-
return true;
|
|
487
|
-
}
|
|
488
|
-
} else {
|
|
489
|
-
if (canEarlyExit) {
|
|
490
|
-
if (targetToken.startsWith(searchToken)) {
|
|
491
|
-
return true;
|
|
492
|
-
}
|
|
493
|
-
if (targetToken > searchToken && targetToken[0] !== searchToken[0]) {
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
} else {
|
|
497
|
-
if (matchToken(searchToken, targetToken, opts)) {
|
|
498
|
-
return true;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
return false;
|
|
504
|
-
}
|
|
505
|
-
function allTokensMatch(searchTokens, targetTokens, opts) {
|
|
506
|
-
for (const searchToken of searchTokens) {
|
|
507
|
-
if (!matchTokenInSortedList(searchToken, targetTokens, opts)) {
|
|
508
|
-
return false;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return true;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// src/common/findInArrayReturnDataAndMeta.ts
|
|
515
|
-
function findInArrayReturnDataAndMeta(query, data, metadata, limit = 10, opts) {
|
|
516
|
-
const queryTokens = prepareStringForSearch(query);
|
|
517
|
-
if (queryTokens.length === 0) {
|
|
518
|
-
return {
|
|
519
|
-
queryTokens,
|
|
520
|
-
results: []
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
const results = [];
|
|
524
|
-
for (const [id, itemTokens] of metadata) {
|
|
525
|
-
if (results.length >= limit) {
|
|
526
|
-
break;
|
|
527
|
-
}
|
|
528
|
-
if (allTokensMatch(queryTokens, itemTokens, opts)) {
|
|
529
|
-
const item = data.get(id);
|
|
530
|
-
if (item) {
|
|
531
|
-
results.push({
|
|
532
|
-
item,
|
|
533
|
-
tokens: itemTokens
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
return {
|
|
539
|
-
queryTokens,
|
|
540
|
-
results
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
function findInArrayReturnIds(query, metadata, limit = 10, opts) {
|
|
544
|
-
const queryTokens = prepareStringForSearch(query);
|
|
545
|
-
if (queryTokens.length === 0) {
|
|
546
|
-
return [];
|
|
547
|
-
}
|
|
548
|
-
const results = [];
|
|
549
|
-
for (const [id, itemTokens] of metadata) {
|
|
550
|
-
if (results.length >= limit) {
|
|
551
|
-
break;
|
|
552
|
-
}
|
|
553
|
-
if (allTokensMatch(queryTokens, itemTokens, opts)) {
|
|
554
|
-
results.push(id);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
return results;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// src/common/findInArray.ts
|
|
561
|
-
function findInArray(query, data, metadata, limit = 10, opts) {
|
|
562
|
-
const result = findInArrayReturnDataAndMeta(query, data, metadata, limit, opts);
|
|
563
|
-
return result.results.map((r) => r.item);
|
|
564
|
-
}
|
|
565
|
-
// src/common/findInLinkedArrays.ts
|
|
566
|
-
function findInLinkedArrays(query, linked, limit = 10, opts) {
|
|
567
|
-
const queryTokens = prepareStringForSearch(query);
|
|
568
|
-
const hasNegation = queryTokens.some((t) => t.startsWith("--") || t.startsWith("~") || t.length > 1 && t[0] === "-" && /^[a-zčćšžđñ]/i.test(t[1]));
|
|
569
|
-
if (queryTokens.length === 0) {
|
|
570
|
-
return { queryTokens, results: [], hasNegation: false };
|
|
571
|
-
}
|
|
572
|
-
const results = [];
|
|
573
|
-
for (const [primaryId, primary] of linked.primaryData) {
|
|
574
|
-
if (results.length >= limit)
|
|
575
|
-
break;
|
|
576
|
-
const primaryTokens = linked.primaryMeta.get(primaryId);
|
|
577
|
-
if (!primaryTokens)
|
|
578
|
-
continue;
|
|
579
|
-
const linkedIds = linked.primaryToLinked.get(primaryId) || [];
|
|
580
|
-
const allTokens = [...primaryTokens];
|
|
581
|
-
for (const linkedId of linkedIds) {
|
|
582
|
-
const linkedTokens = linked.linkedMeta.get(linkedId);
|
|
583
|
-
if (linkedTokens) {
|
|
584
|
-
allTokens.push(...linkedTokens);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
allTokens.sort();
|
|
588
|
-
if (allTokensMatch(queryTokens, allTokens, opts)) {
|
|
589
|
-
let anyMatchInPrimary = false;
|
|
590
|
-
let anyMatchInLinked = false;
|
|
591
|
-
const matchingLinkedIds = new Set;
|
|
592
|
-
const tokensMatchingPrimary = new Set;
|
|
593
|
-
for (const queryToken of queryTokens) {
|
|
594
|
-
if (matchTokenInSortedList(queryToken, primaryTokens, opts)) {
|
|
595
|
-
anyMatchInPrimary = true;
|
|
596
|
-
tokensMatchingPrimary.add(queryToken);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
const tokensForLinkedMatching = queryTokens.filter((t) => !tokensMatchingPrimary.has(t));
|
|
600
|
-
if (tokensForLinkedMatching.length > 0) {
|
|
601
|
-
for (const linkedId of linkedIds) {
|
|
602
|
-
const linkedTokens = linked.linkedMeta.get(linkedId);
|
|
603
|
-
if (linkedTokens) {
|
|
604
|
-
const matchesAllNonPrimaryTokens = tokensForLinkedMatching.every((queryToken) => matchTokenInSortedList(queryToken, linkedTokens, opts));
|
|
605
|
-
if (matchesAllNonPrimaryTokens) {
|
|
606
|
-
anyMatchInLinked = true;
|
|
607
|
-
matchingLinkedIds.add(linkedId);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
if (tokensForLinkedMatching.length > 0 && matchingLinkedIds.size === 0) {
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
615
|
-
const matchedLinked = Array.from(matchingLinkedIds).map((id) => linked.linkedData.get(id)).filter((item) => item !== undefined);
|
|
616
|
-
results.push({
|
|
617
|
-
primary,
|
|
618
|
-
linked: matchedLinked,
|
|
619
|
-
matchedIn: anyMatchInPrimary && anyMatchInLinked ? "both" : anyMatchInPrimary ? "primary" : "linked"
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
return { queryTokens, results, hasNegation };
|
|
624
|
-
}
|
|
625
|
-
function findInLinkedArraysSimple(query, linked, limit = 10, opts) {
|
|
626
|
-
return findInLinkedArrays(query, linked, limit, opts).results;
|
|
627
|
-
}
|
|
628
|
-
// src/common/syncSearchArrayMetadata.ts
|
|
629
|
-
function tokensEqual(a, b) {
|
|
630
|
-
if (a.length !== b.length)
|
|
631
|
-
return false;
|
|
632
|
-
for (let i = 0;i < a.length; i++) {
|
|
633
|
-
if (a[i] !== b[i])
|
|
634
|
-
return false;
|
|
635
|
-
}
|
|
636
|
-
return true;
|
|
637
|
-
}
|
|
638
|
-
function syncSearchArrayMetadataString(metadata, newData, spec) {
|
|
639
|
-
const result = {
|
|
640
|
-
added: 0,
|
|
641
|
-
updated: 0,
|
|
642
|
-
removed: 0,
|
|
643
|
-
addedIds: [],
|
|
644
|
-
updatedIds: [],
|
|
645
|
-
removedIds: []
|
|
646
|
-
};
|
|
647
|
-
for (const id of metadata.keys()) {
|
|
648
|
-
if (!newData.has(id)) {
|
|
649
|
-
metadata.delete(id);
|
|
650
|
-
result.removed++;
|
|
651
|
-
result.removedIds.push(id);
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
for (const [id, item] of newData) {
|
|
655
|
-
const newTokens = prepareObjectForSearch(item, spec);
|
|
656
|
-
if (newTokens === undefined) {
|
|
657
|
-
if (metadata.has(id)) {
|
|
658
|
-
metadata.delete(id);
|
|
659
|
-
result.removed++;
|
|
660
|
-
result.removedIds.push(id);
|
|
661
|
-
}
|
|
662
|
-
continue;
|
|
663
|
-
}
|
|
664
|
-
const existingTokens = metadata.get(id);
|
|
665
|
-
if (existingTokens === undefined) {
|
|
666
|
-
metadata.set(id, newTokens);
|
|
667
|
-
result.added++;
|
|
668
|
-
result.addedIds.push(id);
|
|
669
|
-
} else if (!tokensEqual(existingTokens, newTokens)) {
|
|
670
|
-
metadata.set(id, newTokens);
|
|
671
|
-
result.updated++;
|
|
672
|
-
result.updatedIds.push(id);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
return result;
|
|
676
|
-
}
|
|
677
|
-
function syncSearchArrayMetadataStringWithPrevious(metadata, previousData, newData, options, spec) {
|
|
678
|
-
const result = {
|
|
679
|
-
added: 0,
|
|
680
|
-
updated: 0,
|
|
681
|
-
removed: 0,
|
|
682
|
-
addedIds: [],
|
|
683
|
-
updatedIds: [],
|
|
684
|
-
removedIds: []
|
|
685
|
-
};
|
|
686
|
-
for (const id of previousData.keys()) {
|
|
687
|
-
if (!newData.has(id)) {
|
|
688
|
-
metadata.delete(id);
|
|
689
|
-
result.removed++;
|
|
690
|
-
result.removedIds.push(id);
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
for (const [id, item] of newData) {
|
|
694
|
-
const wasInPrevious = previousData.has(id);
|
|
695
|
-
if (!wasInPrevious) {
|
|
696
|
-
const tokens = prepareObjectForSearch(item, spec);
|
|
697
|
-
if (tokens !== undefined) {
|
|
698
|
-
metadata.set(id, tokens);
|
|
699
|
-
result.added++;
|
|
700
|
-
result.addedIds.push(id);
|
|
701
|
-
}
|
|
702
|
-
} else if (!options?.skipUpdateCheck) {
|
|
703
|
-
const newTokens = prepareObjectForSearch(item, spec);
|
|
704
|
-
if (newTokens === undefined) {
|
|
705
|
-
metadata.delete(id);
|
|
706
|
-
result.removed++;
|
|
707
|
-
result.removedIds.push(id);
|
|
708
|
-
} else {
|
|
709
|
-
const existingTokens = metadata.get(id);
|
|
710
|
-
if (existingTokens && !tokensEqual(existingTokens, newTokens)) {
|
|
711
|
-
metadata.set(id, newTokens);
|
|
712
|
-
result.updated++;
|
|
713
|
-
result.updatedIds.push(id);
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
return result;
|
|
719
|
-
}
|
|
720
|
-
// src/common/updateSearchLinkedMetadata.ts
|
|
721
|
-
function tokensEqual2(a, b) {
|
|
722
|
-
if (a.length !== b.length)
|
|
723
|
-
return false;
|
|
724
|
-
for (let i = 0;i < a.length; i++) {
|
|
725
|
-
if (a[i] !== b[i])
|
|
726
|
-
return false;
|
|
727
|
-
}
|
|
728
|
-
return true;
|
|
729
|
-
}
|
|
730
|
-
function upsertPrimaryItemString(linked, item, spec) {
|
|
731
|
-
const id = item._id;
|
|
732
|
-
const wasAdded = !linked.primaryData.has(id);
|
|
733
|
-
linked.primaryData.set(id, item);
|
|
734
|
-
const tokens = prepareObjectForSearch(item, spec);
|
|
735
|
-
if (tokens !== undefined) {
|
|
736
|
-
linked.primaryMeta.set(id, tokens);
|
|
737
|
-
} else {
|
|
738
|
-
linked.primaryMeta.delete(id);
|
|
739
|
-
}
|
|
740
|
-
if (wasAdded && !linked.primaryToLinked.has(id)) {
|
|
741
|
-
linked.primaryToLinked.set(id, []);
|
|
742
|
-
}
|
|
743
|
-
return { added: wasAdded };
|
|
744
|
-
}
|
|
745
|
-
function removePrimaryItemString(linked, primaryId) {
|
|
746
|
-
if (!linked.primaryData.has(primaryId)) {
|
|
747
|
-
return false;
|
|
748
|
-
}
|
|
749
|
-
linked.primaryData.delete(primaryId);
|
|
750
|
-
linked.primaryMeta.delete(primaryId);
|
|
751
|
-
linked.primaryToLinked.delete(primaryId);
|
|
752
|
-
return true;
|
|
753
|
-
}
|
|
754
|
-
function upsertLinkedItemString(linked, item, foreignKeyGetter, spec) {
|
|
755
|
-
const id = item._id;
|
|
756
|
-
const newPrimaryId = foreignKeyGetter(item);
|
|
757
|
-
let previousPrimaryId;
|
|
758
|
-
const existingItem = linked.linkedData.get(id);
|
|
759
|
-
if (existingItem) {
|
|
760
|
-
previousPrimaryId = foreignKeyGetter(existingItem);
|
|
761
|
-
}
|
|
762
|
-
const wasAdded = !existingItem;
|
|
763
|
-
linked.linkedData.set(id, item);
|
|
764
|
-
const tokens = prepareObjectForSearch(item, spec);
|
|
765
|
-
if (tokens !== undefined) {
|
|
766
|
-
linked.linkedMeta.set(id, tokens);
|
|
767
|
-
} else {
|
|
768
|
-
linked.linkedMeta.delete(id);
|
|
769
|
-
}
|
|
770
|
-
if (previousPrimaryId !== newPrimaryId) {
|
|
771
|
-
if (previousPrimaryId) {
|
|
772
|
-
const oldList = linked.primaryToLinked.get(previousPrimaryId);
|
|
773
|
-
if (oldList) {
|
|
774
|
-
const index = oldList.indexOf(id);
|
|
775
|
-
if (index !== -1) {
|
|
776
|
-
oldList.splice(index, 1);
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
if (newPrimaryId) {
|
|
781
|
-
const newList = linked.primaryToLinked.get(newPrimaryId);
|
|
782
|
-
if (newList) {
|
|
783
|
-
if (!newList.includes(id)) {
|
|
784
|
-
newList.push(id);
|
|
785
|
-
}
|
|
786
|
-
} else {
|
|
787
|
-
linked.primaryToLinked.set(newPrimaryId, [id]);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
return {
|
|
792
|
-
added: wasAdded,
|
|
793
|
-
previousPrimaryId: wasAdded ? undefined : previousPrimaryId
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
function removeLinkedItemString(linked, linkedId, foreignKeyGetter) {
|
|
797
|
-
const existingItem = linked.linkedData.get(linkedId);
|
|
798
|
-
if (!existingItem) {
|
|
799
|
-
return false;
|
|
800
|
-
}
|
|
801
|
-
const primaryId = foreignKeyGetter(existingItem);
|
|
802
|
-
linked.linkedData.delete(linkedId);
|
|
803
|
-
linked.linkedMeta.delete(linkedId);
|
|
804
|
-
if (primaryId) {
|
|
805
|
-
const list = linked.primaryToLinked.get(primaryId);
|
|
806
|
-
if (list) {
|
|
807
|
-
const index = list.indexOf(linkedId);
|
|
808
|
-
if (index !== -1) {
|
|
809
|
-
list.splice(index, 1);
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
return true;
|
|
814
|
-
}
|
|
815
|
-
function syncLinkedItemsForPrimaryString(linked, primaryId, newLinkedItems, foreignKeyGetter, spec) {
|
|
816
|
-
const result = {
|
|
817
|
-
added: 0,
|
|
818
|
-
updated: 0,
|
|
819
|
-
removed: 0
|
|
820
|
-
};
|
|
821
|
-
const currentLinkedIds = new Set(linked.primaryToLinked.get(primaryId) || []);
|
|
822
|
-
const newLinkedIds = new Set;
|
|
823
|
-
for (const [id, item] of newLinkedItems) {
|
|
824
|
-
if (foreignKeyGetter(item) === primaryId) {
|
|
825
|
-
newLinkedIds.add(id);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
for (const id of currentLinkedIds) {
|
|
829
|
-
if (!newLinkedIds.has(id)) {
|
|
830
|
-
const item = linked.linkedData.get(id);
|
|
831
|
-
if (item) {
|
|
832
|
-
linked.linkedData.delete(id);
|
|
833
|
-
linked.linkedMeta.delete(id);
|
|
834
|
-
result.removed++;
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
for (const id of newLinkedIds) {
|
|
839
|
-
const item = newLinkedItems.get(id);
|
|
840
|
-
const tokens = prepareObjectForSearch(item, spec);
|
|
841
|
-
if (currentLinkedIds.has(id)) {
|
|
842
|
-
const existingTokens = linked.linkedMeta.get(id);
|
|
843
|
-
if (tokens !== undefined) {
|
|
844
|
-
if (!existingTokens || !tokensEqual2(existingTokens, tokens)) {
|
|
845
|
-
linked.linkedMeta.set(id, tokens);
|
|
846
|
-
result.updated++;
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
linked.linkedData.set(id, item);
|
|
850
|
-
} else {
|
|
851
|
-
linked.linkedData.set(id, item);
|
|
852
|
-
if (tokens !== undefined) {
|
|
853
|
-
linked.linkedMeta.set(id, tokens);
|
|
854
|
-
}
|
|
855
|
-
result.added++;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
linked.primaryToLinked.set(primaryId, Array.from(newLinkedIds));
|
|
859
|
-
return result;
|
|
860
|
-
}
|
|
861
|
-
export {
|
|
862
|
-
wrapMetadataLegacy,
|
|
863
|
-
upsertPrimaryItemString,
|
|
864
|
-
upsertLinkedItemString,
|
|
865
|
-
updateSearchMetadata as updateSearchMetadataString,
|
|
866
|
-
updateSearchMetadataBatch as updateSearchMetadataBatchString,
|
|
867
|
-
unwrapMetadataLegacy,
|
|
868
|
-
tokenize,
|
|
869
|
-
syncSearchArrayMetadataStringWithPrevious,
|
|
870
|
-
syncSearchArrayMetadataString,
|
|
871
|
-
syncLinkedItemsForPrimaryString,
|
|
872
|
-
searchableDataToArray,
|
|
873
|
-
sanitiseString,
|
|
874
|
-
removePrimaryItemString,
|
|
875
|
-
removeLinkedItemString,
|
|
876
|
-
removeFromSearchMetadata as removeFromSearchMetadataString,
|
|
877
|
-
removeFromSearchMetadataBatch as removeFromSearchMetadataBatchString,
|
|
878
|
-
preprocessString,
|
|
879
|
-
prepareStringForSearch,
|
|
880
|
-
prepareObjectForSearch as prepareObjectForSearchString,
|
|
881
|
-
normalizeDates,
|
|
882
|
-
matchTokenInSortedList,
|
|
883
|
-
matchToken,
|
|
884
|
-
isDeletedOrBlocked,
|
|
885
|
-
findInLinkedArraysSimple,
|
|
886
|
-
findInLinkedArrays,
|
|
887
|
-
findInArrayReturnIds,
|
|
888
|
-
findInArrayReturnDataAndMeta,
|
|
889
|
-
findInArray,
|
|
890
|
-
extractSearchableStringDefault,
|
|
891
|
-
createSearchLinkedMetadata as createSearchLinkedMetadataString,
|
|
892
|
-
createSearchArrayMetadata as createSearchArrayMetadataString,
|
|
893
|
-
arrayToSearchableData,
|
|
894
|
-
allTokensMatch,
|
|
895
|
-
PREFIX_TO_MATCH_MODE,
|
|
896
|
-
MATCH_MODE_PREFIXES,
|
|
897
|
-
DEFAULT_SEARCH_OPTS
|
|
898
|
-
};
|