@devisfuture/mega-collection 1.1.2 → 1.1.5

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,7 +10,7 @@
10
10
 
11
11
  What does this package solve?
12
12
 
13
- Sometimes in projects, you need to iterate through huge collections (20,000, 40,000, 80,000 elements in an array) that have come from the server. Usually, the most common features are searching, filtering, and sorting.
13
+ Sometimes in projects, you need to iterate through huge collections (100K+ elements in an array) that have come from the server. Usually, the most common features are searching, filtering, and sorting.
14
14
  So, this package helps to perform searching, filtering, and sorting of large collections faster than standard JavaScript methods. This operation is performed before rendering the UI content.
15
15
 
16
16
  Zero dependencies. Tree-shakeable. Import only what you need.
@@ -83,7 +83,7 @@ const engine = new MergeEngines<User>({
83
83
  // dataset is passed once at init — no need to repeat it in every call
84
84
  engine.search("john");
85
85
  engine.sort([{ field: "age", direction: "asc" }]);
86
- engine.filter([{ field: "city", values: ["Kyiv", "Lviv"] }]);
86
+ engine.filter([{ field: "city", values: ["Miami", "New York"] }]);
87
87
  ```
88
88
 
89
89
  ---
@@ -102,13 +102,12 @@ const engine = new TextSearchEngine<User>({
102
102
  minQueryLength: 2, // begins searching when query length >= 2
103
103
  });
104
104
 
105
- // note: inputs shorter than `minQueryLength` intentionally clear the
106
- // result set. A one‑character search usually matches most of the dataset,
107
- // so bypassing that work makes typing feel snappier. When the query length
108
- // hits the threshold or exceeds it, the indexed search runs and query
109
- // performance improves dramatically. Empty/blank queries still return an
110
- // empty array, whereas short nonblank queries return the previous valid
111
- // result so the UI doesn’t flush on every keystroke.
105
+ // note: inputs shorter than `minQueryLength` bypass the indexed search and
106
+ // simply return the original dataset (rather than clearing the result).
107
+ // A one‑character search usually matches most of the dataset, so avoiding
108
+ // extra work makes typing feel snappier. Once the query reaches the
109
+ // threshold the indexed search kicks in and performance improves
110
+ // dramatically. Empty/blank queries still return an empty array.
112
111
 
113
112
  engine.search("john"); // searches all indexed fields, deduplicated
114
113
  engine.search("name", "john"); // searches a specific field
@@ -130,13 +129,13 @@ const engine = new FilterEngine<User>({
130
129
  });
131
130
 
132
131
  engine.filter([
133
- { field: "city", values: ["Kyiv", "Lviv"] },
132
+ { field: "city", values: ["Miami", "New York"] },
134
133
  { field: "age", values: [25, 30, 35] },
135
134
  ]);
136
135
 
137
136
  // Sequential mode example:
138
137
  // 1) First call filters by city
139
- const byCity = engine.filter([{ field: "city", values: ["Dnipro"] }]);
138
+ const byCity = engine.filter([{ field: "city", values: ["Miami"] }]);
140
139
  // 2) Second call filters only inside previous result
141
140
  const byCityAndAge = engine.filter([{ field: "age", values: [22] }]);
142
141
  ```
@@ -0,0 +1 @@
1
+ var T=3,f=12;function x(h){let t=h.toLowerCase(),n=Math.min(T,t.length),e=t.length-n+1,r=new Array(e);for(let s=0;s<e;s++)r[s]=t.substring(s,s+n);return r}function m(h){let t=x(h);if(t.length<=f)return new Set(t);let n=new Set,e=t.length-1,r=f-1;for(let s=0;s<=r;s++){let i=Math.round(s*e/r);n.add(t[i]);}return n}function L(h,t){let n=h.get(t);if(n)return n;let e=new Set;return h.set(t,e),e}var y=class{constructor(t={}){this.ngramIndexes=new Map;this.data=[];if(this.minQueryLength=t.minQueryLength??1,!!t.data&&(this.data=t.data,!!t.fields?.length))for(let n of t.fields)this.buildIndex(t.data,n);}buildIndex(t,n){let e,r;if(Array.isArray(t))e=t,r=n;else {if(!this.data.length)throw new Error("TextSearchEngine: no dataset in memory. Either pass `data` in the constructor options, or call buildIndex(data, field).");e=this.data,r=t;}this.data=e;let s=new Map;for(let i=0,d=e.length;i<d;i++){let l=e[i][r];if(typeof l!="string")continue;let o=l.toLowerCase();for(let a=0,u=o.length;a<u;a++){let g=u-a,p=Math.min(T,g);for(let c=1;c<=p;c++){let I=o.substring(a,a+c);L(s,I).add(i);}}}return this.ngramIndexes.set(r,s),this}search(t,n){return n===void 0?this.searchAllFields(t):this.searchField(t,n)}normalizeQuery(t){return t.trim().toLowerCase()}searchAllFields(t){let n=[...this.ngramIndexes.keys()],e=this.normalizeQuery(t);if(!e)return [];if(e.length<this.minQueryLength)return this.data;if(!n.length)return this.searchAllFieldsLinear(e);let r=m(e);if(!r.size)return [];let s=new Set,i=[];for(let d of n)for(let l of this.searchFieldWithPreparedQuery(d,e,r))s.has(l)||(s.add(l),i.push(l));return i}searchField(t,n){let e=this.normalizeQuery(n);if(!e)return [];if(e.length<this.minQueryLength)return this.data;if(!this.ngramIndexes.size)return this.searchFieldLinear(t,e);let r=m(e);return r.size?this.searchFieldWithPreparedQuery(t,e,r):[]}searchFieldWithPreparedQuery(t,n,e){let r=this.ngramIndexes.get(t);if(!r)return [];let s=[];for(let o of e){let a=r.get(o);if(!a)return [];s.push(a);}s.sort((o,a)=>o.size-a.size);let i=s[0],d=s.length,l=[];for(let o of i){let a=true;for(let g=1;g<d;g++)if(!s[g].has(o)){a=false;break}if(!a)continue;let u=this.data[o][t];typeof u=="string"&&u.toLowerCase().includes(n)&&l.push(this.data[o]);}return l}searchAllFieldsLinear(t){if(!this.data.length)return [];let n=[];for(let e=0;e<this.data.length;e++){let r=this.data[e],s=false;for(let i of Object.values(r))if(typeof i=="string"&&i.toLowerCase().includes(t)){s=true;break}s&&n.push(r);}return n}searchFieldLinear(t,n){if(!this.data.length)return [];let e=[];for(let r=0;r<this.data.length;r++){let s=this.data[r][t];typeof s=="string"&&s.toLowerCase().includes(n)&&e.push(this.data[r]);}return e}clear(){this.ngramIndexes.clear(),this.data=[];}};export{y as a};
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export{a as TextSearchEngine}from'./chunk-VSCCECO2.mjs';export{a as FilterEngine}from'./chunk-XFQ56UZU.mjs';export{a as SortEngine}from'./chunk-DBAABXBP.mjs';export{a as MergeEngines}from'./chunk-KMSFPZKF.mjs';
1
+ export{a as TextSearchEngine}from'./chunk-2OBCQ7TF.mjs';export{a as FilterEngine}from'./chunk-XFQ56UZU.mjs';export{a as SortEngine}from'./chunk-DBAABXBP.mjs';export{a as MergeEngines}from'./chunk-KMSFPZKF.mjs';
@@ -26,10 +26,6 @@ declare class TextSearchEngine<T extends CollectionItem> {
26
26
  search(query: string): T[];
27
27
  search(field: keyof T & string, query: string): T[];
28
28
  private normalizeQuery;
29
- /**
30
- * Checks if the query is long enough to search.
31
- */
32
- private isQuerySearchable;
33
29
  /**
34
30
  * Searches all indexed fields.
35
31
  */
@@ -1 +1 @@
1
- export{a as TextSearchEngine}from'../chunk-VSCCECO2.mjs';
1
+ export{a as TextSearchEngine}from'../chunk-2OBCQ7TF.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devisfuture/mega-collection",
3
- "version": "1.1.2",
3
+ "version": "1.1.5",
4
4
  "description": "High-performance search, filter & sort engine for 100K+ item collections in JavaScript/TypeScript",
5
5
  "exports": {
6
6
  ".": {
@@ -1 +0,0 @@
1
- var T=3,f=12;function x(h){let e=h.toLowerCase(),n=Math.min(T,e.length),t=e.length-n+1,r=new Array(t);for(let s=0;s<t;s++)r[s]=e.substring(s,s+n);return r}function m(h){let e=x(h);if(e.length<=f)return new Set(e);let n=new Set,t=e.length-1,r=f-1;for(let s=0;s<=r;s++){let i=Math.round(s*t/r);n.add(e[i]);}return n}function L(h,e){let n=h.get(e);if(n)return n;let t=new Set;return h.set(e,t),t}var y=class{constructor(e={}){this.ngramIndexes=new Map;this.data=[];if(this.minQueryLength=e.minQueryLength??1,!!e.data&&(this.data=e.data,!!e.fields?.length))for(let n of e.fields)this.buildIndex(e.data,n);}buildIndex(e,n){let t,r;if(Array.isArray(e))t=e,r=n;else {if(!this.data.length)throw new Error("TextSearchEngine: no dataset in memory. Either pass `data` in the constructor options, or call buildIndex(data, field).");t=this.data,r=e;}this.data=t;let s=new Map;for(let i=0,u=t.length;i<u;i++){let l=t[i][r];if(typeof l!="string")continue;let o=l.toLowerCase();for(let a=0,d=o.length;a<d;a++){let c=d-a,p=Math.min(T,c);for(let g=1;g<=p;g++){let I=o.substring(a,a+g);L(s,I).add(i);}}}return this.ngramIndexes.set(r,s),this}search(e,n){return n===void 0?this.searchAllFields(e):this.searchField(e,n)}normalizeQuery(e){return e.trim().toLowerCase()}isQuerySearchable(e){return !(!e||e.length<this.minQueryLength)}searchAllFields(e){let n=[...this.ngramIndexes.keys()],t=this.normalizeQuery(e);if(!this.isQuerySearchable(t))return [];if(!n.length)return this.searchAllFieldsLinear(t);let r=m(t);if(!r.size)return [];let s=new Set,i=[];for(let u of n)for(let l of this.searchFieldWithPreparedQuery(u,t,r))s.has(l)||(s.add(l),i.push(l));return i}searchField(e,n){let t=this.normalizeQuery(n);if(!this.isQuerySearchable(t))return [];if(!this.ngramIndexes.size)return this.searchFieldLinear(e,t);let r=m(t);return r.size?this.searchFieldWithPreparedQuery(e,t,r):[]}searchFieldWithPreparedQuery(e,n,t){let r=this.ngramIndexes.get(e);if(!r)return [];let s=[];for(let o of t){let a=r.get(o);if(!a)return [];s.push(a);}s.sort((o,a)=>o.size-a.size);let i=s[0],u=s.length,l=[];for(let o of i){let a=true;for(let c=1;c<u;c++)if(!s[c].has(o)){a=false;break}if(!a)continue;let d=this.data[o][e];typeof d=="string"&&d.toLowerCase().includes(n)&&l.push(this.data[o]);}return l}searchAllFieldsLinear(e){if(!this.data.length)return [];let n=[];for(let t=0;t<this.data.length;t++){let r=this.data[t],s=false;for(let i of Object.values(r))if(typeof i=="string"&&i.toLowerCase().includes(e)){s=true;break}s&&n.push(r);}return n}searchFieldLinear(e,n){if(!this.data.length)return [];let t=[];for(let r=0;r<this.data.length;r++){let s=this.data[r][e];typeof s=="string"&&s.toLowerCase().includes(n)&&t.push(this.data[r]);}return t}clear(){this.ngramIndexes.clear(),this.data=[];}};export{y as a};