Permalink
Browse files

Use match() operator for regex

  • Loading branch information...
kriszyp committed Dec 1, 2010
1 parent b16713b commit e48ec9d57b835cb42cb41de4cdbf4cdd2463bee5
Showing with 39 additions and 51 deletions.
  1. +36 −46 lib/js-array.js
  2. +3 −5 test/js-array.js
View
@@ -46,10 +46,13 @@ exports.operators = {
}); });
return this; return this;
}, },
match: filter(function(value, regex){
return new RegExp(regex).test(value);
}),
"in": filter(function(value, values){ "in": filter(function(value, values){
return values.indexOf(value) > -1; return values.indexOf(value) > -1;
}), }),
"out": filter(function(value, values){ out: filter(function(value, values){
return values.indexOf(value) == -1; return values.indexOf(value) == -1;
}), }),
contains: filter(function(array, value){ contains: filter(function(array, value){
@@ -345,57 +348,44 @@ function query(query, options, target){
var parameters = options.parameters || []; var parameters = options.parameters || [];
var js = ""; var js = "";
function queryToJS(value){ function queryToJS(value){
if(value && typeof value === "object" && !(value instanceof Array)){ if(value && typeof value === "object"){
var jsOperator = exports.jsOperatorMap[value.name]; if(value instanceof Array){
if(jsOperator){ return '[' + value.map(queryToJS) + ']';
// item['foo.bar'] ==> (item && item.foo && item.foo.bar && ...) }else{
var path = value.args[0]; var jsOperator = exports.jsOperatorMap[value.name];
var target = value.args[1]; if(jsOperator){
if (typeof target == "undefined"){ // item['foo.bar'] ==> (item && item.foo && item.foo.bar && ...)
var item = "item"; var path = value.args[0];
target = path; var target = value.args[1];
}else if(path instanceof Array){ if (typeof target == "undefined"){
var item = "item"; var item = "item";
var escaped = []; target = path;
for(var i = 0;i < path.length; i++){ }else if(path instanceof Array){
escaped.push(stringify(path[i])); var item = "item";
item +="&&item[" + escaped.join("][") + ']'; var escaped = [];
for(var i = 0;i < path.length; i++){
escaped.push(stringify(path[i]));
item +="&&item[" + escaped.join("][") + ']';
}
}else{
var item = "item&&item[" + stringify(path) + "]";
} }
}else{ // use native Array.prototype.filter if available
var item = "item&&item[" + stringify(path) + "]"; var condition = item + jsOperator + queryToJS(target);
} if (typeof Array.prototype.filter === 'function') {
// comparison to regexps are special: we cope with eq(), ne(), the others coerce regexp to string return "(function(){return this.filter(function(item){return " + condition + "})})";
if (value.args[1] instanceof RegExp) { //???return "this.filter(function(item){return " + condition + "})";
if (jsOperator === '===' || jsOperator === '!==') {
// N.B. matching requires String
item = 'String('+item + '||"")';
if (jsOperator === '!==') item = '!'+item;
jsOperator = '.match('+value.args[1]+')&&""===';
target = '';
} else { } else {
// TODO: more elegant? return "(function(){var filtered = []; for(var i = 0, length = this.length; i < length; i++){var item = this[i];if(" + condition + "){filtered.push(item);}} return filtered;})";
// FIXME: require()ing ./query at top level makes circular dep and ./query.knownOperators becomes undefined
target = QUERY.encodeValue(target).split(':').slice(1).join(':');
// TODO: RECONSIDER, as under nodules require() is 10 times slower
// PLUS is breaks client-side require()
//value.args[1] = require('./query').encodeValue(value.args[1]).split(':').slice(1).join(':');
} }
}else{
return "(function(){return op('" + value.name + "').call(this" +
(value && value.args && value.args.length > 0 ? (", " + value.args.map(queryToJS).join(",")) : "") +
")})";
} }
// use native Array.prototype.filter if available
var condition = item + jsOperator + queryToJS(target);
if (typeof Array.prototype.filter === 'function') {
return "(function(){return this.filter(function(item){return " + condition + "})})";
//???return "this.filter(function(item){return " + condition + "})";
} else {
return "(function(){var filtered = []; for(var i = 0, length = this.length; i < length; i++){var item = this[i];if(" + condition + "){filtered.push(item);}} return filtered;})";
}
}else{
return "(function(){return op('" + value.name + "').call(this" +
(value && value.args && value.args.length > 0 ? (", " + value.args.map(queryToJS).join(",")) : "") +
")})";
} }
}else{ }else{
return typeof value === "number" ? value : stringify(value); return typeof value === "string" ? stringify(value) : value;
} }
} }
var evaluator = eval("(function(target){return " + queryToJS(query) + ".call(target);})"); var evaluator = eval("(function(target){return " + queryToJS(query) + ".call(target);})");
View
@@ -31,12 +31,10 @@ exports.testFiltering = function() {
assert.equal(executeQuery("excludes(tags,ne(fun))", {}, data).length, 1); assert.equal(executeQuery("excludes(tags,ne(fun))", {}, data).length, 1);
assert.equal(executeQuery("excludes(tags,ne(even))", {}, data).length, 0); assert.equal(executeQuery("excludes(tags,ne(even))", {}, data).length, 0);
// eq() on re: should trigger .match() // eq() on re: should trigger .match()
assert.deepEqual(executeQuery("price=re:10", {}, data), [data[0]]); assert.deepEqual(executeQuery("price=match=10", {}, data), [data[0]]);
// ne() on re: should trigger .not(.match()) // ne() on re: should trigger .not(.match())
assert.deepEqual(executeQuery("ne(price,re:10)", {}, data), [data[1]]); assert.deepEqual(executeQuery("name=match=f.*", {}, data), [data[1]]);
// other comparisons to re: should treat regexp as string assert.deepEqual(executeQuery("name=match=glob:f*", {}, data), [data[1]]);
assert.deepEqual(executeQuery("lt(price,re:10)", {}, data), [data[1]]);
assert.deepEqual(executeQuery("gt(price,re:10)", {}, data), []);
}; };
exports.testFiltering1 = function() { exports.testFiltering1 = function() {

0 comments on commit e48ec9d

Please sign in to comment.