diff --git a/CHANGELOG.md b/CHANGELOG.md index f64b8d8..3408eb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +#### v0.5.0 + +- Where / Find Documents +- Document Tags +- Custom Sort + #### v0.4.0 - Index Documents (Field-Search) diff --git a/README.md b/README.md index 49c9c3e..6a84396 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ FlexSearch also provides you a non-blocking asynchronous processing model as wel FlexSearch Server is also available here: https://github.com/nextapps-de/flexsearch-server. -Installation Guide  •  API Reference  •  Presets  •  Custom Builds  •  Flexsearch Server  •  Changelog +Installation Guide  •  API Reference  •  Custom Builds  •  Flexsearch Server  •  Changelog Supported Platforms: - Browser @@ -123,6 +123,15 @@ All Features: - + + + Where / Find / Tags + + ✔ + - + - + + Partial Matching @@ -681,7 +690,9 @@ index.search({ limit: 1000, threshold: 5, // >= threshold depth: 3, // <= depth - callback: function(results){/* ... */} + callback: function(results){ + // ... + } }); ``` @@ -1080,23 +1091,23 @@ Assume the document array looks more complex (has nested branches etc.), e.g.: var docs = [{ data:{ id: 0, - title: "Title", + title: "Foo", body: { - content: "Body" + content: "Foobar" } } },{ data:{ id: 1, - title: "Title", + title: "Bar", body: { - content: "Body" + content: "Foobar" } } }]; ``` -Then use the colon separated notation ___"root:child"___ to define hierarchy within the document descriptor: +Then use the colon separated notation ___"root:child:child"___ to define hierarchy within the document descriptor: ```js var index = new FlexSearch({ @@ -1104,7 +1115,7 @@ var index = new FlexSearch({ id: "data:id", field: [ "data:title", - "data:content:body" + "data:body:content" ] } }); @@ -1146,7 +1157,9 @@ index.remove(id); #### Field-Search -Searching gives you several options when using documents. +The search gives you several options when using documents. + +> The colon notation also has to be applied for the searching respectively. This will search through all indexed fields: @@ -1159,24 +1172,22 @@ This will search on a specific field): ```js var results = index.search({ field: "title", - query: "title" + query: "foobar" }); ``` -The colon notation also has to be applied for the searching respectively, e.g.: - ```js var results = index.search({ - field: "data:body", - query: "body" + field: "data:body:content", + query: "foobar" }); ``` This could also be written as: ```js -var results = index.search("body", { - field: "data:body", +var results = index.search("foobar", { + field: "data:body:content", }); ``` @@ -1184,7 +1195,7 @@ Search the same query on multiple fields: ```js var results = index.search({ - query: "title", + query: "foobar", field: ["title", "body"] }); ``` @@ -1202,10 +1213,10 @@ Search different queries on multiple fields: ```js var results = index.search([{ field: "title", - query: "title" + query: "foo" },{ field: "body", - query: "body" + query: "bar" }]); ``` @@ -1214,15 +1225,206 @@ Boost scoring on specific fields: ```js var results = index.search([{ field: "title", - query: "title", + query: "foo", boost: 2 },{ field: "body", - query: "body", + query: "bar", boost: 0.5 }]); ``` + +## Find / Where + +When indexing documents, you are also able to get results by specific attributes. + +> The colon notation also has to be applied for using "where" and "find" respectively. + +#### Find a document by an attribute + +```js +index.find("cat", "comedy"); +``` + +Same as: +```js +index.find({"cat": "comedy"}); +``` + +To get by ID, you can also use short form: +```js +index.find(1); +``` + +Find by a custom function: +```js +index.find(function(item){ + return item.cat === "comedy"; +}); +``` + +#### Find documents by multiple attributes + +Get just the first result: +```js +index.find({ + cat: "comedy", + year: "2018" +}); +``` + +Get all matched results: +```js +index.where({ + cat: "comedy", + year: "2018" +}); +``` + +Get all results and set a limit: +```js +index.where({ + cat: "comedy", + year: "2018" + }, 100); +``` + +Get all by a custom function: +```js +index.where(function(item){ + return item.cat === "comedy"; +}); +``` + +#### Combine fuzzy search with a where-clause: + +Add some content, e.g.: +```js +index.add([{ + id: 0, + title: "Foobar", + cat: "adventure", + content: "Body" +},{ + id: 1, + title: "Title", + cat: "comedy", + content: "Foobar" +}]); +``` + +Using search and also apply a where-clause: +```js +index.search("foo", { + field: [ + "title", + "body" + ], + where: { + "cat": "comedy" + }, + limit: 10 +}); +``` + + +## Tags + +Tagging is pretty much the same like adding an index to a database column. Whenever you use ___where___ on an indexed/tagged attribute will improve performance drastically but also at a cost of additional memory. + +> The colon notation also has to be applied for tags respectively. + +Add one single tag to the index: +```js +var index = new FlexSearch({ + doc: { + id: "id", + field: ["title", "content"], + tag: "cat" + } +}); +``` + +Or add multiple tags to the index: +```js +var index = new FlexSearch({ + doc: { + id: "id", + field: ["title", "content"], + tag: ["cat", "year"] + } +}); +``` + +Add some content: +```js +index.add([{ + id: 0, + title: "Foobar", + cat: "adventure", + year: "2018", + content: "Body" +},{ + id: 1, + title: "Title", + cat: "comedy", + year: "2018", + content: "Foobar" +}]); +``` + +Find all documents by an attribute: +```js +index.where({"cat": "comedy"}, 10); +``` + +Since the attribute "cat" was tagged (has its own index) this expression performs extremely fast. This is actually the fastest way to retrieve results from documents. + +Search documents and also apply a where-clause: +```js +index.search("foo", { + field: [ + "title", + "content" + ], + where: { + "cat": "comedy" + }, + limit: 10 +}); +``` + +For a better understanding, using the same expression without the where clause has pretty much the same performance. On the other hand, using a where-clause without a tag on its property has an additional cost. + + +## Custom Sort + +> The colon notation also has to be applied for a custom sort respectively. + +Sort by an attribute: +```js +var results = index.search("John", { + + limit: 100, + sort: "data:title" +}); +``` + +Sort by a custom function: +```js +var results = index.search("John", { + + limit: 100, + sort: function(a, b){ + return ( + a.id < b.id ? -1 : ( + a.id > b.id ? 1 : 0 + )); + } +}); +``` + ### Chaining @@ -1864,45 +2066,36 @@ var comedy = new FlexSearch(); This way you can also provide different settings for each category. -To make this workaround more extendable you can define a tiny helper: +You can also gets the same effect when using documents in combination with tags and a ___where___ clause, e.g.: + ```js -var settings = {}; -var index = {}; - -function add(id, cat, content){ - (index[cat] || ( - index[cat] = new FlexSearch(settings[cat]) - )).add(id, content); -} - -function search(cat, query){ - return index[cat] ? index[cat].search(query) : []; -} -``` - -Provide settings optionally (or skip and use defaults): -```js -settings = { - action: "score", - adventure: "match", - comedy: { - encode: "advanced", - tokenize: "forward", - threshold: 5 +var movies = new FlexSearch({ + doc: { + id: "id", + title: "title" + }, + tag:{ + cat: "cat", } -}; +}); ``` Add content to the index: + ```js -add(1, "action", "Movie Title"); -add(2, "adventure", "Movie Title"); -add(3, "comedy", "Movie Title"); +add({ id: 1, cat: "action", title: "Movie Title" }); +add({ id: 2, cat: "adventure", title: "Movie Title" }); +add({ id: 3, cat: "comedy", title: "Movie Title" }); ``` Perform queries: ```js -var results = search("action", "movie title"); // --> [1] +var results = search("movie title", { + field: "title", + where: { + cat: "adventure" + } +}); ``` Filter queries by categories will hugely improve performance. diff --git a/demo/autocomplete.html b/demo/autocomplete.html index e658ea9..7ec5d7d 100644 --- a/demo/autocomplete.html +++ b/demo/autocomplete.html @@ -14,7 +14,7 @@ table{ width: 300px; table-layout: fixed; - position: sticky; + position: fixed; top: 0; padding-top: 10px; background-color: #fff; @@ -43,7 +43,7 @@ } #suggestions{ position: relative; - top: 35px; + top: 50px; } #suggestions div{ padding: 10px 0; @@ -58,7 +58,7 @@ td, tr, input{ - width: 100%; + width: 97%; } } @@ -83,15 +83,15 @@ suggest: true }); - var suggestions = document.getElementById("suggestions"); - var autocomplete = document.getElementById("autocomplete"); - var userinput = document.getElementById("userinput"); - for(var i = 0; i < data.length; i++){ index.add(i, data[i]); } + var suggestions = document.getElementById("suggestions"); + var autocomplete = document.getElementById("autocomplete"); + var userinput = document.getElementById("userinput"); + userinput.addEventListener("input", show_results, true); userinput.addEventListener("keyup", accept_autocomplete, true); suggestions.addEventListener("click", accept_suggestion, true); @@ -99,7 +99,7 @@ function show_results(){ var value = this.value; - var results = index.search(value, 20); + var results = index.search(value, 25); var entry, childs = suggestions.childNodes; var i = 0, len = results.length; @@ -131,8 +131,7 @@ } else{ - autocomplete.value = value; - autocomplete.current = value; + autocomplete.value = autocomplete.current = value; } } @@ -157,7 +156,6 @@ return false; } - }()); diff --git a/dist/flexsearch.compact.js b/dist/flexsearch.compact.js index aa1a7e1..ed74873 100644 --- a/dist/flexsearch.compact.js +++ b/dist/flexsearch.compact.js @@ -1,27 +1,27 @@ /* - FlexSearch v0.4.0 + FlexSearch v0.5.0 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(f,x,d){let p;(p=d.define)&&p.amd?p([],function(){return x}):(p=d.modules)?p[f.toLowerCase()]=x:"object"===typeof exports?module.exports=x:d[f]=x})("FlexSearch",function(){function f(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:M++;this.init(a,b);x(this,"index",function(){return this.c});x(this,"length",function(){return Object.keys(this.c).length})}function x(a,b,c){Object.defineProperty(a,b,{get:c})}function d(a){return new RegExp(a,"g")}function p(a,b){for(let c=0;c=e&&(a=a[9-(g+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=h);return g}function E(a,b){if(a){const c=Object.keys(a);for(let h=0,g=c.length;ha?1:a?-1:0}function O(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function P(a,b,c,h){let g=[],l;const e=a.length;if(1b&&(g=g.slice(0,b));return g}function B(a){return"string"===typeof a}function C(a){return"function"=== -typeof a}function y(a){return"object"===typeof a}function D(a){return"undefined"===typeof a}function H(a){const b=Array(a);for(let c=0;ck;c--)f=e.substring(k,c),A(t,q,f,a,b,n,m)}break;default:if(d=A(t,q,e,a,1,n,m),p&&1=m)for(d=q._ctx[e]||(q._ctx[e]=v()),e=this.g[e]||(this.g[e]=H(10-(m||0))),n=b-p,f=b+p+1,0>n&&(n=0),f>w&&(f=w);nn&&(b=h));for(n=p?1:0;n=f&&(a=a[9-(h+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=e);return h}function H(a,b){if(a){const c=Object.keys(a);for(let e=0,h=c.length;ea?1:a?-1:0}function T(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function R(a,b){a=a[w];b=b[w];return ab?1:0}function Q(a,b){const c=w.length;for(let e= +0;eb?1:0}function U(a,b,c,e){let h=[],k;const f=a.length;if(1b&&(h=h.slice(0,b));return h}function F(a){return"string"===typeof a}function D(a){return"function"===typeof a}function z(a){return"object"===typeof a}function G(a){return"undefined"===typeof a}function K(a){const b=Array(a);for(let c=0;cg;c--)l=f.substring(g, +c),E(u,k,l,a,b,m,r)}break;default:if(n=E(u,k,f,a,1,m,r),q&&1=r)for(n=k._ctx[f]||(k._ctx[f]=v()),f=this.g[f]||(this.g[f]=K(10-(r||0))),m=b-q,l=b+q+1,0>m&&(m=0),l>B&&(l=B);mm&&(b=l));for(m=u?1:0;m=d&&(this.B=this.h),this.G&&this.B===this.h&&(this.cache&& -this.w.set(b,this.u),this.G(this.u),this.u=[]));return this}function k(a,b,c){Object.defineProperty(a,b,{get:c})}function f(a){return new RegExp(a,"g")}function e(a,b){for(var c=0;c=e&&(a=a[9-(h+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return h}function C(a,b){if(a)for(var c=Object.keys(a),d=0,h=c.length;da?1:a?-1:0}function X(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function W(a,b,c,d){var h=[],u=a.length;if(1b&&(h=h.slice(0,b));return h}function F(a){return"string"===typeof a}function I(a){return"function"===typeof a}function E(a){return"object"===typeof a}function z(a){return"undefined"===typeof a}function N(a){for(var b=Array(a),c=0;c=this.a.length&&(this.v=0),this.a[this.v].postMessage({add:!0,id:a,content:b}),this.b[e]= -""+this.v,c&&c(),this;if(!h){if(this.async&&"function"!==typeof importScripts){var f=this;e=new Promise(function(c){setTimeout(function(){f.add(a,b,null,d,!0);f=null;c()})});if(c)e.then(c);else return e;return this}if(c)return this.add(a,b,null,d,!0),c(),this}b=this.encode(b);if(!b.length)return this;c=this.g;h=I(c)?c(b):b.split(P);var g=B();g._ctx=B();for(var r=this.threshold,m=this.depth,p=this.m,k=h.length,q=this.F,A=0;Ay;z--)w=x.substring(y,z),D(p,g,w,a,t,n,r);break;default:if(v=D(p,g,x,a,1,n,r),m&&1=r)for(v=g._ctx[x]||(g._ctx[x]=B()),x=this.s[x]||(this.s[x]=N(10-(r||0))),n=A-m,w=A+m+1,0>n&&(n=0),w>k&&(w=k);nm&&(v=r));for(m=k?1:0;mf;d--)k=g[d- -1],g[d]=k,e[k]=d;g[f]=a;e[a]=f}}}return b};return a}();return d}(function(){var g={},l="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(d,m,k,f,e){k=l?URL.createObjectURL(new Blob(["("+k.toString()+")()"],{type:"text/javascript"})):d+".es5.js";d+="-"+m;g[d]||(g[d]=[]);g[d][e]=new Worker(k);g[d][e].onmessage=f;console.log("Register Worker: "+d+"@"+e);return g[d][e]}}()),this); +'use strict';function Q(f){var k=0;return function(){return k=m&&(this.B=this.h),this.G&&this.B===this.h&&(this.cache&& +this.w.set(b,this.u),this.G(this.u),this.u=[]));return this}function l(a,b){a=a.concat.apply([],a);b&&(K(b)||(E=b.split(":"),1=e&&(a=a[9-(c+.5>>0)],a=a[d]||(a[d]=[]),a[a.length]=m);return c}function G(a, +b){if(a)for(var d=Object.keys(a),c=0,e=d.length;c +a?1:a?-1:0}function aa(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function ba(a,b){a=a[E];b=b[E];return ab?1:0}function ca(a,b){for(var d=E.length,c=0;cb?1:0}function P(a,b,d,c){var e=[],h=a.length;if(1b&&(e=e.slice(0,b));return e}function M(a){return"string"===typeof a}function K(a){return"function"===typeof a}function J(a){return"object"===typeof a}function H(a){return"undefined"=== +typeof a}function S(a){for(var b=Array(a),d=0;d=this.a.length&&(this.v=0),this.a[this.v].postMessage({add:!0,id:a,content:b}),this.c[h]=""+this.v,d&&d(),this;if(!e){if(this.async&&"function"!==typeof importScripts){var m=this;h=new Promise(function(d){setTimeout(function(){m.add(a, +b,null,c,!0);m=null;d()})});if(d)h.then(d);else return h;return this}if(d)return this.add(a,b,null,c,!0),d(),this}b=this.encode(b);if(!b.length)return this;d=this.g;e=K(d)?d(b):b.split(U);var q=C();q._ctx=C();for(var f=this.threshold,w=this.depth,n=this.m,g=e.length,u=this.F,t=0;tx;z--)y=l.substring(x,z),A(n,q,y,a,r,p,f);break;default:if(v=A(n,q,l,a,1,p,f),w&&1=f)for(v=q._ctx[l]||(q._ctx[l]=C()),l=this.s[l]||(this.s[l]=S(10-(f||0))),p=t-w,y=t+w+1,0>p&&(p=0),y>g&&(y=g);pm&&(y=n));for(m=u?1:0;mf;c--)l=g[c-1],g[c]=l,e[l]=c;g[f]=a;e[a]=f}}}return b};return a}();return e}(function(){var f={},k="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(e,g,l,I,c){l=k?URL.createObjectURL(new Blob(["("+l.toString()+")()"],{type:"text/javascript"})):e+".es5.js";e+="-"+g;f[e]|| +(f[e]=[]);f[e][c]=new Worker(l);f[e][c].onmessage=I;console.log("Register Worker: "+e+"@"+c);return f[e][c]}}()),this); diff --git a/dist/flexsearch.light.js b/dist/flexsearch.light.js index 3c74d9d..0f9ce9f 100644 --- a/dist/flexsearch.light.js +++ b/dist/flexsearch.light.js @@ -1,5 +1,5 @@ /* - FlexSearch v0.4.0 + FlexSearch v0.5.0 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence diff --git a/dist/flexsearch.min.js b/dist/flexsearch.min.js index 7805714..5facd5b 100644 --- a/dist/flexsearch.min.js +++ b/dist/flexsearch.min.js @@ -1,35 +1,37 @@ /* - FlexSearch v0.4.0 + FlexSearch v0.5.0 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(t,A,g){let w;(w=g.define)&&w.amd?w([],function(){return A}):(w=g.modules)?w[t.toLowerCase()]=A:"object"===typeof exports?module.exports=A:g[t]=A})("FlexSearch",function Q(t){function g(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:R++;this.init(a,b);B(this,"index",function(){return this.a});B(this,"length",function(){return Object.keys(this.a).length})}function w(a,b,c,e){this.s!==this.f&&(this.j=this.j.concat(c),this.s++,e&&this.j.length>=e&&(this.s=this.f),this.F&&this.s=== -this.f&&(this.cache&&this.m.set(b,this.j),this.F(this.j),this.j=[]));return this}function B(a,b,c){Object.defineProperty(a,b,{get:c})}function f(a){return new RegExp(a,"g")}function n(a,b){for(let c=0;c=h&&(a=a[9-(d+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=e);return d}function J(a,b){if(a){const c=Object.keys(a);for(let e=0,d=c.length;ea?1:a?-1:0}function T(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function U(a, -b,c,e){let d=[],l;const h=a.length;if(1b&&(d=d.slice(0,b));return d}function G(a){return"string"===typeof a}function H(a){return"function"===typeof a}function z(a){return"object"===typeof a}function y(a){return"undefined"===typeof a}function L(a){const b=Array(a);for(let c=0;c=this.l.length&&(this.C=0),this.l[this.C].postMessage({add:!0,id:a,content:b}), -this.a[l]=""+this.C,c&&c(),this;if(!d){if(this.async&&"function"!==typeof importScripts){let d=this;l=new Promise(function(c){setTimeout(function(){d.add(a,b,null,e,!0);d=null;c()})});if(c)l.then(c);else return l;return this}if(c)return this.add(a,b,null,e,!0),c(),this}b=this.encode(b);if(!b.length)return this;c=this.c;d=H(c)?c(b):b.split(N);const r=u();r._ctx=u();const m=this.threshold,x=this.depth,v=this.h,D=d.length,n=this.D;for(let b=0;bp;c--)k=h.substring(p,c),F(v,r,k,a,b,g,m)}break;default:if(f=F(v,r,h,a,1,g,m),x&&1=m)for(f=r._ctx[h]||(r._ctx[h]=u()),h=this.i[h]||(this.i[h]=L(10-(m||0))),g=b-x,k=b+x+1,0>g&&(g=0),k>D&&(k=D);gn&&(a=g));for(n=k?1:0;nc;e--)d=f[e-1],f[e]=d,b[d]=e;f[c]=a;b[a]=c}}}return b};return a}();return g}(function(){const t={},A="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(g,w,B,f,n){B=A?URL.createObjectURL(new Blob(["("+B.toString()+")()"],{type:"text/javascript"})):g+".min.js";g+="-"+w;t[g]||(t[g]=[]);t[g][n]=new Worker(B);t[g][n].onmessage=f;return t[g][n]}}()), -this); +'use strict';(function(x,F,f){let y;(y=f.define)&&y.amd?y([],function(){return F}):(y=f.modules)?y[x.toLowerCase()]=F:"object"===typeof exports?module.exports=F:f[x]=F})("FlexSearch",function U(x){function f(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:V++;this.init(a,b);K(this,"index",function(){return this.b});K(this,"length",function(){return Object.keys(this.b).length})}function y(a,b,c,d){this.s!==this.f&&(this.j=this.j.concat(c),this.s++,d&&this.j.length>=d&&(this.s=this.f),this.F&&this.s=== +this.f&&(this.cache&&this.m.set(b,this.j),this.F(this.j),this.j=[]));return this}function A(a,b){a=a.concat.apply([],a);b&&(G(b)||(z=b.split(":"),1=k&&(a=a[9-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d); +return e}function N(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;da?1:a?-1:0}function Z(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function X(a,b){a=a[z];b=b[z];return ab?1:0}function W(a,b){const c=z.length;for(let d=0;db?1:0}function aa(a,b,c,d){let e=[],g;const k=a.length;if(1b&&(e=e.slice(0,b));return e}function J(a){return"string"===typeof a}function G(a){return"function"===typeof a}function D(a){return"object"=== +typeof a}function B(a){return"undefined"===typeof a}function P(a){const b=Array(a);for(let c=0;c=this.l.length&&(this.C=0),this.l[this.C].postMessage({add:!0,id:a,content:b}),this.b[g]=""+this.C,c&&c(),this;if(!e){if(this.async&&"function"!==typeof importScripts){let e=this;g=new Promise(function(c){setTimeout(function(){e.add(a, +b,null,d,!0);e=null;c()})});if(c)g.then(c);else return g;return this}if(c)return this.add(a,b,null,d,!0),c(),this}b=this.encode(b);if(!b.length)return this;c=this.c;e=G(c)?c(b):b.split(R);const m=q();m._ctx=q();const n=this.threshold,r=this.depth,t=this.h,v=e.length,L=this.D;for(let b=0;bf;c--)l=k.substring(f,c),I(t,m,l,a,b,h,n)}break;default:if(p=I(t,m,k,a,1,h,n),r&&1=n)for(p=m._ctx[k]||(m._ctx[k]=q()),k=this.i[k]||(this.i[k]=P(10-(n||0))),h=b-r,l=b+r+1,0>h&&(h=0),l>v&&(l=v);hr&&(a=m));for(r=n?1:0;rc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return a}();return f}(function(){const x={},F="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL; +return function(f,y,A,K,h){A=F?URL.createObjectURL(new Blob(["("+A.toString()+")()"],{type:"text/javascript"})):f+".min.js";f+="-"+y;x[f]||(x[f]=[]);x[f][h]=new Worker(A);x[f][h].onmessage=K;return x[f][h]}}()),this); diff --git a/dist/flexsearch.node.js b/dist/flexsearch.node.js index 21ba0a9..29ef3cd 100644 --- a/dist/flexsearch.node.js +++ b/dist/flexsearch.node.js @@ -1,31 +1,33 @@ /* - FlexSearch v0.4.0 + FlexSearch v0.5.0 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(h,w,d){let p;(p=d.define)&&p.amd?p([],function(){return w}):(p=d.modules)?p[h.toLowerCase()]=w:"object"===typeof exports?module.exports=w:d[h]=w})("FlexSearch",function(){function h(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:N++;this.init(a,b);w(this,"index",function(){return this.b});w(this,"length",function(){return Object.keys(this.b).length})}function w(a,b,c){Object.defineProperty(a,b,{get:c})}function d(a){return new RegExp(a,"g")}function p(a,b){for(let c=0;c=g&&(a=a[9-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=f);return e}function G(a,b){if(a){const c=Object.keys(a);for(let f=0,e=c.length;fa?1:a?-1:0}function P(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function Q(a,b,c,f){let e=[],l;const g=a.length;if(1b&&(e=e.slice(0,b));return e}function D(a){return"string"===typeof a}function E(a){return"function"=== -typeof a}function x(a){return"object"===typeof a}function z(a){return"undefined"===typeof a}function I(a){const b=Array(a);for(let c=0;ch;c--)k=g.substring(h,c),C(v,r,k,a,b,n,m)}break;default:if(d=C(v,r,g,a,1,n,m),p&&1=m)for(d=r._ctx[g]||(r._ctx[g]=u()),g= -this.h[g]||(this.h[g]=I(10-(m||0))),n=b-p,k=b+p+1,0>n&&(n=0),k>A&&(k=A);nn&&(a=h));for(n=k?1:0;nc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b}; -return a}();return h}(!1),this); +'use strict';(function(h,w,C){let f;(f=C.define)&&f.amd?f([],function(){return w}):(f=C.modules)?f[h.toLowerCase()]=w:"object"===typeof exports?module.exports=w:C[h]=w})("FlexSearch",function(){function h(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:R++;this.init(a,b);C(this,"index",function(){return this.b});C(this,"length",function(){return Object.keys(this.b).length})}function w(a,b){a=a.concat.apply([],a);b&&(D(b)||(x=b.split(":"),1=l&&(a=a[9-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function K(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;da?1:a?-1:0}function V(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function T(a,b){a=a[x];b=b[x];return ab?1:0}function S(a,b){const c=x.length;for(let d= +0;db?1:0}function W(a,b,c,d){let e=[],g;const l=a.length;if(1b&&(e=e.slice(0,b));return e}function I(a){return"string"===typeof a}function D(a){return"function"===typeof a}function z(a){return"object"===typeof a}function B(a){return"undefined"===typeof a}function M(a){const b=Array(a);for(let c=0;cm;c--)n=l.substring(m,c),H(r,h,n,a,b,f,p)}break;default:if(k=H(r,h,l,a,1,f,p),E&&1=p)for(k=h._ctx[l]||(h._ctx[l]=u()),l=this.h[l]||(this.h[l]=M(10-(p||0))),f=b-E,n=b+E+1,0>f&&(f=0),n>t&&(n=t);fh&&(a=m));for(h=p?1:0;hc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return a}();return h}(!1),this); diff --git a/flexsearch.js b/flexsearch.js index 68d6f16..12f13e0 100644 --- a/flexsearch.js +++ b/flexsearch.js @@ -1,5 +1,5 @@ /**! - * @preserve FlexSearch v0.4.0 + * @preserve FlexSearch v0.5.0 * Copyright 2019 Nextapps GmbH * Author: Thomas Wilkerling * Released under the Apache 2.0 Licence @@ -18,6 +18,7 @@ /** @define {boolean} */ const SUPPORT_SERIALIZE = true; /** @define {boolean} */ const SUPPORT_INFO = true; /** @define {boolean} */ const SUPPORT_DOCUMENTS = true; +/** @define {boolean} */ const SUPPORT_WHERE = true; // noinspection ThisExpressionReferencesGlobalObjectJS (function(){ @@ -494,14 +495,18 @@ let doc; - if(SUPPORT_DOCUMENTS) /** @private */ this.doc = doc = ( + if(SUPPORT_DOCUMENTS) { - (custom = options["doc"]) ? + /** @private */ + this.doc = doc = ( - custom - : - this.doc || defaults.doc - ); + (custom = options["doc"]) ? + + custom + : + this.doc || defaults.doc + ); + } // initialize primary index @@ -512,28 +517,43 @@ /** @private */ this._ids = create_object(); - if(SUPPORT_DOCUMENTS){ - - /** @private */ - this._doc = doc && create_object(); - } - - /** @private */ - //this._stack = create_object(); - /** @private */ - //this._stack_keys = []; - if(doc){ + this._doc = create_object(); + options["doc"] = null; - const field = doc["field"]; const index = doc["index"] = []; const ref = doc["ref"] = {}; + let field = doc["field"]; + let tag = doc["tag"]; + doc["id"] = doc["id"].split(":"); - if(is_array(field)){ + if(SUPPORT_WHERE && tag){ + + this._tag = create_object(); + + if(!is_array(tag)){ + + doc["tag"] = tag = [tag]; + } + + for(let i = 0; i < tag.length; i++){ + + this._tag[tag[i]] = create_object(); + + tag[i] = tag[i].split(":"); + } + } + + if(field){ + + if(!is_array(field)){ + + doc["field"] = field = [field]; + } for(let i = 0; i < field.length; i++){ @@ -541,14 +561,12 @@ field[i] = field[i].split(":"); index[i] = new FlexSearch(options); index[i]._doc = this._doc; - } - } - else{ - ref[field] = 0; - doc["field"] = [field.split(":")]; - index[0] = new FlexSearch(options); - index[0]._doc = this._doc; + if(SUPPORT_WHERE && tag){ + + index[i]._tag = this._tag; + } + } } } @@ -992,14 +1010,24 @@ else{ const index = this.doc["index"]; + const tags = this.doc["tag"]; let tree = this.doc["id"]; let id; + let tag; for(let i = 0; i < tree.length; i++){ id = (id || docs)[tree[i]]; } + if(tags){ + + for(let i = 0; i < tags.length; i++){ + + tag = (tag || docs)[tags[i]]; + } + } + if(job === "remove"){ delete this._doc["@" + id]; @@ -1197,6 +1225,37 @@ return this; }; + let field_to_sort; + + // TODO: apply intersect here + + function merge_and_sort(arrays, sort){ + + arrays = arrays.concat.apply([], arrays); + + if(sort){ + + if(!is_function(sort)){ + + field_to_sort = sort.split(":"); + + if(field_to_sort.length > 1){ + + sort = sort_by_deep_field_up; + } + else{ + + field_to_sort = field_to_sort[0]; + sort = sort_by_field_up; + } + } + + arrays.sort(sort); + } + + return arrays; + } + /** * @param {!string|Object|Array} query * @param {number|Function=} limit @@ -1229,6 +1288,8 @@ let _query = query; let threshold; let boost; + let where; + let sort; let result = []; if(is_object(query) && (!SUPPORT_DOCUMENTS || !is_array(query))){ @@ -1245,9 +1306,15 @@ } } + if(SUPPORT_DOCUMENTS){ + + boost = query["boost"]; + where = query["where"]; + sort = query["sort"]; + } + limit = query["limit"]; threshold = query["threshold"]; - boost = query["boost"]; query = query["query"]; } @@ -1303,7 +1370,7 @@ if(SUPPORT_ASYNC && callback){ - return callback(result.concat.apply([], result)); + return callback(merge_and_sort(result, sort)); } else if(SUPPORT_ASYNC && this.async){ @@ -1311,13 +1378,13 @@ Promise.all(/** @type {!Iterable} */ (result)).then(function(values){ - resolve(values.concat.apply([], values)); + resolve(merge_and_sort(values, sort)); }); }); } else{ - return result.concat.apply([], result); + return merge_and_sort(result, sort); } } else{ @@ -1579,6 +1646,16 @@ //result = intersect_3d(check, limit, this.suggest); } + if(SUPPORT_WHERE && where){ + + result = this.where(where, null, limit, result); + } + + if(sort){ + + result = merge_and_sort([result], sort); + } + // store result to cache if(SUPPORT_CACHE && this.cache){ @@ -1594,6 +1671,137 @@ return result; }; + if(SUPPORT_DOCUMENTS && SUPPORT_WHERE){ + + /** + * @export + */ + + FlexSearch.prototype.find = function(key, value){ + + return this.where(key, value, 1)[0] || null; + }; + + /** + * @param key + * @param value + * @param limit + * @param {Array=} result + * @returns {Array} + * @export + */ + + FlexSearch.prototype.where = function(key, value, limit, result){ + + const doc = result || this._doc; + const results = []; + + let count = 0; + let keys; + let keys_len; + let has_value; + let tree; + + if(is_string(key)){ + + if(key === "id"){ + + return [doc["@" + value]]; + } + + //keys = [key]; + keys_len = 1; + tree = [key.split(":")]; + has_value = true; + } + else if(is_function(key)){ + + const ids = result || get_keys(doc); + const length = ids.length; + + for(let x = 0; x < length; x++){ + + const obj = result ? result[x] : doc[ids[x]]; + + if(key(obj)){ + + results[count++] = obj; + } + } + + return results; + } + else{ + + limit || (limit = value); + keys = get_keys(key); + keys_len = keys.length; + has_value = false; + + if((keys_len === 1) && (keys[0] === "id")){ + + return [doc["@" + key["id"]]]; + } + + tree = new Array(keys_len); + + for(let i = 0; i < keys_len; i++){ + + tree[i] = keys[i].split(":"); + } + } + + const ids = result || get_keys(doc); // this._ids; + const length = ids.length; + + for(let x = 0; x < length; x++){ + + const obj = result ? result[x] : doc[ids[x]]; + let found = true; + + for(let i = 0; i < keys_len; i++){ + + has_value || (value = key[keys[i]]); + + const tree_cur = tree[i]; + const tree_len = tree_cur.length; + + let ref = obj; + + if(tree_len > 1){ + + for(let z = 0; z < tree_len; z++){ + + ref = ref[tree_cur[z]]; + } + } + else{ + + ref = ref[tree_cur[0]]; + } + + if(ref !== value){ + + found = false; + break; + } + } + + if(found){ + + results[count++] = obj; + + if(limit && (count === limit)){ + + break; + } + } + } + + return results; + } + } + if(SUPPORT_INFO){ /** @@ -1704,6 +1912,7 @@ if(SUPPORT_SERIALIZE){ /** + * TODO: also export settings? * @export */ @@ -2592,6 +2801,51 @@ ); } + function sort_by_field_up(a, b){ + + a = a[field_to_sort]; + b = b[field_to_sort]; + + return ( + + a < b ? + + -1 + :( + a > b ? + + 1 + : + 0 + ) + ); + } + + function sort_by_deep_field_up(a, b){ + + const field_len = field_to_sort.length; + + for(let i = 0; i < field_len; i++){ + + a = a[field_to_sort[i]]; + b = b[field_to_sort[i]]; + } + + return ( + + a < b ? + + -1 + :( + a > b ? + + 1 + : + 0 + ) + ); + } + /** * @param {!Array>} arrays * @param {number=} limit @@ -3269,6 +3523,7 @@ "var SUPPORT_SERIALIZE = " + (SUPPORT_SERIALIZE ? "true" : "false") + ";" + "var SUPPORT_INFO = " + (SUPPORT_INFO ? "true" : "false") + ";" + "var SUPPORT_DOCUMENTS = " + (SUPPORT_DOCUMENTS ? "true" : "false") + ";" + + "var SUPPORT_WHERE = " + (SUPPORT_WHERE ? "true" : "false") + ";" + "var SUPPORT_WORKER = true;" ) + "(" + _worker.toString() + ")()" diff --git a/package.json b/package.json index 9ff173d..d30bbb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flexsearch", - "version": "0.4.0", + "version": "0.5.0", "description": "Next-Generation full text search library with zero dependencies.", "homepage": "https://github.com/nextapps-de/flexsearch/", "author": "Thomas Wilkerling", @@ -26,12 +26,12 @@ "url": "https://github.com/nextapps-de/flexsearch.git" }, "scripts": { - "build": "node compile RELEASE=min DEBUG=false PROFILER=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENTS=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", - "build-light": "node compile RELEASE=light DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_SUGGESTIONS=false SUPPORT_SERIALIZE=false SUPPORT_INFO=false SUPPORT_DOCUMENTS=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", - "build-compact": "node compile RELEASE=compact DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=false SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=false SUPPORT_SERIALIZE=false SUPPORT_INFO=false SUPPORT_DOCUMENTS=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", - "build-custom": "node compile RELEASE=custom DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_SUGGESTIONS=false SUPPORT_SERIALIZE=false SUPPORT_INFO=false SUPPORT_DOCUMENTS=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", - "build-es5": "node compile RELEASE=es5 DEBUG=true PROFILER=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENTS=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false LANGUAGE_OUT=ECMASCRIPT5_STRICT", - "build-node": "node compile RELEASE=node DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENTS=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build": "node compile RELEASE=min DEBUG=false PROFILER=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENTS=true SUPPORT_WHERE=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build-light": "node compile RELEASE=light DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_SUGGESTIONS=false SUPPORT_SERIALIZE=false SUPPORT_INFO=false SUPPORT_DOCUMENTS=false SUPPORT_WHERE=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build-compact": "node compile RELEASE=compact DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=false SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=false SUPPORT_SERIALIZE=false SUPPORT_INFO=false SUPPORT_DOCUMENTS=true SUPPORT_WHERE=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build-custom": "node compile RELEASE=custom DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_SUGGESTIONS=false SUPPORT_SERIALIZE=false SUPPORT_INFO=false SUPPORT_DOCUMENTS=false SUPPORT_WHERE=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build-es5": "node compile RELEASE=es5 DEBUG=true PROFILER=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENTS=true SUPPORT_WHERE=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false LANGUAGE_OUT=ECMASCRIPT5_STRICT", + "build-node": "node compile RELEASE=node DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENTS=true SUPPORT_WHERE=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", "build-lang": "node compile RELEASE=lang", "build-all": "npm run build && npm run build-light && npm run build-compact && npm run build-es5 && npm run build-node && npm run build-lang", "test-production": "nyc --reporter=html --reporter=text mocha --timeout=3000 test --exit", diff --git a/test/test.es6.js b/test/test.es6.js index b909d40..9fa6ccd 100644 --- a/test/test.es6.js +++ b/test/test.es6.js @@ -13,41 +13,41 @@ module.exports = function(FlexSearch, env){ var data = [{ + id: 2, data:{ - id: 0, - title: "Title 1", - body: "Body 1" + title: "Title 3", + body: "Body 3" } },{ + id: 1, data:{ - id: 1, title: "Title 2", body: "Body 2" } },{ + id: 0, data:{ - id: 2, - title: "Title 3", - body: "Body 3" + title: "Title 1", + body: "Body 1" } }]; var update = [{ + id: 0, data:{ - id: 0, title: "Foo 1", body: "Bar 1" } },{ + id: 1, data:{ - id: 1, title: "Foo 2", body: "Bar 2" } },{ + id: 2, data:{ - id: 2, title: "Foo 3", body: "Bar 3" } @@ -59,7 +59,7 @@ module.exports = function(FlexSearch, env){ doc: { - id: "data:id", + id: "id", field: [ "data:title", "data:body" @@ -200,7 +200,7 @@ module.exports = function(FlexSearch, env){ async: true, doc: { - id: "data:id", + id: "id", field: [ "data:title", "data:body" @@ -246,7 +246,7 @@ module.exports = function(FlexSearch, env){ async: true, doc: { - id: "data:id", + id: "id", field: [ "data:title", "data:body" @@ -283,6 +283,69 @@ module.exports = function(FlexSearch, env){ expect(await index.doc.index[0].length).to.equal(0); expect(await index.doc.index[1].length).to.equal(0); }); + + it("Should have been sorted properly", function(){ + + var index = new FlexSearch({ + + doc: { + + id: "id", + field: [ + "data:title" + ] + } + }); + + index.add(data); + + var results = index.search({ + + field: "data:title", + query: "title" + }); + + expect(results[0]).to.equal(data[0]); + expect(results[1]).to.equal(data[1]); + expect(results[2]).to.equal(data[2]); + + results = index.search({ + + query: "title", + field: "data:title", + sort: function(a, b){ + + const diff = a.id - b.id; + return (diff < 0 ? -1 : (diff ? 1 : 0)); + } + }); + + expect(results[0]).to.equal(data[2]); + expect(results[1]).to.equal(data[1]); + expect(results[2]).to.equal(data[0]); + + results = index.search({ + + query: "title", + field: "data:title", + sort: "id" + }); + + expect(results[0]).to.equal(data[2]); + expect(results[1]).to.equal(data[1]); + expect(results[2]).to.equal(data[0]); + + results = index.search({ + + query: "title", + field: "data:title", + sort: "data:title" + }); + + expect(results[0]).to.equal(data[2]); + expect(results[1]).to.equal(data[1]); + expect(results[2]).to.equal(data[0]); + }); }); // ------------------------------------------------------------------------ diff --git a/test/test.js b/test/test.js index bfe87cc..a609daf 100644 --- a/test/test.js +++ b/test/test.js @@ -1077,7 +1077,7 @@ describe("Relevance", function(){ // Suggestion Tests // ------------------------------------------------------------------------ -if(env !== "light") describe("Suggestion", function(){ +if(env !== "light") describe("Suggestions", function(){ it("Should have been suggested properly by relevance", function(){ @@ -1100,11 +1100,82 @@ if(env !== "light") describe("Suggestion", function(){ }); }); +// ------------------------------------------------------------------------ +// Where Clause +// ------------------------------------------------------------------------ + +if(env === "") describe("Where/Find", function(){ + + var data = [{ + id: 0, + title: "Title 1", + cat: "1", + flag: false + },{ + id: 1, + title: "Title 2", + cat: "2", + flag: false + },{ + id: 2, + title: "Title 3", + cat: "1", + flag: true + }]; + + it("Should have been found properly", function(){ + + var index = new FlexSearch({ + doc: { + id: "id", + field: "title", + tag: "cat" + } + }); + + index.add(data); + + //expect(index.length).to.equal(3); + + //expect(index.find(0)).to.equal(data[0]); + expect(index.find("id", 0)).to.equal(data[0]); + expect(index.where("id", 0)).to.have.members([data[0]]); + expect(index.find(function(val){return val.id === 0;})).to.equal(data[0]); + + expect(index.find({id: 1})).to.equal(data[1]); + expect(index.where({id: 1})).to.have.members([data[1]]); + expect(index.where(function(val){return val.id === 1;})).to.have.members([data[1]]); + + expect(index.find({cat: "1"})).to.equal(data[0]); + expect(index.find({cat: "2"})).to.equal(data[1]); + expect(index.find({cat: "2", flag: true})).to.equal(null); + expect(index.find(data[2])).to.equal(data[2]); + expect(index.where(data[2])).to.have.members([data[2]]); + + expect(index.where({cat: "1"})).to.have.members([data[0], data[2]]); + expect(index.search("title", {sort: "cat"})[1]).to.equal(data[2]); + expect(index.search("title")).to.have.members(data); + + expect(index.search("title", { + where: { + cat: "1" + } + })).to.have.members([data[0], data[2]]); + + expect(index.search("title", { + where: { + cat: "1", + flag: true + } + })).to.have.members([data[2]]); + }); +}); + // ------------------------------------------------------------------------ // Multi-Field Documents // ------------------------------------------------------------------------ -if(!this._phantom){ +if((typeof require !== "undefined") && !this._phantom){ require("./test.es6.js")(FlexSearch, env); }