@devisfuture/mega-collection 2.3.5 → 2.4.2

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 CHANGED
@@ -10,11 +10,14 @@ If this package saved you some time, a ⭐ on GitHub would be much appreciated.
10
10
 
11
11
  - [What does this package solve](#what-does-this-package-solve) – what problem this package helps with
12
12
  - [Features](#features) – what the package can do
13
+ - [How it works](#how-it-works) – plain-English explanation of how each engine works internally
14
+ - [Benchmarks](#benchmarks) – performance numbers and how to run them
13
15
  - [React demo](#react-demo) – example project and live demo
14
16
  - [Install](#install) – how to install the package
15
17
  - [Quick Start](#quick-start) – basic usage examples
16
18
  - [All-in-one: `MergeEngines`](#all-in-one-mergeengines) – use search, filter, and sort from one engine
17
19
  - [Add items with `add([])`](#add-items-with-add) – append multiple items to stored data
20
+ - [Update items with `update(...)`](#update-items-with-update) – replace one stored item by unique field
18
21
  - [Search only](#search-only) – use only text search
19
22
  - [Flat collections search](#flat-collections-search) – search simple fields like `name` or `city`
20
23
  - [Nested collections search](#nested-collections-search) – search inside nested arrays like `orders.status`
@@ -38,11 +41,19 @@ If this package saved you some time, a ⭐ on GitHub would be much appreciated.
38
41
 
39
42
  ## What does this package solve
40
43
 
41
- Sometimes the server returns a very large array, for example 100K+ items.
42
- Most often you then need to search, filter, or sort this data.
44
+ When your API returns thousands of items, you usually need to let the user search, filter, or sort them on the client side.
43
45
 
44
- This package helps do these operations faster than plain JavaScript methods.
45
- Usually this happens before data is shown in the UI.
46
+ The typical way to do this is with built-in array methods:
47
+
48
+ ```ts
49
+ const results = users.filter((u) => u.city === "New York");
50
+ const sorted = [...users].sort((a, b) => a.age - b.age);
51
+ const found = users.filter((u) => u.name.toLowerCase().includes(query));
52
+ ```
53
+
54
+ This works fine for small arrays. But with 10 000–100 000+ items, every call to `filter` or `sort` scans the whole array from scratch. If you run it on every keystroke, it adds up.
55
+
56
+ This package solves this by building indexes ahead of time — special data structures that let you look up results without scanning the full array every time. You pay the cost once when the data arrives, and then each search, filter, or sort is much cheaper.
46
57
 
47
58
  The package has no dependencies.
48
59
  You can import only the parts you need.
@@ -51,16 +62,52 @@ Each engine has its own entry point: `/search`, `/filter`, `/sort`.
51
62
  If you import only `@devisfuture/mega-collection/search`, only search code goes into the bundle.
52
63
  Unused modules are not included.
53
64
 
54
- ## Features
65
+ ## How it works
66
+
67
+ ### Search
68
+
69
+ Native `Array.prototype.filter` with `String.includes` checks every item in the array on each keystroke. For 50 000 items that's 50 000 string comparisons per call.
55
70
 
56
- | Capability | Strategy | Complexity |
57
- | ---------------------------- | -------------------------------------- | ---------------------------------- |
58
- | **Indexed filter** | Hash-Map index (`Map<value, T[]>`) | **O(1)** |
59
- | **Multi-value filter** | Index intersection + `Set` membership | **O(k)** indexed / **O(n)** linear |
60
- | **Nested collection filter** | Pre-built nested index + `Set` lookup | **O(k)** indexed / **O(n)** linear |
61
- | **Text search** (contains) | Trigram inverted index + verify | **O(candidates)** |
62
- | **Nested collection search** | Nested trigram index + verify | **O(candidates)** |
63
- | **Sorting** | Pre-sorted index (cached) / V8 TimSort | **O(n)** cached / **O(n log n)** |
71
+ `TextSearchEngine` avoids this by building an **n-gram inverted index** upfront:
72
+
73
+ 1. Each string value is split into overlapping 2- and 3-character pieces called n-grams. For example, `"hello"` produces `"he"`, `"hel"`, `"el"`, `"ell"`, `"ll"`, `"llo"`, `"lo"`.
74
+ 2. For every n-gram the engine keeps a set of item positions that contain it.
75
+ 3. When you search for `"john"`, the engine splits that query into the same n-gram pieces, then intersects the sets only items that share all query n-grams survive. This candidate set is usually tiny even for 100 000 items.
76
+ 4. Each surviving candidate is checked with a fast `String.includes` to confirm the full substring match.
77
+
78
+ For very short queries (fewer than 2 characters) the engine falls back to a linear scan — n-grams that short would match too many items to be useful.
79
+
80
+ ### Filter
81
+
82
+ Native `Array.prototype.filter` with `===` still checks every item on every call.
83
+
84
+ `FilterEngine` builds a **hash-map** for each indexed field:
85
+
86
+ ```
87
+ field "city" → { "New York": [item0, item4, ...], "Miami": [item1, ...], ... }
88
+ ```
89
+
90
+ A filter call becomes a map lookup: `index.get("New York")` returns the array of matches in O(1). Multiple values from the same field are concatenated. Multiple fields are intersected using a `Set`.
91
+
92
+ When the `fields` option is not provided, the engine falls back to a linear scan — which works but is slower.
93
+
94
+ ### Sort
95
+
96
+ Native `Array.prototype.sort` re-sorts the whole array from scratch every call.
97
+
98
+ `SortEngine` pre-sorts and stores results in a `Uint32Array` of positions:
99
+
100
+ ```
101
+ cache["age"] = [index of youngest item, index of next, ..., index of oldest]
102
+ ```
103
+
104
+ The first sort call builds this index. Subsequent calls just read it in O(n). The cache is invalidated on mutations and rebuilt lazily on the next sort call.
105
+
106
+ ---
107
+
108
+ ## Benchmarks
109
+
110
+ Benchmarks for `TextSearchEngine`, `FilterEngine`, and `SortEngine` are collected in [BENCHMARKS](./BENCHMARKS.md).
64
111
 
65
112
  ## React demo
66
113
 
@@ -103,12 +150,12 @@ Use `MergeEngines` when you want one class that works with one dataset.
103
150
  Add needed engines to `imports`. Only those engines will be created.
104
151
 
105
152
  You can create many engine instances in one project for different collections.
106
- Each instance stores its own data and indexes, so they do not affect each other.
153
+ Each instance keeps its own dataset and runtime indexes inside an internal shared `State`, so separate instances do not affect each other.
107
154
 
108
155
  Each engine can receive an optional `fields` array through `search`, `filter`, or `sort` options.
109
156
  These fields are used for indexes.
110
157
 
111
- Indexes are built lazily on first use, so engine creation stays fast.
158
+ Indexes are built lazily on first use inside that shared state, so engine creation stays fast.
112
159
  If you skip `fields`, everything still works, but the engine may scan the full array.
113
160
 
114
161
  ```ts
@@ -120,8 +167,9 @@ import { FilterEngine } from "@devisfuture/mega-collection/filter";
120
167
  const engine = new MergeEngines<User>({
121
168
  imports: [TextSearchEngine, SortEngine, FilterEngine],
122
169
  data: users,
170
+ filterByPreviousResult: true,
123
171
  search: { fields: ["name", "city"], minQueryLength: 2 },
124
- filter: { fields: ["city", "age"], filterByPreviousResult: true },
172
+ filter: { fields: ["city", "age"] },
125
173
  sort: { fields: ["age", "name", "city"] },
126
174
  });
127
175
 
@@ -137,10 +185,19 @@ engine
137
185
  .sort([{ field: "age", direction: "asc" }])
138
186
  .filter([{ field: "city", values: ["Miami", "New York"] }]);
139
187
 
188
+ // Separate calls also continue from the last result when
189
+ // `filterByPreviousResult` is enabled on MergeEngines.
190
+ const searchResult = engine.search("john");
191
+ const filteredResult = engine.filter([
192
+ { field: "city", values: ["Miami", "New York"] },
193
+ ]);
194
+ const sortedResult = engine.sort([{ field: "age", direction: "asc" }]);
195
+
140
196
  // Example with nested fields, for example `orders` inside each user.
141
197
  const nestedEngine = new MergeEngines<UserWithOrders>({
142
198
  imports: [TextSearchEngine, SortEngine, FilterEngine],
143
199
  data: usersWithOrders,
200
+ filterByPreviousResult: true,
144
201
  search: {
145
202
  fields: ["name", "city"],
146
203
  nestedFields: ["orders.status"],
@@ -149,7 +206,6 @@ const nestedEngine = new MergeEngines<UserWithOrders>({
149
206
  filter: {
150
207
  fields: ["city", "age"],
151
208
  nestedFields: ["orders.status"],
152
- filterByPreviousResult: true,
153
209
  },
154
210
  sort: { fields: ["age", "name", "city"] },
155
211
  });
@@ -188,7 +244,12 @@ This is different from `data(...)`:
188
244
  - `data(...)` replaces the whole stored dataset.
189
245
  - `add([])` appends new items to the existing stored dataset.
190
246
 
191
- If indexes are already built, the engine updates only the new items instead of rebuilding the whole dataset.
247
+ If indexes are already built, `add()` updates them incrementally for the new items only:
248
+
249
+ - **TextSearchEngine / FilterEngine**: O(k) — only the new items are written into the n-gram or hash-map index (existing index entries are untouched).
250
+ - **SortEngine**: the sort cache for each configured field is invalidated on `add()` and rebuilt lazily on the next `sort()` call. This avoids O(N) work per add and is optimal when multiple adds happen between sorts.
251
+
252
+ If indexes have not been built yet (first `sort()` has not been called), `add()` appends the items without touching any index.
192
253
  If you cleared indexes with `clearIndexes()`, `add([])` does not rebuild them automatically.
193
254
 
194
255
  ```ts
@@ -255,6 +316,56 @@ sortEngine.add([
255
316
 
256
317
  ---
257
318
 
319
+ ### Update items with `update(...)`
320
+
321
+ Use `update(...)` when you need to replace one stored item by a unique field such as `id`.
322
+
323
+ - `update(...)` keeps the same stored array reference.
324
+ - `update(...)` replaces only the matched item in stored data.
325
+ - configured indexes or caches refresh only the affected item instead of rebuilding the whole dataset.
326
+
327
+ ```ts
328
+ import { MergeEngines } from "@devisfuture/mega-collection";
329
+ import { TextSearchEngine } from "@devisfuture/mega-collection/search";
330
+ import { SortEngine } from "@devisfuture/mega-collection/sort";
331
+ import { FilterEngine } from "@devisfuture/mega-collection/filter";
332
+
333
+ const merge = new MergeEngines<User>({
334
+ imports: [TextSearchEngine, SortEngine, FilterEngine],
335
+ data: users,
336
+ search: { fields: ["name", "city"], minQueryLength: 2 },
337
+ filter: { fields: ["city", "age"] },
338
+ sort: { fields: ["age", "name"] },
339
+ });
340
+
341
+ merge.update({
342
+ field: "id",
343
+ data: { id: 2, name: "Bob", city: "Paris", age: 19 },
344
+ });
345
+
346
+ merge.search("Paris");
347
+ merge.filter([{ field: "city", values: ["Paris"] }]);
348
+ merge.sort([{ field: "age", direction: "asc" }]);
349
+ ```
350
+
351
+ The same method works in each engine:
352
+
353
+ ```ts
354
+ import { TextSearchEngine } from "@devisfuture/mega-collection/search";
355
+
356
+ const searchEngine = new TextSearchEngine<User>({
357
+ data: users,
358
+ fields: ["name", "city"],
359
+ });
360
+
361
+ searchEngine.update({
362
+ field: "id",
363
+ data: { id: 2, name: "Bob", city: "Paris", age: 19 },
364
+ });
365
+ ```
366
+
367
+ ---
368
+
258
369
  ### Search only
259
370
 
260
371
  Use `TextSearchEngine` when you only need text search.
@@ -279,10 +390,17 @@ const engine = new TextSearchEngine<User>({
279
390
 
280
391
  engine.search("john"); // searches all indexed fields, deduplicated
281
392
  engine.search("name", "john"); // searches a specific field
393
+ engine.search("john", { limit: 20, offset: 20 }); // paginate broad result sets
282
394
 
283
395
  // replace dataset without re-initializing
284
396
  engine.data(users);
285
397
 
398
+ // replace one stored item by unique field
399
+ engine.update({
400
+ field: "id",
401
+ data: { id: 2, name: "Bob", city: "Paris", age: 19 },
402
+ });
403
+
286
404
  // access original dataset stored in the engine
287
405
  engine.getOriginData();
288
406
 
@@ -335,6 +453,12 @@ engine.filter([
335
453
  // Replace dataset without creating a new engine.
336
454
  engine.data(users);
337
455
 
456
+ // Replace one stored item by unique field.
457
+ engine.update({
458
+ field: "id",
459
+ data: { id: 2, name: "Bob", city: "Paris", age: 19, active: true },
460
+ });
461
+
338
462
  // Get original stored dataset.
339
463
  engine.getOriginData();
340
464
 
@@ -487,6 +611,12 @@ engine.sort([{ field: "age", direction: "asc" }]);
487
611
  // replace dataset without re-initializing
488
612
  engine.data(users);
489
613
 
614
+ // replace one stored item by unique field
615
+ engine.update({
616
+ field: "id",
617
+ data: { id: 2, name: "Bob", city: "Paris", age: 19 },
618
+ });
619
+
490
620
  // access original dataset stored in the engine
491
621
  engine.getOriginData();
492
622
 
@@ -511,13 +641,14 @@ One class that combines search, filter, and sort for the same dataset.
511
641
 
512
642
  **Constructor options:**
513
643
 
514
- | Option | Type | Description |
515
- | --------- | -------------------------------------------------------------------------- | -------------------------------------------- |
516
- | `imports` | `(typeof TextSearchEngine \| SortEngine \| FilterEngine)[]` | Engine classes to create |
517
- | `data` | `T[]` | Shared dataset — passed once at construction |
518
- | `search` | `{ fields, nestedFields?, minQueryLength? }` | Config for TextSearchEngine |
519
- | `filter` | `{ fields, nestedFields?, filterByPreviousResult?, mutableExcludeField? }` | Config for FilterEngine |
520
- | `sort` | `{ fields }` | Config for SortEngine |
644
+ | Option | Type | Description |
645
+ | ------------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
646
+ | `imports` | `(typeof TextSearchEngine \| SortEngine \| FilterEngine)[]` | Engine classes to create |
647
+ | `data` | `T[]` | Shared dataset — passed once at construction |
648
+ | `filterByPreviousResult` | `boolean` | When `true`, separate `filter(...)` and `sort(...)` calls continue from the last result stored in shared State |
649
+ | `search` | `{ fields, nestedFields?, minQueryLength? }` | Config for TextSearchEngine |
650
+ | `filter` | `{ fields, nestedFields?, mutableExcludeField? }` | Config for FilterEngine |
651
+ | `sort` | `{ fields }` | Config for SortEngine |
521
652
 
522
653
  **Methods:**
523
654
 
@@ -531,12 +662,10 @@ One class that combines search, filter, and sort for the same dataset.
531
662
  | `filter(data, criteria)` | Filter with an explicit dataset |
532
663
  | `getOriginData()` | Get the shared original dataset |
533
664
  | `add(items)` | Append multiple items to the stored dataset and update existing indexes or caches for new items only |
665
+ | `update({ field, data })` | Replace one stored item by a unique field and refresh only the affected cached or indexed data |
534
666
  | `data(data)` | Replace stored dataset for all imported modules, rebuilding configured indexes and resetting filter state where applicable |
535
667
  | `clearIndexes(module)` | Clear indexes for one module (`"search"`, `"sort"`, `"filter"`) |
536
- | `clearData(module)` | Clear stored data for one module (`"search"`, `"sort"`, `"filter"`) |
537
-
538
- If `filter.mutableExcludeField` is configured, `filter([{ field, exclude }])` on that field removes items from the stored filter dataset with swap-pop.
539
- This changes the stored filter dataset and does not preserve order.
668
+ | `clearData(module)` | Clear the shared stored dataset through one imported module (`"search"`, `"sort"`, `"filter"`) |
540
669
 
541
670
  ---
542
671
 
@@ -546,15 +675,27 @@ Text search engine.
546
675
  It supports `nestedFields` if you need to search inside nested collections such as `["orders.status"]`.
547
676
  Search methods return plain arrays.
548
677
 
549
- | Method | Description |
550
- | ---------------------- | ---------------------------------------------------------- |
551
- | `search(query)` | Search all indexed fields (including nested), deduplicated |
552
- | `search(field, query)` | Search a specific indexed field or nested field path |
553
- | `getOriginData()` | Get the original stored dataset |
554
- | `add(items)` | Append multiple items to the stored dataset |
555
- | `data(data)` | Replace stored dataset and rebuild configured indexes |
556
- | `clearIndexes()` | Clear n-gram indexes (including nested) |
557
- | `clearData()` | Clear stored data |
678
+ Main constructor options:
679
+
680
+ | Option | Type | Description |
681
+ | ------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
682
+ | `filterByPreviousResult` | `boolean` | When `true`, a query that narrows the previous one (new query includes old query) searches only the previous result instead of the full dataset. Any mutation resets the state. |
683
+ | `nestedFields` | `string[]` | Nested field paths in dot notation, for example `["orders.status"]`. |
684
+
685
+ | Method | Description |
686
+ | -------------------------------- | -------------------------------------------------------------------- |
687
+ | `search(query, options?)` | Search all indexed fields (including nested), deduplicated |
688
+ | `search(field, query, options?)` | Search a specific indexed field or nested field path |
689
+ | `searchAll(query, options?)` | Explicit all-fields alias when you want pagination on broad searches |
690
+ | `resetSearchState()` | Reset previous-result state for sequential narrowing search |
691
+ | `getOriginData()` | Get the original stored dataset |
692
+ | `add(items)` | Append multiple items to the stored dataset |
693
+ | `update({ field, data })` | Replace one stored item by a unique field |
694
+ | `data(data)` | Replace stored dataset and rebuild configured indexes |
695
+ | `clearIndexes()` | Clear n-gram indexes (including nested) |
696
+ | `clearData()` | Clear stored data |
697
+
698
+ `options.limit` and `options.offset` are useful for broad result sets where you only need the current page.
558
699
 
559
700
  ### `FilterEngine<T>` (filter module)
560
701
 
@@ -570,16 +711,17 @@ Main constructor options:
570
711
  | `mutableExcludeField` | `string` | Optional field for removing items from stored data with swap-pop. This changes the stored dataset and does not preserve order. |
571
712
  | `nestedFields` | `string[]` | Nested field paths in dot notation, for example `["orders.status"]`. |
572
713
 
573
- | Method | Description |
574
- | ------------------------ | -------------------------------------------------------------------------- |
575
- | `filter(criteria)` | Filter using stored dataset (supports nested field criteria) |
576
- | `filter(data, criteria)` | Filter with an explicit dataset |
577
- | `getOriginData()` | Get the original stored dataset |
578
- | `add(items)` | Append multiple items to the stored dataset |
579
- | `data(data)` | Replace stored dataset, rebuild configured indexes, and reset filter state |
580
- | `resetFilterState()` | Reset previous-result state for sequential filtering |
581
- | `clearIndexes()` | Free all index memory (including nested indexes) |
582
- | `clearData()` | Clear stored data |
714
+ | Method | Description |
715
+ | ------------------------- | -------------------------------------------------------------------------- |
716
+ | `filter(criteria)` | Filter using stored dataset (supports nested field criteria) |
717
+ | `filter(data, criteria)` | Filter with an explicit dataset |
718
+ | `getOriginData()` | Get the original stored dataset |
719
+ | `add(items)` | Append multiple items to the stored dataset |
720
+ | `update({ field, data })` | Replace one stored item by a unique field |
721
+ | `data(data)` | Replace stored dataset, rebuild configured indexes, and reset filter state |
722
+ | `resetFilterState()` | Reset previous-result state for sequential filtering |
723
+ | `clearIndexes()` | Free all index memory (including nested indexes) |
724
+ | `clearData()` | Clear stored data |
583
725
 
584
726
  ### `SortEngine<T>` (sort module)
585
727
 
@@ -592,54 +734,13 @@ Sort methods return plain arrays.
592
734
  | `sort(data, descriptors, inPlace?)` | Sort with an explicit dataset |
593
735
  | `getOriginData()` | Get the original stored dataset |
594
736
  | `add(items)` | Append multiple items to the stored dataset |
737
+ | `update({ field, data })` | Replace one stored item by a unique field |
595
738
  | `data(data)` | Replace stored dataset and rebuild configured indexes |
596
739
  | `clearIndexes()` | Free all cached indexes |
597
740
  | `clearData()` | Clear stored data |
598
741
 
599
742
  ---
600
743
 
601
- **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.
602
-
603
- ## Types
604
-
605
- All types are exported from the root package and from each sub-module:
606
-
607
- ```ts
608
- import type {
609
- CollectionItem,
610
- IndexableKey,
611
- FilterCriterion,
612
- SortDescriptor,
613
- SortDirection,
614
- MergeEnginesOptions,
615
- } from "@devisfuture/mega-collection";
616
- ```
617
-
618
- You can also import them from individual sub-modules:
619
-
620
- ```ts
621
- import type {
622
- CollectionItem,
623
- IndexableKey,
624
- } from "@devisfuture/mega-collection/search";
625
- import type { FilterCriterion } from "@devisfuture/mega-collection/filter";
626
- import type {
627
- SortDescriptor,
628
- SortDirection,
629
- } from "@devisfuture/mega-collection/sort";
630
- ```
631
-
632
- ---
633
-
634
- ## Build
635
-
636
- ```bash
637
- npm install
638
- npm run build # Build ESM + declarations
639
- npm run typecheck # Type-check without emitting
640
- npm run dev # Watch mode
641
- ```
642
-
643
744
  ## Contributing
644
745
 
645
746
  See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
@@ -0,0 +1,44 @@
1
+ import { C as CollectionItem, S as StateOptions, a as StateListener, b as StatePreviousResult, c as StateRegistryFactory, U as UpdateDescriptor, I as IndexableKey } from './types-DONld7xY.mjs';
2
+
3
+ declare class State<T extends CollectionItem> {
4
+ private originData;
5
+ private filterByPreviousResult;
6
+ private itemIndexLookup;
7
+ private mutationVersion;
8
+ private namespaceSequence;
9
+ private previousResultState;
10
+ private readonly indexMaps;
11
+ private readonly scopedRegistry;
12
+ private readonly listeners;
13
+ constructor(data?: T[], options?: StateOptions);
14
+ subscribe(listener: StateListener<T>): () => void;
15
+ getOriginData(): T[];
16
+ getItemIndex(item: T): number | undefined;
17
+ getMutationVersion(): number;
18
+ isFilterByPreviousResultEnabled(): boolean;
19
+ setFilterByPreviousResult(enabled: boolean): void;
20
+ getPreviousResult(): T[] | null;
21
+ getPreviousResultState(): StatePreviousResult<T> | null;
22
+ setPreviousResult(result: T[], sourceData: T[]): void;
23
+ clearPreviousResult(): void;
24
+ createNamespace(prefix?: string): string;
25
+ getScopedValue<TValue>(namespace: string, key: string): TValue | undefined;
26
+ getOrCreateScopedValue<TValue>(namespace: string, key: string, createValue: StateRegistryFactory<TValue>): TValue;
27
+ setScopedValue<TValue>(namespace: string, key: string, value: TValue): TValue;
28
+ deleteScopedValue(namespace: string, key: string): void;
29
+ clearScope(namespace: string): void;
30
+ data(data: T[]): void;
31
+ add(items: T[]): void;
32
+ update(descriptor: UpdateDescriptor<T>): void;
33
+ clearData(): void;
34
+ removeByFieldValue(field: IndexableKey<T> & string, value: any): void;
35
+ removeByFieldValues(field: IndexableKey<T> & string, values: any[]): void;
36
+ private emit;
37
+ private getOrCreateScope;
38
+ private bumpMutationVersion;
39
+ private getOrCreateIndexMap;
40
+ private rebuildIndexMap;
41
+ private rebuildItemIndexLookup;
42
+ }
43
+
44
+ export { State as S };
@@ -0,0 +1 @@
1
+ import {a,b}from'./chunk-MB56OSRQ.mjs';function p(o){return {value:o,enumerable:false,configurable:true,writable:true}}var f=class{constructor(e){this.callbacks=e;}create(e){let t=e;return Object.defineProperties(t,{search:p((i,r)=>r===void 0?this.callbacks.search(i):this.callbacks.search(i,r)),sort:p((i,r,n)=>r===void 0?this.callbacks.sort(e,i,n):this.callbacks.sort(i,r,n)),filter:p((i,r)=>r===void 0?this.callbacks.filter(e,i):this.callbacks.filter(i,r)),add:p(i=>this.callbacks.add(i)),update:p(i=>this.callbacks.update(i)),clearIndexes:p(i=>(this.callbacks.clearIndexes(i),this.create(e))),clearData:p(i=>(this.callbacks.clearData(i),this.create(e))),data:p(i=>this.callbacks.data(i)),getOriginData:p(()=>this.callbacks.getOriginData())}),t}};function T(o){return typeof o=="object"&&o!==null}function M(o,e){return T(o)&&typeof o[e]=="function"}function F(o){return M(o,"search")&&M(o,"getOriginData")}function m(o){return M(o,"sort")&&M(o,"getOriginData")}function D(o){return M(o,"rawFilter")&&M(o,"getOriginData")}var I=o=>{let{prototype:e}=o;return D(e)?"filter":m(e)?"sort":F(e)?"search":null},x=(o,e,t,i)=>{let r=new o({data:e,state:t,...i});return D(r)?{moduleName:"filter",executeFilter:(n,s)=>s===void 0?r.rawFilter(n):r.rawFilter(n,s),clearIndexes:()=>r.clearIndexes()}:m(r)?{moduleName:"sort",executeSort:(n,s,l)=>s===void 0?r.sort(n):r.sort(n,s,l),clearIndexes:()=>r.clearIndexes()}:F(r)?{moduleName:"search",executeSearch:(n,s)=>s===void 0?r.search(n):r.search(n,s),clearIndexes:()=>r.clearIndexes()}:null};var y="deferSortMutationCacheUpdates",P="deferSearchMutationIndexUpdates",R="deferFilterMutationIndexUpdates",w={search:"TextSearchEngine",sort:"SortEngine",filter:"FilterEngine"};var d=class o extends Error{constructor(e){super(e),this.name="MergeEnginesError";}static unavailableEngine(e){let t=w[e];return new o(`MergeEngines: ${t} is not available.`)}static unavailableGetOriginData(){return new o("MergeEngines: getOriginData is not available.")}static invalidFilterByPreviousResultOption(){return new o('MergeEngines: "filter.filterByPreviousResult" is not supported. Configure "filterByPreviousResult" on the MergeEngines root options.')}};var C=class{constructor(e){this.previousSearchState=null;this.previousFilterState=null;this.previousSortState=null;let{imports:t,data:i,filterByPreviousResult:r=false,...n}=e;this.validateFilterByPreviousResultOptions(n.filter),this.state=new a(i,{filterByPreviousResult:r});let s=new Set(t),l=null,u=null,c=null;for(let a of s){let h=I(a);if(!h)continue;let v=this.getModuleInitOptions(h,a.name,n),g=x(a,i,this.state,v);g&&(g.moduleName==="search"&&!l&&(l=g),g.moduleName==="sort"&&!u&&(u=g),g.moduleName==="filter"&&!c&&(c=g));}this.searchModule=l,this.sortModule=u,this.filterModule=c,this.sortModule&&this.state.setScopedValue(b,y,true),this.searchModule&&this.state.setScopedValue(b,P,true),this.filterModule&&this.state.setScopedValue(b,R,true),this.state.subscribe(a=>this.handleStateMutation(a)),this.chainBuilder=new f({search:(a,h)=>h===void 0?this.search(a):this.search(a,h),sort:(a,h,v)=>this.sort(a,h,v),filter:(a,h)=>this.filter(a,h),getOriginData:()=>this.getOriginData(),add:a=>this.add(a),update:a=>this.update(a),data:a=>this.data(a),clearIndexes:a=>this.clearIndexes(a),clearData:a=>this.clearData(a)});}getAdapter(e){return e==="search"?this.searchModule:e==="sort"?this.sortModule:this.filterModule}getModuleInitOptions(e,t,i){let r={};for(let n of [e,t]){let s=i[n];T(s)&&Object.assign(r,s);}return r}validateFilterByPreviousResultOptions(e){if(T(e)&&Object.prototype.hasOwnProperty.call(e,"filterByPreviousResult"))throw d.invalidFilterByPreviousResultOption()}isPreviousResultEnabled(){return this.state.isFilterByPreviousResultEnabled()}getPreviousResultInput(){return this.isPreviousResultEnabled()?this.state.getPreviousResult():null}trackPreviousResult(e,t){return this.isPreviousResultEnabled()&&this.state.setPreviousResult(e,t),e}clearOperationState(e){(!e||e==="search")&&(this.previousSearchState=null),(!e||e==="filter")&&(this.previousFilterState=null),(!e||e==="sort")&&(this.previousSortState=null);}createSearchCacheKey(e,t){return JSON.stringify([e,t??null])}createSortCacheKey(e,t){return JSON.stringify({descriptors:e,inPlace:t??false})}createFilterCacheKey(e){return JSON.stringify(e)}handleStateMutation(e){switch(e.type){case "add":this.queueSearchCacheMutation(e),this.queueFilterCacheMutation(e),this.queueSortCacheMutation(e);return;case "update":this.queueSearchCacheMutation(e),this.queueFilterCacheMutation(e),this.queueSortCacheMutation(e);return;case "remove":this.previousSearchState=null,this.previousFilterState=null,this.queueSortCacheMutation(e);return;case "removeMany":this.previousSearchState=null,this.previousFilterState=null,this.queueSortCacheMutation(e);return;case "data":case "clearData":this.previousSearchState=null,this.previousFilterState=null,this.previousSortState=null;return}}queueSearchCacheMutation(e){let t=this.previousSearchState;if(t!==null){if(!this.canPatchStoredDatasetSearch(t)){this.previousSearchState=null;return}this.previousSearchState={...t,version:this.state.getMutationVersion(),pendingMutations:t.pendingMutations.concat(e)};}}queueFilterCacheMutation(e){let t=this.previousFilterState;if(t!==null){if(!this.canPatchStoredDatasetFilter(t)){this.previousFilterState=null;return}this.previousFilterState={...t,version:this.state.getMutationVersion(),pendingMutations:t.pendingMutations.concat(e)};}}queueSortCacheMutation(e){let t=this.previousSortState;if(t!==null){if(!this.canPatchStoredDatasetSort(t)){this.previousSortState=null;return}this.previousSortState={...t,version:this.state.getMutationVersion(),pendingMutations:t.pendingMutations.concat(e)};}}resolvePendingSortCache(e){if(e.pendingMutations.length===0)return e;let t={...e,pendingMutations:[]};for(let i=0;i<e.pendingMutations.length;i++)if(t=this.applySortCacheMutation(t,e.pendingMutations[i]),t===null)return null;return t}resolvePendingSearchCache(e){if(e.pendingMutations.length===0)return e;let t={...e,pendingMutations:[]};for(let i=0;i<e.pendingMutations.length;i++)if(t=this.applySearchCacheMutation(t,e.pendingMutations[i]),t===null)return null;return t}resolvePendingFilterCache(e){if(e.pendingMutations.length===0)return e;let t={...e,pendingMutations:[]};for(let i=0;i<e.pendingMutations.length;i++)if(t=this.applyFilterCacheMutation(t,e.pendingMutations[i]),t===null)return null;return t}applySortCacheMutation(e,t){switch(t.type){case "add":return this.patchSortCacheForAddedItems(e,t.items);case "update":return this.patchSortCacheForUpdatedItem(e,t.previousItem,t.nextItem);case "remove":return this.patchSortCacheForRemovedItems(e,[t.removedItem]);case "removeMany":return this.patchSortCacheForRemovedItems(e,t.entries.map(i=>i.removedItem));case "data":case "clearData":return null}}applySearchCacheMutation(e,t){switch(t.type){case "add":return this.patchSearchCacheForAddedItems(e,t.items);case "update":return this.patchSearchCacheForUpdatedItem(e,t.previousItem,t.nextItem);case "remove":case "removeMany":case "data":case "clearData":return null}}applyFilterCacheMutation(e,t){switch(t.type){case "add":return this.patchFilterCacheForAddedItems(e,t.items);case "update":return this.patchFilterCacheForUpdatedItem(e,t.previousItem,t.nextItem);case "remove":case "removeMany":case "data":case "clearData":return null}}canPatchStoredDatasetSearch(e){return e.originData===this.state.getOriginData()&&e.field!==null}canPatchStoredDatasetFilter(e){if(e.sourceData!==this.state.getOriginData())return false;for(let t=0;t<e.criteria.length;t++)if(!this.isPatchableFilterCriterion(e.criteria[t]))return false;return true}canPatchStoredDatasetSort(e){return e.sourceData===this.state.getOriginData()}compareItemsByDescriptors(e,t,i){for(let r=0;r<i.length;r++){let{field:n,direction:s}=i[r],l=e[n],u=t[n];if(l<u)return s==="asc"?-1:1;if(l>u)return s==="asc"?1:-1}return (this.state.getItemIndex(e)??-1)-(this.state.getItemIndex(t)??-1)}findSortInsertPosition(e,t,i){let r=0,n=e.length;for(;r<n;){let s=r+n>>1;this.compareItemsByDescriptors(e[s],t,i)<=0?r=s+1:n=s;}return r}findDatasetInsertPosition(e,t){let i=this.state.getItemIndex(t)??Number.MAX_SAFE_INTEGER;for(let r=0;r<e.length;r++)if((this.state.getItemIndex(e[r])??Number.MAX_SAFE_INTEGER)>i)return r;return e.length}doesItemMatchSearchCache(e,t){if(e.field===null||e.lowerQuery.length===0)return false;let i=t[e.field];return typeof i=="string"&&i.toLowerCase().includes(e.lowerQuery)}patchSearchCacheForAddedItems(e,t){if(!this.canPatchStoredDatasetSearch(e))return null;let i=e.result.slice();for(let r=0;r<t.length;r++){let n=t[r];this.doesItemMatchSearchCache(e,n)&&i.push(n);}return {...e,result:i,pendingMutations:[],version:this.state.getMutationVersion()}}patchSearchCacheForUpdatedItem(e,t,i){if(!this.canPatchStoredDatasetSearch(e))return null;let r=e.result.slice(),n=r.indexOf(t),s=this.doesItemMatchSearchCache(e,i);if(n!==-1)s?r[n]=i:r.splice(n,1);else if(s){let l=this.findDatasetInsertPosition(r,i);r.splice(l,0,i);}return {...e,result:r,pendingMutations:[],version:this.state.getMutationVersion()}}isPatchableFilterCriterion(e){return !String(e.field).includes(".")}doesItemMatchFilterCache(e,t){for(let i=0;i<e.criteria.length;i++){let r=e.criteria[i];if(!this.isPatchableFilterCriterion(r))return false;let n=t[r.field];if(r.values!==void 0&&r.values.length>0&&!r.values.includes(n)||r.exclude!==void 0&&r.exclude.length>0&&r.exclude.includes(n))return false}return true}patchFilterCacheForAddedItems(e,t){if(!this.canPatchStoredDatasetFilter(e))return null;let i=e.result.slice();for(let r=0;r<t.length;r++){let n=t[r];this.doesItemMatchFilterCache(e,n)&&i.push(n);}return {...e,result:i,pendingMutations:[],version:this.state.getMutationVersion()}}patchFilterCacheForUpdatedItem(e,t,i){if(!this.canPatchStoredDatasetFilter(e))return null;let r=e.result.slice(),n=r.indexOf(t),s=this.doesItemMatchFilterCache(e,i);if(n!==-1)s?r[n]=i:r.splice(n,1);else if(s){let l=this.findDatasetInsertPosition(r,i);r.splice(l,0,i);}return {...e,result:r,pendingMutations:[],version:this.state.getMutationVersion()}}patchSortCacheForAddedItems(e,t){if(!this.canPatchStoredDatasetSort(e))return null;let i=e.result.slice();for(let r=0;r<t.length;r++){let n=t[r],s=this.findSortInsertPosition(i,n,e.descriptors);i.splice(s,0,n);}return {...e,result:i,pendingMutations:[],version:this.state.getMutationVersion()}}patchSortCacheForUpdatedItem(e,t,i){if(!this.canPatchStoredDatasetSort(e))return null;let r=e.result.slice(),n=r.indexOf(t);if(n===-1)return e.result.indexOf(i)!==-1?{...e,pendingMutations:[],version:this.state.getMutationVersion()}:null;if(!e.descriptors.some(({field:u})=>t[u]!==i[u]))return r[n]=i,{...e,result:r,pendingMutations:[],version:this.state.getMutationVersion()};r.splice(n,1);let l=this.findSortInsertPosition(r,i,e.descriptors);return r.splice(l,0,i),{...e,result:r,pendingMutations:[],version:this.state.getMutationVersion()}}patchSortCacheForRemovedItems(e,t){if(!this.canPatchStoredDatasetSort(e))return null;let i=new Set(t);return {...e,result:Array.prototype.filter.call(e.result,r=>!i.has(r)),pendingMutations:[],version:this.state.getMutationVersion()}}search(e,t){if(!this.searchModule)throw d.unavailableEngine("search");let i=this.state.getOriginData(),r=this.state.getMutationVersion(),n=this.createSearchCacheKey(e,t),s=this.previousSearchState;if(s?.originData===i&&s.key===n&&s.version===r){let u=this.resolvePendingSearchCache(s);if(u!==null)return this.previousSearchState=u,this.withChain(this.trackPreviousResult(u.result,i));this.previousSearchState=null;}let l=t===void 0?this.searchModule.executeSearch(e):this.searchModule.executeSearch(e,t);return this.previousSearchState={key:n,originData:i,result:l,version:r,field:t===void 0?null:e,lowerQuery:(t??e).trim().toLowerCase(),pendingMutations:[]},this.withChain(this.trackPreviousResult(l,i))}sort(e,t,i){if(!this.sortModule)throw d.unavailableEngine("sort");let r,n;if(t===void 0?(n=e,r=this.getPreviousResultInput()??this.state.getOriginData()):(r=e,n=t),!i){let s=this.state.getMutationVersion(),l=this.createSortCacheKey(n,i),u=this.previousSortState;if(u?.sourceData===r&&u.key===l&&u.version===s){let a=this.resolvePendingSortCache(u);if(a!==null)return this.previousSortState=a,this.withChain(this.trackPreviousResult(a.result,r));this.previousSortState=null;}let c=t===void 0&&r===this.state.getOriginData()?this.sortModule.executeSort(n):this.sortModule.executeSort(r,n,i);return this.previousSortState={key:l,sourceData:r,result:c,version:s,descriptors:n,pendingMutations:[]},this.withChain(this.trackPreviousResult(c,r))}return this.withChain(this.trackPreviousResult(this.sortModule.executeSort(r,n,i),r))}filter(e,t){if(!this.filterModule)throw d.unavailableEngine("filter");if(t===void 0){let r=this.getPreviousResultInput(),n=r??this.state.getOriginData(),s=e,l=this.state.getMutationVersion(),u=this.createFilterCacheKey(s),c=this.previousFilterState;if(c?.sourceData===n&&c.key===u&&c.version===l){let h=this.resolvePendingFilterCache(c);if(h!==null)return this.previousFilterState=h,this.withChain(this.trackPreviousResult(h.result,n));this.previousFilterState=null;}let a=r===null?this.filterModule.executeFilter(s):this.filterModule.executeFilter(r,s);return this.previousFilterState={key:u,sourceData:n,result:a,version:l,criteria:s,pendingMutations:[]},this.withChain(this.trackPreviousResult(a,n))}let i=e;return this.withChain(this.trackPreviousResult(this.filterModule.executeFilter(i,t),i))}withChain(e){return this.chainBuilder.create(e)}getOriginData(){if(this.searchModule||this.sortModule||this.filterModule)return this.state.getOriginData();throw d.unavailableGetOriginData()}add(e){return e.length===0?this:(this.state.add(e),this)}update(e){return this.state.update(e),this}clearIndexes(e){let t=this.getAdapter(e);if(t)return t.clearIndexes(),this.clearOperationState(e),this;throw d.unavailableEngine(e)}data(e){return this.state.data(e),this}clearData(e){if(this.getAdapter(e))return this.state.clearData(),this;throw d.unavailableEngine(e)}};export{C as a};
@@ -0,0 +1 @@
1
+ var g=class{constructor(e=[],t={}){this.itemIndexLookup=new WeakMap;this.mutationVersion=0;this.namespaceSequence=0;this.previousResultState=null;this.indexMaps=new Map;this.scopedRegistry=new Map;this.listeners=new Set;this.originData=e,this.filterByPreviousResult=t.filterByPreviousResult??false,this.rebuildItemIndexLookup();}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e);}}getOriginData(){return this.originData}getItemIndex(e){return this.itemIndexLookup.get(e)}getMutationVersion(){return this.mutationVersion}isFilterByPreviousResultEnabled(){return this.filterByPreviousResult}setFilterByPreviousResult(e){this.filterByPreviousResult=e,e||this.clearPreviousResult();}getPreviousResult(){return this.getPreviousResultState()?.result??null}getPreviousResultState(){return this.previousResultState===null||this.previousResultState.version!==this.mutationVersion?null:this.previousResultState}setPreviousResult(e,t){this.previousResultState={result:e,sourceData:t,version:this.mutationVersion};}clearPreviousResult(){this.previousResultState=null;}createNamespace(e="scope"){return this.namespaceSequence+=1,`${e}:${this.namespaceSequence}`}getScopedValue(e,t){return this.scopedRegistry.get(e)?.get(t)}getOrCreateScopedValue(e,t,i){let n=this.getScopedValue(e,t);if(n!==void 0)return n;let o=this.getOrCreateScope(e),r=i();return o.set(t,r),r}setScopedValue(e,t,i){return this.getOrCreateScope(e).set(t,i),i}deleteScopedValue(e,t){let i=this.scopedRegistry.get(e);i&&(i.delete(t),i.size===0&&this.scopedRegistry.delete(e));}clearScope(e){this.scopedRegistry.delete(e);}data(e){this.originData=e,this.bumpMutationVersion(),this.rebuildItemIndexLookup();for(let t of this.indexMaps.keys())this.rebuildIndexMap(t);this.emit({type:"data",data:e});}add(e){if(e.length===0)return;let t=this.originData.length;for(let i=0;i<e.length;i++)this.originData.push(e[i]),this.itemIndexLookup.set(e[i],t+i);this.bumpMutationVersion();for(let[i,n]of this.indexMaps)for(let o=0;o<e.length;o++)n.set(e[o][i],t+o);this.emit({type:"add",items:e,startIndex:t});}update(e){let{field:t,data:i}=e,n=i[t];if(n==null)return;let r=this.getOrCreateIndexMap(t).get(n);if(r===void 0)return;let s=this.originData[r];this.originData[r]=i,this.itemIndexLookup.delete(s),this.itemIndexLookup.set(i,r),this.bumpMutationVersion();for(let[d,u]of this.indexMaps){let a=s[d],l=i[d];a!==l&&(u.get(a)===r&&u.delete(a),u.set(l,r));}this.emit({type:"update",field:t,index:r,previousItem:s,nextItem:i});}clearData(){let e=[];this.originData=e,this.itemIndexLookup=new WeakMap,this.bumpMutationVersion();for(let t of this.indexMaps.values())t.clear();this.emit({type:"clearData",data:e});}removeByFieldValue(e,t){let n=this.getOrCreateIndexMap(e).get(t);if(n===void 0)return;let o=this.originData.length-1,r=this.originData[n],s=n===o?null:this.originData[o];n!==o&&s&&(this.originData[n]=s,this.itemIndexLookup.set(s,n)),this.originData.pop(),this.itemIndexLookup.delete(r),this.bumpMutationVersion();for(let[d,u]of this.indexMaps){let a=r[d];u.get(a)===n&&u.delete(a),s&&u.set(s[d],n);}this.emit({type:"remove",field:e,value:t,removedItem:r,removedIndex:n,movedItem:s,movedFromIndex:s?o:null});}removeByFieldValues(e,t){if(t.length===0)return;let i=this.getOrCreateIndexMap(e),n=[];for(let o=0;o<t.length;o++){let r=t[o],s=i.get(r);if(s===void 0)continue;let d=this.originData.length-1,u=this.originData[s],a=s===d?null:this.originData[d];s!==d&&a&&(this.originData[s]=a,this.itemIndexLookup.set(a,s)),this.originData.pop(),this.itemIndexLookup.delete(u);for(let[l,p]of this.indexMaps){let h=u[l];p.get(h)===s&&p.delete(h),a&&p.set(a[l],s);}n.push({value:r,removedItem:u,removedIndex:s,movedItem:a,movedFromIndex:a?d:null});}n.length!==0&&(this.bumpMutationVersion(),this.emit({type:"removeMany",field:e,entries:n}));}emit(e){for(let t of this.listeners)t(e);}getOrCreateScope(e){let t=this.scopedRegistry.get(e);if(t)return t;let i=new Map;return this.scopedRegistry.set(e,i),i}bumpMutationVersion(){this.mutationVersion+=1,this.clearPreviousResult();}getOrCreateIndexMap(e){let t=this.indexMaps.get(e);return t||this.rebuildIndexMap(e)}rebuildIndexMap(e){let t=new Map;for(let i=0;i<this.originData.length;i++)t.set(this.originData[i][e],i);return this.indexMaps.set(e,t),t}rebuildItemIndexLookup(){this.itemIndexLookup=new WeakMap;for(let e=0;e<this.originData.length;e++)this.itemIndexLookup.set(this.originData[e],e);}};var m="__merge__";export{g as a,m as b};
@@ -1,11 +1,13 @@
1
- import { C as CollectionItem, F as FilterCriterion } from '../types-4YEflcxU.mjs';
2
- export { I as IndexableKey } from '../types-4YEflcxU.mjs';
1
+ import { S as State } from '../State-2vKzwNrQ.mjs';
2
+ import { C as CollectionItem, F as FilterCriterion, U as UpdateDescriptor } from '../types-DONld7xY.mjs';
3
+ export { I as IndexableKey } from '../types-DONld7xY.mjs';
3
4
 
4
5
  interface FilterEngineChain<T extends CollectionItem> {
5
6
  filter(criteria: FilterCriterion<T>[]): T[] & FilterEngineChain<T>;
6
7
  filter(data: T[], criteria: FilterCriterion<T>[]): T[] & FilterEngineChain<T>;
7
8
  getOriginData(): T[];
8
9
  add(items: T[]): FilterEngine<T>;
10
+ update(descriptor: UpdateDescriptor<T>): FilterEngine<T>;
9
11
  data(data: T[]): FilterEngine<T>;
10
12
  clearIndexes(): FilterEngine<T>;
11
13
  clearData(): FilterEngine<T>;
@@ -25,23 +27,27 @@ interface FilterEngineOptions<T extends CollectionItem = CollectionItem> {
25
27
  */
26
28
 
27
29
  declare class FilterEngine<T extends CollectionItem> {
28
- private indexer;
30
+ private readonly indexer;
29
31
  private readonly filterByPreviousResult;
30
32
  private readonly mutableExcludeField;
31
- private dataset;
32
- private readonly datasetPositions;
33
- private hasDuplicateMutableExcludeValues;
34
- private readonly indexedFields;
33
+ private readonly state;
34
+ private readonly namespace;
35
35
  private readonly nestedCollection;
36
- private previousResult;
37
- private previousCriteria;
38
- private previousBaseData;
39
- private readonly previousResultsByCriteria;
40
36
  private readonly chainBuilder;
41
37
  /**
42
38
  * Creates a new FilterEngine with optional data and fields to index.
43
39
  */
44
- constructor(options?: FilterEngineOptions<T>);
40
+ constructor(options?: FilterEngineOptions<T> & {
41
+ state?: State<T>;
42
+ });
43
+ private get dataset();
44
+ private get runtime();
45
+ private get mutableExcludeState();
46
+ private get indexedFields();
47
+ private get sequentialCache();
48
+ private shouldDeferMutationIndexUpdates;
49
+ private markDeferredMutationState;
50
+ private ensureRuntimeReady;
45
51
  private rebuildConfiguredIndexes;
46
52
  /**
47
53
  * Builds an index for the given field.
@@ -52,6 +58,7 @@ declare class FilterEngine<T extends CollectionItem> {
52
58
  clearData(): this;
53
59
  data(data: T[]): this;
54
60
  add(items: T[]): this;
61
+ update(descriptor: UpdateDescriptor<T>): this;
55
62
  private applyAddedItems;
56
63
  getOriginData(): T[];
57
64
  /**
@@ -61,11 +68,19 @@ declare class FilterEngine<T extends CollectionItem> {
61
68
  filter(data: T[], criteria: FilterCriterion<T>[]): T[] & FilterEngineChain<T>;
62
69
  rawFilter(criteria: FilterCriterion<T>[]): T[];
63
70
  rawFilter(data: T[], criteria: FilterCriterion<T>[]): T[];
71
+ private resolveWithSequentialCache;
64
72
  private withChain;
73
+ private handleStateMutation;
65
74
  private rebuildMutableExcludeState;
66
75
  private updateMutableExcludeStateForAddedItems;
67
76
  private applyMutableExclude;
68
- private removeStoredItem;
77
+ private applyUpdatedItem;
78
+ private applyRemovedItem;
79
+ private applyRemovedItems;
80
+ private updateMutableExcludeStateForUpdatedItem;
81
+ private clearMutableExcludeState;
82
+ private registerMutableExcludeValue;
83
+ private unregisterMutableExcludeValue;
69
84
  /**
70
85
  * Filters data linearly without index.
71
86
  */
@@ -82,6 +97,7 @@ declare class FilterEngine<T extends CollectionItem> {
82
97
  private createEmptyResult;
83
98
  private storePreviousResult;
84
99
  private createCriteriaCacheKey;
100
+ private createSequentialCacheEntry;
85
101
  private createSequentialExecutionCriteria;
86
102
  private hasCriteriaBacktrack;
87
103
  private canApplySequentiallyToEmptyResult;