@devisfuture/mega-collection 2.2.0 → 2.3.1
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/README.md +3 -571
- package/dist/chunk-5FVJLC7Y.mjs +1 -0
- package/dist/chunk-U3IU4NI6.mjs +1 -0
- package/dist/chunk-Y7NSBYLS.mjs +3 -0
- package/dist/chunk-Z4QO4GOM.mjs +1 -0
- package/dist/filter/index.d.mts +4 -0
- package/dist/filter/index.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/merge/index.d.mts +4 -0
- package/dist/merge/index.mjs +1 -1
- package/dist/search/index.d.mts +3 -0
- package/dist/search/index.mjs +1 -1
- package/dist/sort/index.d.mts +7 -0
- package/dist/sort/index.mjs +1 -1
- package/package.json +1 -99
- package/LICENSE +0 -21
- package/dist/chunk-LSQXPQRE.mjs +0 -1
- package/dist/chunk-NHFG4LIO.mjs +0 -1
- package/dist/chunk-XCB43Y63.mjs +0 -2
- package/dist/chunk-ZJ6RQRJN.mjs +0 -1
package/README.md
CHANGED
|
@@ -1,573 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="./illustration.png" alt="mega-collection illustration" width="100%" />
|
|
3
|
-
</p>
|
|
1
|
+
# @devisfuture/mega-collection
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
Docs and examples: https://github.com/trae-op/mega-collection#readme
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Table of Contents
|
|
10
|
-
|
|
11
|
-
- [What does this package solve](#what-does-this-package-solve) – what problem this package helps with
|
|
12
|
-
- [Features](#features) – what the package can do
|
|
13
|
-
- [React demo](#react-demo) – example project and live demo
|
|
14
|
-
- [Install](#install) – how to install the package
|
|
15
|
-
- [Quick Start](#quick-start) – basic usage examples
|
|
16
|
-
- [All-in-one: `MergeEngines`](#all-in-one-mergeengines) – use search, filter, and sort from one engine
|
|
17
|
-
- [Search only](#search-only) – use only text search
|
|
18
|
-
- [Flat collections search](#flat-collections-search) – search simple fields like `name` or `city`
|
|
19
|
-
- [Nested collections search](#nested-collections-search) – search inside nested arrays like `orders.status`
|
|
20
|
-
- [Filter only](#filter-only) – use only filtering
|
|
21
|
-
- [Flat collections filter](#flat-collections-filter) – filter by simple top-level fields
|
|
22
|
-
- [Exclude items with `exclude`](#exclude-items-with-exclude) – remove matching items from the result
|
|
23
|
-
- [Result-only exclude](#result-only-exclude) – return a filtered result without mutating stored data
|
|
24
|
-
- [Mutable exclude with `mutableExcludeField`](#mutable-exclude-with-mutableexcludefield) – fast delete-like removal via swap-pop
|
|
25
|
-
- [Nested collections filter](#nested-collections-filter) – filter by nested array fields
|
|
26
|
-
- [Sort only](#sort-only) – use only sorting
|
|
27
|
-
- [API Reference](#api-reference) – list of options and methods
|
|
28
|
-
- [`MergeEngines<T>`](#mergeenginest-root-module) – one engine that combines everything
|
|
29
|
-
- [`TextSearchEngine<T>`](#textsearchenginet-search-module) – engine for text search
|
|
30
|
-
- [`FilterEngine<T>`](#filterenginet-filter-module) – engine for filtering
|
|
31
|
-
- [`SortEngine<T>`](#sortenginet-sort-module) – engine for sorting
|
|
32
|
-
- [Types](#types) – TypeScript types you can import
|
|
33
|
-
- [Build](#build) – commands for build and development
|
|
34
|
-
- [Contributing](#contributing) – contribution rules
|
|
35
|
-
- [Security](#security) – security policy
|
|
36
|
-
- [License](#license) – license information
|
|
37
|
-
|
|
38
|
-
## What does this package solve
|
|
39
|
-
|
|
40
|
-
Sometimes the server returns a very large array, for example 100K+ items.
|
|
41
|
-
Most often you then need to search, filter, or sort this data.
|
|
42
|
-
|
|
43
|
-
This package helps do these operations faster than plain JavaScript methods.
|
|
44
|
-
Usually this happens before data is shown in the UI.
|
|
45
|
-
|
|
46
|
-
The package has no dependencies.
|
|
47
|
-
You can import only the parts you need.
|
|
48
|
-
|
|
49
|
-
Each engine has its own entry point: `/search`, `/filter`, `/sort`.
|
|
50
|
-
If you import only `@devisfuture/mega-collection/search`, only search code goes into the bundle.
|
|
51
|
-
Unused modules are not included.
|
|
52
|
-
|
|
53
|
-
## Features
|
|
54
|
-
|
|
55
|
-
| Capability | Strategy | Complexity |
|
|
56
|
-
| ---------------------------- | -------------------------------------- | ---------------------------------- |
|
|
57
|
-
| **Indexed filter** | Hash-Map index (`Map<value, T[]>`) | **O(1)** |
|
|
58
|
-
| **Multi-value filter** | Index intersection + `Set` membership | **O(k)** indexed / **O(n)** linear |
|
|
59
|
-
| **Nested collection filter** | Pre-built nested index + `Set` lookup | **O(k)** indexed / **O(n)** linear |
|
|
60
|
-
| **Text search** (contains) | Trigram inverted index + verify | **O(candidates)** |
|
|
61
|
-
| **Nested collection search** | Nested trigram index + verify | **O(candidates)** |
|
|
62
|
-
| **Sorting** | Pre-sorted index (cached) / V8 TimSort | **O(n)** cached / **O(n log n)** |
|
|
63
|
-
|
|
64
|
-
## React demo
|
|
65
|
-
|
|
66
|
-
A small [repository](https://github.com/trae-op/quick-start_react_mega-collection) shows how to use `@devisfuture/mega-collection` in React.
|
|
67
|
-
It has examples for search, filter, sort, and `MergeEngines` with a simple UI.
|
|
68
|
-
|
|
69
|
-
There is also a live [demo](https://trae-op.github.io/quick-start_react_mega-collection/).
|
|
70
|
-
|
|
71
|
-
## Install
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
npm install @devisfuture/mega-collection
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
_This package is framework-agnostic and works in all popular front‑end frameworks including React, Angular, Vue and so on._
|
|
78
|
-
|
|
79
|
-
## Quick Start
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
interface User {
|
|
83
|
-
id: number;
|
|
84
|
-
name: string;
|
|
85
|
-
city: string;
|
|
86
|
-
age: number;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
interface Order {
|
|
90
|
-
id: string;
|
|
91
|
-
status: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
interface UserWithOrders extends User {
|
|
95
|
-
orders: Order[];
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### All-in-one: `MergeEngines`
|
|
100
|
-
|
|
101
|
-
Use `MergeEngines` when you want one class that works with one dataset.
|
|
102
|
-
Add needed engines to `imports`. Only those engines will be created.
|
|
103
|
-
|
|
104
|
-
You can create many engine instances in one project for different collections.
|
|
105
|
-
Each instance stores its own data and indexes, so they do not affect each other.
|
|
106
|
-
|
|
107
|
-
Each engine can receive an optional `fields` array through `search`, `filter`, or `sort` options.
|
|
108
|
-
These fields are used for indexes.
|
|
109
|
-
|
|
110
|
-
Indexes are built lazily on first use, so engine creation stays fast.
|
|
111
|
-
If you skip `fields`, everything still works, but the engine may scan the full array.
|
|
112
|
-
|
|
113
|
-
```ts
|
|
114
|
-
import { MergeEngines } from "@devisfuture/mega-collection";
|
|
115
|
-
import { TextSearchEngine } from "@devisfuture/mega-collection/search";
|
|
116
|
-
import { SortEngine } from "@devisfuture/mega-collection/sort";
|
|
117
|
-
import { FilterEngine } from "@devisfuture/mega-collection/filter";
|
|
118
|
-
|
|
119
|
-
const engine = new MergeEngines<User>({
|
|
120
|
-
imports: [TextSearchEngine, SortEngine, FilterEngine],
|
|
121
|
-
data: users,
|
|
122
|
-
search: { fields: ["name", "city"], minQueryLength: 2 },
|
|
123
|
-
filter: { fields: ["city", "age"], filterByPreviousResult: true },
|
|
124
|
-
sort: { fields: ["age", "name", "city"] },
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const mutableMerge = new MergeEngines<User>({
|
|
128
|
-
imports: [FilterEngine],
|
|
129
|
-
data: users,
|
|
130
|
-
filter: { fields: ["id", "city"], mutableExcludeField: "id" },
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Dataset is passed once in the constructor.
|
|
134
|
-
engine
|
|
135
|
-
.search("john")
|
|
136
|
-
.sort([{ field: "age", direction: "asc" }])
|
|
137
|
-
.filter([{ field: "city", values: ["Miami", "New York"] }]);
|
|
138
|
-
|
|
139
|
-
// Example with nested fields, for example `orders` inside each user.
|
|
140
|
-
const nestedEngine = new MergeEngines<UserWithOrders>({
|
|
141
|
-
imports: [TextSearchEngine, SortEngine, FilterEngine],
|
|
142
|
-
data: usersWithOrders,
|
|
143
|
-
search: {
|
|
144
|
-
fields: ["name", "city"],
|
|
145
|
-
nestedFields: ["orders.status"],
|
|
146
|
-
minQueryLength: 2,
|
|
147
|
-
},
|
|
148
|
-
filter: {
|
|
149
|
-
fields: ["city", "age"],
|
|
150
|
-
nestedFields: ["orders.status"],
|
|
151
|
-
filterByPreviousResult: true,
|
|
152
|
-
},
|
|
153
|
-
sort: { fields: ["age", "name", "city"] },
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
nestedEngine.search("pending"); // finds users whose orders contain "pending"
|
|
157
|
-
nestedEngine.filter([{ field: "orders.status", values: ["delivered"] }]);
|
|
158
|
-
|
|
159
|
-
// Replace dataset later without creating a new instance.
|
|
160
|
-
engine.data([
|
|
161
|
-
{
|
|
162
|
-
id: 1,
|
|
163
|
-
name: "Tim",
|
|
164
|
-
city: "New-York",
|
|
165
|
-
age: 30,
|
|
166
|
-
},
|
|
167
|
-
]);
|
|
168
|
-
|
|
169
|
-
// Clear indexes or data for one module.
|
|
170
|
-
engine.clearIndexes("search").clearIndexes("sort").clearIndexes("filter");
|
|
171
|
-
engine.clearData("search").clearData("sort").clearData("filter");
|
|
172
|
-
|
|
173
|
-
// Get shared original dataset.
|
|
174
|
-
engine.getOriginData();
|
|
175
|
-
|
|
176
|
-
// Remove items through the root facade.
|
|
177
|
-
mutableMerge.filter([{ field: "id", exclude: [1, 4] }]);
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
### Search only
|
|
183
|
-
|
|
184
|
-
Use `TextSearchEngine` when you only need text search.
|
|
185
|
-
The examples below show search by simple fields and nested fields.
|
|
186
|
-
|
|
187
|
-
#### Flat collections search
|
|
188
|
-
|
|
189
|
-
```ts
|
|
190
|
-
import { TextSearchEngine } from "@devisfuture/mega-collection/search";
|
|
191
|
-
|
|
192
|
-
// `fields` tells the engine which fields should use indexed search.
|
|
193
|
-
// The index is built only when it is needed for the first time.
|
|
194
|
-
// If you skip `fields`, search still works, but it scans the full dataset.
|
|
195
|
-
const engine = new TextSearchEngine<User>({
|
|
196
|
-
data: users,
|
|
197
|
-
fields: ["name", "city"],
|
|
198
|
-
minQueryLength: 2, // begins searching when query length >= 2
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// If the query is shorter than `minQueryLength`, the engine returns
|
|
202
|
-
// the original dataset. Empty or blank queries do the same.
|
|
203
|
-
|
|
204
|
-
engine.search("john"); // searches all indexed fields, deduplicated
|
|
205
|
-
engine.search("name", "john"); // searches a specific field
|
|
206
|
-
|
|
207
|
-
// replace dataset without re-initializing
|
|
208
|
-
engine.data(users);
|
|
209
|
-
|
|
210
|
-
// access original dataset stored in the engine
|
|
211
|
-
engine.getOriginData();
|
|
212
|
-
|
|
213
|
-
// service methods stay on the engine instance
|
|
214
|
-
engine.clearIndexes();
|
|
215
|
-
engine.clearData();
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
#### Nested collections search
|
|
219
|
-
|
|
220
|
-
```ts
|
|
221
|
-
import { TextSearchEngine } from "@devisfuture/mega-collection/search";
|
|
222
|
-
|
|
223
|
-
// Search inside nested arrays. `nestedFields` uses dot notation.
|
|
224
|
-
const nestedSearch = new TextSearchEngine<UserWithOrders>({
|
|
225
|
-
data: usersWithOrders,
|
|
226
|
-
fields: ["name", "city"],
|
|
227
|
-
nestedFields: ["orders.status"],
|
|
228
|
-
minQueryLength: 2,
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
nestedSearch.search("pending"); // finds users whose orders match
|
|
232
|
-
nestedSearch.search("orders.status", "delivered"); // search a specific nested field
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Filter only
|
|
236
|
-
|
|
237
|
-
Use `FilterEngine` when you only need filtering.
|
|
238
|
-
The examples below show filtering by simple fields and nested fields.
|
|
239
|
-
|
|
240
|
-
#### Flat collections filter
|
|
241
|
-
|
|
242
|
-
```ts
|
|
243
|
-
import { FilterEngine } from "@devisfuture/mega-collection/filter";
|
|
244
|
-
|
|
245
|
-
// `fields` tells the engine which fields should use indexes for filtering.
|
|
246
|
-
// The index is built only when it is needed for the first time.
|
|
247
|
-
// Without `fields`, filtering still works, but it scans the data.
|
|
248
|
-
const engine = new FilterEngine<User>({
|
|
249
|
-
data: users,
|
|
250
|
-
fields: ["city", "age"],
|
|
251
|
-
filterByPreviousResult: true,
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
engine.filter([
|
|
255
|
-
{ field: "city", values: ["Miami", "New York"] },
|
|
256
|
-
{ field: "age", values: [25, 30, 35] },
|
|
257
|
-
]);
|
|
258
|
-
|
|
259
|
-
// Replace dataset without creating a new engine.
|
|
260
|
-
engine.data(users);
|
|
261
|
-
|
|
262
|
-
// Get original stored dataset.
|
|
263
|
-
engine.getOriginData();
|
|
264
|
-
|
|
265
|
-
// Sequential mode example:
|
|
266
|
-
// 1) First call filters by city.
|
|
267
|
-
const byCity = engine.filter([{ field: "city", values: ["Miami"] }]);
|
|
268
|
-
// 2) Second call works only on the previous result.
|
|
269
|
-
const byCityAndAge = engine.filter([{ field: "age", values: [22] }]);
|
|
270
|
-
// 3) Returning to an earlier criteria state restores its previous result.
|
|
271
|
-
const byCityAgain = engine.filter([{ field: "city", values: ["Miami"] }]);
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
#### Exclude items with `exclude`
|
|
275
|
-
|
|
276
|
-
Use `exclude` when you want to remove items from the result by exact field values.
|
|
277
|
-
This is useful when you already know which `id` values or other field values should not be in the result.
|
|
278
|
-
|
|
279
|
-
`exclude` changes only the returned result. It does not change the stored dataset inside the engine.
|
|
280
|
-
|
|
281
|
-
There are two ways to work with `exclude`:
|
|
282
|
-
|
|
283
|
-
- Result-only exclude: returns a filtered array and leaves the stored dataset unchanged.
|
|
284
|
-
- Mutable exclude with `mutableExcludeField`: removes items from the stored dataset with **swap-pop**.
|
|
285
|
-
|
|
286
|
-
**Swap-pop** is an efficient array removal technique where the element to be removed is swapped with the last element in the array, and then the array length is decreased by one. This provides O(1) time complexity for removal but does not preserve the original order of elements.
|
|
287
|
-
|
|
288
|
-
#### Result-only exclude
|
|
289
|
-
|
|
290
|
-
If the engine already stores the full dataset, `exclude` alone is enough. For example,
|
|
291
|
-
`engine.filter([{ field: "id", exclude: [1, 4] }])` returns all stored users except users with `id` `1` and `4`.
|
|
292
|
-
|
|
293
|
-
This mode does not use swap-pop on the stored dataset. `filter(...)` returns a new array,
|
|
294
|
-
so the engine still needs one pass over the current data to build the result.
|
|
295
|
-
If `id` is indexed, the engine does not scan the full dataset again for each excluded `id`,
|
|
296
|
-
but it still has to build the final array.
|
|
297
|
-
|
|
298
|
-
If you need repeated removals from a large collection and do not want O(n) work for each removed item,
|
|
299
|
-
use mutable exclude mode.
|
|
300
|
-
In this mode the engine removes items from the stored dataset with swap-pop.
|
|
301
|
-
Order is not preserved.
|
|
302
|
-
|
|
303
|
-
If the field is listed in `fields`, the engine uses indexes for exclude values
|
|
304
|
-
instead of scanning the full dataset again for every removed value.
|
|
305
|
-
|
|
306
|
-
```ts
|
|
307
|
-
import { FilterEngine } from "@devisfuture/mega-collection/filter";
|
|
308
|
-
|
|
309
|
-
const engine = new FilterEngine<User>({
|
|
310
|
-
data: users,
|
|
311
|
-
fields: ["id", "city"],
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
// Returns all users except users with ids 1 and 3.
|
|
315
|
-
const visibleUsers = engine.filter([{ field: "id", exclude: [1, 3] }]);
|
|
316
|
-
|
|
317
|
-
// You can combine normal filtering and exclude.
|
|
318
|
-
engine.filter([
|
|
319
|
-
{ field: "city", values: ["Miami", "New York"] },
|
|
320
|
-
{ field: "id", exclude: [1, 3] },
|
|
321
|
-
]);
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
#### Mutable exclude with `mutableExcludeField`
|
|
325
|
-
|
|
326
|
-
If you need repeated fast removals from a large stored dataset, use `mutableExcludeField`.
|
|
327
|
-
In this mode the engine removes items from the stored dataset with swap-pop.
|
|
328
|
-
|
|
329
|
-
Use this mode when all of these points are true:
|
|
330
|
-
|
|
331
|
-
- the engine already stores the full dataset
|
|
332
|
-
- the exclude field is unique, for example `id`
|
|
333
|
-
- order does not need to be preserved
|
|
334
|
-
- you want repeated removals without O(n) per removed id
|
|
335
|
-
|
|
336
|
-
This mode changes the stored dataset.
|
|
337
|
-
After exclusion, `getOriginData()` returns the reduced collection.
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
import { FilterEngine } from "@devisfuture/mega-collection/filter";
|
|
341
|
-
|
|
342
|
-
const mutableEngine = new FilterEngine<User>({
|
|
343
|
-
data: users,
|
|
344
|
-
fields: ["id", "city"],
|
|
345
|
-
mutableExcludeField: "id",
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Removes items from the stored dataset with swap-pop.
|
|
349
|
-
mutableEngine.filter([{ field: "id", exclude: [1, 4] }]);
|
|
350
|
-
|
|
351
|
-
// The stored dataset is now smaller.
|
|
352
|
-
mutableEngine.getOriginData();
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
The same mode also works through `MergeEngines`:
|
|
356
|
-
|
|
357
|
-
```ts
|
|
358
|
-
import { MergeEngines } from "@devisfuture/mega-collection";
|
|
359
|
-
import { FilterEngine } from "@devisfuture/mega-collection/filter";
|
|
360
|
-
|
|
361
|
-
const mutableMerge = new MergeEngines<User>({
|
|
362
|
-
imports: [FilterEngine],
|
|
363
|
-
data: users,
|
|
364
|
-
filter: {
|
|
365
|
-
fields: ["id", "city"],
|
|
366
|
-
mutableExcludeField: "id",
|
|
367
|
-
},
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
mutableMerge.filter([{ field: "id", exclude: [1, 4] }]);
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
#### Nested collections filter
|
|
374
|
-
|
|
375
|
-
```ts
|
|
376
|
-
import { FilterEngine } from "@devisfuture/mega-collection/filter";
|
|
377
|
-
|
|
378
|
-
// Filter inside nested arrays. `nestedFields` uses dot notation.
|
|
379
|
-
const nestedFilter = new FilterEngine<UserWithOrders>({
|
|
380
|
-
data: usersWithOrders,
|
|
381
|
-
fields: ["city", "age"],
|
|
382
|
-
nestedFields: ["orders.status"],
|
|
383
|
-
filterByPreviousResult: true,
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
nestedFilter.filter([{ field: "orders.status", values: ["pending"] }]);
|
|
387
|
-
nestedFilter.filter([
|
|
388
|
-
{ field: "orders.status", values: ["pending"] },
|
|
389
|
-
{ field: "city", values: ["New-York"] },
|
|
390
|
-
]);
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
### Sort only
|
|
394
|
-
|
|
395
|
-
Use `SortEngine` when you only need sorting.
|
|
396
|
-
|
|
397
|
-
```ts
|
|
398
|
-
import { SortEngine } from "@devisfuture/mega-collection/sort";
|
|
399
|
-
|
|
400
|
-
// `fields` tells the engine which fields should use cached single-field
|
|
401
|
-
// sorting. The cache is built lazily on first use. If you skip `fields`,
|
|
402
|
-
// sorting still works.
|
|
403
|
-
const engine = new SortEngine<User>({
|
|
404
|
-
data: users,
|
|
405
|
-
fields: ["age", "name", "city"],
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
// Single-field sort
|
|
409
|
-
engine.sort([{ field: "age", direction: "asc" }]);
|
|
410
|
-
|
|
411
|
-
// replace dataset without re-initializing
|
|
412
|
-
engine.data(users);
|
|
413
|
-
|
|
414
|
-
// access original dataset stored in the engine
|
|
415
|
-
engine.getOriginData();
|
|
416
|
-
|
|
417
|
-
// service methods stay on the engine instance
|
|
418
|
-
engine.clearIndexes();
|
|
419
|
-
engine.clearData();
|
|
420
|
-
|
|
421
|
-
// Multi-field sort
|
|
422
|
-
engine.sort([
|
|
423
|
-
{ field: "age", direction: "asc" },
|
|
424
|
-
{ field: "name", direction: "desc" },
|
|
425
|
-
]);
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
---
|
|
429
|
-
|
|
430
|
-
## API Reference
|
|
431
|
-
|
|
432
|
-
### `MergeEngines<T>` (root module)
|
|
433
|
-
|
|
434
|
-
One class that combines search, filter, and sort for the same dataset.
|
|
435
|
-
|
|
436
|
-
**Constructor options:**
|
|
437
|
-
|
|
438
|
-
| Option | Type | Description |
|
|
439
|
-
| --------- | -------------------------------------------------------------------------- | -------------------------------------------- |
|
|
440
|
-
| `imports` | `(typeof TextSearchEngine \| SortEngine \| FilterEngine)[]` | Engine classes to create |
|
|
441
|
-
| `data` | `T[]` | Shared dataset — passed once at construction |
|
|
442
|
-
| `search` | `{ fields, nestedFields?, minQueryLength? }` | Config for TextSearchEngine |
|
|
443
|
-
| `filter` | `{ fields, nestedFields?, filterByPreviousResult?, mutableExcludeField? }` | Config for FilterEngine |
|
|
444
|
-
| `sort` | `{ fields }` | Config for SortEngine |
|
|
445
|
-
|
|
446
|
-
**Methods:**
|
|
447
|
-
|
|
448
|
-
| Method | Description |
|
|
449
|
-
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
450
|
-
| `search(query)` | Search all indexed fields |
|
|
451
|
-
| `search(field, query)` | Search a specific field |
|
|
452
|
-
| `sort(descriptors)` | Sort using stored dataset |
|
|
453
|
-
| `sort(data, descriptors, inPlace?)` | Sort with an explicit dataset |
|
|
454
|
-
| `filter(criteria)` | Filter using stored dataset |
|
|
455
|
-
| `filter(data, criteria)` | Filter with an explicit dataset |
|
|
456
|
-
| `getOriginData()` | Get the shared original dataset |
|
|
457
|
-
| `data(data)` | Replace stored dataset for all imported modules, rebuilding configured indexes and resetting filter state where applicable |
|
|
458
|
-
| `clearIndexes(module)` | Clear indexes for one module (`"search"`, `"sort"`, `"filter"`) |
|
|
459
|
-
| `clearData(module)` | Clear stored data for one module (`"search"`, `"sort"`, `"filter"`) |
|
|
460
|
-
|
|
461
|
-
If `filter.mutableExcludeField` is configured, `filter([{ field, exclude }])` on that field removes items from the stored filter dataset with swap-pop.
|
|
462
|
-
This changes the stored filter dataset and does not preserve order.
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
|
|
466
|
-
### `TextSearchEngine<T>` (search module)
|
|
467
|
-
|
|
468
|
-
Text search engine.
|
|
469
|
-
It supports `nestedFields` if you need to search inside nested collections such as `["orders.status"]`.
|
|
470
|
-
Search methods return plain arrays.
|
|
471
|
-
|
|
472
|
-
| Method | Description |
|
|
473
|
-
| ---------------------- | ---------------------------------------------------------- |
|
|
474
|
-
| `search(query)` | Search all indexed fields (including nested), deduplicated |
|
|
475
|
-
| `search(field, query)` | Search a specific indexed field or nested field path |
|
|
476
|
-
| `getOriginData()` | Get the original stored dataset |
|
|
477
|
-
| `data(data)` | Replace stored dataset and rebuild configured indexes |
|
|
478
|
-
| `clearIndexes()` | Clear n-gram indexes (including nested) |
|
|
479
|
-
| `clearData()` | Clear stored data |
|
|
480
|
-
|
|
481
|
-
### `FilterEngine<T>` (filter module)
|
|
482
|
-
|
|
483
|
-
Filter engine for one or more rules.
|
|
484
|
-
It supports `nestedFields` if you need to filter by values inside nested collections such as `["orders.status"]`.
|
|
485
|
-
Each criterion can use `values`, `exclude`, or both in the same rule.
|
|
486
|
-
|
|
487
|
-
Main constructor options:
|
|
488
|
-
|
|
489
|
-
| Option | Type | Description |
|
|
490
|
-
| ------------------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
491
|
-
| `filterByPreviousResult` | `boolean` | When `true`, the next `filter(criteria)` call works on the previous result. By default each call starts from the original dataset. |
|
|
492
|
-
| `mutableExcludeField` | `string` | Optional field for removing items from stored data with swap-pop. This changes the stored dataset and does not preserve order. |
|
|
493
|
-
| `nestedFields` | `string[]` | Nested field paths in dot notation, for example `["orders.status"]`. |
|
|
494
|
-
|
|
495
|
-
| Method | Description |
|
|
496
|
-
| ------------------------ | -------------------------------------------------------------------------- |
|
|
497
|
-
| `filter(criteria)` | Filter using stored dataset (supports nested field criteria) |
|
|
498
|
-
| `filter(data, criteria)` | Filter with an explicit dataset |
|
|
499
|
-
| `getOriginData()` | Get the original stored dataset |
|
|
500
|
-
| `data(data)` | Replace stored dataset, rebuild configured indexes, and reset filter state |
|
|
501
|
-
| `resetFilterState()` | Reset previous-result state for sequential filtering |
|
|
502
|
-
| `clearIndexes()` | Free all index memory (including nested indexes) |
|
|
503
|
-
| `clearData()` | Clear stored data |
|
|
504
|
-
|
|
505
|
-
### `SortEngine<T>` (sort module)
|
|
506
|
-
|
|
507
|
-
Sort engine with prepared indexes for faster sorting in common cases.
|
|
508
|
-
Sort methods return plain arrays.
|
|
509
|
-
|
|
510
|
-
| Method | Description |
|
|
511
|
-
| ----------------------------------- | ----------------------------------------------------- |
|
|
512
|
-
| `sort(descriptors)` | Sort using stored dataset |
|
|
513
|
-
| `sort(data, descriptors, inPlace?)` | Sort with an explicit dataset |
|
|
514
|
-
| `getOriginData()` | Get the original stored dataset |
|
|
515
|
-
| `data(data)` | Replace stored dataset and rebuild configured indexes |
|
|
516
|
-
| `clearIndexes()` | Free all cached indexes |
|
|
517
|
-
| `clearData()` | Clear stored data |
|
|
518
|
-
|
|
519
|
-
---
|
|
520
|
-
|
|
521
|
-
**Note on `data` method:** Calling `data` updates the stored dataset. It also rebuilds configured indexes and resets internal state when needed, so usually you do not need to call `clearIndexes` before it.
|
|
522
|
-
|
|
523
|
-
## Types
|
|
524
|
-
|
|
525
|
-
All types are exported from the root package and from each sub-module:
|
|
526
|
-
|
|
527
|
-
```ts
|
|
528
|
-
import type {
|
|
529
|
-
CollectionItem,
|
|
530
|
-
IndexableKey,
|
|
531
|
-
FilterCriterion,
|
|
532
|
-
SortDescriptor,
|
|
533
|
-
SortDirection,
|
|
534
|
-
MergeEnginesOptions,
|
|
535
|
-
} from "@devisfuture/mega-collection";
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
You can also import them from individual sub-modules:
|
|
539
|
-
|
|
540
|
-
```ts
|
|
541
|
-
import type {
|
|
542
|
-
CollectionItem,
|
|
543
|
-
IndexableKey,
|
|
544
|
-
} from "@devisfuture/mega-collection/search";
|
|
545
|
-
import type { FilterCriterion } from "@devisfuture/mega-collection/filter";
|
|
546
|
-
import type {
|
|
547
|
-
SortDescriptor,
|
|
548
|
-
SortDirection,
|
|
549
|
-
} from "@devisfuture/mega-collection/sort";
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
---
|
|
553
|
-
|
|
554
|
-
## Build
|
|
555
|
-
|
|
556
|
-
```bash
|
|
557
|
-
npm install
|
|
558
|
-
npm run build # Build ESM + declarations
|
|
559
|
-
npm run typecheck # Type-check without emitting
|
|
560
|
-
npm run dev # Watch mode
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
## Contributing
|
|
564
|
-
|
|
565
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
566
|
-
|
|
567
|
-
## Security
|
|
568
|
-
|
|
569
|
-
See [SECURITY.md](SECURITY.md) for our security policy.
|
|
570
|
-
|
|
571
|
-
## License
|
|
572
|
-
|
|
573
|
-
MIT — see [LICENSE](LICENSE) for details.
|
|
5
|
+
Imports: @devisfuture/mega-collection, /search, /filter, /sort, /merge
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {a}from'./chunk-Y7NSBYLS.mjs';import {a as a$2}from'./chunk-U3IU4NI6.mjs';import {a as a$1}from'./chunk-Z4QO4GOM.mjs';function c(o){return {value:o,enumerable:false,configurable:true,writable:true}}var p=class{constructor(e){this.callbacks=e;}create(e){let a=e;return Object.defineProperties(a,{search:c((t,r)=>r===void 0?this.callbacks.search(t):this.callbacks.search(t,r)),sort:c((t,r,i)=>r===void 0?this.callbacks.sort(e,t,i):this.callbacks.sort(t,r,i)),filter:c((t,r)=>r===void 0?this.callbacks.filter(e,t):this.callbacks.filter(t,r)),add:c(t=>this.callbacks.add(t)),clearIndexes:c(t=>(this.callbacks.clearIndexes(t),this.create(e))),clearData:c(t=>(this.callbacks.clearData(t),this.create(e))),data:c(t=>this.callbacks.data(t)),getOriginData:c(()=>this.callbacks.getOriginData())}),a}};var v=o=>o===a?"search":o===a$1?"sort":o===a$2?"filter":null,w=(o,e,a$3)=>{if(o===a){let t=new a({data:e,...a$3});return {moduleName:"search",executeSearch:(r,i)=>i===void 0?t.search(r):t.search(r,i),add:(r,i=true)=>t.applyAddedItems(r,i),clearIndexes:()=>t.clearIndexes(),clearData:()=>t.clearData(),data:r=>t.data(r),getOriginData:()=>t.getOriginData()}}if(o===a$1){let t=new a$1({data:e,...a$3});return {moduleName:"sort",executeSort:(r,i,s)=>i===void 0?t.sort(r):t.sort(r,i,s),add:(r,i=true)=>t.applyAddedItems(r,i),clearIndexes:()=>t.clearIndexes(),clearData:()=>t.clearData(),data:r=>t.data(r),getOriginData:()=>t.getOriginData()}}if(o===a$2){let t=new a$2({data:e,...a$3});return {moduleName:"filter",executeFilter:(r,i)=>i===void 0?t.rawFilter(r):t.rawFilter(r,i),add:(r,i=true)=>t.applyAddedItems(r,i),clearIndexes:()=>t.clearIndexes(),clearData:()=>t.clearData(),data:r=>t.data(r),getOriginData:()=>t.getOriginData()}}return null};var b={search:"TextSearchEngine",sort:"SortEngine",filter:"FilterEngine"},l=class o extends Error{constructor(e){super(e),this.name="MergeEnginesError";}static unavailableMethod(e){return new o(`MergeEngines: Method "${e}" is not available.`)}static unavailableEngine(e){let a=b[e];return new o(`MergeEngines: ${a} is not available.`)}static unavailableGetOriginData(){return new o("MergeEngines: getOriginData is not available.")}};var f=class{constructor(e){this.previousSearchState=null;this.previousSortState=null;this.chainBuilder=new p({search:(e,a)=>a===void 0?this.search(e):this.search(e,a),sort:(e,a,t)=>a===void 0?this.sort(e):this.sort(e,a,t),filter:(e,a)=>a===void 0?this.filter(e):this.filter(e,a),getOriginData:()=>this.getOriginData(),add:e=>this.add(e),data:e=>this.data(e),clearIndexes:e=>this.clearIndexes(e),clearData:e=>this.clearData(e)});let{imports:a,data:t,...r}=e,i=new Set(a),s=null,d=null,u=null,S={},D={},C={},E={},x={},y=null;for(let T of i){let N=v(T);if(!N)continue;let k=this.getModuleInitOptions(N,T.name,r),n=w(T,t,k);n&&(n.moduleName==="search"&&!s&&(s=n),n.moduleName==="sort"&&!d&&(d=n),n.moduleName==="filter"&&!u&&(u=n),S[n.moduleName]=()=>n.clearIndexes(),D[n.moduleName]=()=>n.clearData(),C[n.moduleName]=(m,O)=>n.add(m,O),E[n.moduleName]=()=>n.getOriginData(),x[n.moduleName]=m=>n.data(m),y??(y=()=>n.getOriginData()));}this.searchModule=s,this.sortModule=d,this.filterModule=u,this.clearIndexMethods=S,this.clearDataMethods=D,this.addMethods=C,this.getOriginDataMethods=E,this.setDataMethods=x,this.getOriginDataMethod=y;}getModuleInitOptions(e,a,t){let r={};for(let i of [e,a]){let s=t[i];this.isRecord(s)&&Object.assign(r,s);}return r}isRecord(e){return typeof e=="object"&&e!==null}clearOperationState(e){(!e||e==="search")&&(this.previousSearchState=null),(!e||e==="sort")&&(this.previousSortState=null);}createSearchCacheKey(e,a){return JSON.stringify([e,a??null])}createSortCacheKey(e,a){return JSON.stringify({descriptors:e,inPlace:a??false})}search(e,a){if(!this.searchModule)throw l.unavailableEngine("search");let t=this.searchModule.getOriginData(),r=this.createSearchCacheKey(e,a);if(this.previousSearchState?.originData===t&&this.previousSearchState.key===r)return this.withChain(this.previousSearchState.result);let i;return a===void 0?i=this.searchModule.executeSearch(e):i=this.searchModule.executeSearch(e,a),this.previousSearchState={key:r,originData:t,result:i},this.withChain(i)}sort(e,a,t){if(!this.sortModule)throw l.unavailableEngine("sort");if(a===void 0)return this.withChain(this.sortModule.executeSort(e));let r=e;if(!t){let i=this.createSortCacheKey(a,t);if(this.previousSortState?.sourceData===r&&this.previousSortState.key===i)return this.withChain(this.previousSortState.result);let s=this.sortModule.executeSort(r,a,t);return this.previousSortState={key:i,sourceData:r,result:s},this.withChain(s)}return this.withChain(this.sortModule.executeSort(r,a,t))}filter(e,a){if(!this.filterModule)throw l.unavailableEngine("filter");return a===void 0?this.withChain(this.filterModule.executeFilter(e)):this.withChain(this.filterModule.executeFilter(e,a))}withChain(e){return this.chainBuilder.create(e)}getOriginData(){if(this.getOriginDataMethod)return this.getOriginDataMethod();throw l.unavailableGetOriginData()}add(e){if(e.length===0)return this;let a=["search","sort","filter"],t=new Set;this.clearOperationState();for(let r of a){let i=this.addMethods[r],s=this.getOriginDataMethods[r];if(!i)continue;let d=s?.(),u=d===void 0||!t.has(d);i(e,u),d!==void 0&&t.add(d);}return this}clearIndexes(e){let a=this.clearIndexMethods[e];if(a)return a(),this.clearOperationState(e),this;throw l.unavailableEngine(e)}data(e){let a=["search","sort","filter"];this.clearOperationState();for(let t of a){let r=this.setDataMethods[t];r&&r(e);}return this}clearData(e){let a=this.clearDataMethods[e];if(a)return a(),this.clearOperationState(e),this;throw l.unavailableEngine(e)}};export{f as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var I=class{constructor(){this.indexes=new Map;this.itemPositions=new Map;}addItems(e){if(!(e.length===0||this.indexes.size===0))for(let t=0;t<e.length;t++)this.addItem(e[t]);}buildIndex(e,t){let n=new Map,i=new Map;for(let s=0,r=e.length;s<r;s++){let l=e[s],a=l[t];if(a==null)continue;let u=n.get(a);if(u)u.push(l),i.get(a).set(l,u.length-1);else {n.set(a,[l]);let o=new WeakMap;o.set(l,0),i.set(a,o);}}this.indexes.set(t,n),this.itemPositions.set(t,i);}getByValue(e,t){let n=this.indexes.get(e);return n?n.get(t)??[]:[]}getByValues(e,t){let n=this.indexes.get(e);if(!n)return [];if(t.length===1)return n.get(t[0])??[];let i=new Set,s=[];for(let r=0;r<t.length;r++){let l=n.get(t[r]);if(l!==void 0)for(let a=0;a<l.length;a++){let u=l[a];i.has(u)||(i.add(u),s.push(u));}}return s}hasIndex(e){return this.indexes.has(e)}addItem(e){for(let t of this.indexes.keys())this.addItemToField(t,e);}removeItem(e){for(let t of this.indexes.keys())this.removeItemFromField(t,e);}clear(){this.indexes.clear(),this.itemPositions.clear();}getIndexMap(e){return this.indexes.get(e)}removeItemFromField(e,t){let n=t[e];if(n==null)return;let i=this.indexes.get(e),s=this.itemPositions.get(e),r=i?.get(n),l=s?.get(n),a=l?.get(t);if(!i||!s||!r||!l||a===void 0)return;let u=r.length-1,o=r[u];a!==u&&(r[a]=o,l.set(o,a)),r.pop(),l.delete(t),r.length===0&&(i.delete(n),s.delete(n));}addItemToField(e,t){let n=t[e];if(n==null)return;let i=this.indexes.get(e),s=this.itemPositions.get(e);if(!i||!s)return;let r=i.get(n),l=s.get(n);if(r&&l){r.push(t),l.set(t,r.length-1);return}i.set(n,[t]);let a=new WeakMap;a.set(t,0),s.set(n,a);}};function g(x){return {value:x,enumerable:false,configurable:true,writable:true}}var y=class{constructor(e){this.callbacks=e;}create(e){let t=e;return Object.defineProperties(t,{filter:g((n,i)=>i===void 0?this.callbacks.filter(e,n):this.callbacks.filter(n,i)),add:g(n=>this.callbacks.add(n)),clearIndexes:g(()=>this.callbacks.clearIndexes()),data:g(n=>this.callbacks.data(n)),getOriginData:g(()=>this.callbacks.getOriginData()),clearData:g(()=>this.callbacks.clearData()),resetFilterState:g(()=>this.callbacks.resetFilterState())}),t}};var v=class x extends Error{constructor(e){super(e),this.name="FilterEngineError";}static missingDatasetForBuildIndex(){return new x("FilterEngine: no dataset in memory.")}static missingDatasetForFilter(){return new x("FilterEngine: no dataset in memory.")}static duplicateMutableExcludeField(e){return new x(`FilterEngine: cannot use mutable exclude on field \`${e}\` because it contains duplicate values.`)}};function m(x){let e=[];for(let t=0;t<x.length;t++){let n=x[t],i=Array.isArray(n.values),s=E(n.exclude),r=s!==null,l=i?R(n.values,s):null;!i&&!r||e.push({field:n.field,values:l?[...l]:[],exclude:s?[...s]:[],hasValues:i,hasExclude:r,includedValues:l,excludedValues:s});}return e}function C(x,e){return !(x.hasValues&&!x.includedValues.has(e)||x.hasExclude&&x.excludedValues.has(e))}function b(x){return x.hasValues&&x.values.length===0}function E(x){return !Array.isArray(x)||x.length===0?null:new Set(x)}function R(x,e){let t=new Set;for(let n=0;n<x.length;n++){let i=x[n];e?.has(i)||t.add(i);}return t}var F=class{constructor(){this.registeredFields=new Set;this.fieldDescriptors=new Map;this.indexes=new Map;this.itemPositions=new Map;}registerFields(e){if(e?.length)for(let t=0;t<e.length;t++)this.registerField(e[t]);}hasRegisteredFields(){return this.registeredFields.size>0}hasField(e){return this.registeredFields.has(e)}clearIndexes(){this.indexes.clear(),this.itemPositions.clear();}buildIndexes(e){this.indexes.clear(),this.itemPositions.clear();for(let t of this.registeredFields)this.buildIndex(e,t);}addItems(e){if(!(e.length===0||this.indexes.size===0))for(let t=0;t<e.length;t++)this.addItem(e[t]);}removeItem(e){for(let t of this.indexes.keys())this.removeItemFromIndex(t,e);}filter(e,t,n){let i=this.resolveCriteria(t);if(e.length===0||i.length===0)return e;let s=[],r=[];for(let a=0;a<i.length;a++){let u=i[a];if(this.indexes.has(u.field)){s.push(u);continue}r.push(u);}let l=e;if(s.length>0&&(l=this.filterByIndexes(s,e,n),l.length===0))return l;for(let a=0;a<r.length;a++)if(l=this.filterLinearly(l,r[a]),l.length===0)return l;return l}resolveCriteria(e){if(e.length===0)return [];let t=e[0];return "hasValues"in t&&"hasExclude"in t&&"includedValues"in t?e:m(e)}registerField(e){let t=this.createDescriptor(e);t&&(this.registeredFields.add(e),this.fieldDescriptors.set(e,t));}createDescriptor(e){let t=e.indexOf(".");return t===-1?null:{collectionKey:e.substring(0,t),nestedKey:e.substring(t+1)}}buildIndex(e,t){let n=this.fieldDescriptors.get(t);if(!n)return;let{collectionKey:i,nestedKey:s}=n,r=new Map,l=new Map;for(let a=0,u=e.length;a<u;a++){let o=e[a],h=o[i];if(Array.isArray(h))for(let d=0;d<h.length;d++){let c=h[d][s];if(c==null)continue;let f=r.get(c);if(f){f[f.length-1]!==o&&(f.push(o),l.get(c).set(o,f.length-1));continue}r.set(c,[o]);let p=new WeakMap;p.set(o,0),l.set(c,p);}}this.indexes.set(t,r),this.itemPositions.set(t,l);}removeItemFromIndex(e,t){let n=this.fieldDescriptors.get(e),i=this.indexes.get(e),s=this.itemPositions.get(e);if(!n||!i||!s)return;let{collectionKey:r,nestedKey:l}=n,a=t[r];if(!Array.isArray(a)||a.length===0)return;let u=new Set;for(let o=0;o<a.length;o++){let h=a[o][l];h!=null&&u.add(h);}for(let o of u){let h=i.get(o),d=s.get(o),c=d?.get(t);if(!h||!d||c===void 0)continue;let f=h.length-1,p=h[f];c!==f&&(h[c]=p,d.set(p,c)),h.pop(),d.delete(t),h.length===0&&(i.delete(o),s.delete(o));}}addItem(e){for(let t of this.indexes.keys())this.addItemToIndex(t,e);}addItemToIndex(e,t){let n=this.fieldDescriptors.get(e),i=this.indexes.get(e),s=this.itemPositions.get(e);if(!n||!i||!s)return;let{collectionKey:r,nestedKey:l}=n,a=t[r];if(!Array.isArray(a)||a.length===0)return;let u=new Set;for(let o=0;o<a.length;o++){let h=a[o][l];h!=null&&u.add(h);}for(let o of u){let h=i.get(o),d=s.get(o);if(h&&d){h.push(t),d.set(t,h.length-1);continue}i.set(o,[t]);let c=new WeakMap;c.set(t,0),s.set(o,c);}}filterByIndexes(e,t,n){let i=e.filter(o=>o.hasValues),s=e.filter(o=>o.hasExclude),r=t===n?null:new Set(t);if(i.length===0)return this.applyIndexedExclusions(t,s);if(i.length===1){let o=this.indexes.get(i[0].field);if(!o)return [];let h=this.getItemsByValues(o,i[0].values);if(h.length===0)return [];let d=[];for(let c=0;c<h.length;c++){let f=h[c];r&&!r.has(f)||d.push(f);}return this.applyIndexedExclusions(d,s)}let l=i.map(o=>({criterion:o,size:this.estimateIndexSize(o)})).sort((o,h)=>o.size-h.size),a=r,u=[];for(let o=0;o<l.length;o++){let{criterion:h}=l[o],d=this.indexes.get(h.field);if(!d)return [];let c=this.getItemsByValues(d,h.values);if(c.length===0)return [];if(a===null)u=c;else {u=[];for(let f=0;f<c.length;f++){let p=c[f];a.has(p)&&u.push(p);}}if(u.length===0)return [];a=new Set(u);}return this.applyIndexedExclusions(u,s)}getItemsByValues(e,t){if(t.length===1)return e.get(t[0])??[];let n=new Set,i=[];for(let s=0;s<t.length;s++){let r=e.get(t[s]);if(r)for(let l=0;l<r.length;l++){let a=r[l];n.has(a)||(n.add(a),i.push(a));}}return i}estimateIndexSize(e){let t=this.indexes.get(e.field);return t?e.values.reduce((n,i)=>{let s=t.get(i);return s?n+s.length:n},0):1/0}filterLinearly(e,t){let n=this.fieldDescriptors.get(t.field);if(!n)return e;let{collectionKey:i,nestedKey:s}=n,r=[];for(let l=0;l<e.length;l++){let a=e[l],u=a[i];if(!Array.isArray(u))continue;let o=!t.hasValues,h=false;for(let d=0;d<u.length;d++){let c=u[d][s];if(t.hasExclude&&t.excludedValues.has(c)){h=true;break}t.hasValues&&t.includedValues.has(c)&&(o=true);}!h&&o&&r.push(a);}return r}applyIndexedExclusions(e,t){if(t.length===0||e.length===0)return e;let n=new Set;for(let s=0;s<t.length;s++){let r=t[s],l=this.indexes.get(r.field);if(!l)continue;let a=this.getItemsByValues(l,r.exclude);for(let u=0;u<a.length;u++)n.add(a[u]);}if(n.size===0)return e;let i=[];for(let s=0;s<e.length;s++){let r=e[s];n.has(r)||i.push(r);}return i}};var V=class{constructor(e={}){this.dataset=[];this.datasetPositions=new Map;this.hasDuplicateMutableExcludeValues=false;this.indexedFields=new Set;this.nestedCollection=new F;this.previousResult=null;this.previousCriteria=null;this.previousBaseData=null;this.previousResultsByCriteria=new Map;this.chainBuilder=new y({filter:(e,t)=>t===void 0?this.filter(e):this.filter(e,t),getOriginData:()=>this.getOriginData(),add:e=>this.add(e),data:e=>this.data(e),clearIndexes:()=>this.clearIndexes(),clearData:()=>this.clearData(),resetFilterState:()=>this.resetFilterState()});if(this.indexer=new I,this.filterByPreviousResult=e.filterByPreviousResult??false,this.mutableExcludeField=e.mutableExcludeField??null,this.nestedCollection.registerFields(e.nestedFields),!e.data)return;this.dataset=e.data,this.rebuildMutableExcludeState();let t=e.fields?.length,n=this.nestedCollection.hasRegisteredFields();if(t)for(let i of e.fields)this.indexedFields.add(i);(t||n)&&this.rebuildConfiguredIndexes();}rebuildConfiguredIndexes(){this.indexer.clear(),this.nestedCollection.clearIndexes();for(let e of this.indexedFields)this.buildIndex(this.dataset,e);this.nestedCollection.hasRegisteredFields()&&this.nestedCollection.buildIndexes(this.dataset);}buildIndex(e,t){if(!Array.isArray(e)){if(!this.dataset.length)throw v.missingDatasetForBuildIndex();return this.indexer.buildIndex(this.dataset,e),this}return this.dataset=e,this.resetFilterState(),this.rebuildMutableExcludeState(),this.indexer.buildIndex(e,t),this}clearIndexes(){return this.indexer.clear(),this.nestedCollection.clearIndexes(),this}resetFilterState(){return this.previousResult=null,this.previousCriteria=null,this.previousBaseData=null,this.previousResultsByCriteria.clear(),this}clearData(){return this.dataset=[],this.datasetPositions.clear(),this.hasDuplicateMutableExcludeValues=false,this.indexer.clear(),this.nestedCollection.clearIndexes(),this.resetFilterState(),this}data(e){return this.dataset=e,this.rebuildMutableExcludeState(),this.resetFilterState(),this.rebuildConfiguredIndexes(),this}add(e){return this.applyAddedItems(e,true)}applyAddedItems(e,t){if(e.length===0)return this;let n=t?this.dataset.length:this.dataset.length-e.length;return t&&this.dataset.push(...e),this.updateMutableExcludeStateForAddedItems(e,n),this.resetFilterState(),this.indexer.addItems(e),this.nestedCollection.addItems(e),this}getOriginData(){return this.dataset}filter(e,t){return t===void 0?this.withChain(this.rawFilter(e)):this.withChain(this.rawFilter(e,t))}rawFilter(e,t){let n=t===void 0,i,s,r;if(n){if(!this.dataset.length)throw v.missingDatasetForFilter();s=m(e);let d=this.applyMutableExclude(s);if(d!==void 0)return d;if(this.filterByPreviousResult&&this.previousResult!==null&&this.previousCriteria!==null&&this.previousBaseData===this.dataset){let c=this.createCriteriaCacheKey(s),f=this.createCriteriaCacheKey(this.previousCriteria),p=this.previousResultsByCriteria.get(c);if(c===f)return this.previousResult;if(p!==void 0)return this.storePreviousResult(p,true,this.dataset,s),p;let T=this.hasCriteriaBacktrack(this.previousCriteria,s)||this.previousResult.length===0&&!this.canApplySequentiallyToEmptyResult(this.previousCriteria,s);i=T?this.dataset:this.previousResult,r=T?s:this.createSequentialExecutionCriteria(this.previousCriteria,s);}else i=this.dataset,r=s;}else if(s=m(t),i=e,this.filterByPreviousResult&&this.previousResult!==null&&this.previousCriteria!==null&&this.previousBaseData===i){let d=this.createCriteriaCacheKey(s),c=this.createCriteriaCacheKey(this.previousCriteria),f=this.previousResultsByCriteria.get(d);if(d===c)return this.previousResult;if(f!==void 0)return this.storePreviousResult(f,false,e,s),f;let p=this.hasCriteriaBacktrack(this.previousCriteria,s)||this.previousResult.length===0&&!this.canApplySequentiallyToEmptyResult(this.previousCriteria,s);i=p?e:this.previousResult,r=p?s:this.createSequentialExecutionCriteria(this.previousCriteria,s);}else r=s;if(s.length===0)return this.filterByPreviousResult&&this.resetFilterState(),n?this.dataset:e;for(let d=0;d<r.length;d++)if(b(r[d]))return this.createEmptyResult(n,e,s);let l=[],a=[];for(let d=0;d<r.length;d++){let c=r[d];this.nestedCollection.hasField(c.field)?l.push(c):a.push(c);}if(l.length>0&&(i=this.nestedCollection.filter(i,l,this.dataset),i.length===0))return this.createEmptyResult(n,e,s);if(a.length===0)return this.storePreviousResult(i,n,e,s),i;let{indexedCriteria:u,linearCriteria:o}=a.reduce((d,c)=>(this.indexer.hasIndex(c.field)?d.indexedCriteria.push(c):d.linearCriteria.push(c),d),{indexedCriteria:[],linearCriteria:[]}),h;if(u.length>0&&o.length===0)return h=this.filterViaIndex(u,i),this.storePreviousResult(h,n,e,s),h;if(u.length>0&&o.length>0){let d=this.filterViaIndex(u,i);return h=this.linearFilter(d,o),this.storePreviousResult(h,n,e,s),h}return h=this.linearFilter(i,a),this.storePreviousResult(h,n,e,s),h}withChain(e){return this.chainBuilder.create(e)}rebuildMutableExcludeState(){if(this.datasetPositions.clear(),this.hasDuplicateMutableExcludeValues=false,this.mutableExcludeField!==null)for(let e=0;e<this.dataset.length;e++){let n=this.dataset[e][this.mutableExcludeField];n!=null&&(this.datasetPositions.has(n)&&(this.hasDuplicateMutableExcludeValues=true),this.datasetPositions.set(n,e));}}updateMutableExcludeStateForAddedItems(e,t){if(this.mutableExcludeField!==null)for(let n=0;n<e.length;n++){let i=e[n][this.mutableExcludeField];i!=null&&(this.datasetPositions.has(i)&&(this.hasDuplicateMutableExcludeValues=true),this.datasetPositions.set(i,t+n));}}applyMutableExclude(e){if(this.mutableExcludeField===null||e.length!==1)return;let t=e[0];if(!(t.field!==this.mutableExcludeField||t.hasValues||!t.hasExclude)){if(this.hasDuplicateMutableExcludeValues)throw v.duplicateMutableExcludeField(this.mutableExcludeField);for(let n=0;n<t.exclude.length;n++)this.removeStoredItem(t.exclude[n]);return this.resetFilterState(),this.dataset}}removeStoredItem(e){let t=this.datasetPositions.get(e);if(t===void 0)return;let n=this.dataset.length-1,i=this.dataset[t],s=this.dataset[n];if(this.indexer.removeItem(i),this.nestedCollection.removeItem(i),t!==n&&(this.dataset[t]=s,this.mutableExcludeField!==null)){let r=s[this.mutableExcludeField];r!=null&&this.datasetPositions.set(r,t);}this.dataset.pop(),this.datasetPositions.delete(e);}linearFilter(e,t){let n=[];for(let i=0;i<e.length;i++){let s=e[i],r=true;for(let l=0;l<t.length;l++){let a=t[l];if(!C(a,s[a.field])){r=false;break}}r&&n.push(s);}return n}filterViaIndex(e,t){let i=t!==this.dataset?new Set(t):null,s=e.filter(d=>d.hasValues),r=e.filter(d=>d.hasExclude);if(s.length===0)return this.applyIndexedExclusions(t,r);if(s.length===1){let d=this.indexer.getByValues(s[0].field,s[0].values),c=[];for(let f=0;f<d.length;f++){let p=d[f];i&&!i.has(p)||C(s[0],p[s[0].field])&&c.push(p);}return this.applyIndexedExclusions(c,r)}let l=s.map(d=>({criterion:d,size:this.estimateIndexSize(d)})).sort((d,c)=>d.size-c.size),{field:a,values:u}=l[0].criterion,o=this.indexer.getByValues(a,u);if(o.length===0)return [];let h=[];for(let d=0;d<o.length;d++){let c=o[d],f=true;if(!(i&&!i.has(c))){for(let p=0;p<l.length;p++){let T=l[p].criterion;if(!C(T,c[T.field])){f=false;break}}f&&h.push(c);}}return this.applyIndexedExclusions(h,r)}estimateIndexSize(e){let t=this.indexer.getIndexMap(e.field);return t?e.values.reduce((n,i)=>{let s=t.get(i);return s?n+s.length:n},0):1/0}applyIndexedExclusions(e,t){if(t.length===0||e.length===0)return e.slice();let n=new Set;for(let s=0;s<t.length;s++){let r=t[s],l=this.indexer.getIndexMap(r.field);if(l)for(let a=0;a<r.exclude.length;a++){let u=l.get(r.exclude[a]);if(u)for(let o=0;o<u.length;o++)n.add(u[o]);}}if(n.size===0)return e.slice();let i=[];for(let s=0;s<e.length;s++){let r=e[s];n.has(r)||i.push(r);}return i}createEmptyResult(e,t,n){let i=[];return this.storePreviousResult(i,e,t,n),i}storePreviousResult(e,t,n,i){this.filterByPreviousResult&&(this.previousResult=e,this.previousCriteria=i,this.previousBaseData=t?this.dataset:n,this.previousResultsByCriteria.set(this.createCriteriaCacheKey(i),e));}createCriteriaCacheKey(e){let t=this.createCriteriaStateMap(e);return JSON.stringify([...t.entries()].sort(([n],[i])=>n.localeCompare(i)).map(([n,i])=>({field:n,hasValues:i.hasValues,hasExclude:i.hasExclude,values:i.values.map(s=>JSON.stringify(s)).sort(),exclude:i.exclude.map(s=>JSON.stringify(s)).sort()})))}createSequentialExecutionCriteria(e,t){let n=new Map;for(let i=0;i<e.length;i++){let s=e[i];n.set(s.field,s);}return t.map(i=>{let s=n.get(i.field);if(!s||!s.hasValues||!i.hasValues||s.hasExclude||i.hasExclude||i.includedValues.size<=s.includedValues.size)return i;for(let l of s.includedValues)if(!i.includedValues.has(l))return i;let r=[];for(let l of i.includedValues)s.includedValues.has(l)||r.push(l);return r.length===0?i:{...i,values:r,includedValues:new Set(r)}})}hasCriteriaBacktrack(e,t){let n=this.createCriteriaStateMap(e),i=this.createCriteriaStateMap(t);for(let[s,r]of n){let l=i.get(s);if(!l||this.isCriterionBacktracked(r,l))return true}return false}canApplySequentiallyToEmptyResult(e,t){let n=this.createCriteriaStateMap(e),i=this.createCriteriaStateMap(t);for(let[s,r]of i){let l=n.get(s);if(l){if(l.hasValues!==r.hasValues&&(l.hasValues||!r.hasValues))return false;if(l.hasValues&&r.hasValues){let a=l.includedValues,u=r.includedValues;if(!this.areSetsEqual(a,u)&&!this.isSubset(a,u))return false}if(l.hasExclude!==r.hasExclude&&(l.hasExclude||!r.hasExclude))return false;if(l.hasExclude&&r.hasExclude){let a=l.excludedValues,u=r.excludedValues;if(!this.areSetsEqual(a,u)&&!this.isSubset(a,u))return false}}}return true}createCriteriaStateMap(e){let t=new Map;for(let n=0;n<e.length;n++){let i=e[n],s=t.get(i.field);if(!s){t.set(i.field,{...i,values:i.values.slice(),exclude:i.exclude.slice(),includedValues:i.includedValues?new Set(i.includedValues):null,excludedValues:i.excludedValues?new Set(i.excludedValues):null});continue}if(i.hasValues)if(!s.hasValues)s.hasValues=true,s.includedValues=new Set(i.includedValues);else for(let r of s.includedValues)i.includedValues.has(r)||s.includedValues.delete(r);if(i.hasExclude)if(!s.hasExclude)s.hasExclude=true,s.excludedValues=new Set(i.excludedValues);else for(let r of i.excludedValues)s.excludedValues.add(r);if(s.hasValues&&s.hasExclude)for(let r of s.excludedValues)s.includedValues.delete(r);s.values=s.includedValues?[...s.includedValues]:[],s.exclude=s.excludedValues?[...s.excludedValues]:[];}return t}isCriterionBacktracked(e,t){if(e.hasValues&&!t.hasValues)return true;if(e.hasValues&&t.hasValues){let n=e.includedValues,i=t.includedValues;if(!this.areSetsEqual(n,i))return this.isSubset(i,n)}if(!e.hasValues&&t.hasValues)return false;if(e.hasExclude&&!t.hasExclude)return true;if(!e.hasExclude&&t.hasExclude)return false;if(e.hasExclude&&t.hasExclude){let n=e.excludedValues,i=t.excludedValues;if(!this.areSetsEqual(n,i))return this.isSubset(i,n)}return false}isSubset(e,t){for(let n of e)if(!t.has(n))return false;return true}areSetsEqual(e,t){if(e===t)return true;if(!e||!t||e.size!==t.size)return false;for(let n of e)if(!t.has(n))return false;return true}};export{V as a};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var I=class g extends Error{constructor(e){super(e),this.name="TextSearchEngineError";}static missingDatasetForBuildIndex(){return new g("TextSearchEngine: no dataset in memory.")}};function L(g){let e=g.toLowerCase(),t=Math.min(3,e.length),s=e.length-t+1,n=new Array(s);for(let i=0;i<s;i++)n[i]=e.substring(i,i+t);return n}function w(g,e){let t=g.get(e);if(t)return t;let s=new Set;return g.set(e,s),s}function x(g){let e=L(g);if(e.length<=12)return new Set(e);let t=new Set,s=e.length-1,n=11;for(let i=0;i<=n;i++){let r=Math.round(i*s/n);t.add(e[r]);}return t}function p(g,e,t){for(let s=0,n=e.length;s<n;s++){let i=n-s,r=Math.min(3,i);for(let o=1;o<=r;o++){let a=e.substring(s,s+o);w(g,a).add(t);}}}var y=class{constructor(){this.registeredFields=new Set;this.fieldDescriptors=new Map;this.ngramIndexes=new Map;this.normalizedFieldValues=new Map;}registerFields(e){if(e?.length)for(let t=0;t<e.length;t++)this.registerField(e[t]);}hasRegisteredFields(){return this.registeredFields.size>0}hasField(e){return this.registeredFields.has(e)}hasIndexes(){return this.ngramIndexes.size>0}clearIndexes(){this.ngramIndexes.clear(),this.normalizedFieldValues.clear();}buildIndexes(e){this.clearIndexes();for(let t of this.registeredFields)this.buildIndex(e,t);}addItems(e,t){if(!(e.length===0||this.ngramIndexes.size===0))for(let s of this.ngramIndexes.keys())this.addItemsToField(s,e,t);}searchAllIndexedFields(e,t,s){let n=new Set,i=[];for(let r of this.registeredFields)for(let o of this.searchIndexedField(e,r,t,s))n.has(o)||(n.add(o),i.push(o));return i}searchIndexedField(e,t,s,n){let i=this.ngramIndexes.get(t);if(!i)return [];let r=[];for(let d of n){let c=i.get(d);if(!c)return [];r.push(c);}r.sort((d,c)=>d.size-c.size);let o=r[0],a=r.length,l=[],h=this.normalizedFieldValues.get(t);for(let d of o){let c=true;for(let m=1;m<a;m++)if(!r[m].has(d)){c=false;break}if(!c)continue;let u=e[d];!u||!h?.[d]?.includes(s)||l.push(u);}return l}searchFieldLinear(e,t,s){let n=this.fieldDescriptors.get(t);if(!n)return [];let{collectionKey:i,nestedKey:r}=n,o=[];for(let a=0;a<e.length;a++){let l=e[a],h=l[i];if(!Array.isArray(h))continue;let d=false;for(let c=0;c<h.length;c++){let u=h[c][r];if(typeof u=="string"&&u.toLowerCase().includes(s)){d=true;break}}d&&o.push(l);}return o}matchesAnyField(e,t){for(let s of this.registeredFields){let n=this.fieldDescriptors.get(s);if(!n)continue;let{collectionKey:i,nestedKey:r}=n,o=e[i];if(Array.isArray(o))for(let a=0;a<o.length;a++){let l=o[a][r];if(typeof l=="string"&&l.toLowerCase().includes(t))return true}}return false}registerField(e){let t=this.createDescriptor(e);t&&(this.registeredFields.add(e),this.fieldDescriptors.set(e,t));}createDescriptor(e){let t=e.indexOf(".");return t===-1?null:{collectionKey:e.substring(0,t),nestedKey:e.substring(t+1)}}buildIndex(e,t){let s=this.fieldDescriptors.get(t);if(!s)return;let{collectionKey:n,nestedKey:i}=s,r=new Map,o=new Array(e.length);for(let a=0,l=e.length;a<l;a++){let d=e[a][n];if(!Array.isArray(d))continue;let c=[];for(let u=0;u<d.length;u++){let f=d[u][i];if(typeof f!="string")continue;let m=f.toLowerCase();c.push(m),p(r,m,a);}c.length!==0&&(o[a]=c.join(`
|
|
2
|
+
`));}this.ngramIndexes.set(t,r),this.normalizedFieldValues.set(t,o);}addItemsToField(e,t,s){let n=this.fieldDescriptors.get(e),i=this.ngramIndexes.get(e);if(!n||!i)return;let r=this.normalizedFieldValues.get(e)??[],{collectionKey:o,nestedKey:a}=n;for(let l=0;l<t.length;l++){let d=t[l][o];if(!Array.isArray(d))continue;let c=[],u=s+l;for(let f=0;f<d.length;f++){let m=d[f][a];if(typeof m!="string")continue;let F=m.toLowerCase();c.push(F),p(i,F,u);}c.length!==0&&(r[u]=c.join(`
|
|
3
|
+
`));}this.normalizedFieldValues.set(e,r);}};var T=class{constructor(e={}){this.ngramIndexes=new Map;this.normalizedFieldValues=new Map;this.dataset=[];this.indexedFields=new Set;this.nestedCollection=new y;if(this.minQueryLength=e.minQueryLength??1,this.nestedCollection.registerFields(e.nestedFields),!e.data)return;this.dataset=e.data;let t=e.fields?.length,s=this.nestedCollection.hasRegisteredFields();if(t)for(let n of e.fields)this.indexedFields.add(n);(t||s)&&this.rebuildConfiguredIndexes();}rebuildConfiguredIndexes(){this.ngramIndexes.clear(),this.normalizedFieldValues.clear(),this.nestedCollection.clearIndexes();for(let e of this.indexedFields)this.buildIndex(this.dataset,e);this.nestedCollection.hasRegisteredFields()&&this.nestedCollection.buildIndexes(this.dataset);}buildIndex(e,t){let s,n;if(Array.isArray(e))s=e,n=t;else {if(!this.dataset.length)throw I.missingDatasetForBuildIndex();s=this.dataset,n=e;}this.dataset=s;let i=new Map,r=new Array(s.length);for(let o=0,a=s.length;o<a;o++){let l=s[o][n];if(typeof l!="string")continue;let h=l.toLowerCase();r[o]=h,p(i,h,o);}return this.ngramIndexes.set(n,i),this.normalizedFieldValues.set(n,r),this}search(e,t){return t===void 0?this.searchAllFields(e):this.searchField(e,t)}normalizeQuery(e){return e.trim().toLowerCase()}searchAllFields(e){let t=this.normalizeQuery(e);if(!t)return this.dataset;if(t.length<this.minQueryLength)return this.dataset;if(!this.ngramIndexes.size&&!this.nestedCollection.hasIndexes())return this.searchAllFieldsLinear(t);let s=x(t);if(!s.size)return [];let n=new Set,i=[];for(let r of this.ngramIndexes.keys())for(let o of this.searchFieldWithPreparedQuery(r,t,s))n.has(o)||(n.add(o),i.push(o));for(let r of this.nestedCollection.searchAllIndexedFields(this.dataset,t,s))n.has(r)||(n.add(r),i.push(r));return i}searchField(e,t){let s=this.normalizeQuery(t);if(!s)return this.dataset;if(s.length<this.minQueryLength)return this.dataset;if(this.nestedCollection.hasField(e)){let i=x(s);return i.size?this.nestedCollection.hasIndexes()?this.nestedCollection.searchIndexedField(this.dataset,e,s,i):this.nestedCollection.searchFieldLinear(this.dataset,e,s):[]}if(!this.ngramIndexes.size)return this.searchFieldLinear(e,s);let n=x(s);return n.size?this.searchFieldWithPreparedQuery(e,s,n):[]}searchFieldWithPreparedQuery(e,t,s){let n=this.ngramIndexes.get(e);if(!n)return [];let i=[];for(let h of s){let d=n.get(h);if(!d)return [];i.push(d);}i.sort((h,d)=>h.size-d.size);let r=i[0],o=i.length,a=[],l=this.normalizedFieldValues.get(e);for(let h of r){let d=true;for(let f=1;f<o;f++)if(!i[f].has(h)){d=false;break}if(!d)continue;let c=this.dataset[h];if(!c)continue;l?.[h]?.includes(t)&&a.push(c);}return a}searchAllFieldsLinear(e){if(!this.dataset.length)return [];let t=[];for(let s=0;s<this.dataset.length;s++){let n=this.dataset[s],i=false;for(let r in n){let o=n[r];if(typeof o=="string"&&o.toLowerCase().includes(e)){i=true;break}}i||(i=this.nestedCollection.matchesAnyField(n,e)),i&&t.push(n);}return t}searchFieldLinear(e,t){if(!this.dataset.length)return [];if(this.nestedCollection.hasField(e))return this.nestedCollection.searchFieldLinear(this.dataset,e,t);let s=[];for(let n=0;n<this.dataset.length;n++){let i=this.dataset[n][e];typeof i=="string"&&i.toLowerCase().includes(t)&&s.push(this.dataset[n]);}return s}clearIndexes(){return this.ngramIndexes.clear(),this.normalizedFieldValues.clear(),this.nestedCollection.clearIndexes(),this}getOriginData(){return this.dataset}data(e){return this.dataset=e,this.rebuildConfiguredIndexes(),this}add(e){return this.applyAddedItems(e,true)}applyAddedItems(e,t){if(e.length===0)return this;let s=t?this.dataset.length:this.dataset.length-e.length;t&&this.dataset.push(...e);for(let n of this.indexedFields)this.addItemsToField(n,e,s);return this.nestedCollection.addItems(e,s),this}clearData(){return this.dataset=[],this.ngramIndexes.clear(),this.normalizedFieldValues.clear(),this.nestedCollection.clearIndexes(),this}addItemsToField(e,t,s){let n=this.ngramIndexes.get(e);if(!n)return;let i=this.normalizedFieldValues.get(e)??[];for(let r=0;r<t.length;r++){let o=t[r][e];if(typeof o!="string")continue;let a=o.toLowerCase(),l=s+r;i[l]=a,p(n,a,l);}this.normalizedFieldValues.set(e,i);}};export{T as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var h=class u extends Error{constructor(r){super(r),this.name="SortEngineError";}static missingDatasetForBuildIndex(){return new u("SortEngine: no dataset in memory.")}static missingDatasetForSort(){return new u("SortEngine: no dataset in memory.")}};var g=class{constructor(r={}){this.cache=new Map;this.dataset=[];this.indexedFields=new Set;this.dirtyIndexedFields=new Set;if(r.data&&(this.dataset=r.data,r.fields?.length)){for(let n of r.fields)this.indexedFields.add(n);this.rebuildConfiguredIndexes();}}rebuildConfiguredIndexes(){this.cache.clear();for(let r of this.indexedFields)this.buildIndex(this.dataset,r);}buildIndex(r,n){let s,e;if(Array.isArray(r))s=r,e=n;else {if(!this.dataset.length)throw h.missingDatasetForBuildIndex();s=this.dataset,e=r;}this.dataset=s;let t=s.length,i=new Uint32Array(t),a=new Array(t);for(let d=0;d<t;d++)i[d]=d,a[d]=s[d][e];if(typeof a[0]=="number"){let d=new Float64Array(t);for(let l=0;l<t;l++)d[l]=a[l];i.sort((l,c)=>d[l]-d[c]);}else i.sort((d,l)=>{let c=a[d],f=a[l];return c<f?-1:c>f?1:0});return this.cache.set(e,{indexes:i,dataRef:s,itemCount:t}),this.dirtyIndexedFields.delete(e),this}clearIndexes(){return this.cache.clear(),this.dirtyIndexedFields.clear(),this}clearData(){return this.dataset=[],this.cache.clear(),this.dirtyIndexedFields.clear(),this}data(r){return this.dataset=r,this.dirtyIndexedFields.clear(),this.rebuildConfiguredIndexes(),this}add(r){return this.applyAddedItems(r,true)}applyAddedItems(r,n){if(r.length===0)return this;let s=n?this.dataset.length:this.dataset.length-r.length;n&&this.dataset.push(...r);for(let e of this.indexedFields){let t=this.cache.get(e);if(t){if(this.dirtyIndexedFields.has(e)||t.dataRef!==this.dataset||t.itemCount!==s){this.dirtyIndexedFields.add(e);continue}this.updateCachedIndexForAddedItems(e,s,r.length);}}return this}getOriginData(){return this.dataset}sort(r,n,s=false){let e,t,i=n===void 0;if(n===void 0){if(!this.dataset.length)throw h.missingDatasetForSort();e=this.dataset,t=r;}else e=r,t=n;if(t.length===0||e.length===0)return e;if(t.length===1){let{field:d,direction:l}=t[0];i&&this.dirtyIndexedFields.has(d)&&this.cache.has(d)&&this.buildIndex(d);let c=this.cache.get(d);if(i&&c?.dataRef===e&&c.itemCount===e.length)return this.reconstructFromIndex(e,c.indexes,l)}let a=s?e:e.slice();if(t.length===1&&e.length>0&&typeof e[0][t[0].field]=="number")return this.radixSortNumeric(a,t[0].field,t[0].direction);let o=this.buildComparator(t);return a.sort(o),a}reconstructFromIndex(r,n,s){let e=r.length,t=new Array(e);if(s==="asc")for(let i=0;i<e;i++)t[i]=r[n[i]];else for(let i=0;i<e;i++)t[i]=r[n[e-1-i]];return t}updateCachedIndexForAddedItems(r,n,s){let e=this.cache.get(r);if(!e)return;let t=this.buildSortedIndexesForRange(r,n,s);this.cache.set(r,{indexes:this.mergeSortedIndexes(r,e.indexes,t),dataRef:this.dataset,itemCount:n+s}),this.dirtyIndexedFields.delete(r);}buildSortedIndexesForRange(r,n,s){let e=new Uint32Array(s);for(let t=0;t<s;t++)e[t]=n+t;return e.sort((t,i)=>this.compareIndexesByField(r,t,i)),e}mergeSortedIndexes(r,n,s){let e=new Uint32Array(n.length+s.length),t=0,i=0,a=0;for(;t<n.length&&i<s.length;){if(this.compareIndexesByField(r,n[t],s[i])<=0){e[a++]=n[t++];continue}e[a++]=s[i++];}for(;t<n.length;)e[a++]=n[t++];for(;i<s.length;)e[a++]=s[i++];return e}compareIndexesByField(r,n,s){let e=this.dataset[n]?.[r],t=this.dataset[s]?.[r];if(typeof e=="number"&&typeof t=="number"){let i=e-t;if(i!==0)return i}else {if(e<t)return -1;if(e>t)return 1}return n-s}buildComparator(r){let n=r.map(({field:t})=>t),s=r.map(({direction:t})=>t==="asc"?1:-1),e=n.length;return (t,i)=>{for(let a=0;a<e;a++){let o=t[n[a]],d=i[n[a]];if(o<d)return -s[a];if(o>d)return s[a]}return 0}}radixSortNumeric(r,n,s){let e=r.length,t=new Float64Array(e);for(let o=0;o<e;o++)t[o]=r[o][n];let i=new Uint32Array(e);for(let o=0;o<e;o++)i[o]=o;i.sort((o,d)=>t[o]-t[d]);let a=new Array(e);if(s==="asc")for(let o=0;o<e;o++)a[o]=r[i[o]];else for(let o=0;o<e;o++)a[e-1-o]=r[i[o]];return a}};export{g as a};
|
package/dist/filter/index.d.mts
CHANGED
|
@@ -5,6 +5,7 @@ interface FilterEngineChain<T extends CollectionItem> {
|
|
|
5
5
|
filter(criteria: FilterCriterion<T>[]): T[] & FilterEngineChain<T>;
|
|
6
6
|
filter(data: T[], criteria: FilterCriterion<T>[]): T[] & FilterEngineChain<T>;
|
|
7
7
|
getOriginData(): T[];
|
|
8
|
+
add(items: T[]): FilterEngine<T>;
|
|
8
9
|
data(data: T[]): FilterEngine<T>;
|
|
9
10
|
clearIndexes(): FilterEngine<T>;
|
|
10
11
|
clearData(): FilterEngine<T>;
|
|
@@ -50,6 +51,8 @@ declare class FilterEngine<T extends CollectionItem> {
|
|
|
50
51
|
resetFilterState(): this;
|
|
51
52
|
clearData(): this;
|
|
52
53
|
data(data: T[]): this;
|
|
54
|
+
add(items: T[]): this;
|
|
55
|
+
private applyAddedItems;
|
|
53
56
|
getOriginData(): T[];
|
|
54
57
|
/**
|
|
55
58
|
* Filters the data based on the given criteria.
|
|
@@ -60,6 +63,7 @@ declare class FilterEngine<T extends CollectionItem> {
|
|
|
60
63
|
rawFilter(data: T[], criteria: FilterCriterion<T>[]): T[];
|
|
61
64
|
private withChain;
|
|
62
65
|
private rebuildMutableExcludeState;
|
|
66
|
+
private updateMutableExcludeStateForAddedItems;
|
|
63
67
|
private applyMutableExclude;
|
|
64
68
|
private removeStoredItem;
|
|
65
69
|
/**
|
package/dist/filter/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{a as FilterEngine}from'../chunk-
|
|
1
|
+
export{a as FilterEngine}from'../chunk-U3IU4NI6.mjs';
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{a as MergeEngines}from'./chunk-
|
|
1
|
+
export{a as MergeEngines}from'./chunk-5FVJLC7Y.mjs';export{a as TextSearchEngine}from'./chunk-Y7NSBYLS.mjs';export{a as FilterEngine}from'./chunk-U3IU4NI6.mjs';export{a as SortEngine}from'./chunk-Z4QO4GOM.mjs';
|
package/dist/merge/index.d.mts
CHANGED
|
@@ -13,6 +13,7 @@ interface MergeEnginesChain<T extends CollectionItem> {
|
|
|
13
13
|
filter(criteria: FilterCriterion<T>[]): T[] & MergeEnginesChain<T>;
|
|
14
14
|
filter(data: T[], criteria: FilterCriterion<T>[]): T[] & MergeEnginesChain<T>;
|
|
15
15
|
getOriginData(): T[];
|
|
16
|
+
add(items: T[]): MergeEngines<T>;
|
|
16
17
|
data(data: T[]): MergeEngines<T>;
|
|
17
18
|
clearIndexes(module: MergeModuleName): T[] & MergeEnginesChain<T>;
|
|
18
19
|
clearData(module: MergeModuleName): T[] & MergeEnginesChain<T>;
|
|
@@ -45,6 +46,8 @@ declare class MergeEngines<T extends CollectionItem> {
|
|
|
45
46
|
private readonly filterModule;
|
|
46
47
|
private readonly clearIndexMethods;
|
|
47
48
|
private readonly clearDataMethods;
|
|
49
|
+
private readonly addMethods;
|
|
50
|
+
private readonly getOriginDataMethods;
|
|
48
51
|
private readonly setDataMethods;
|
|
49
52
|
private readonly getOriginDataMethod;
|
|
50
53
|
private previousSearchState;
|
|
@@ -71,6 +74,7 @@ declare class MergeEngines<T extends CollectionItem> {
|
|
|
71
74
|
filter(data: T[], criteria: FilterCriterion<T>[]): T[] & MergeEnginesChain<T>;
|
|
72
75
|
private withChain;
|
|
73
76
|
getOriginData(): T[];
|
|
77
|
+
add(items: T[]): this;
|
|
74
78
|
clearIndexes(module: MergeModuleName): this;
|
|
75
79
|
data(data: T[]): this;
|
|
76
80
|
clearData(module: MergeModuleName): this;
|
package/dist/merge/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{a as MergeEngines}from'../chunk-
|
|
1
|
+
export{a as MergeEngines}from'../chunk-5FVJLC7Y.mjs';import'../chunk-Y7NSBYLS.mjs';import'../chunk-U3IU4NI6.mjs';import'../chunk-Z4QO4GOM.mjs';
|
package/dist/search/index.d.mts
CHANGED
|
@@ -49,7 +49,10 @@ declare class TextSearchEngine<T extends CollectionItem> {
|
|
|
49
49
|
clearIndexes(): this;
|
|
50
50
|
getOriginData(): T[];
|
|
51
51
|
data(data: T[]): this;
|
|
52
|
+
add(items: T[]): this;
|
|
53
|
+
private applyAddedItems;
|
|
52
54
|
clearData(): this;
|
|
55
|
+
private addItemsToField;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
export { CollectionItem, TextSearchEngine, TextSearchEngineOptions };
|
package/dist/search/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{a as TextSearchEngine}from'../chunk-
|
|
1
|
+
export{a as TextSearchEngine}from'../chunk-Y7NSBYLS.mjs';
|
package/dist/sort/index.d.mts
CHANGED
|
@@ -11,6 +11,7 @@ declare class SortEngine<T extends CollectionItem> {
|
|
|
11
11
|
private cache;
|
|
12
12
|
private dataset;
|
|
13
13
|
private readonly indexedFields;
|
|
14
|
+
private readonly dirtyIndexedFields;
|
|
14
15
|
/**
|
|
15
16
|
* Creates a new SortEngine with optional data and fields to index.
|
|
16
17
|
*/
|
|
@@ -26,6 +27,8 @@ declare class SortEngine<T extends CollectionItem> {
|
|
|
26
27
|
clearIndexes(): this;
|
|
27
28
|
clearData(): this;
|
|
28
29
|
data(data: T[]): this;
|
|
30
|
+
add(items: T[]): this;
|
|
31
|
+
private applyAddedItems;
|
|
29
32
|
getOriginData(): T[];
|
|
30
33
|
/**
|
|
31
34
|
* Sorts the data based on the given descriptors.
|
|
@@ -36,6 +39,10 @@ declare class SortEngine<T extends CollectionItem> {
|
|
|
36
39
|
* Reconstructs the sorted array from the cached index.
|
|
37
40
|
*/
|
|
38
41
|
private reconstructFromIndex;
|
|
42
|
+
private updateCachedIndexForAddedItems;
|
|
43
|
+
private buildSortedIndexesForRange;
|
|
44
|
+
private mergeSortedIndexes;
|
|
45
|
+
private compareIndexesByField;
|
|
39
46
|
/**
|
|
40
47
|
* Builds a comparator function for sorting.
|
|
41
48
|
*/
|
package/dist/sort/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{a as SortEngine}from'../chunk-
|
|
1
|
+
export{a as SortEngine}from'../chunk-Z4QO4GOM.mjs';
|
package/package.json
CHANGED
|
@@ -1,99 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@devisfuture/mega-collection",
|
|
3
|
-
"version": "2.2.0",
|
|
4
|
-
"description": "High-performance search, filter & sort engine for 100K+ item collections in JavaScript/TypeScript",
|
|
5
|
-
"exports": {
|
|
6
|
-
".": {
|
|
7
|
-
"types": "./dist/index.d.mts",
|
|
8
|
-
"default": "./dist/index.mjs"
|
|
9
|
-
},
|
|
10
|
-
"./search": {
|
|
11
|
-
"types": "./dist/search/index.d.mts",
|
|
12
|
-
"default": "./dist/search/index.mjs"
|
|
13
|
-
},
|
|
14
|
-
"./filter": {
|
|
15
|
-
"types": "./dist/filter/index.d.mts",
|
|
16
|
-
"default": "./dist/filter/index.mjs"
|
|
17
|
-
},
|
|
18
|
-
"./sort": {
|
|
19
|
-
"types": "./dist/sort/index.d.mts",
|
|
20
|
-
"default": "./dist/sort/index.mjs"
|
|
21
|
-
},
|
|
22
|
-
"./merge": {
|
|
23
|
-
"types": "./dist/merge/index.d.mts",
|
|
24
|
-
"default": "./dist/merge/index.mjs"
|
|
25
|
-
},
|
|
26
|
-
"./package.json": "./package.json"
|
|
27
|
-
},
|
|
28
|
-
"typesVersions": {
|
|
29
|
-
"*": {
|
|
30
|
-
"search": [
|
|
31
|
-
"./dist/search/index.d.mts"
|
|
32
|
-
],
|
|
33
|
-
"filter": [
|
|
34
|
-
"./dist/filter/index.d.mts"
|
|
35
|
-
],
|
|
36
|
-
"sort": [
|
|
37
|
-
"./dist/sort/index.d.mts"
|
|
38
|
-
],
|
|
39
|
-
"merge": [
|
|
40
|
-
"./dist/merge/index.d.mts"
|
|
41
|
-
]
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
"files": [
|
|
45
|
-
"dist"
|
|
46
|
-
],
|
|
47
|
-
"sideEffects": false,
|
|
48
|
-
"scripts": {
|
|
49
|
-
"build": "tsup",
|
|
50
|
-
"build:watch": "tsup --watch",
|
|
51
|
-
"dev": "tsup --watch",
|
|
52
|
-
"test": "vitest run",
|
|
53
|
-
"test:watch": "vitest",
|
|
54
|
-
"test:coverage": "vitest run --coverage",
|
|
55
|
-
"test:ci": "vitest run --coverage --reporter=verbose --reporter=json",
|
|
56
|
-
"clean": "rm -rf dist",
|
|
57
|
-
"prepublishOnly": "npm run build",
|
|
58
|
-
"typecheck": "tsc --noEmit"
|
|
59
|
-
},
|
|
60
|
-
"keywords": [
|
|
61
|
-
"javascript",
|
|
62
|
-
"search",
|
|
63
|
-
"filter",
|
|
64
|
-
"sort",
|
|
65
|
-
"collection",
|
|
66
|
-
"performance",
|
|
67
|
-
"trigram",
|
|
68
|
-
"inverted-index",
|
|
69
|
-
"hashmap",
|
|
70
|
-
"large-dataset",
|
|
71
|
-
"big-data",
|
|
72
|
-
"typescript",
|
|
73
|
-
"zero-dependencies",
|
|
74
|
-
"tree-shakeable",
|
|
75
|
-
"esm",
|
|
76
|
-
"indexer",
|
|
77
|
-
"50k",
|
|
78
|
-
"100k",
|
|
79
|
-
"text-search",
|
|
80
|
-
"multi-filter",
|
|
81
|
-
"sort-engine",
|
|
82
|
-
"merge-engines",
|
|
83
|
-
"o1-lookup"
|
|
84
|
-
],
|
|
85
|
-
"publishConfig": {
|
|
86
|
-
"access": "public"
|
|
87
|
-
},
|
|
88
|
-
"repository": {
|
|
89
|
-
"type": "git",
|
|
90
|
-
"url": "git+https://github.com/trae-op/mega-collection.git"
|
|
91
|
-
},
|
|
92
|
-
"devDependencies": {
|
|
93
|
-
"@vitest/coverage-v8": "^2.1.9",
|
|
94
|
-
"tsup": "^8.0.0",
|
|
95
|
-
"typescript": "^5.3.0",
|
|
96
|
-
"vitest": "^2.1.8"
|
|
97
|
-
},
|
|
98
|
-
"license": "MIT"
|
|
99
|
-
}
|
|
1
|
+
{"name":"@devisfuture/mega-collection","version":"2.3.1","license":"MIT","sideEffects":false,"types":"./dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./search":{"types":"./dist/search/index.d.mts","default":"./dist/search/index.mjs"},"./filter":{"types":"./dist/filter/index.d.mts","default":"./dist/filter/index.mjs"},"./sort":{"types":"./dist/sort/index.d.mts","default":"./dist/sort/index.mjs"},"./merge":{"types":"./dist/merge/index.d.mts","default":"./dist/merge/index.mjs"},"./package.json":"./package.json"},"typesVersions":{"*":{"search":["./dist/search/index.d.mts"],"filter":["./dist/filter/index.d.mts"],"sort":["./dist/sort/index.d.mts"],"merge":["./dist/merge/index.d.mts"]}},"repository":{"type":"git","url":"https://github.com/trae-op/mega-collection"}}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 devisfuture
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/dist/chunk-LSQXPQRE.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var C=class{constructor(){this.indexes=new Map;this.itemPositions=new Map;}buildIndex(e,t){let n=new Map,s=new Map;for(let i=0,r=e.length;i<r;i++){let l=e[i],a=l[t];if(a==null)continue;let d=n.get(a);if(d)d.push(l),s.get(a).set(l,d.length-1);else {n.set(a,[l]);let u=new WeakMap;u.set(l,0),s.set(a,u);}}this.indexes.set(t,n),this.itemPositions.set(t,s);}getByValue(e,t){let n=this.indexes.get(e);return n?n.get(t)??[]:[]}getByValues(e,t){let n=this.indexes.get(e);if(!n)return [];if(t.length===1)return n.get(t[0])??[];let s=new Set,i=[];for(let r=0;r<t.length;r++){let l=n.get(t[r]);if(l!==void 0)for(let a=0;a<l.length;a++){let d=l[a];s.has(d)||(s.add(d),i.push(d));}}return i}hasIndex(e){return this.indexes.has(e)}removeItem(e){for(let t of this.indexes.keys())this.removeItemFromField(t,e);}clear(){this.indexes.clear(),this.itemPositions.clear();}getIndexMap(e){return this.indexes.get(e)}removeItemFromField(e,t){let n=t[e];if(n==null)return;let s=this.indexes.get(e),i=this.itemPositions.get(e),r=s?.get(n),l=i?.get(n),a=l?.get(t);if(!s||!i||!r||!l||a===void 0)return;let d=r.length-1,u=r[d];a!==d&&(r[a]=u,l.set(u,a)),r.pop(),l.delete(t),r.length===0&&(s.delete(n),i.delete(n));}};function g(x){return {value:x,enumerable:false,configurable:true,writable:true}}var y=class{constructor(e){this.callbacks=e;}create(e){let t=e;return Object.defineProperties(t,{filter:g((n,s)=>s===void 0?this.callbacks.filter(e,n):this.callbacks.filter(n,s)),clearIndexes:g(()=>this.callbacks.clearIndexes()),data:g(n=>this.callbacks.data(n)),getOriginData:g(()=>this.callbacks.getOriginData()),clearData:g(()=>this.callbacks.clearData()),resetFilterState:g(()=>this.callbacks.resetFilterState())}),t}};var v=class x extends Error{constructor(e){super(e),this.name="FilterEngineError";}static missingDatasetForBuildIndex(){return new x("FilterEngine: no dataset in memory.")}static missingDatasetForFilter(){return new x("FilterEngine: no dataset in memory.")}static duplicateMutableExcludeField(e){return new x(`FilterEngine: cannot use mutable exclude on field \`${e}\` because it contains duplicate values.`)}};function T(x){let e=[];for(let t=0;t<x.length;t++){let n=x[t],s=Array.isArray(n.values),i=E(n.exclude),r=i!==null,l=s?R(n.values,i):null;!s&&!r||e.push({field:n.field,values:l?[...l]:[],exclude:i?[...i]:[],hasValues:s,hasExclude:r,includedValues:l,excludedValues:i});}return e}function F(x,e){return !(x.hasValues&&!x.includedValues.has(e)||x.hasExclude&&x.excludedValues.has(e))}function b(x){return x.hasValues&&x.values.length===0}function E(x){return !Array.isArray(x)||x.length===0?null:new Set(x)}function R(x,e){let t=new Set;for(let n=0;n<x.length;n++){let s=x[n];e?.has(s)||t.add(s);}return t}var I=class{constructor(){this.registeredFields=new Set;this.fieldDescriptors=new Map;this.indexes=new Map;this.itemPositions=new Map;}registerFields(e){if(e?.length)for(let t=0;t<e.length;t++)this.registerField(e[t]);}hasRegisteredFields(){return this.registeredFields.size>0}hasField(e){return this.registeredFields.has(e)}clearIndexes(){this.indexes.clear(),this.itemPositions.clear();}buildIndexes(e){this.indexes.clear(),this.itemPositions.clear();for(let t of this.registeredFields)this.buildIndex(e,t);}removeItem(e){for(let t of this.indexes.keys())this.removeItemFromIndex(t,e);}filter(e,t,n){let s=this.resolveCriteria(t);if(e.length===0||s.length===0)return e;let i=[],r=[];for(let a=0;a<s.length;a++){let d=s[a];if(this.indexes.has(d.field)){i.push(d);continue}r.push(d);}let l=e;if(i.length>0&&(l=this.filterByIndexes(i,e,n),l.length===0))return l;for(let a=0;a<r.length;a++)if(l=this.filterLinearly(l,r[a]),l.length===0)return l;return l}resolveCriteria(e){if(e.length===0)return [];let t=e[0];return "hasValues"in t&&"hasExclude"in t&&"includedValues"in t?e:T(e)}registerField(e){let t=this.createDescriptor(e);t&&(this.registeredFields.add(e),this.fieldDescriptors.set(e,t));}createDescriptor(e){let t=e.indexOf(".");return t===-1?null:{collectionKey:e.substring(0,t),nestedKey:e.substring(t+1)}}buildIndex(e,t){let n=this.fieldDescriptors.get(t);if(!n)return;let{collectionKey:s,nestedKey:i}=n,r=new Map,l=new Map;for(let a=0,d=e.length;a<d;a++){let u=e[a],h=u[s];if(Array.isArray(h))for(let o=0;o<h.length;o++){let c=h[o][i];if(c==null)continue;let f=r.get(c);if(f){f[f.length-1]!==u&&(f.push(u),l.get(c).set(u,f.length-1));continue}r.set(c,[u]);let p=new WeakMap;p.set(u,0),l.set(c,p);}}this.indexes.set(t,r),this.itemPositions.set(t,l);}removeItemFromIndex(e,t){let n=this.fieldDescriptors.get(e),s=this.indexes.get(e),i=this.itemPositions.get(e);if(!n||!s||!i)return;let{collectionKey:r,nestedKey:l}=n,a=t[r];if(!Array.isArray(a)||a.length===0)return;let d=new Set;for(let u=0;u<a.length;u++){let h=a[u][l];h!=null&&d.add(h);}for(let u of d){let h=s.get(u),o=i.get(u),c=o?.get(t);if(!h||!o||c===void 0)continue;let f=h.length-1,p=h[f];c!==f&&(h[c]=p,o.set(p,c)),h.pop(),o.delete(t),h.length===0&&(s.delete(u),i.delete(u));}}filterByIndexes(e,t,n){let s=e.filter(u=>u.hasValues),i=e.filter(u=>u.hasExclude),r=t===n?null:new Set(t);if(s.length===0)return this.applyIndexedExclusions(t,i);if(s.length===1){let u=this.indexes.get(s[0].field);if(!u)return [];let h=this.getItemsByValues(u,s[0].values);if(h.length===0)return [];let o=[];for(let c=0;c<h.length;c++){let f=h[c];r&&!r.has(f)||o.push(f);}return this.applyIndexedExclusions(o,i)}let l=s.map(u=>({criterion:u,size:this.estimateIndexSize(u)})).sort((u,h)=>u.size-h.size),a=r,d=[];for(let u=0;u<l.length;u++){let{criterion:h}=l[u],o=this.indexes.get(h.field);if(!o)return [];let c=this.getItemsByValues(o,h.values);if(c.length===0)return [];if(a===null)d=c;else {d=[];for(let f=0;f<c.length;f++){let p=c[f];a.has(p)&&d.push(p);}}if(d.length===0)return [];a=new Set(d);}return this.applyIndexedExclusions(d,i)}getItemsByValues(e,t){if(t.length===1)return e.get(t[0])??[];let n=new Set,s=[];for(let i=0;i<t.length;i++){let r=e.get(t[i]);if(r)for(let l=0;l<r.length;l++){let a=r[l];n.has(a)||(n.add(a),s.push(a));}}return s}estimateIndexSize(e){let t=this.indexes.get(e.field);return t?e.values.reduce((n,s)=>{let i=t.get(s);return i?n+i.length:n},0):1/0}filterLinearly(e,t){let n=this.fieldDescriptors.get(t.field);if(!n)return e;let{collectionKey:s,nestedKey:i}=n,r=[];for(let l=0;l<e.length;l++){let a=e[l],d=a[s];if(!Array.isArray(d))continue;let u=!t.hasValues,h=false;for(let o=0;o<d.length;o++){let c=d[o][i];if(t.hasExclude&&t.excludedValues.has(c)){h=true;break}t.hasValues&&t.includedValues.has(c)&&(u=true);}!h&&u&&r.push(a);}return r}applyIndexedExclusions(e,t){if(t.length===0||e.length===0)return e;let n=new Set;for(let i=0;i<t.length;i++){let r=t[i],l=this.indexes.get(r.field);if(!l)continue;let a=this.getItemsByValues(l,r.exclude);for(let d=0;d<a.length;d++)n.add(a[d]);}if(n.size===0)return e;let s=[];for(let i=0;i<e.length;i++){let r=e[i];n.has(r)||s.push(r);}return s}};var V=class{constructor(e={}){this.dataset=[];this.datasetPositions=new Map;this.hasDuplicateMutableExcludeValues=false;this.indexedFields=new Set;this.nestedCollection=new I;this.previousResult=null;this.previousCriteria=null;this.previousBaseData=null;this.previousResultsByCriteria=new Map;this.chainBuilder=new y({filter:(e,t)=>t===void 0?this.filter(e):this.filter(e,t),getOriginData:()=>this.getOriginData(),data:e=>this.data(e),clearIndexes:()=>this.clearIndexes(),clearData:()=>this.clearData(),resetFilterState:()=>this.resetFilterState()});if(this.indexer=new C,this.filterByPreviousResult=e.filterByPreviousResult??false,this.mutableExcludeField=e.mutableExcludeField??null,this.nestedCollection.registerFields(e.nestedFields),!e.data)return;this.dataset=e.data,this.rebuildMutableExcludeState();let t=e.fields?.length,n=this.nestedCollection.hasRegisteredFields();if(t)for(let s of e.fields)this.indexedFields.add(s);(t||n)&&this.rebuildConfiguredIndexes();}rebuildConfiguredIndexes(){this.indexer.clear(),this.nestedCollection.clearIndexes();for(let e of this.indexedFields)this.buildIndex(this.dataset,e);this.nestedCollection.hasRegisteredFields()&&this.nestedCollection.buildIndexes(this.dataset);}buildIndex(e,t){if(!Array.isArray(e)){if(!this.dataset.length)throw v.missingDatasetForBuildIndex();return this.indexer.buildIndex(this.dataset,e),this}return this.dataset=e,this.resetFilterState(),this.rebuildMutableExcludeState(),this.indexer.buildIndex(e,t),this}clearIndexes(){return this.indexer.clear(),this.nestedCollection.clearIndexes(),this}resetFilterState(){return this.previousResult=null,this.previousCriteria=null,this.previousBaseData=null,this.previousResultsByCriteria.clear(),this}clearData(){return this.dataset=[],this.datasetPositions.clear(),this.hasDuplicateMutableExcludeValues=false,this.indexer.clear(),this.nestedCollection.clearIndexes(),this.resetFilterState(),this}data(e){return this.dataset=e,this.rebuildMutableExcludeState(),this.resetFilterState(),this.rebuildConfiguredIndexes(),this}getOriginData(){return this.dataset}filter(e,t){return t===void 0?this.withChain(this.rawFilter(e)):this.withChain(this.rawFilter(e,t))}rawFilter(e,t){let n=t===void 0,s,i,r;if(n){if(!this.dataset.length)throw v.missingDatasetForFilter();i=T(e);let o=this.applyMutableExclude(i);if(o!==void 0)return o;if(this.filterByPreviousResult&&this.previousResult!==null&&this.previousCriteria!==null&&this.previousBaseData===this.dataset){let c=this.createCriteriaCacheKey(i),f=this.createCriteriaCacheKey(this.previousCriteria),p=this.previousResultsByCriteria.get(c);if(c===f)return this.previousResult;if(p!==void 0)return this.storePreviousResult(p,true,this.dataset,i),p;let m=this.hasCriteriaBacktrack(this.previousCriteria,i)||this.previousResult.length===0&&!this.canApplySequentiallyToEmptyResult(this.previousCriteria,i);s=m?this.dataset:this.previousResult,r=m?i:this.createSequentialExecutionCriteria(this.previousCriteria,i);}else s=this.dataset,r=i;}else if(i=T(t),s=e,this.filterByPreviousResult&&this.previousResult!==null&&this.previousCriteria!==null&&this.previousBaseData===s){let o=this.createCriteriaCacheKey(i),c=this.createCriteriaCacheKey(this.previousCriteria),f=this.previousResultsByCriteria.get(o);if(o===c)return this.previousResult;if(f!==void 0)return this.storePreviousResult(f,false,e,i),f;let p=this.hasCriteriaBacktrack(this.previousCriteria,i)||this.previousResult.length===0&&!this.canApplySequentiallyToEmptyResult(this.previousCriteria,i);s=p?e:this.previousResult,r=p?i:this.createSequentialExecutionCriteria(this.previousCriteria,i);}else r=i;if(i.length===0)return this.filterByPreviousResult&&this.resetFilterState(),n?this.dataset:e;for(let o=0;o<r.length;o++)if(b(r[o]))return this.createEmptyResult(n,e,i);let l=[],a=[];for(let o=0;o<r.length;o++){let c=r[o];this.nestedCollection.hasField(c.field)?l.push(c):a.push(c);}if(l.length>0&&(s=this.nestedCollection.filter(s,l,this.dataset),s.length===0))return this.createEmptyResult(n,e,i);if(a.length===0)return this.storePreviousResult(s,n,e,i),s;let{indexedCriteria:d,linearCriteria:u}=a.reduce((o,c)=>(this.indexer.hasIndex(c.field)?o.indexedCriteria.push(c):o.linearCriteria.push(c),o),{indexedCriteria:[],linearCriteria:[]}),h;if(d.length>0&&u.length===0)return h=this.filterViaIndex(d,s),this.storePreviousResult(h,n,e,i),h;if(d.length>0&&u.length>0){let o=this.filterViaIndex(d,s);return h=this.linearFilter(o,u),this.storePreviousResult(h,n,e,i),h}return h=this.linearFilter(s,a),this.storePreviousResult(h,n,e,i),h}withChain(e){return this.chainBuilder.create(e)}rebuildMutableExcludeState(){if(this.datasetPositions.clear(),this.hasDuplicateMutableExcludeValues=false,this.mutableExcludeField!==null)for(let e=0;e<this.dataset.length;e++){let n=this.dataset[e][this.mutableExcludeField];n!=null&&(this.datasetPositions.has(n)&&(this.hasDuplicateMutableExcludeValues=true),this.datasetPositions.set(n,e));}}applyMutableExclude(e){if(this.mutableExcludeField===null||e.length!==1)return;let t=e[0];if(!(t.field!==this.mutableExcludeField||t.hasValues||!t.hasExclude)){if(this.hasDuplicateMutableExcludeValues)throw v.duplicateMutableExcludeField(this.mutableExcludeField);for(let n=0;n<t.exclude.length;n++)this.removeStoredItem(t.exclude[n]);return this.resetFilterState(),this.dataset}}removeStoredItem(e){let t=this.datasetPositions.get(e);if(t===void 0)return;let n=this.dataset.length-1,s=this.dataset[t],i=this.dataset[n];if(this.indexer.removeItem(s),this.nestedCollection.removeItem(s),t!==n&&(this.dataset[t]=i,this.mutableExcludeField!==null)){let r=i[this.mutableExcludeField];r!=null&&this.datasetPositions.set(r,t);}this.dataset.pop(),this.datasetPositions.delete(e);}linearFilter(e,t){let n=[];for(let s=0;s<e.length;s++){let i=e[s],r=true;for(let l=0;l<t.length;l++){let a=t[l];if(!F(a,i[a.field])){r=false;break}}r&&n.push(i);}return n}filterViaIndex(e,t){let s=t!==this.dataset?new Set(t):null,i=e.filter(o=>o.hasValues),r=e.filter(o=>o.hasExclude);if(i.length===0)return this.applyIndexedExclusions(t,r);if(i.length===1){let o=this.indexer.getByValues(i[0].field,i[0].values),c=[];for(let f=0;f<o.length;f++){let p=o[f];s&&!s.has(p)||F(i[0],p[i[0].field])&&c.push(p);}return this.applyIndexedExclusions(c,r)}let l=i.map(o=>({criterion:o,size:this.estimateIndexSize(o)})).sort((o,c)=>o.size-c.size),{field:a,values:d}=l[0].criterion,u=this.indexer.getByValues(a,d);if(u.length===0)return [];let h=[];for(let o=0;o<u.length;o++){let c=u[o],f=true;if(!(s&&!s.has(c))){for(let p=0;p<l.length;p++){let m=l[p].criterion;if(!F(m,c[m.field])){f=false;break}}f&&h.push(c);}}return this.applyIndexedExclusions(h,r)}estimateIndexSize(e){let t=this.indexer.getIndexMap(e.field);return t?e.values.reduce((n,s)=>{let i=t.get(s);return i?n+i.length:n},0):1/0}applyIndexedExclusions(e,t){if(t.length===0||e.length===0)return e.slice();let n=new Set;for(let i=0;i<t.length;i++){let r=t[i],l=this.indexer.getIndexMap(r.field);if(l)for(let a=0;a<r.exclude.length;a++){let d=l.get(r.exclude[a]);if(d)for(let u=0;u<d.length;u++)n.add(d[u]);}}if(n.size===0)return e.slice();let s=[];for(let i=0;i<e.length;i++){let r=e[i];n.has(r)||s.push(r);}return s}createEmptyResult(e,t,n){let s=[];return this.storePreviousResult(s,e,t,n),s}storePreviousResult(e,t,n,s){this.filterByPreviousResult&&(this.previousResult=e,this.previousCriteria=s,this.previousBaseData=t?this.dataset:n,this.previousResultsByCriteria.set(this.createCriteriaCacheKey(s),e));}createCriteriaCacheKey(e){let t=this.createCriteriaStateMap(e);return JSON.stringify([...t.entries()].sort(([n],[s])=>n.localeCompare(s)).map(([n,s])=>({field:n,hasValues:s.hasValues,hasExclude:s.hasExclude,values:s.values.map(i=>JSON.stringify(i)).sort(),exclude:s.exclude.map(i=>JSON.stringify(i)).sort()})))}createSequentialExecutionCriteria(e,t){let n=new Map;for(let s=0;s<e.length;s++){let i=e[s];n.set(i.field,i);}return t.map(s=>{let i=n.get(s.field);if(!i||!i.hasValues||!s.hasValues||i.hasExclude||s.hasExclude||s.includedValues.size<=i.includedValues.size)return s;for(let l of i.includedValues)if(!s.includedValues.has(l))return s;let r=[];for(let l of s.includedValues)i.includedValues.has(l)||r.push(l);return r.length===0?s:{...s,values:r,includedValues:new Set(r)}})}hasCriteriaBacktrack(e,t){let n=this.createCriteriaStateMap(e),s=this.createCriteriaStateMap(t);for(let[i,r]of n){let l=s.get(i);if(!l||this.isCriterionBacktracked(r,l))return true}return false}canApplySequentiallyToEmptyResult(e,t){let n=this.createCriteriaStateMap(e),s=this.createCriteriaStateMap(t);for(let[i,r]of s){let l=n.get(i);if(l){if(l.hasValues!==r.hasValues&&(l.hasValues||!r.hasValues))return false;if(l.hasValues&&r.hasValues){let a=l.includedValues,d=r.includedValues;if(!this.areSetsEqual(a,d)&&!this.isSubset(a,d))return false}if(l.hasExclude!==r.hasExclude&&(l.hasExclude||!r.hasExclude))return false;if(l.hasExclude&&r.hasExclude){let a=l.excludedValues,d=r.excludedValues;if(!this.areSetsEqual(a,d)&&!this.isSubset(a,d))return false}}}return true}createCriteriaStateMap(e){let t=new Map;for(let n=0;n<e.length;n++){let s=e[n],i=t.get(s.field);if(!i){t.set(s.field,{...s,values:s.values.slice(),exclude:s.exclude.slice(),includedValues:s.includedValues?new Set(s.includedValues):null,excludedValues:s.excludedValues?new Set(s.excludedValues):null});continue}if(s.hasValues)if(!i.hasValues)i.hasValues=true,i.includedValues=new Set(s.includedValues);else for(let r of i.includedValues)s.includedValues.has(r)||i.includedValues.delete(r);if(s.hasExclude)if(!i.hasExclude)i.hasExclude=true,i.excludedValues=new Set(s.excludedValues);else for(let r of s.excludedValues)i.excludedValues.add(r);if(i.hasValues&&i.hasExclude)for(let r of i.excludedValues)i.includedValues.delete(r);i.values=i.includedValues?[...i.includedValues]:[],i.exclude=i.excludedValues?[...i.excludedValues]:[];}return t}isCriterionBacktracked(e,t){if(e.hasValues&&!t.hasValues)return true;if(e.hasValues&&t.hasValues){let n=e.includedValues,s=t.includedValues;if(!this.areSetsEqual(n,s))return this.isSubset(s,n)}if(!e.hasValues&&t.hasValues)return false;if(e.hasExclude&&!t.hasExclude)return true;if(!e.hasExclude&&t.hasExclude)return false;if(e.hasExclude&&t.hasExclude){let n=e.excludedValues,s=t.excludedValues;if(!this.areSetsEqual(n,s))return this.isSubset(s,n)}return false}isSubset(e,t){for(let n of e)if(!t.has(n))return false;return true}areSetsEqual(e,t){if(e===t)return true;if(!e||!t||e.size!==t.size)return false;for(let n of e)if(!t.has(n))return false;return true}};export{V as a};
|
package/dist/chunk-NHFG4LIO.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import {a}from'./chunk-XCB43Y63.mjs';import {a as a$2}from'./chunk-LSQXPQRE.mjs';import {a as a$1}from'./chunk-ZJ6RQRJN.mjs';function c(a){return {value:a,enumerable:false,configurable:true,writable:true}}var g=class{constructor(e){this.callbacks=e;}create(e){let r=e;return Object.defineProperties(r,{search:c((t,i)=>i===void 0?this.callbacks.search(t):this.callbacks.search(t,i)),sort:c((t,i,n)=>i===void 0?this.callbacks.sort(e,t,n):this.callbacks.sort(t,i,n)),filter:c((t,i)=>i===void 0?this.callbacks.filter(e,t):this.callbacks.filter(t,i)),clearIndexes:c(t=>(this.callbacks.clearIndexes(t),this.create(e))),clearData:c(t=>(this.callbacks.clearData(t),this.create(e))),data:c(t=>this.callbacks.data(t)),getOriginData:c(()=>this.callbacks.getOriginData())}),r}};var x=a$3=>a$3===a?"search":a$3===a$1?"sort":a$3===a$2?"filter":null,y=(a$3,e,r)=>{if(a$3===a){let t=new a({data:e,...r});return {moduleName:"search",executeSearch:(i,n)=>n===void 0?t.search(i):t.search(i,n),clearIndexes:()=>t.clearIndexes(),clearData:()=>t.clearData(),data:i=>t.data(i),getOriginData:()=>t.getOriginData()}}if(a$3===a$1){let t=new a$1({data:e,...r});return {moduleName:"sort",executeSort:(i,n,s)=>n===void 0?t.sort(i):t.sort(i,n,s),clearIndexes:()=>t.clearIndexes(),clearData:()=>t.clearData(),data:i=>t.data(i),getOriginData:()=>t.getOriginData()}}if(a$3===a$2){let t=new a$2({data:e,...r});return {moduleName:"filter",executeFilter:(i,n)=>n===void 0?t.rawFilter(i):t.rawFilter(i,n),clearIndexes:()=>t.clearIndexes(),clearData:()=>t.clearData(),data:i=>t.data(i),getOriginData:()=>t.getOriginData()}}return null};var w={search:"TextSearchEngine",sort:"SortEngine",filter:"FilterEngine"},l=class a extends Error{constructor(e){super(e),this.name="MergeEnginesError";}static unavailableMethod(e){return new a(`MergeEngines: Method "${e}" is not available.`)}static unavailableEngine(e){let r=w[e];return new a(`MergeEngines: ${r} is not available.`)}static unavailableGetOriginData(){return new a("MergeEngines: getOriginData is not available.")}};var f=class{constructor(e){this.previousSearchState=null;this.previousSortState=null;this.chainBuilder=new g({search:(e,r)=>r===void 0?this.search(e):this.search(e,r),sort:(e,r,t)=>r===void 0?this.sort(e):this.sort(e,r,t),filter:(e,r)=>r===void 0?this.filter(e):this.filter(e,r),getOriginData:()=>this.getOriginData(),data:e=>this.data(e),clearIndexes:e=>this.clearIndexes(e),clearData:e=>this.clearData(e)});let{imports:r,data:t,...i}=e,n=new Set(r),s=null,M=null,p=null,m={},S={},D={},C=null;for(let T of n){let E=x(T);if(!E)continue;let N=this.getModuleInitOptions(E,T.name,i),o=y(T,t,N);o&&(o.moduleName==="search"&&!s&&(s=o),o.moduleName==="sort"&&!M&&(M=o),o.moduleName==="filter"&&!p&&(p=o),m[o.moduleName]=()=>o.clearIndexes(),S[o.moduleName]=()=>o.clearData(),D[o.moduleName]=v=>o.data(v),C??(C=()=>o.getOriginData()));}this.searchModule=s,this.sortModule=M,this.filterModule=p,this.clearIndexMethods=m,this.clearDataMethods=S,this.setDataMethods=D,this.getOriginDataMethod=C;}getModuleInitOptions(e,r,t){let i={};for(let n of [e,r]){let s=t[n];this.isRecord(s)&&Object.assign(i,s);}return i}isRecord(e){return typeof e=="object"&&e!==null}clearOperationState(e){(!e||e==="search")&&(this.previousSearchState=null),(!e||e==="sort")&&(this.previousSortState=null);}createSearchCacheKey(e,r){return JSON.stringify([e,r??null])}createSortCacheKey(e,r){return JSON.stringify({descriptors:e,inPlace:r??false})}search(e,r){if(!this.searchModule)throw l.unavailableEngine("search");let t=this.searchModule.getOriginData(),i=this.createSearchCacheKey(e,r);if(this.previousSearchState?.originData===t&&this.previousSearchState.key===i)return this.withChain(this.previousSearchState.result);let n;return r===void 0?n=this.searchModule.executeSearch(e):n=this.searchModule.executeSearch(e,r),this.previousSearchState={key:i,originData:t,result:n},this.withChain(n)}sort(e,r,t){if(!this.sortModule)throw l.unavailableEngine("sort");if(r===void 0)return this.withChain(this.sortModule.executeSort(e));let i=e;if(!t){let n=this.createSortCacheKey(r,t);if(this.previousSortState?.sourceData===i&&this.previousSortState.key===n)return this.withChain(this.previousSortState.result);let s=this.sortModule.executeSort(i,r,t);return this.previousSortState={key:n,sourceData:i,result:s},this.withChain(s)}return this.withChain(this.sortModule.executeSort(i,r,t))}filter(e,r){if(!this.filterModule)throw l.unavailableEngine("filter");return r===void 0?this.withChain(this.filterModule.executeFilter(e)):this.withChain(this.filterModule.executeFilter(e,r))}withChain(e){return this.chainBuilder.create(e)}getOriginData(){if(this.getOriginDataMethod)return this.getOriginDataMethod();throw l.unavailableGetOriginData()}clearIndexes(e){let r=this.clearIndexMethods[e];if(r)return r(),this.clearOperationState(e),this;throw l.unavailableEngine(e)}data(e){let r=["search","sort","filter"];this.clearOperationState();for(let t of r){let i=this.setDataMethods[t];i&&i(e);}return this}clearData(e){let r=this.clearDataMethods[e];if(r)return r(),this.clearOperationState(e),this;throw l.unavailableEngine(e)}};export{f as a};
|
package/dist/chunk-XCB43Y63.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var p=class u extends Error{constructor(e){super(e),this.name="TextSearchEngineError";}static missingDatasetForBuildIndex(){return new u("TextSearchEngine: no dataset in memory.")}};function T(u){let e=u.toLowerCase(),t=Math.min(3,e.length),s=e.length-t+1,n=new Array(s);for(let i=0;i<s;i++)n[i]=e.substring(i,i+t);return n}function L(u,e){let t=u.get(e);if(t)return t;let s=new Set;return u.set(e,s),s}function I(u){let e=T(u);if(e.length<=12)return new Set(e);let t=new Set,s=e.length-1,n=11;for(let i=0;i<=n;i++){let o=Math.round(i*s/n);t.add(e[o]);}return t}function x(u,e,t){for(let s=0,n=e.length;s<n;s++){let i=n-s,o=Math.min(3,i);for(let r=1;r<=o;r++){let a=e.substring(s,s+r);L(u,a).add(t);}}}var y=class{constructor(){this.registeredFields=new Set;this.fieldDescriptors=new Map;this.ngramIndexes=new Map;this.normalizedFieldValues=new Map;}registerFields(e){if(e?.length)for(let t=0;t<e.length;t++)this.registerField(e[t]);}hasRegisteredFields(){return this.registeredFields.size>0}hasField(e){return this.registeredFields.has(e)}hasIndexes(){return this.ngramIndexes.size>0}clearIndexes(){this.ngramIndexes.clear(),this.normalizedFieldValues.clear();}buildIndexes(e){this.clearIndexes();for(let t of this.registeredFields)this.buildIndex(e,t);}searchAllIndexedFields(e,t,s){let n=new Set,i=[];for(let o of this.registeredFields)for(let r of this.searchIndexedField(e,o,t,s))n.has(r)||(n.add(r),i.push(r));return i}searchIndexedField(e,t,s,n){let i=this.ngramIndexes.get(t);if(!i)return [];let o=[];for(let d of n){let l=i.get(d);if(!l)return [];o.push(l);}o.sort((d,l)=>d.size-l.size);let r=o[0],a=o.length,h=[],c=this.normalizedFieldValues.get(t);for(let d of r){let l=true;for(let m=1;m<a;m++)if(!o[m].has(d)){l=false;break}if(!l)continue;let g=e[d];!g||!c?.[d]?.includes(s)||h.push(g);}return h}searchFieldLinear(e,t,s){let n=this.fieldDescriptors.get(t);if(!n)return [];let{collectionKey:i,nestedKey:o}=n,r=[];for(let a=0;a<e.length;a++){let h=e[a],c=h[i];if(!Array.isArray(c))continue;let d=false;for(let l=0;l<c.length;l++){let g=c[l][o];if(typeof g=="string"&&g.toLowerCase().includes(s)){d=true;break}}d&&r.push(h);}return r}matchesAnyField(e,t){for(let s of this.registeredFields){let n=this.fieldDescriptors.get(s);if(!n)continue;let{collectionKey:i,nestedKey:o}=n,r=e[i];if(Array.isArray(r))for(let a=0;a<r.length;a++){let h=r[a][o];if(typeof h=="string"&&h.toLowerCase().includes(t))return true}}return false}registerField(e){let t=this.createDescriptor(e);t&&(this.registeredFields.add(e),this.fieldDescriptors.set(e,t));}createDescriptor(e){let t=e.indexOf(".");return t===-1?null:{collectionKey:e.substring(0,t),nestedKey:e.substring(t+1)}}buildIndex(e,t){let s=this.fieldDescriptors.get(t);if(!s)return;let{collectionKey:n,nestedKey:i}=s,o=new Map,r=new Array(e.length);for(let a=0,h=e.length;a<h;a++){let d=e[a][n];if(!Array.isArray(d))continue;let l=[];for(let g=0;g<d.length;g++){let f=d[g][i];if(typeof f!="string")continue;let m=f.toLowerCase();l.push(m),x(o,m,a);}l.length!==0&&(r[a]=l.join(`
|
|
2
|
-
`));}this.ngramIndexes.set(t,o),this.normalizedFieldValues.set(t,r);}};var F=class{constructor(e={}){this.ngramIndexes=new Map;this.normalizedFieldValues=new Map;this.dataset=[];this.indexedFields=new Set;this.nestedCollection=new y;if(this.minQueryLength=e.minQueryLength??1,this.nestedCollection.registerFields(e.nestedFields),!e.data)return;this.dataset=e.data;let t=e.fields?.length,s=this.nestedCollection.hasRegisteredFields();if(t)for(let n of e.fields)this.indexedFields.add(n);(t||s)&&this.rebuildConfiguredIndexes();}rebuildConfiguredIndexes(){this.ngramIndexes.clear(),this.normalizedFieldValues.clear(),this.nestedCollection.clearIndexes();for(let e of this.indexedFields)this.buildIndex(this.dataset,e);this.nestedCollection.hasRegisteredFields()&&this.nestedCollection.buildIndexes(this.dataset);}buildIndex(e,t){let s,n;if(Array.isArray(e))s=e,n=t;else {if(!this.dataset.length)throw p.missingDatasetForBuildIndex();s=this.dataset,n=e;}this.dataset=s;let i=new Map,o=new Array(s.length);for(let r=0,a=s.length;r<a;r++){let h=s[r][n];if(typeof h!="string")continue;let c=h.toLowerCase();o[r]=c,x(i,c,r);}return this.ngramIndexes.set(n,i),this.normalizedFieldValues.set(n,o),this}search(e,t){return t===void 0?this.searchAllFields(e):this.searchField(e,t)}normalizeQuery(e){return e.trim().toLowerCase()}searchAllFields(e){let t=this.normalizeQuery(e);if(!t)return this.dataset;if(t.length<this.minQueryLength)return this.dataset;if(!this.ngramIndexes.size&&!this.nestedCollection.hasIndexes())return this.searchAllFieldsLinear(t);let s=I(t);if(!s.size)return [];let n=new Set,i=[];for(let o of this.ngramIndexes.keys())for(let r of this.searchFieldWithPreparedQuery(o,t,s))n.has(r)||(n.add(r),i.push(r));for(let o of this.nestedCollection.searchAllIndexedFields(this.dataset,t,s))n.has(o)||(n.add(o),i.push(o));return i}searchField(e,t){let s=this.normalizeQuery(t);if(!s)return this.dataset;if(s.length<this.minQueryLength)return this.dataset;if(this.nestedCollection.hasField(e)){let i=I(s);return i.size?this.nestedCollection.hasIndexes()?this.nestedCollection.searchIndexedField(this.dataset,e,s,i):this.nestedCollection.searchFieldLinear(this.dataset,e,s):[]}if(!this.ngramIndexes.size)return this.searchFieldLinear(e,s);let n=I(s);return n.size?this.searchFieldWithPreparedQuery(e,s,n):[]}searchFieldWithPreparedQuery(e,t,s){let n=this.ngramIndexes.get(e);if(!n)return [];let i=[];for(let c of s){let d=n.get(c);if(!d)return [];i.push(d);}i.sort((c,d)=>c.size-d.size);let o=i[0],r=i.length,a=[],h=this.normalizedFieldValues.get(e);for(let c of o){let d=true;for(let f=1;f<r;f++)if(!i[f].has(c)){d=false;break}if(!d)continue;let l=this.dataset[c];if(!l)continue;h?.[c]?.includes(t)&&a.push(l);}return a}searchAllFieldsLinear(e){if(!this.dataset.length)return [];let t=[];for(let s=0;s<this.dataset.length;s++){let n=this.dataset[s],i=false;for(let o in n){let r=n[o];if(typeof r=="string"&&r.toLowerCase().includes(e)){i=true;break}}i||(i=this.nestedCollection.matchesAnyField(n,e)),i&&t.push(n);}return t}searchFieldLinear(e,t){if(!this.dataset.length)return [];if(this.nestedCollection.hasField(e))return this.nestedCollection.searchFieldLinear(this.dataset,e,t);let s=[];for(let n=0;n<this.dataset.length;n++){let i=this.dataset[n][e];typeof i=="string"&&i.toLowerCase().includes(t)&&s.push(this.dataset[n]);}return s}clearIndexes(){return this.ngramIndexes.clear(),this.normalizedFieldValues.clear(),this.nestedCollection.clearIndexes(),this}getOriginData(){return this.dataset}data(e){return this.dataset=e,this.rebuildConfiguredIndexes(),this}clearData(){return this.dataset=[],this.ngramIndexes.clear(),this.normalizedFieldValues.clear(),this.nestedCollection.clearIndexes(),this}};export{F as a};
|
package/dist/chunk-ZJ6RQRJN.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var u=class f extends Error{constructor(r){super(r),this.name="SortEngineError";}static missingDatasetForBuildIndex(){return new f("SortEngine: no dataset in memory.")}static missingDatasetForSort(){return new f("SortEngine: no dataset in memory.")}};var g=class{constructor(r={}){this.cache=new Map;this.dataset=[];this.indexedFields=new Set;if(r.data&&(this.dataset=r.data,r.fields?.length)){for(let a of r.fields)this.indexedFields.add(a);this.rebuildConfiguredIndexes();}}rebuildConfiguredIndexes(){this.cache.clear();for(let r of this.indexedFields)this.buildIndex(this.dataset,r);}buildIndex(r,a){let l,t;if(Array.isArray(r))l=r,t=a;else {if(!this.dataset.length)throw u.missingDatasetForBuildIndex();l=this.dataset,t=r;}this.dataset=l;let e=l.length,s=new Uint32Array(e),n=new Array(e);for(let o=0;o<e;o++)s[o]=o,n[o]=l[o][t];if(typeof n[0]=="number"){let o=new Float64Array(e);for(let d=0;d<e;d++)o[d]=n[d];s.sort((d,c)=>o[d]-o[c]);}else s.sort((o,d)=>{let c=n[o],h=n[d];return c<h?-1:c>h?1:0});return this.cache.set(t,{indexes:s,dataRef:l,itemCount:e}),this}clearIndexes(){return this.cache.clear(),this}clearData(){return this.dataset=[],this.cache.clear(),this}data(r){return this.dataset=r,this.rebuildConfiguredIndexes(),this}getOriginData(){return this.dataset}sort(r,a,l=false){let t,e,s=a===void 0;if(a===void 0){if(!this.dataset.length)throw u.missingDatasetForSort();t=this.dataset,e=r;}else t=r,e=a;if(e.length===0||t.length===0)return t;if(e.length===1){let{field:o,direction:d}=e[0],c=this.cache.get(o);if(s&&c?.dataRef===t&&c.itemCount===t.length)return this.reconstructFromIndex(t,c.indexes,d)}let n=l?t:t.slice();if(e.length===1&&t.length>0&&typeof t[0][e[0].field]=="number")return this.radixSortNumeric(n,e[0].field,e[0].direction);let i=this.buildComparator(e);return n.sort(i),n}reconstructFromIndex(r,a,l){let t=r.length,e=new Array(t);if(l==="asc")for(let s=0;s<t;s++)e[s]=r[a[s]];else for(let s=0;s<t;s++)e[s]=r[a[t-1-s]];return e}buildComparator(r){let a=r.map(({field:e})=>e),l=r.map(({direction:e})=>e==="asc"?1:-1),t=a.length;return (e,s)=>{for(let n=0;n<t;n++){let i=e[a[n]],o=s[a[n]];if(i<o)return -l[n];if(i>o)return l[n]}return 0}}radixSortNumeric(r,a,l){let t=r.length,e=new Float64Array(t);for(let i=0;i<t;i++)e[i]=r[i][a];let s=new Uint32Array(t);for(let i=0;i<t;i++)s[i]=i;s.sort((i,o)=>e[i]-e[o]);let n=new Array(t);if(l==="asc")for(let i=0;i<t;i++)n[i]=r[s[i]];else for(let i=0;i<t;i++)n[t-1-i]=r[s[i]];return n}};export{g as a};
|