@devisfuture/mega-collection 2.4.5 → 2.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +2 -2
  2. package/dist/State.d.ts +42 -0
  3. package/dist/{chunk-BJZg_1dI.mjs → State.mjs} +2 -2
  4. package/dist/constants.d.ts +5 -0
  5. package/dist/constants.mjs +4 -0
  6. package/dist/filter/chain.d.ts +9 -0
  7. package/dist/filter/chain.mjs +22 -0
  8. package/dist/filter/constants.d.ts +2 -0
  9. package/dist/filter/criterion.d.ts +6 -0
  10. package/dist/filter/criterion.mjs +64 -0
  11. package/dist/filter/errors.d.ts +7 -0
  12. package/dist/filter/errors.mjs +17 -0
  13. package/dist/filter/filter.d.ts +89 -0
  14. package/dist/filter/filter.mjs +439 -0
  15. package/dist/filter/index.mjs +2 -891
  16. package/dist/filter/nested.d.ts +32 -0
  17. package/dist/filter/nested.mjs +246 -0
  18. package/dist/filter/types.d.ts +74 -0
  19. package/dist/filter/utils.d.ts +4 -0
  20. package/dist/filter/utils.mjs +29 -0
  21. package/dist/index.mjs +1 -1
  22. package/dist/indexer.d.ts +41 -0
  23. package/dist/indexer.mjs +101 -0
  24. package/dist/internal.d.ts +6 -0
  25. package/dist/{chunk-C5Zpu_ol.mjs → internal.mjs} +1 -1
  26. package/dist/merge/chain.d.ts +9 -0
  27. package/dist/merge/chain.mjs +23 -0
  28. package/dist/merge/constants.d.ts +6 -0
  29. package/dist/merge/constants.mjs +8 -0
  30. package/dist/merge/errors.d.ts +8 -0
  31. package/dist/merge/errors.mjs +19 -0
  32. package/dist/merge/index.mjs +1 -1
  33. package/dist/merge/merge-engines.d.ts +75 -0
  34. package/dist/{chunk-BURK5sks.mjs → merge/merge-engines.mjs} +35 -108
  35. package/dist/merge/module-adapters.d.ts +7 -0
  36. package/dist/merge/module-adapters.mjs +41 -0
  37. package/dist/merge/types.d.ts +125 -0
  38. package/dist/search/constants.d.ts +5 -0
  39. package/dist/search/index.mjs +2 -1010
  40. package/dist/search/nested.d.ts +41 -0
  41. package/dist/search/nested.mjs +210 -0
  42. package/dist/search/ngram.d.ts +23 -0
  43. package/dist/search/ngram.mjs +96 -0
  44. package/dist/search/text-search.d.ts +146 -0
  45. package/dist/search/text-search.mjs +696 -0
  46. package/dist/search/types.d.ts +93 -0
  47. package/dist/search/utils.d.ts +4 -0
  48. package/dist/search/utils.mjs +22 -0
  49. package/dist/sort/errors.d.ts +5 -0
  50. package/dist/sort/errors.mjs +11 -0
  51. package/dist/sort/index.mjs +2 -416
  52. package/dist/sort/sorter.d.ts +47 -0
  53. package/dist/sort/sorter.mjs +375 -0
  54. package/dist/sort/types.d.ts +18 -0
  55. package/dist/sort/utils.d.ts +17 -0
  56. package/dist/sort/utils.mjs +38 -0
  57. package/dist/types.d.ts +73 -0
  58. package/package.json +11 -34
  59. /package/dist/filter/{index.d.mts → index.d.ts} +0 -0
  60. /package/dist/{index.d.mts → index.d.ts} +0 -0
  61. /package/dist/merge/{index.d.mts → index.d.ts} +0 -0
  62. /package/dist/search/{index.d.mts → index.d.ts} +0 -0
  63. /package/dist/sort/{index.d.mts → index.d.ts} +0 -0
package/README.md CHANGED
@@ -52,9 +52,9 @@ This works fine for small arrays. But with 10 000–100 000+ items, every call t
52
52
 
53
53
  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.
54
54
 
55
- The package has no dependencies.
56
- You can import only the parts you need.
55
+ ### Important
57
56
 
57
+ The package has no dependencies. You can import only the parts you need.
58
58
  Each engine has its own entry point: `/search`, `/filter`, `/sort`.
59
59
  If you import only `@devisfuture/mega-collection/search`, only search code goes into the bundle.
60
60
  Unused modules are not included.
@@ -0,0 +1,42 @@
1
+ import type { CollectionItem, IndexableKey, StateListener, StateOptions, StatePreviousResult, StateRegistryFactory, UpdateDescriptor } from "./types";
2
+ export declare class State<T extends CollectionItem> {
3
+ private originData;
4
+ private filterByPreviousResult;
5
+ private itemIndexLookup;
6
+ private mutationVersion;
7
+ private namespaceSequence;
8
+ private previousResultState;
9
+ private readonly indexMaps;
10
+ private readonly scopedRegistry;
11
+ private readonly listeners;
12
+ constructor(data?: T[], options?: StateOptions);
13
+ subscribe(listener: StateListener<T>): () => void;
14
+ getOriginData(): T[];
15
+ getItemIndex(item: T): number | undefined;
16
+ getMutationVersion(): number;
17
+ isFilterByPreviousResultEnabled(): boolean;
18
+ setFilterByPreviousResult(enabled: boolean): void;
19
+ getPreviousResult(): T[] | null;
20
+ getPreviousResultState(): StatePreviousResult<T> | null;
21
+ setPreviousResult(result: T[], sourceData: T[]): void;
22
+ clearPreviousResult(): void;
23
+ createNamespace(prefix?: string): string;
24
+ getScopedValue<TValue>(namespace: string, key: string): TValue | undefined;
25
+ getOrCreateScopedValue<TValue>(namespace: string, key: string, createValue: StateRegistryFactory<TValue>): TValue;
26
+ setScopedValue<TValue>(namespace: string, key: string, value: TValue): TValue;
27
+ deleteScopedValue(namespace: string, key: string): void;
28
+ clearScope(namespace: string): void;
29
+ data(data: T[]): void;
30
+ add(items: T[]): void;
31
+ update(descriptor: UpdateDescriptor<T>): void;
32
+ clearData(): void;
33
+ removeByFieldValue(field: IndexableKey<T> & string, value: any): void;
34
+ removeByFieldValues(field: IndexableKey<T> & string, values: any[]): void;
35
+ private emit;
36
+ private getOrCreateScope;
37
+ private bumpMutationVersion;
38
+ private getOrCreateIndexMap;
39
+ private rebuildIndexMap;
40
+ private rebuildItemIndexLookup;
41
+ }
42
+ //# sourceMappingURL=State.d.ts.map
@@ -178,6 +178,6 @@ var e = class {
178
178
  this.itemIndexLookup = /* @__PURE__ */ new WeakMap();
179
179
  for (let e = 0; e < this.originData.length; e++) this.itemIndexLookup.set(this.originData[e], e);
180
180
  }
181
- }, t = "__merge__", n = "deferFilterMutationIndexUpdates", r = "deferSearchMutationIndexUpdates", i = "deferSortMutationCacheUpdates";
181
+ };
182
182
  //#endregion
183
- export { e as a, t as i, r as n, i as r, n as t };
183
+ export { e as State };
@@ -0,0 +1,5 @@
1
+ export declare const MERGE_SHARED_SCOPE = "__merge__";
2
+ export declare const DEFER_FILTER_MUTATION_INDEX_UPDATES_KEY = "deferFilterMutationIndexUpdates";
3
+ export declare const DEFER_SEARCH_MUTATION_INDEX_UPDATES_KEY = "deferSearchMutationIndexUpdates";
4
+ export declare const DEFER_SORT_MUTATION_CACHE_UPDATES_KEY = "deferSortMutationCacheUpdates";
5
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1,4 @@
1
+ //#region src/constants.ts
2
+ var e = "__merge__", t = "deferFilterMutationIndexUpdates", n = "deferSearchMutationIndexUpdates", r = "deferSortMutationCacheUpdates";
3
+ //#endregion
4
+ export { t as DEFER_FILTER_MUTATION_INDEX_UPDATES_KEY, n as DEFER_SEARCH_MUTATION_INDEX_UPDATES_KEY, r as DEFER_SORT_MUTATION_CACHE_UPDATES_KEY, e as MERGE_SHARED_SCOPE };
@@ -0,0 +1,9 @@
1
+ import type { CollectionItem } from "../types";
2
+ import type { FilterEngineChain, FilterEngineChainCallbacks } from "./types";
3
+ export type { FilterEngineChain } from "./types";
4
+ export declare class FilterEngineChainBuilder<T extends CollectionItem> {
5
+ private readonly callbacks;
6
+ constructor(callbacks: FilterEngineChainCallbacks<T>);
7
+ create(result: T[]): T[] & FilterEngineChain<T>;
8
+ }
9
+ //# sourceMappingURL=chain.d.ts.map
@@ -0,0 +1,22 @@
1
+ import { createChainMethodDescriptor as e } from "../internal.mjs";
2
+ //#region src/filter/chain.ts
3
+ var t = class {
4
+ constructor(e) {
5
+ this.callbacks = e;
6
+ }
7
+ create(t) {
8
+ let n = t;
9
+ return Object.defineProperties(n, {
10
+ filter: e((e, n) => n === void 0 ? this.callbacks.filter(t, e) : this.callbacks.filter(e, n)),
11
+ add: e((e) => this.callbacks.add(e)),
12
+ update: e((e) => this.callbacks.update(e)),
13
+ clearIndexes: e(() => this.callbacks.clearIndexes()),
14
+ data: e((e) => this.callbacks.data(e)),
15
+ getOriginData: e(() => this.callbacks.getOriginData()),
16
+ clearData: e(() => this.callbacks.clearData()),
17
+ resetFilterState: e(() => this.callbacks.resetFilterState())
18
+ }), n;
19
+ }
20
+ };
21
+ //#endregion
22
+ export { t as FilterEngineChainBuilder };
@@ -0,0 +1,2 @@
1
+ export { DEFER_FILTER_MUTATION_INDEX_UPDATES_KEY } from "../constants";
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1,6 @@
1
+ import type { CollectionItem, FilterCriterion } from "../types";
2
+ import type { ResolvedFilterCriterion } from "./types";
3
+ export declare function resolveCriteria<T extends CollectionItem>(criteria: FilterCriterion<T>[]): ResolvedFilterCriterion<T>[];
4
+ export declare function matchesCriterionValue<T extends CollectionItem>(criterion: ResolvedFilterCriterion<T>, value: any): boolean;
5
+ export declare function isCriterionUnsatisfiable<T extends CollectionItem>(criterion: ResolvedFilterCriterion<T>): boolean;
6
+ //# sourceMappingURL=criterion.d.ts.map
@@ -0,0 +1,64 @@
1
+ //#region src/filter/criterion.ts
2
+ function e(e) {
3
+ let t = /* @__PURE__ */ new Map();
4
+ for (let n = 0; n < e.length; n++) {
5
+ let a = e[n], o = Array.isArray(a.values), s = r(a.exclude), c = s !== null, l = o ? i(a.values, s) : null;
6
+ if (!o && !c) continue;
7
+ let u = a.field, d = t.get(u);
8
+ if (!d) {
9
+ t.set(u, {
10
+ field: a.field,
11
+ values: [],
12
+ exclude: [],
13
+ hasValues: o,
14
+ hasExclude: c,
15
+ includedValues: l ? new Set(l) : null,
16
+ excludedValues: s ? new Set(s) : null,
17
+ cacheKeySegment: ""
18
+ });
19
+ continue;
20
+ }
21
+ if (o) if (!d.hasValues) d.hasValues = !0, d.includedValues = new Set(l);
22
+ else for (let e of d.includedValues) l.has(e) || d.includedValues.delete(e);
23
+ if (c) if (!d.hasExclude) d.hasExclude = !0, d.excludedValues = new Set(s);
24
+ else for (let e of s) d.excludedValues.add(e);
25
+ }
26
+ let n = [...t.values()].sort((e, t) => e.field.localeCompare(t.field));
27
+ for (let e = 0; e < n.length; e++) a(n[e]);
28
+ return n;
29
+ }
30
+ function t(e, t) {
31
+ return !(e.hasValues && !e.includedValues.has(t) || e.hasExclude && e.excludedValues.has(t));
32
+ }
33
+ function n(e) {
34
+ return e.hasValues && e.values.length === 0;
35
+ }
36
+ function r(e) {
37
+ return !Array.isArray(e) || e.length === 0 ? null : new Set(e);
38
+ }
39
+ function i(e, t) {
40
+ let n = /* @__PURE__ */ new Set();
41
+ for (let r = 0; r < e.length; r++) {
42
+ let i = e[r];
43
+ t?.has(i) || n.add(i);
44
+ }
45
+ return n;
46
+ }
47
+ function a(e) {
48
+ if (e.hasValues && e.hasExclude) for (let t of e.excludedValues) e.includedValues.delete(t);
49
+ e.values = e.includedValues ? [...e.includedValues] : [], e.exclude = e.excludedValues ? [...e.excludedValues] : [], e.cacheKeySegment = o(e);
50
+ }
51
+ function o(e) {
52
+ let t = e.field;
53
+ return t += `|hv:${e.hasValues ? "1" : "0"}|v:`, e.hasValues && (t += s(e.values)), t += `|hx:${e.hasExclude ? "1" : "0"}|x:`, e.hasExclude && (t += s(e.exclude)), t;
54
+ }
55
+ function s(e) {
56
+ return e.length === 0 ? "" : e.map((e) => c(e)).sort().join(",");
57
+ }
58
+ function c(e) {
59
+ if (e === null) return "null:null";
60
+ let t = typeof e;
61
+ return t === "object" ? `object:${JSON.stringify(e)}` : `${t}:${String(e)}`;
62
+ }
63
+ //#endregion
64
+ export { n as isCriterionUnsatisfiable, t as matchesCriterionValue, e as resolveCriteria };
@@ -0,0 +1,7 @@
1
+ export declare class FilterEngineError extends Error {
2
+ constructor(message: string);
3
+ static missingDatasetForBuildIndex(): FilterEngineError;
4
+ static missingDatasetForFilter(): FilterEngineError;
5
+ static duplicateMutableExcludeField(field: string): FilterEngineError;
6
+ }
7
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,17 @@
1
+ //#region src/filter/errors.ts
2
+ var e = class e extends Error {
3
+ constructor(e) {
4
+ super(e), this.name = "FilterEngineError";
5
+ }
6
+ static missingDatasetForBuildIndex() {
7
+ return new e("FilterEngine: no dataset in memory. Call data() or add() before buildIndex().");
8
+ }
9
+ static missingDatasetForFilter() {
10
+ return new e("FilterEngine: no dataset in memory. Call data() or add() before filter().");
11
+ }
12
+ static duplicateMutableExcludeField(t) {
13
+ return new e(`FilterEngine: cannot use mutable exclude on field \`${t}\` because it contains duplicate values.`);
14
+ }
15
+ };
16
+ //#endregion
17
+ export { e as FilterEngineError };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * FilterEngine class for filtering collections by multiple criteria,
3
+ * supporting indexed lookups and linear scans for large datasets.
4
+ */
5
+ import { State } from "../State";
6
+ import { CollectionItem, FilterCriterion, type UpdateDescriptor } from "../types";
7
+ import { FilterEngineChain } from "./chain";
8
+ import type { FilterEngineOptions } from "./types";
9
+ export declare class FilterEngine<T extends CollectionItem> {
10
+ private readonly indexer;
11
+ private readonly filterByPreviousResult;
12
+ private readonly mutableExcludeField;
13
+ private readonly state;
14
+ private readonly namespace;
15
+ private readonly nestedCollection;
16
+ private readonly chainBuilder;
17
+ /**
18
+ * Creates a new FilterEngine with optional data and fields to index.
19
+ */
20
+ constructor(options?: FilterEngineOptions<T> & {
21
+ state?: State<T>;
22
+ });
23
+ private get dataset();
24
+ private get runtime();
25
+ private get mutableExcludeState();
26
+ private get indexedFields();
27
+ private get sequentialCache();
28
+ private shouldDeferMutationIndexUpdates;
29
+ private markDeferredMutationState;
30
+ private ensureRuntimeReady;
31
+ private rebuildConfiguredIndexes;
32
+ /**
33
+ * Builds an index for the given field.
34
+ */
35
+ private buildIndex;
36
+ clearIndexes(): this;
37
+ resetFilterState(): this;
38
+ clearData(): this;
39
+ data(data: T[]): this;
40
+ add(items: T[]): this;
41
+ update(descriptor: UpdateDescriptor<T>): this;
42
+ private applyAddedItems;
43
+ getOriginData(): T[];
44
+ /**
45
+ * Filters the data based on the given criteria.
46
+ */
47
+ filter(criteria: FilterCriterion<T>[]): T[] & FilterEngineChain<T>;
48
+ filter(data: T[], criteria: FilterCriterion<T>[]): T[] & FilterEngineChain<T>;
49
+ rawFilter(criteria: FilterCriterion<T>[]): T[];
50
+ rawFilter(data: T[], criteria: FilterCriterion<T>[]): T[];
51
+ private resolveWithSequentialCache;
52
+ private withChain;
53
+ private handleStateMutation;
54
+ private rebuildMutableExcludeState;
55
+ private updateMutableExcludeStateForAddedItems;
56
+ private applyMutableExclude;
57
+ private applyUpdatedItem;
58
+ private applyRemovedItem;
59
+ private applyRemovedItems;
60
+ private updateMutableExcludeStateForUpdatedItem;
61
+ private clearMutableExcludeState;
62
+ private registerMutableExcludeValue;
63
+ private unregisterMutableExcludeValue;
64
+ /**
65
+ * Filters data linearly without index.
66
+ */
67
+ private linearFilter;
68
+ /**
69
+ * Filters data using the index.
70
+ */
71
+ private filterViaIndex;
72
+ /**
73
+ * Estimates the size of the index for a criterion.
74
+ */
75
+ private estimateIndexSize;
76
+ private applyIndexedExclusions;
77
+ private createEmptyResult;
78
+ private storePreviousResult;
79
+ private createCriteriaCacheKey;
80
+ private createSequentialCacheEntry;
81
+ private createSequentialExecutionCriteria;
82
+ private hasCriteriaBacktrack;
83
+ private canApplySequentiallyToEmptyResult;
84
+ private createCriteriaStateMap;
85
+ private isCriterionBacktracked;
86
+ private isSubset;
87
+ private areSetsEqual;
88
+ }
89
+ //# sourceMappingURL=filter.d.ts.map