@devisfuture/mega-collection 2.4.6 → 2.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/State.d.ts +42 -0
- package/dist/{chunk-BJZg_1dI.mjs → State.mjs} +2 -2
- package/dist/constants.d.ts +5 -0
- package/dist/constants.mjs +4 -0
- package/dist/filter/chain.d.ts +9 -0
- package/dist/filter/chain.mjs +22 -0
- package/dist/filter/constants.d.ts +2 -0
- package/dist/filter/criterion.d.ts +6 -0
- package/dist/filter/criterion.mjs +64 -0
- package/dist/filter/errors.d.ts +7 -0
- package/dist/filter/errors.mjs +17 -0
- package/dist/filter/filter.d.ts +89 -0
- package/dist/filter/filter.mjs +439 -0
- package/dist/filter/index.mjs +2 -891
- package/dist/filter/nested.d.ts +32 -0
- package/dist/filter/nested.mjs +246 -0
- package/dist/filter/types.d.ts +74 -0
- package/dist/filter/utils.d.ts +4 -0
- package/dist/filter/utils.mjs +29 -0
- package/dist/index.mjs +1 -1
- package/dist/indexer.d.ts +41 -0
- package/dist/indexer.mjs +101 -0
- package/dist/internal.d.ts +6 -0
- package/dist/{chunk-C5Zpu_ol.mjs → internal.mjs} +1 -1
- package/dist/merge/chain.d.ts +9 -0
- package/dist/merge/chain.mjs +23 -0
- package/dist/merge/constants.d.ts +6 -0
- package/dist/merge/constants.mjs +8 -0
- package/dist/merge/errors.d.ts +8 -0
- package/dist/merge/errors.mjs +19 -0
- package/dist/merge/index.mjs +1 -1
- package/dist/merge/merge-engines.d.ts +75 -0
- package/dist/{chunk-BURK5sks.mjs → merge/merge-engines.mjs} +35 -108
- package/dist/merge/module-adapters.d.ts +7 -0
- package/dist/merge/module-adapters.mjs +41 -0
- package/dist/merge/types.d.ts +125 -0
- package/dist/search/constants.d.ts +5 -0
- package/dist/search/index.mjs +2 -1010
- package/dist/search/nested.d.ts +41 -0
- package/dist/search/nested.mjs +210 -0
- package/dist/search/ngram.d.ts +23 -0
- package/dist/search/ngram.mjs +96 -0
- package/dist/search/text-search.d.ts +146 -0
- package/dist/search/text-search.mjs +696 -0
- package/dist/search/types.d.ts +93 -0
- package/dist/search/utils.d.ts +4 -0
- package/dist/search/utils.mjs +22 -0
- package/dist/sort/errors.d.ts +5 -0
- package/dist/sort/errors.mjs +11 -0
- package/dist/sort/index.mjs +2 -416
- package/dist/sort/sorter.d.ts +47 -0
- package/dist/sort/sorter.mjs +375 -0
- package/dist/sort/types.d.ts +18 -0
- package/dist/sort/utils.d.ts +17 -0
- package/dist/sort/utils.mjs +38 -0
- package/dist/types.d.ts +73 -0
- package/package.json +11 -34
- /package/dist/filter/{index.d.mts → index.d.ts} +0 -0
- /package/dist/{index.d.mts → index.d.ts} +0 -0
- /package/dist/merge/{index.d.mts → index.d.ts} +0 -0
- /package/dist/search/{index.d.mts → index.d.ts} +0 -0
- /package/dist/sort/{index.d.mts → index.d.ts} +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CollectionItem } from "../types";
|
|
2
|
+
import type { SearchNestedCollectionStorage } from "./types";
|
|
3
|
+
export declare class SearchNestedCollection<T extends CollectionItem> {
|
|
4
|
+
private readonly storage;
|
|
5
|
+
private readonly registeredFields;
|
|
6
|
+
private readonly fieldDescriptors;
|
|
7
|
+
constructor(storage?: SearchNestedCollectionStorage);
|
|
8
|
+
registerFields(fieldPaths?: readonly string[]): void;
|
|
9
|
+
hasRegisteredFields(): boolean;
|
|
10
|
+
hasField(fieldPath: string): boolean;
|
|
11
|
+
hasIndexes(): boolean;
|
|
12
|
+
clearIndexes(): void;
|
|
13
|
+
buildIndexes(data: T[]): void;
|
|
14
|
+
addItems(items: T[], startIndex: number): void;
|
|
15
|
+
updateItem(item: T, previousItem: T, itemIndex: number): void;
|
|
16
|
+
removeItem(item: T, itemIndex: number): void;
|
|
17
|
+
moveItem(item: T, fromIndex: number, toIndex: number): void;
|
|
18
|
+
/**
|
|
19
|
+
* Returns dataset indices of items matching the query across all registered
|
|
20
|
+
* nested fields. Deduplicates indices that appear in multiple nested fields.
|
|
21
|
+
*/
|
|
22
|
+
searchAllIndexedFieldIndices(lowerQuery: string, uniqueQueryGrams: ReadonlySet<string>, restrictionLookup?: Uint8Array | null, candidateIndices?: readonly number[] | null): number[];
|
|
23
|
+
searchIndexedField(data: T[], fieldPath: string, lowerQuery: string, uniqueQueryGrams: ReadonlySet<string>, restrictionLookup?: Uint8Array | null, candidateIndices?: readonly number[] | null, take?: number): T[];
|
|
24
|
+
/**
|
|
25
|
+
* Core indexed search for a nested field: returns dataset indices of items
|
|
26
|
+
* whose nested values match the query.
|
|
27
|
+
*/
|
|
28
|
+
searchIndexedFieldIndices(fieldPath: string, lowerQuery: string, uniqueQueryGrams: ReadonlySet<string>, restrictionLookup?: Uint8Array | null, candidateIndices?: readonly number[] | null, take?: number): number[];
|
|
29
|
+
searchFieldLinear(data: T[], fieldPath: string, lowerQuery: string): T[];
|
|
30
|
+
searchFieldLinearIndices(data: T[], fieldPath: string, lowerQuery: string, sourceIndices?: readonly number[]): number[];
|
|
31
|
+
matchesAnyField(item: T, lowerQuery: string): boolean;
|
|
32
|
+
private registerField;
|
|
33
|
+
private getNormalizedValues;
|
|
34
|
+
private buildIndex;
|
|
35
|
+
private addItemsToField;
|
|
36
|
+
private updateItemInField;
|
|
37
|
+
private removeItemFromField;
|
|
38
|
+
private moveItemForField;
|
|
39
|
+
private getNormalizedItemValue;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=nested.d.ts.map
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { createNestedFieldDescriptor as e } from "../internal.mjs";
|
|
2
|
+
import { indexLowerValue as t, intersectPostingLists as n, intersectPostingListsInCandidates as r, removeLowerValue as i } from "./ngram.mjs";
|
|
3
|
+
//#region src/search/nested.ts
|
|
4
|
+
var a = class {
|
|
5
|
+
constructor(e = {
|
|
6
|
+
ngramIndexes: /* @__PURE__ */ new Map(),
|
|
7
|
+
normalizedFieldValues: /* @__PURE__ */ new Map()
|
|
8
|
+
}) {
|
|
9
|
+
this.storage = e, this.registeredFields = /* @__PURE__ */ new Set(), this.fieldDescriptors = /* @__PURE__ */ new Map();
|
|
10
|
+
}
|
|
11
|
+
registerFields(e) {
|
|
12
|
+
if (e?.length) for (let t of e) this.registerField(t);
|
|
13
|
+
}
|
|
14
|
+
hasRegisteredFields() {
|
|
15
|
+
return this.registeredFields.size > 0;
|
|
16
|
+
}
|
|
17
|
+
hasField(e) {
|
|
18
|
+
return this.registeredFields.has(e);
|
|
19
|
+
}
|
|
20
|
+
hasIndexes() {
|
|
21
|
+
return this.storage.ngramIndexes.size > 0;
|
|
22
|
+
}
|
|
23
|
+
clearIndexes() {
|
|
24
|
+
this.storage.ngramIndexes.clear(), this.storage.normalizedFieldValues.clear();
|
|
25
|
+
}
|
|
26
|
+
buildIndexes(e) {
|
|
27
|
+
this.clearIndexes();
|
|
28
|
+
for (let t of this.registeredFields) this.buildIndex(e, t);
|
|
29
|
+
}
|
|
30
|
+
addItems(e, t) {
|
|
31
|
+
if (!(e.length === 0 || this.storage.ngramIndexes.size === 0)) for (let n of this.storage.ngramIndexes.keys()) this.addItemsToField(n, e, t);
|
|
32
|
+
}
|
|
33
|
+
updateItem(e, t, n) {
|
|
34
|
+
if (this.storage.ngramIndexes.size !== 0) for (let r of this.storage.ngramIndexes.keys()) this.updateItemInField(r, e, t, n);
|
|
35
|
+
}
|
|
36
|
+
removeItem(e, t) {
|
|
37
|
+
if (this.storage.ngramIndexes.size !== 0) for (let n of this.storage.ngramIndexes.keys()) this.removeItemFromField(n, e, t);
|
|
38
|
+
}
|
|
39
|
+
moveItem(e, t, n) {
|
|
40
|
+
if (!(this.storage.ngramIndexes.size === 0 || t === n)) for (let r of this.storage.ngramIndexes.keys()) this.moveItemForField(r, e, t, n);
|
|
41
|
+
}
|
|
42
|
+
searchAllIndexedFieldIndices(e, t, n, r) {
|
|
43
|
+
let i = /* @__PURE__ */ new Set(), a = [];
|
|
44
|
+
for (let o of this.storage.ngramIndexes.keys()) for (let s of this.searchIndexedFieldIndices(o, e, t, n, r)) i.has(s) || (i.add(s), a.push(s));
|
|
45
|
+
return a;
|
|
46
|
+
}
|
|
47
|
+
searchIndexedField(e, t, n, r, i, a, o = Infinity) {
|
|
48
|
+
let s = this.searchIndexedFieldIndices(t, n, r, i, a, o), c = [];
|
|
49
|
+
for (let t = 0; t < s.length; t++) {
|
|
50
|
+
let n = e[s[t]];
|
|
51
|
+
n && c.push(n);
|
|
52
|
+
}
|
|
53
|
+
return c;
|
|
54
|
+
}
|
|
55
|
+
searchIndexedFieldIndices(e, t, i, a, o, s = Infinity) {
|
|
56
|
+
let c = this.storage.ngramIndexes.get(e);
|
|
57
|
+
if (!c) return [];
|
|
58
|
+
let l = this.storage.normalizedFieldValues.get(e) ?? [];
|
|
59
|
+
return o == null ? n(c, i, l, t, {
|
|
60
|
+
restrictionLookup: a,
|
|
61
|
+
take: s
|
|
62
|
+
}) : r(c, i, l, t, {
|
|
63
|
+
candidateIndices: o,
|
|
64
|
+
restrictionLookup: a,
|
|
65
|
+
take: s
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
searchFieldLinear(e, t, n) {
|
|
69
|
+
let r = this.searchFieldLinearIndices(e, t, n), i = [];
|
|
70
|
+
for (let t = 0; t < r.length; t++) {
|
|
71
|
+
let n = e[r[t]];
|
|
72
|
+
n && i.push(n);
|
|
73
|
+
}
|
|
74
|
+
return i;
|
|
75
|
+
}
|
|
76
|
+
searchFieldLinearIndices(e, t, n, r) {
|
|
77
|
+
let i = this.fieldDescriptors.get(t);
|
|
78
|
+
if (!i) return [];
|
|
79
|
+
let { collectionKey: a, nestedKey: o } = i, s = [];
|
|
80
|
+
if (r) {
|
|
81
|
+
for (let t = 0; t < r.length; t++) {
|
|
82
|
+
let i = r[t], c = e[i][a];
|
|
83
|
+
if (!Array.isArray(c)) continue;
|
|
84
|
+
let l = !1;
|
|
85
|
+
for (let e = 0; e < c.length; e++) {
|
|
86
|
+
let t = c[e][o];
|
|
87
|
+
if (typeof t == "string" && t.toLowerCase().includes(n)) {
|
|
88
|
+
l = !0;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
l && s.push(i);
|
|
93
|
+
}
|
|
94
|
+
return s;
|
|
95
|
+
}
|
|
96
|
+
for (let t = 0; t < e.length; t++) {
|
|
97
|
+
let r = e[t][a];
|
|
98
|
+
if (!Array.isArray(r)) continue;
|
|
99
|
+
let i = !1;
|
|
100
|
+
for (let e = 0; e < r.length; e++) {
|
|
101
|
+
let t = r[e][o];
|
|
102
|
+
if (typeof t == "string" && t.toLowerCase().includes(n)) {
|
|
103
|
+
i = !0;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
i && s.push(t);
|
|
108
|
+
}
|
|
109
|
+
return s;
|
|
110
|
+
}
|
|
111
|
+
matchesAnyField(e, t) {
|
|
112
|
+
for (let n of this.registeredFields) {
|
|
113
|
+
let r = this.fieldDescriptors.get(n);
|
|
114
|
+
if (!r) continue;
|
|
115
|
+
let { collectionKey: i, nestedKey: a } = r, o = e[i];
|
|
116
|
+
if (Array.isArray(o)) for (let e = 0; e < o.length; e++) {
|
|
117
|
+
let n = o[e][a];
|
|
118
|
+
if (typeof n == "string" && n.toLowerCase().includes(t)) return !0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return !1;
|
|
122
|
+
}
|
|
123
|
+
registerField(t) {
|
|
124
|
+
let n = e(t);
|
|
125
|
+
n && (this.registeredFields.add(t), this.fieldDescriptors.set(t, n));
|
|
126
|
+
}
|
|
127
|
+
getNormalizedValues(e) {
|
|
128
|
+
let t = this.storage.normalizedFieldValues.get(e);
|
|
129
|
+
if (t) return t;
|
|
130
|
+
let n = [];
|
|
131
|
+
return this.storage.normalizedFieldValues.set(e, n), n;
|
|
132
|
+
}
|
|
133
|
+
buildIndex(e, n) {
|
|
134
|
+
let r = this.fieldDescriptors.get(n);
|
|
135
|
+
if (!r) return;
|
|
136
|
+
let { collectionKey: i, nestedKey: a } = r, o = /* @__PURE__ */ new Map(), s = Array(e.length);
|
|
137
|
+
for (let n = 0, r = e.length; n < r; n++) {
|
|
138
|
+
let r = e[n][i];
|
|
139
|
+
if (!Array.isArray(r)) continue;
|
|
140
|
+
let c = [];
|
|
141
|
+
for (let e = 0; e < r.length; e++) {
|
|
142
|
+
let t = r[e][a];
|
|
143
|
+
typeof t == "string" && c.push(t.toLowerCase());
|
|
144
|
+
}
|
|
145
|
+
if (c.length === 0) continue;
|
|
146
|
+
let l = c.join("\n");
|
|
147
|
+
s[n] = l, t(o, l, n);
|
|
148
|
+
}
|
|
149
|
+
this.storage.ngramIndexes.set(n, o), this.storage.normalizedFieldValues.set(n, s);
|
|
150
|
+
}
|
|
151
|
+
addItemsToField(e, n, r) {
|
|
152
|
+
let i = this.fieldDescriptors.get(e), a = this.storage.ngramIndexes.get(e);
|
|
153
|
+
if (!i || !a) return;
|
|
154
|
+
let o = this.getNormalizedValues(e), { collectionKey: s, nestedKey: c } = i;
|
|
155
|
+
for (let e = 0; e < n.length; e++) {
|
|
156
|
+
let i = n[e][s];
|
|
157
|
+
if (!Array.isArray(i)) continue;
|
|
158
|
+
let l = [], u = r + e;
|
|
159
|
+
for (let e = 0; e < i.length; e++) {
|
|
160
|
+
let t = i[e][c];
|
|
161
|
+
typeof t == "string" && l.push(t.toLowerCase());
|
|
162
|
+
}
|
|
163
|
+
if (l.length === 0) continue;
|
|
164
|
+
let d = l.join("\n");
|
|
165
|
+
o[u] = d, t(a, d, u);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
updateItemInField(e, n, r, a) {
|
|
169
|
+
let o = this.storage.ngramIndexes.get(e);
|
|
170
|
+
if (!o) return;
|
|
171
|
+
let s = this.getNormalizedValues(e), c = this.getNormalizedItemValue(e, r), l = this.getNormalizedItemValue(e, n);
|
|
172
|
+
if (c !== l) {
|
|
173
|
+
if (c && i(o, c, a), !l) {
|
|
174
|
+
delete s[a];
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
s[a] = l, t(o, l, a);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
removeItemFromField(e, t, n) {
|
|
181
|
+
let r = this.storage.ngramIndexes.get(e);
|
|
182
|
+
if (!r) return;
|
|
183
|
+
let a = this.getNormalizedValues(e), o = a[n] ?? this.getNormalizedItemValue(e, t);
|
|
184
|
+
o && i(r, o, n), delete a[n];
|
|
185
|
+
}
|
|
186
|
+
moveItemForField(e, n, r, a) {
|
|
187
|
+
let o = this.storage.ngramIndexes.get(e);
|
|
188
|
+
if (!o) return;
|
|
189
|
+
let s = this.getNormalizedValues(e), c = s[r] ?? this.getNormalizedItemValue(e, n);
|
|
190
|
+
if (!c) {
|
|
191
|
+
delete s[r];
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
i(o, c, r), t(o, c, a), s[a] = c, delete s[r];
|
|
195
|
+
}
|
|
196
|
+
getNormalizedItemValue(e, t) {
|
|
197
|
+
let n = this.fieldDescriptors.get(e);
|
|
198
|
+
if (!n) return null;
|
|
199
|
+
let { collectionKey: r, nestedKey: i } = n, a = t[r];
|
|
200
|
+
if (!Array.isArray(a)) return null;
|
|
201
|
+
let o = [];
|
|
202
|
+
for (let e = 0; e < a.length; e++) {
|
|
203
|
+
let t = a[e][i];
|
|
204
|
+
typeof t == "string" && o.push(t.toLowerCase());
|
|
205
|
+
}
|
|
206
|
+
return o.length === 0 ? null : o.join("\n");
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
//#endregion
|
|
210
|
+
export { a as SearchNestedCollection };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimum query length required to use the n-gram index directly.
|
|
3
|
+
* Queries shorter than this fall back to a linear scan.
|
|
4
|
+
*/
|
|
5
|
+
import type { IntersectPostingListsInCandidatesOptions, IntersectPostingListsOptions } from "./types";
|
|
6
|
+
export type IntersectionPlan = {
|
|
7
|
+
smallestPostingList: ReadonlySet<number>;
|
|
8
|
+
matches: (candidateIndex: number) => boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function createIntersectionPlan(ngramMap: Map<string, Set<number>>, uniqueQueryGrams: ReadonlySet<string>, normalizedValues: (string | undefined)[], lowerQuery: string): IntersectionPlan | null;
|
|
11
|
+
export declare const MINIMUM_SHORT_QUERY_INDEX_LENGTH = 2;
|
|
12
|
+
export declare function buildIntersectionQueryGrams(lowerQuery: string): ReadonlySet<string>;
|
|
13
|
+
export declare function indexLowerValue(ngramMap: Map<string, Set<number>>, lowerValue: string, itemIndex: number): void;
|
|
14
|
+
export declare function estimateIntersectionCandidateCount(ngramMap: Map<string, Set<number>>, uniqueQueryGrams: ReadonlySet<string>): number;
|
|
15
|
+
/**
|
|
16
|
+
* Intersects posting lists for the given query grams and confirms each
|
|
17
|
+
* candidate against the full normalizedValues string. Returns dataset indices
|
|
18
|
+
* of confirmed matches.
|
|
19
|
+
*/
|
|
20
|
+
export declare function intersectPostingLists(ngramMap: Map<string, Set<number>>, uniqueQueryGrams: ReadonlySet<string>, normalizedValues: (string | undefined)[], lowerQuery: string, options?: IntersectPostingListsOptions): number[];
|
|
21
|
+
export declare function intersectPostingListsInCandidates(ngramMap: Map<string, Set<number>>, uniqueQueryGrams: ReadonlySet<string>, normalizedValues: (string | undefined)[], lowerQuery: string, options: IntersectPostingListsInCandidatesOptions): number[];
|
|
22
|
+
export declare function removeLowerValue(ngramMap: Map<string, Set<number>>, lowerValue: string, itemIndex: number): void;
|
|
23
|
+
//# sourceMappingURL=ngram.d.ts.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//#region src/search/ngram.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
for (let t = 0; t < e.length - 1; t++) {
|
|
4
|
+
let n = t;
|
|
5
|
+
for (let r = t + 1; r < e.length; r++) e[r].size < e[n].size && (n = r);
|
|
6
|
+
if (n !== t) {
|
|
7
|
+
let r = e[t];
|
|
8
|
+
e[t] = e[n], e[n] = r;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function t(t, n) {
|
|
13
|
+
let r = [];
|
|
14
|
+
for (let e of n) {
|
|
15
|
+
let n = t.get(e);
|
|
16
|
+
if (!n) return null;
|
|
17
|
+
r.push(n);
|
|
18
|
+
}
|
|
19
|
+
return e(r), r;
|
|
20
|
+
}
|
|
21
|
+
function n(e, t) {
|
|
22
|
+
for (let n = 0; n < t.length; n++) if (!t[n].has(e)) return !1;
|
|
23
|
+
return !0;
|
|
24
|
+
}
|
|
25
|
+
function r(e, r, i, a) {
|
|
26
|
+
let o = t(e, r);
|
|
27
|
+
if (o === null) return null;
|
|
28
|
+
let s = o[0];
|
|
29
|
+
return {
|
|
30
|
+
smallestPostingList: s,
|
|
31
|
+
matches: (e) => s.has(e) && n(e, o) && !!i[e]?.includes(a)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function i(e) {
|
|
35
|
+
let t = Math.min(3, Math.max(2, e.length)), n = e.length - t + 1, r = Array(n);
|
|
36
|
+
for (let i = 0; i < n; i++) r[i] = e.substring(i, i + t);
|
|
37
|
+
return r;
|
|
38
|
+
}
|
|
39
|
+
function a(e, t) {
|
|
40
|
+
let n = e.get(t);
|
|
41
|
+
if (n) return n;
|
|
42
|
+
let r = /* @__PURE__ */ new Set();
|
|
43
|
+
return e.set(t, r), r;
|
|
44
|
+
}
|
|
45
|
+
function o(e) {
|
|
46
|
+
let t = i(e);
|
|
47
|
+
if (t.length <= 12) return new Set(t);
|
|
48
|
+
let n = /* @__PURE__ */ new Set(), r = t.length - 1;
|
|
49
|
+
for (let e = 0; e <= 11; e++) {
|
|
50
|
+
let i = Math.round(e * r / 11);
|
|
51
|
+
n.add(t[i]);
|
|
52
|
+
}
|
|
53
|
+
return n;
|
|
54
|
+
}
|
|
55
|
+
function s(e, t, n) {
|
|
56
|
+
let r = Math.min(3, t.length);
|
|
57
|
+
for (let i = 2; i <= r; i++) {
|
|
58
|
+
let r = t.length - i;
|
|
59
|
+
for (let o = 0; o <= r; o++) a(e, t.substring(o, o + i)).add(n);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function c(e, t, n, i, a = {}) {
|
|
63
|
+
let { restrictionLookup: o = null, take: s = Infinity } = a, c = r(e, t, n, i);
|
|
64
|
+
if (c === null) return [];
|
|
65
|
+
let l = [];
|
|
66
|
+
for (let e of c.smallestPostingList) if (!(o !== null && !o[e]) && c.matches(e) && (l.push(e), l.length >= s)) break;
|
|
67
|
+
return l;
|
|
68
|
+
}
|
|
69
|
+
function l(e, t, n, i, a) {
|
|
70
|
+
let { candidateIndices: o, restrictionLookup: s = null, take: c = Infinity } = a;
|
|
71
|
+
if (o.length === 0) return [];
|
|
72
|
+
let l = r(e, t, n, i);
|
|
73
|
+
if (l === null) return [];
|
|
74
|
+
let u = [];
|
|
75
|
+
if (s === null || o.length <= l.smallestPostingList.size) {
|
|
76
|
+
for (let e = 0; e < o.length; e++) {
|
|
77
|
+
let t = o[e];
|
|
78
|
+
if (l.matches(t) && (u.push(t), u.length >= c)) break;
|
|
79
|
+
}
|
|
80
|
+
return u;
|
|
81
|
+
}
|
|
82
|
+
for (let e of l.smallestPostingList) if (s[e] && l.matches(e) && (u.push(e), u.length >= c)) break;
|
|
83
|
+
return u;
|
|
84
|
+
}
|
|
85
|
+
function u(e, t, n) {
|
|
86
|
+
let r = Math.min(3, t.length);
|
|
87
|
+
for (let i = 2; i <= r; i++) {
|
|
88
|
+
let r = t.length - i;
|
|
89
|
+
for (let a = 0; a <= r; a++) {
|
|
90
|
+
let r = t.substring(a, a + i), o = e.get(r);
|
|
91
|
+
o && (o.delete(n), o.size === 0 && e.delete(r));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { o as buildIntersectionQueryGrams, r as createIntersectionPlan, s as indexLowerValue, c as intersectPostingLists, l as intersectPostingListsInCandidates, u as removeLowerValue };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TextSearchEngine class for performing fast substring search on string fields
|
|
3
|
+
* using n-gram indexing and intersection.
|
|
4
|
+
*/
|
|
5
|
+
import { State } from "../State";
|
|
6
|
+
import { CollectionItem, type UpdateDescriptor } from "../types";
|
|
7
|
+
import type { SearchQueryOptions, TextSearchEngineStats, TextSearchEngineOptions } from "./types";
|
|
8
|
+
export declare class TextSearchEngine<T extends CollectionItem> {
|
|
9
|
+
private readonly state;
|
|
10
|
+
private readonly namespace;
|
|
11
|
+
private readonly nestedCollection;
|
|
12
|
+
private readonly minQueryLength;
|
|
13
|
+
private readonly silent;
|
|
14
|
+
private cachedIndexedFieldsList;
|
|
15
|
+
private cachedLinearSearchFieldsList;
|
|
16
|
+
private readonly emittedWarningKeys;
|
|
17
|
+
private readonly warnings;
|
|
18
|
+
/**
|
|
19
|
+
* Lightweight normalizedValues-only cache for fields without n-gram index.
|
|
20
|
+
* Built lazily on first full-dataset linear scan for non-indexed fields.
|
|
21
|
+
*/
|
|
22
|
+
private normalizedValuesCache;
|
|
23
|
+
private combinedNormalizedValuesCache;
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new TextSearchEngine with optional data and fields to index.
|
|
26
|
+
*/
|
|
27
|
+
constructor(options?: TextSearchEngineOptions<T> & {
|
|
28
|
+
state?: State<T>;
|
|
29
|
+
});
|
|
30
|
+
private get dataset();
|
|
31
|
+
private get runtime();
|
|
32
|
+
private get flatIndexes();
|
|
33
|
+
private get indexedFields();
|
|
34
|
+
private shouldDeferMutationIndexUpdates;
|
|
35
|
+
private markDeferredMutationState;
|
|
36
|
+
private ensureConfiguredIndexesReady;
|
|
37
|
+
private rebuildConfiguredIndexes;
|
|
38
|
+
/**
|
|
39
|
+
* Builds an n-gram index for the given field from arbitrary data.
|
|
40
|
+
*/
|
|
41
|
+
private buildIndexFromData;
|
|
42
|
+
search(query: string, options?: SearchQueryOptions): T[];
|
|
43
|
+
search(field: (keyof T & string) | (string & {}), query: string, options?: SearchQueryOptions): T[];
|
|
44
|
+
searchAll(query: string, options?: SearchQueryOptions): T[];
|
|
45
|
+
private normalizeQuery;
|
|
46
|
+
private normalizeSearchWindow;
|
|
47
|
+
private shouldTrackPreviousResult;
|
|
48
|
+
private hasReachedWindowLimit;
|
|
49
|
+
private sliceItems;
|
|
50
|
+
private collectItemsFromIndices;
|
|
51
|
+
private createLookup;
|
|
52
|
+
private getRestrictionLookup;
|
|
53
|
+
/**
|
|
54
|
+
* Returns the data source for search based on filterByPreviousResult setting.
|
|
55
|
+
* When the new query narrows the previous one, returns previousResult with indices.
|
|
56
|
+
* Otherwise resets previous state and returns the full dataset.
|
|
57
|
+
*/
|
|
58
|
+
private getSearchSource;
|
|
59
|
+
/**
|
|
60
|
+
* Saves the search result for potential reuse on subsequent narrowing queries.
|
|
61
|
+
*/
|
|
62
|
+
private saveSearchResult;
|
|
63
|
+
private persistSearchResult;
|
|
64
|
+
/**
|
|
65
|
+
* Resets the previous search result, forcing the next search to use the full dataset.
|
|
66
|
+
*
|
|
67
|
+
* @see {@link TextSearchEngineOptions.filterByPreviousResult}
|
|
68
|
+
*/
|
|
69
|
+
resetSearchState(): this;
|
|
70
|
+
getWarnings(): string[];
|
|
71
|
+
getStats(): TextSearchEngineStats;
|
|
72
|
+
resetStats(): this;
|
|
73
|
+
private clearPreviousSearchState;
|
|
74
|
+
private recordIndexedQuery;
|
|
75
|
+
private recordFallbackQuery;
|
|
76
|
+
private shouldEmitFallbackWarning;
|
|
77
|
+
private warnAboutFallback;
|
|
78
|
+
private getResolvedFlatIndex;
|
|
79
|
+
private getQueryGrams;
|
|
80
|
+
/**
|
|
81
|
+
* Searches all indexed fields.
|
|
82
|
+
*/
|
|
83
|
+
private searchAllFields;
|
|
84
|
+
private searchAllFieldsIndexed;
|
|
85
|
+
private searchAllFieldsIndexedInCandidates;
|
|
86
|
+
/**
|
|
87
|
+
* Searches a specific field.
|
|
88
|
+
*/
|
|
89
|
+
private searchField;
|
|
90
|
+
/**
|
|
91
|
+
* Searches a field using prepared query grams, returning matched items and indices.
|
|
92
|
+
* Delegates to searchFieldWithPreparedQueryIndices for the core intersection logic.
|
|
93
|
+
*/
|
|
94
|
+
private searchFieldWithPreparedQuery;
|
|
95
|
+
/**
|
|
96
|
+
* Core indexed search: returns dataset indices of matching items.
|
|
97
|
+
* If the cached index is stale (version mismatch), rebuilds it lazily.
|
|
98
|
+
*/
|
|
99
|
+
private searchFieldWithPreparedQueryIndices;
|
|
100
|
+
/**
|
|
101
|
+
* Returns the cached list of indexed field names, rebuilding if stale.
|
|
102
|
+
*/
|
|
103
|
+
private getIndexedFieldsList;
|
|
104
|
+
private materializeIndicesResult;
|
|
105
|
+
private getLinearSearchFields;
|
|
106
|
+
/**
|
|
107
|
+
* Eagerly builds normalizedValues for a field without n-gram overhead.
|
|
108
|
+
* Stores in a lightweight cache so subsequent linear scans reuse it.
|
|
109
|
+
*/
|
|
110
|
+
private buildNormalizedValuesOnly;
|
|
111
|
+
private buildCombinedNormalizedValues;
|
|
112
|
+
private buildCombinedNormalizedValue;
|
|
113
|
+
private getCombinedNormalizedValues;
|
|
114
|
+
/**
|
|
115
|
+
* Updates only the entry at `index` in every cached normalizedValues array,
|
|
116
|
+
* avoiding a full O(n) rebuild when a single item is updated.
|
|
117
|
+
*/
|
|
118
|
+
private invalidateNormalizedValuesCacheEntry;
|
|
119
|
+
/**
|
|
120
|
+
* Searches all fields linearly, using pre-normalized values when available.
|
|
121
|
+
* When `sourceIndices` is provided, iterates only those dataset positions
|
|
122
|
+
* (previousResult narrowing path) and resolves items via this.dataset[idx].
|
|
123
|
+
*/
|
|
124
|
+
private searchLinearAllFields;
|
|
125
|
+
/**
|
|
126
|
+
* Searches a specific field linearly, using pre-normalized values when available.
|
|
127
|
+
* When `sourceIndices` is provided, resolves items via this.dataset[idx].
|
|
128
|
+
*/
|
|
129
|
+
private searchLinearSingleField;
|
|
130
|
+
clearIndexes(): this;
|
|
131
|
+
getOriginData(): T[];
|
|
132
|
+
data(data: T[]): this;
|
|
133
|
+
add(items: T[]): this;
|
|
134
|
+
update(descriptor: UpdateDescriptor<T>): this;
|
|
135
|
+
private applyAddedItems;
|
|
136
|
+
clearData(): this;
|
|
137
|
+
private handleStateMutation;
|
|
138
|
+
private addItemsToField;
|
|
139
|
+
private applyUpdatedItem;
|
|
140
|
+
private applyRemovedItem;
|
|
141
|
+
private updateIndexedField;
|
|
142
|
+
private removeIndexedFieldValue;
|
|
143
|
+
private moveIndexedFieldValue;
|
|
144
|
+
private getNormalizedFieldValue;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=text-search.d.ts.map
|