Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

various assorted fixes

  • Loading branch information...
commit aac0d6295e72fead6bc3f69176ee007c3ed21491 1 parent be2de2c
@dvv dvv authored
Showing with 80 additions and 22 deletions.
  1. +33 −10 lib/js-array.js
  2. +40 −12 lib/query.js
  3. +7 −0 test/js-array.js
View
43 lib/js-array.js
@@ -4,8 +4,10 @@
*
*/
-({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./parser"));}}).
-define(["exports", "./parser"], function(exports, parser){
+({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./parser"), require("./query"));}}).
+define(["exports", "./parser", "./query"], function(exports, parser, QUERY){
+//({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./parser"));}}).
+//define(["exports", "./parser"], function(exports, parser){
var parseQuery = parser.parseQuery;
var stringify = JSON.stringify || function(str){
@@ -339,6 +341,9 @@ function query(query, options, target){
for(var i in options.operators){
operators[i] = options.operators[i];
}
+ function op(name){
+ return operators[name]||exports.missingOperator(name);
+ }
var parameters = options.parameters || [];
var js = "";
function queryToJS(value){
@@ -357,16 +362,34 @@ function query(query, options, target){
}else{
var item = "(item[" + stringify(path) + "]";
}
- item += ')';
- if (jsOperator === '===' && value.args[1] instanceof RegExp){
- // N.B. matching requires String
- item = 'String('+item + '||"")';
- jsOperator = '.match('+value.args[1]+')&&""===';
- value.args[1] = '';
+ item += ')';
+ // comparison to regexps are special: we cope with eq(), ne(), the others coerce regexp to string
+ if (value.args[1] instanceof RegExp) {
+ if (jsOperator === '===' || jsOperator === '!==') {
+ // N.B. matching requires String
+ item = 'String('+item + '||"")';
+ if (jsOperator === '!==') item = '!'+item;
+ jsOperator = '.match('+value.args[1]+')&&""===';
+ value.args[1] = '';
+ } else {
+ // TODO: more elegant?
+ // FIXME: require()ing ./query at top level makes circular dep and ./query.knownOperators becomes undefined
+ value.args[1] = QUERY.encodeValue(value.args[1]).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(':');
+ }
+ }
+ // use native Array.prototype.filter if available
+ var condition = item + jsOperator + queryToJS(value.args[1]);
+ 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;})";
}
- return "(function(){var filtered = []; for(var i = 0, length = this.length; i < length; i++){var item = this[i];if(" + item + jsOperator + queryToJS(value.args[1]) + "){filtered.push(item);}} return filtered;})";
}else{
- return "(function(){return (operators['" + value.name + "']||exports.missingOperator('" + value.name + "')).call(this" +
+ return "(function(){return op('" + value.name + "').call(this" +
(value && value.args && value.args.length > 0 ? (", " + value.args.map(queryToJS).join(",")) : "") +
")})";
}
View
52 lib/query.js
@@ -9,8 +9,10 @@
* // for each object that matches the query
* });
*/
-({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./parser"), require("./js-array"));}}).
-define(["exports", "./parser", "./js-array"], function(exports, parser, jsarray){
+//({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./parser"), require("./js-array"));}}).
+//define(["exports", "./parser", "./js-array"], function(exports, parser, jsarray){
+({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./parser"));}}).
+define(["exports", "./parser"], function(exports, parser){
var parseQuery = parser.parseQuery;
try{
@@ -28,8 +30,8 @@ parser.Query = function(seed, params){
return q;
};
exports.Query = parser.Query;
-//exports.knownOperators = ["and", "or", "eq", "ne", "le", "lt", "gt", "ge", "sort", "in", "notin", "select", "exclude", "contains", "notcontains", "values","aggregate","distinct","limit","recurse"];
-exports.knownOperators = Object.keys(jsarray.operators).concat(Object.keys(jsarray.jsOperatorMap));
+//TODO:THE RIGHT WAY IS:exports.knownOperators = Object.keys(jsarray.operators || {}).concat(Object.keys(jsarray.jsOperatorMap || {}));
+exports.knownOperators = ["sort", "in", "not", "any", "all", "or", "and", "select", "exclude", "values", "limit", "distinct", "recurse", "aggregate", "between", "sum", "mean", "max", "min", "count", "first", "one", "eq", "ne", "le", "ge", "lt", "gt"];
exports.knownScalarOperators = ["mean", "sum", "min", "max", "count", "first", "one"];
exports.arrayMethods = ["forEach", "reduce", "map", "filter", "indexOf", "some", "every"];
@@ -155,7 +157,9 @@ Query.prototype.walk = function(fn, options){
if (args[0] instanceof Query) {
walk.call(this, func, args);
} else {
- fn.call(this, func, args);
+ var newTerm = fn.call(this, func, args);
+ if (newTerm && newTerm.name && newTerm.args)
+ arr[i] = newTerm;
}
});
}
@@ -166,6 +170,7 @@ Query.prototype.walk = function(fn, options){
Query.prototype.normalize = function(options){
options = options || {};
options.primaryKey = options.primaryKey || 'id';
+ options.map = options.map || {};
var result = {
original: this,
sort: [],
@@ -174,24 +179,26 @@ Query.prototype.normalize = function(options){
limit: Infinity,
select: [],
values: false
- // TODO: cache conditions
- // TODO: flag for non-void conditions
};
function normal(func, args){
+ // cache some parameters
if (func === 'sort' || func === 'select') {
result[func] = args;
- result[func+'1'] = result[func].map(function(x){
+ result[func+'Arr'] = result[func].map(function(x, pos){
+ if (pos === 0 && x instanceof Array) x = x.join('.');
var o = {};
var a = /([-+]*)(.+)/.exec(x);
o[a[2]] = a[1].charAt(0) === '-' ? -1 : 1;
return o;
});
- result[func+'2'] = {};
- result[func].forEach(function(x){
+ result[func+'Obj'] = {};
+ result[func].forEach(function(x, pos){
+ if (pos === 0 && x instanceof Array) x = x.join('.');
var a = /([-+]*)(.+)/.exec(x);
- result[func+'2'][a[2]] = a[1].charAt(0) === '-' ? -1 : 1;
+ result[func+'Obj'][a[2]] = a[1].charAt(0) === '-' ? -1 : 1;
});
} else if (func === 'limit') {
+ // validate limit() args to be numbers, with sane defaults
var limit = args;
result.skip = +limit[1] || 0;
limit = +limit[0] || 0;
@@ -200,18 +207,39 @@ Query.prototype.normalize = function(options){
result.limit = limit;
result.needCount = true;
} else if (func === 'values') {
+ // N.B. values() just signals we want array of what we select()
result.values = true;
} else if (func === 'eq') {
// cache primary key equality -- useful to distinguish between .get(id) and .query(query)
var t = typeof args[1];
+ //if ((args[0] instanceof Array ? args[0][args[0].length-1] : args[0]) === options.primaryKey && ['string','number'].indexOf(t) >= 0) {
if (args[0] === options.primaryKey && ['string','number'].indexOf(t) >= 0) {
- result.id = String(args[1]);
+ result.pk = String(args[1]);
}
}
+ // cache search conditions
+ //if (options.known[func])
+ // map some functions
+ /*if (options.map[func]) {
+ func = options.map[func];
+ }*/
}
this.walk(normal);
return result;
};
+/* FIXME: an example will be welcome
+Query.prototype.toMongo = function(options){
+ return this.normalize({
+ primaryKey: '_id',
+ map: {
+ ge: 'gte',
+ le: 'lte'
+ },
+ known: ['lt','lte','gt','gte','ne','in','nin','not','mod','all','size','exists','type','elemMatch']
+ });
+};
+*/
+
return exports;
});
View
7 test/js-array.js
@@ -30,6 +30,13 @@ exports.testFiltering = function() {
assert.equal(executeQuery("all(tags,fun)", {}, data).length, 1);
assert.equal(executeQuery("all(tags,even)", {}, data).length, 0);
assert.equal(executeQuery("not(all(tags,even))", {}, data).length, 2);
+ // eq() on re: should trigger .match()
+ assert.deepEqual(executeQuery("price=re:10", {}, data), [data[0]]);
+ // ne() on re: should trigger .not(.match())
+ assert.deepEqual(executeQuery("ne(price,re:10)", {}, data), [data[1]]);
+ // other comparisons to re: should treat regexp as string
+ assert.deepEqual(executeQuery("lt(price,re:10)", {}, data), [data[1]]);
+ assert.deepEqual(executeQuery("gt(price,re:10)", {}, data), []);
};
exports.testFiltering1 = function() {
Please sign in to comment.
Something went wrong with that request. Please try again.