-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquery.js
More file actions
143 lines (142 loc) · 4.88 KB
/
query.js
File metadata and controls
143 lines (142 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
Query processor -
Handles queries of the form
{ age : { $lt : 40 } }
object - one property, the name is the 'field_name'
the value is an expression which is an object
with one property, the name the operator, the value the 'value'
*/
function Expression(expression) {
var self = this;
if ( typeof expression != 'object' ) { // implicit equals case here
expression = { $eq : expression };
}
self.operator = Object.keys(expression)[0];
self.value = expression[self.operator];
self.evaluators = {};
self.evaluators["$eq"]="==";
self.evaluators["$nq"]="!=";
self.evaluators["$lt"]="<";
self.evaluators["$lte"]="<=";
self.evaluators["$gt"]=">";
self.evaluators["$gte"]=">=";
}
Expression.prototype.toString = function() {
return JSON.stringify(self);
}
Expression.prototype.evaluate = function(value) {
var self = this;
// build a code expression
// wrap in quotes if NaN
if (isNaN(value)) {
var exp='"'+value+'"'+self.evaluators[self.operator]+'"'+self.value+'"';
} else {
var exp=value+self.evaluators[self.operator]+self.value;
}
//console.dir(exp);
var result = eval(exp);
return result;
}
/*
* A query is one or more field_name/expression pairs.
* If just one expression - then just a simple expression object
* If more than one expression - then an array of expressions
* which are embedded in an object with one-single property, the
* name of which is the "joiner" = "$and" or "$or" and whose value
* is the array of expressions.
* TO-DO - support initial argument which is an array of $and/$or clauses,
* each of which is one or more expressions
*/
function Query(query) {
var self = this;
self.query_stack = []; // array of field/expressions
debugger;
var joiners = {
$and : "&&",
$or : "||"
};
Object.keys(query).forEach(function(prop) {
if ( prop[0]=="$" ) { // got 'joiner'
join_mode = prop;
if ( Array.isArray( query[prop] ) ) {
for(var i=0; i<query[prop].length; i++) {
// TO-DO error hanlding - what if not good expression!
self.query_stack.push( query[prop][i] );
}
} else {
self.query_stack.push( quer[prop] );
}
// TO-DO check for valid joiner!
self.query_stack.push(joiners[prop]);
} else { // just expression
self.query_stack.push(query); // ??? not sure here
}
});
//console.dir(self.query_stack);
}
Query.prototype.toString = function() {
return JSON.stringify(self);
}
Query.prototype.execute = function(data_set) {
var self = this;
var results = [];
//console.dir(self);
for(var i=0; i<data_set.length; i++) {
var data_row = data_set[i];
var eval_results = [];
var hit_joiner = false;
for(var j=0;j<self.query_stack.length;j++) {
var e = self.query_stack[j];
if ( typeof e === 'string' ) { // a joiner
// if OR, then add row if ANY eval_result was true
// if AND, then add row only if ALL eval_results's were true
//
hit_joiner = true;
var rr='';
for(k=0;k<eval_results.length;k++) {
rr+=eval_results[k];
if ( k<eval_results.length-1 ) {
rr+=e; // append operator
}
}
//console.dir(rr);
var add_row = eval(rr);
if ( add_row ) {
results.push( data_row );
}
continue;
}
var prop_name = Object.keys(e)[0];
// if row does not contain property, then continue
var gotProperty = false;
Object.keys(data_row).forEach(function(rp) {
if ( rp==prop_name ) {
gotProperty = true;
}
});
if ( !gotProperty ) {
continue;
}
var exp = new Expression(e[prop_name]); // TO-DO cache expressions?
var r = exp.evaluate(data_row[prop_name]);
eval_results.push(r);
}
// if we did not it a joiner clause, and we did find results
// then we should push them out - :
if ( !hit_joiner ) {
var add_row = false;
// if eval_results.length > 1 - should be error,
// only in this case if the query was just a single
// prop_name/expression pair
// TO-DO handle error in that case
if ( eval_results.length>0 ) {
if ( eval_results[0] ) {
results.push(data_row);
}
}
}
}
return results;
}
exports.Expression = Expression;
exports.Query = Query;