Skip to content

Commit

Permalink
Query.normalize() -- a helper to disambiguate and post-parse query
Browse files Browse the repository at this point in the history
  • Loading branch information
dvv committed Nov 29, 2010
1 parent 9fd7aa4 commit 1a1b5d9
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 52 deletions.
22 changes: 22 additions & 0 deletions lib/parser.js
Expand Up @@ -153,6 +153,28 @@ exports.parseGently = function(){
return terms;
}

/*
* reduces query to simple SQL-ish one
*
* that is only cond1(args1)&...condN(argsN)&sort(...)&limit(...)&select(...)[&values()] are supported and no hierarchy is supported
*/
exports.parseSimple = function(){
var terms;
try {
// vanilla parse
terms = parse.apply(this, arguments);
// delete any doubled lastSeens

terms = {
sele: 1
};
} catch(err) {
terms = new exports.Query();
terms.error = err.message;
}
return terms;
}

exports.commonOperatorMap = {
"and" : "&",
"or" : "|",
Expand Down
177 changes: 125 additions & 52 deletions lib/query.js
Expand Up @@ -3,10 +3,10 @@
* var Query = require("./query").Query;
* query = Query();
* query.executor = function(query){
* require("./js-array").query(query, params, data); // if we want to operate on an array
* require("./js-array").query(query, params, data); // if we want to operate on an array
* };
* query.eq("a", 3).le("b", 4).forEach(function(object){
* // for each object that matches the query
* // for each object that matches the query
* });
*/
({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./parser"));}}).
Expand Down Expand Up @@ -44,62 +44,62 @@ Query.prototype.toString = function(){
};

function queryToString(part) {
if (part instanceof Array) {
return '('+part.map(function(arg) {
return queryToString(arg);
}).join(",")+')';
}
if (part && part.name && part.args) {
return [
part.name,
"(",
part.args.map(function(arg) {
return queryToString(arg);
}).join(","),
")"
].join("");
}
return exports.encodeValue(part);
if (part instanceof Array) {
return '('+part.map(function(arg) {
return queryToString(arg);
}).join(",")+')';
}
if (part && part.name && part.args) {
return [
part.name,
"(",
part.args.map(function(arg) {
return queryToString(arg);
}).join(","),
")"
].join("");
}
return exports.encodeValue(part);
};

function encodeString(s) {
if (typeof s === "string") {
s = encodeURIComponent(s);
if (s.match(/[\(\)]/)) {
s = s.replace("(","%28").replace(")","%29");
};
}
return s;
if (typeof s === "string") {
s = encodeURIComponent(s);
if (s.match(/[\(\)]/)) {
s = s.replace("(","%28").replace(")","%29");
};
}
return s;
}

exports.encodeValue = function(val) {
var encoded;
if (val === null) val = 'null';
if (val !== parser.converters["default"]('' + (
val.toISOString && val.toISOString() || val.toString()
))) {
var type = typeof val;
if(val instanceof RegExp){
// TODO: control whether to we want simpler glob() style
val = val.toString();
var i = val.lastIndexOf('/');
type = val.substring(i).indexOf('i') >= 0 ? "re" : "RE";
val = encodeString(val.substring(1, i));
encoded = true;
}
if(type === "object"){
type = "epoch";
val = val.getTime();
encoded = true;
}
if(type === "string") {
val = encodeString(val);
encoded = true;
}
val = [type, val].join(":");
}
if (!encoded && typeof val === "string") val = encodeString(val);
return val;
var encoded;
if (val === null) val = 'null';
if (val !== parser.converters["default"]('' + (
val.toISOString && val.toISOString() || val.toString()
))) {
var type = typeof val;
if(val instanceof RegExp){
// TODO: control whether to we want simpler glob() style
val = val.toString();
var i = val.lastIndexOf('/');
type = val.substring(i).indexOf('i') >= 0 ? "re" : "RE";
val = encodeString(val.substring(1, i));
encoded = true;
}
if(type === "object"){
type = "epoch";
val = val.getTime();
encoded = true;
}
if(type === "string") {
val = encodeString(val);
encoded = true;
}
val = [type, val].join(":");
}
if (!encoded && typeof val === "string") val = encodeString(val);
return val;
};

exports.updateQueryMethods = function(){
Expand Down Expand Up @@ -136,5 +136,78 @@ exports.updateQueryMethods = function(){

exports.updateQueryMethods();

/* recursively iterate over query terms calling 'fn' for each term */
Query.prototype.walk = function(fn, options){
options = options || {};
function walk(name, terms){
(terms || []).forEach(function(term, i, arr) {
var args, func, key, x;
term != null ? term : term = {};
func = term.name;
args = term.args;
if (!func || !args) {
return;
}
if (args[0] instanceof Query) {
walk.call(this, func, args);
} else {
fn.call(this, func, args);
}
});
}
walk.call(this, this.name, this.args);
};

/* disambiguate query */
Query.prototype.normalize = function(options){
options = options || {};
options.primaryKey = options.primaryKey || 'id';
var result = {
original: this,
sort: [],
limit: [Infinity, 0, Infinity],
skip: 0,
limit: Infinity,
select: [],
values: false
// TODO: cache conditions
// TODO: flag for non-void conditions
};
function normal(func, args){
if (func === 'sort' || func === 'select') {
result[func] = args;
result[func+'1'] = result[func].map(function(x){
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){
var a = /([-+]*)(.+)/.exec(x);
result[func+'2'][a[2]] = a[1].charAt(0) === '-' ? -1 : 1;
});
} else if (func === 'limit') {
var limit = args;
result.skip = +limit[1] || 0;
limit = +limit[0] || 0;
if (options.hardLimit && limit > options.hardLimit)
limit = options.hardLimit;
result.limit = limit;
result.needCount = true;
} else if (func === 'values') {
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] === options.primaryKey && ['string','number'].indexOf(t) >= 0) {
result.id = String(args[1]);
}
}
}
this.walk(normal);
return result;
};

return exports;
});

0 comments on commit 1a1b5d9

Please sign in to comment.