Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added a case insensitive likeI operator and adjusted docs accordingly

  • Loading branch information...
commit c2a334718a1abf3c7cd7d2918dd1d2cbf64a43b4 1 parent f6ad168
@davidgtonge authored
View
11 README.md
@@ -175,10 +175,19 @@ Uses indexOf rather than regex for performance reasons
```js
MyCollection.query({ title: {$like: "Test" } });
-//Returns all models which have a "title" attribute what
+//Returns all models which have a "title" attribute that
//contains the string "Test", e.g. "Testing", "Tests", "Test", etc.
```
+### $likeI
+The same as above but performs a case insensitive search using indexOf and toLowerCase (still faster than Regex)
+
+```js
+MyCollection.query({ title: {$likeI: "Test" } });
+//Returns all models which have a "title" attribute that
+//contains the string "Test", "test", "tEst","tesT", etc.
+```
+
### $regex
Checks if the model attribute matches the supplied regular expression. The regex query can be supplied without the `$regex` keyword
View
99 js/backbone-query.js
@@ -6,7 +6,7 @@ May be freely distributed according to MIT license.
*/
(function() {
- var get_cache, get_models, get_sorted_models, iterator, page_models, parse_query, process_query, sort_models, test_model_attribute, test_query_value,
+ var get_cache, get_models, get_sorted_models, iterator, page_models, parse_query, perform_query, process_query, sort_models, test_model_attribute, test_query_value,
__indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
parse_query = function(raw_query) {
@@ -49,6 +49,7 @@ May be freely distributed according to MIT license.
case "$regex":
return _(value).isRegExp();
case "$like":
+ case "$likeI":
return _(value).isString();
case "$between":
return _(value).isArray() && (value.length === 2);
@@ -62,6 +63,7 @@ May be freely distributed according to MIT license.
test_model_attribute = function(type, value) {
switch (type) {
case "$like":
+ case "$likeI":
case "$regex":
return _(value).isString();
case "$contains":
@@ -78,6 +80,54 @@ May be freely distributed according to MIT license.
}
};
+ perform_query = function(type, value, attr, model) {
+ switch (type) {
+ case "$equal":
+ return attr === value;
+ case "$contains":
+ return __indexOf.call(attr, value) >= 0;
+ case "$ne":
+ return attr !== value;
+ case "$lt":
+ return attr < value;
+ case "$gt":
+ return attr > value;
+ case "$lte":
+ return attr <= value;
+ case "$gte":
+ return attr >= value;
+ case "$between":
+ return (value[0] < attr && attr < value[1]);
+ case "$in":
+ return __indexOf.call(value, attr) >= 0;
+ case "$nin":
+ return __indexOf.call(value, attr) < 0;
+ case "$all":
+ return _(attr).all(function(item) {
+ return __indexOf.call(value, item) >= 0;
+ });
+ case "$any":
+ return _(attr).any(function(item) {
+ return __indexOf.call(value, item) >= 0;
+ });
+ case "$size":
+ return attr.length === value;
+ case "$exists":
+ case "$has":
+ return (attr != null) === value;
+ case "$like":
+ return attr.indexOf(value) !== -1;
+ case "$likeI":
+ return attr.toLowerCase().indexOf(value.toLowerCase()) !== -1;
+ case "$regex":
+ return value.test(attr);
+ case "$cb":
+ return value.call(model, attr);
+ default:
+ return false;
+ }
+ };
+
iterator = function(models, query, andOr, filterReject) {
var parsed_query;
parsed_query = parse_query(query);
@@ -87,52 +137,7 @@ May be freely distributed according to MIT license.
q = parsed_query[_i];
attr = model.get(q.key);
test = test_model_attribute(q.type, attr);
- if (test) {
- test = (function() {
- var _ref;
- switch (q.type) {
- case "$equal":
- return attr === q.value;
- case "$contains":
- return _ref = q.value, __indexOf.call(attr, _ref) >= 0;
- case "$ne":
- return attr !== q.value;
- case "$lt":
- return attr < q.value;
- case "$gt":
- return attr > q.value;
- case "$lte":
- return attr <= q.value;
- case "$gte":
- return attr >= q.value;
- case "$between":
- return (q.value[0] < attr && attr < q.value[1]);
- case "$in":
- return __indexOf.call(q.value, attr) >= 0;
- case "$nin":
- return __indexOf.call(q.value, attr) < 0;
- case "$all":
- return _(model.get(q.key)).all(function(item) {
- return __indexOf.call(q.value, item) >= 0;
- });
- case "$any":
- return _(model.get(q.key)).any(function(item) {
- return __indexOf.call(q.value, item) >= 0;
- });
- case "$size":
- return attr.length === q.value;
- case "$exists":
- case "$has":
- return model.has(q.key) === q.value;
- case "$like":
- return attr.indexOf(q.value) !== -1;
- case "$regex":
- return q.value.test(attr);
- case "$cb":
- return q.value.call(model, attr);
- }
- })();
- }
+ if (test) test = perform_query(q.type, q.value, attr, model);
if (andOr === test) return andOr;
}
return !andOr;
View
2  js/backbone-query.min.js
@@ -1 +1 @@
-((function(){var a,b,c,d,e,f,g,h,i,j,k=Array.prototype.indexOf||function(a){for(var b=0,c=this.length;b<c;b++)if(b in this&&this[b]===a)return b;return-1};f=function(a){var b,c,d,e,f,g;g=[];for(b in a){d=a[b],c={key:b};if(_.isRegExp(d))c.type="$regex",c.value=d;else if(_(d).isObject())for(e in d)f=d[e],j(e,f)&&(c.type=e,c.value=f);else c.type="$equal",c.value=d;g.push(c)}return g},j=function(a,b){switch(a){case"$in":case"$nin":case"$all":case"$any":return _(b).isArray();case"$size":return _(b).isNumber();case"$regex":return _(b).isRegExp();case"$like":return _(b).isString();case"$between":return _(b).isArray()&&b.length===2;case"$cb":return _(b).isFunction();default:return!0}},i=function(a,b){switch(a){case"$like":case"$regex":return _(b).isString();case"$contains":case"$all":case"$any":return _(b).isArray();case"$size":return _(b).isArray()||_(b).isString();case"$in":case"$nin":return b!=null;default:return!0}},d=function(a,b,c,d){var e;return e=f(b),_[d](a,function(a){var b,d,f,g,h;for(g=0,h=e.length;g<h;g++){d=e[g],b=a.get(d.key),f=i(d.type,b),f&&(f=function(){var c;switch(d.type){case"$equal":return b===d.value;case"$contains":return c=d.value,k.call(b,c)>=0;case"$ne":return b!==d.value;case"$lt":return b<d.value;case"$gt":return b>d.value;case"$lte":return b<=d.value;case"$gte":return b>=d.value;case"$between":return d.value[0]<b&&b<d.value[1];case"$in":return k.call(d.value,b)>=0;case"$nin":return k.call(d.value,b)<0;case"$all":return _(a.get(d.key)).all(function(a){return k.call(d.value,a)>=0});case"$any":return _(a.get(d.key)).any(function(a){return k.call(d.value,a)>=0});case"$size":return b.length===d.value;case"$exists":case"$has":return a.has(d.key)===d.value;case"$like":return b.indexOf(d.value)!==-1;case"$regex":return d.value.test(b);case"$cb":return d.value.call(a,b)}}());if(c===f)return c}return!c})},g={$and:function(a,b){return d(a,b,!1,"filter")},$or:function(a,b){return d(a,b,!0,"filter")},$nor:function(a,b){return d(a,b,!0,"reject")},$not:function(a,b){return d(a,b,!1,"reject")}},a=function(a,b,d){var e,f,g,h;return g=JSON.stringify(b),e=(h=a._query_cache)!=null?h:a._query_cache={},f=e[g],f||(f=c(a,b,d),e[g]=f),f},b=function(a,b){var c,d,e,f;c=_.intersection(["$and","$not","$or","$nor"],_(b).keys()),d=a.models;switch(c.length){case 0:return g.$and(d,b);case 1:return e=c[0],g[e](d,b[e]);default:return f=function(a,c){return g[c](a,b[c])},_.reduce(c,f,d)}},c=function(a,c,d){var e;return e=b(a,c),d.sortBy&&(e=h(e,d)),e},h=function(a,b){return _(b.sortBy).isString()?a=_(a).sortBy(function(a){return a.get(b.sortBy)}):_(b.sortBy).isFunction()&&(a=_(a).sortBy(b.sortBy)),b.order==="desc"&&(a=a.reverse()),a},e=function(a,b){var c,d,e,f;return b.offset?e=b.offset:b.page?e=(b.page-1)*b.limit:e=0,c=e+b.limit,d=a.slice(e,c),b.pager&&_.isFunction(b.pager)&&(f=Math.ceil(a.length/b.limit),b.pager(f,d)),d};if(typeof require!="undefined"){if(typeof _=="undefined"||_===null)_=require("underscore");if(typeof Backbone=="undefined"||Backbone===null)Backbone=require("backbone")}Backbone.QueryCollection=Backbone.Collection.extend({query:function(b,d){var f;return d==null&&(d={}),d.cache?f=a(this,b,d):f=c(this,b,d),d.limit&&(f=e(f,d)),f},reset_query_cache:function(){return this._query_cache={}}}),typeof exports!="undefined"&&(exports.QueryCollection=Backbone.QueryCollection)})).call(this)
+((function(){var a,b,c,d,e,f,g,h,i,j,k,l=Array.prototype.indexOf||function(a){for(var b=0,c=this.length;b<c;b++)if(b in this&&this[b]===a)return b;return-1};f=function(a){var b,c,d,e,f,g;g=[];for(b in a){d=a[b],c={key:b};if(_.isRegExp(d))c.type="$regex",c.value=d;else if(_(d).isObject())for(e in d)f=d[e],k(e,f)&&(c.type=e,c.value=f);else c.type="$equal",c.value=d;g.push(c)}return g},k=function(a,b){switch(a){case"$in":case"$nin":case"$all":case"$any":return _(b).isArray();case"$size":return _(b).isNumber();case"$regex":return _(b).isRegExp();case"$like":case"$likeI":return _(b).isString();case"$between":return _(b).isArray()&&b.length===2;case"$cb":return _(b).isFunction();default:return!0}},j=function(a,b){switch(a){case"$like":case"$likeI":case"$regex":return _(b).isString();case"$contains":case"$all":case"$any":return _(b).isArray();case"$size":return _(b).isArray()||_(b).isString();case"$in":case"$nin":return b!=null;default:return!0}},g=function(a,b,c,d){switch(a){case"$equal":return c===b;case"$contains":return l.call(c,b)>=0;case"$ne":return c!==b;case"$lt":return c<b;case"$gt":return c>b;case"$lte":return c<=b;case"$gte":return c>=b;case"$between":return b[0]<c&&c<b[1];case"$in":return l.call(b,c)>=0;case"$nin":return l.call(b,c)<0;case"$all":return _(c).all(function(a){return l.call(b,a)>=0});case"$any":return _(c).any(function(a){return l.call(b,a)>=0});case"$size":return c.length===b;case"$exists":case"$has":return c!=null===b;case"$like":return c.indexOf(b)!==-1;case"$likeI":return c.toLowerCase().indexOf(b.toLowerCase())!==-1;case"$regex":return b.test(c);case"$cb":return b.call(d,c);default:return!1}},d=function(a,b,c,d){var e;return e=f(b),_[d](a,function(a){var b,d,f,h,i;for(h=0,i=e.length;h<i;h++){d=e[h],b=a.get(d.key),f=j(d.type,b),f&&(f=g(d.type,d.value,b,a));if(c===f)return c}return!c})},h={$and:function(a,b){return d(a,b,!1,"filter")},$or:function(a,b){return d(a,b,!0,"filter")},$nor:function(a,b){return d(a,b,!0,"reject")},$not:function(a,b){return d(a,b,!1,"reject")}},a=function(a,b,d){var e,f,g,h;return g=JSON.stringify(b),e=(h=a._query_cache)!=null?h:a._query_cache={},f=e[g],f||(f=c(a,b,d),e[g]=f),f},b=function(a,b){var c,d,e,f;c=_.intersection(["$and","$not","$or","$nor"],_(b).keys()),d=a.models;switch(c.length){case 0:return h.$and(d,b);case 1:return e=c[0],h[e](d,b[e]);default:return f=function(a,c){return h[c](a,b[c])},_.reduce(c,f,d)}},c=function(a,c,d){var e;return e=b(a,c),d.sortBy&&(e=i(e,d)),e},i=function(a,b){return _(b.sortBy).isString()?a=_(a).sortBy(function(a){return a.get(b.sortBy)}):_(b.sortBy).isFunction()&&(a=_(a).sortBy(b.sortBy)),b.order==="desc"&&(a=a.reverse()),a},e=function(a,b){var c,d,e,f;return b.offset?e=b.offset:b.page?e=(b.page-1)*b.limit:e=0,c=e+b.limit,d=a.slice(e,c),b.pager&&_.isFunction(b.pager)&&(f=Math.ceil(a.length/b.limit),b.pager(f,d)),d};if(typeof require!="undefined"){if(typeof _=="undefined"||_===null)_=require("underscore");if(typeof Backbone=="undefined"||Backbone===null)Backbone=require("backbone")}Backbone.QueryCollection=Backbone.Collection.extend({query:function(b,d){var f;return d==null&&(d={}),d.cache?f=a(this,b,d):f=c(this,b,d),d.limit&&(f=e(f,d)),f},reset_query_cache:function(){return this._query_cache={}}}),typeof exports!="undefined"&&(exports.QueryCollection=Backbone.QueryCollection)})).call(this)
View
48 src/backbone-query.coffee
@@ -32,7 +32,7 @@ test_query_value = (type, value) ->
when "$in","$nin","$all", "$any" then _(value).isArray()
when "$size" then _(value).isNumber()
when "$regex" then _(value).isRegExp()
- when "$like" then _(value).isString()
+ when "$like", "$likeI" then _(value).isString()
when "$between" then _(value).isArray() and (value.length is 2)
when "$cb" then _(value).isFunction()
else true
@@ -40,12 +40,36 @@ test_query_value = (type, value) ->
# Test each attribute that is being tested to ensure that is of the correct type
test_model_attribute = (type, value) ->
switch type
- when "$like", "$regex" then _(value).isString()
+ when "$like", "$likeI", "$regex" then _(value).isString()
when "$contains", "$all", "$any" then _(value).isArray()
when "$size" then _(value).isArray() or _(value).isString()
when "$in", "$nin" then value?
else true
+# Perform the actual query logic for each query and each model/attribute
+perform_query = (type, value, attr, model) ->
+ switch type
+ when "$equal" then attr is value
+ when "$contains" then value in attr
+ when "$ne" then attr isnt value
+ when "$lt" then attr < value
+ when "$gt" then attr > value
+ when "$lte" then attr <= value
+ when "$gte" then attr >= value
+ when "$between" then value[0] < attr < value[1]
+ when "$in" then attr in value
+ when "$nin" then attr not in value
+ when "$all" then _(attr).all (item) -> item in value
+ when "$any" then _(attr).any (item) -> item in value
+ when "$size" then attr.length is value
+ when "$exists", "$has" then attr? is value
+ when "$like" then attr.indexOf(value) isnt -1
+ when "$likeI" then attr.toLowerCase().indexOf(value.toLowerCase()) isnt -1
+ when "$regex" then value.test attr
+ when "$cb" then value.call model, attr
+ else false
+
+
# The main iterator that actually applies the query
iterator = (models, query, andOr, filterReject) ->
parsed_query = parse_query query
@@ -58,25 +82,7 @@ iterator = (models, query, andOr, filterReject) ->
# Check if the attribute value is the right type (some operators need a string, or an array)
test = test_model_attribute(q.type, attr)
# If the attribute test is true, perform the query
- if test then test = switch q.type
- when "$equal" then attr is q.value
- when "$contains" then q.value in attr
- when "$ne" then attr isnt q.value
- when "$lt" then attr < q.value
- when "$gt" then attr > q.value
- when "$lte" then attr <= q.value
- when "$gte" then attr >= q.value
- when "$between" then q.value[0] < attr < q.value[1]
- when "$in" then attr in q.value
- when "$nin" then attr not in q.value
- when "$all" then _(model.get q.key).all (item) -> item in q.value
- when "$any" then _(model.get q.key).any (item) -> item in q.value
- when "$size" then attr.length is q.value
- when "$exists", "$has" then model.has(q.key) is q.value
- when "$like" then attr.indexOf(q.value) isnt -1
- when "$regex" then q.value.test attr
- when "$cb" then q.value.call model, attr
-
+ if test then test = perform_query q.type, q.value, attr, model
# If the query is an "or" query than as soon as a match is found we return "true"
# Whereas if the query is an "and" query then we return "false" as soon as a match isn't found.
return andOr if andOr is test
View
11 test/backbone-query-test.coffee
@@ -86,7 +86,7 @@ test "$in operator", ->
test "$in operator with wrong query value", ->
a = create()
result = a.query title: {$in: "Home"}
- equal result.length, 3
+ equal result.length, 0
test "$nin operator", ->
a = create()
@@ -105,7 +105,7 @@ test "$all operator (wrong values)", ->
equal result.length, 0
result = a.query colors: {$all: "red"}
- equal result.length, 3
+ equal result.length, 0
test "$any operator", ->
a = create()
@@ -143,6 +143,13 @@ test "$like operator 2", ->
result = a.query content: {$like: "content"}
equal result.length, 3
+test "$likeI operator", ->
+ a = create()
+ result = a.query content: {$likeI: "dummy"}
+ equal result.length, 3
+ result = a.query content: {$like: "dummy"}
+ equal result.length, 1
+
test "$regex", ->
a = create()
result = a.query content: {$regex: /javascript/gi}
View
21 test/backbone-query-test.js
@@ -183,7 +183,7 @@
$in: "Home"
}
});
- return equal(result.length, 3);
+ return equal(result.length, 0);
});
test("$nin operator", function() {
@@ -223,7 +223,7 @@
$all: "red"
}
});
- return equal(result.length, 3);
+ return equal(result.length, 0);
});
test("$any operator", function() {
@@ -301,6 +301,23 @@
return equal(result.length, 3);
});
+ test("$likeI operator", function() {
+ var a, result;
+ a = create();
+ result = a.query({
+ content: {
+ $likeI: "dummy"
+ }
+ });
+ equal(result.length, 3);
+ result = a.query({
+ content: {
+ $like: "dummy"
+ }
+ });
+ return equal(result.length, 1);
+ });
+
test("$regex", function() {
var a, result;
a = create();

0 comments on commit c2a3347

Please sign in to comment.
Something went wrong with that request. Please try again.