blob: 207c393856a13313ea4fd05d83ca9bba4aca9b01 [file] [log] [blame]
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -07001// Temporary AsterixExpression Placeholder
2function AExpression () {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -07003 this._properties = {};
4 this._success = function() {};
5
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -07006 return this;
7}
8
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -07009
10AExpression.prototype.bind = function(options) {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070011 var options = options || {};
12
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070013 if (options.hasOwnProperty("success")) {
14 this._success = options["success"];
15 }
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070016
17 if (options.hasOwnProperty("return")) {
18 this._properties["return"] = " return " + options["return"].val();
19 }
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070020};
21
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070022
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070023AExpression.prototype.run = function(successFn) {
24 var success_fn = successFn;
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070025
26 $.ajax({
27 type : 'GET',
genia.likes.science@gmail.comfc5f5092013-06-12 00:49:46 -070028 url : "http://localhost:19002/query",
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070029 data : {"query" : "use dataverse TinySocial;\n" + this.val()},
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070030 dataType : "json",
31 success : function(data) {
32 success_fn(data);
genia.likes.science@gmail.com5f425342013-06-13 13:51:26 -070033 },
34 error: function(r) {
35 //alert(JSON.stringify(r));
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070036 }
37 });
38
39 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070040};
41
42
43AExpression.prototype.val = function() {
44
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070045 var value = "";
46
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070047 // If there is a dataverse defined, provide it.
48 if (this._properties.hasOwnProperty("dataverse")) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070049 value += "use dataverse " + this._properties["dataverse"] + ";\n";
50 };
51
52 if (this._properties.hasOwnProperty("value")) {
53 value += this._properties["value"];
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070054 }
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070055
56 return value;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070057};
58
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070059// @param expressionValue [String]
60AExpression.prototype.set = function(expressionValue) {
61 this._properties["value"] = expressionValue;
62 return this;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070063};
64
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -070065
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070066// FunctionExpression
67// Parent: AsterixExpression
68//
69// @param options [Various],
70// @key function [String], a function to be applid to the expression
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070071// @key expression [AsterixExpression or AQLClause] an AsterixExpression/Clause to which the fn will be applied
72function FunctionExpression() {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070073
74 // Initialize superclass
75 AExpression.call(this);
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070076
77 this._properties["function"] = "";
78 this._properties["expression"] = new AExpression().set("");
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070079
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070080 // Check for fn/expression input
81 if (arguments.length == 2 && typeof arguments[0] == "string" &&
82 (arguments[1] instanceof AExpression || arguments[1] instanceof AQLClause)) {
83
84 this._properties["function"] = arguments[0];
85 this._properties["expression"] = arguments[1];
86
87 }
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070088
89 // Return object
90 return this;
91}
92
93
94FunctionExpression.prototype = Object.create(AExpression.prototype);
95FunctionExpression.prototype.constructor = FunctionExpression;
96
97
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070098FunctionExpression.prototype.fn = function(fnName) {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070099
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700100 if (typeof fnName == "string") {
101 this._properties["function"] = fnName;
102 }
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700103
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700104 return this;
105};
106
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700107
108FunctionExpression.prototype.expression = function(expression) {
109 if (expression instanceof AExpression || expression instanceof AQLClause) {
110 this._properties["expression"] = expression;
111 }
112
113 return this;
114};
115
116
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700117FunctionExpression.prototype.val = function () {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700118 return this._properties["function"] + "(" + this._properties["expression"].val() + ")";
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700119};
120
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700121
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700122// FLWOGR ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
123// Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700124//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700125// WhereClause ::= "where" Expression
126// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
genia.likes.science@gmail.comb4cb6b32013-05-29 04:30:38 -0700127//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700128// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
129// LimitClause ::= "limit" Expression ( "offset" Expression )?
130// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700131
132
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700133// FLWOGRExpression
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700134//
135// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700136function FLWOGRExpression (options) {
137 // Initialize superclass
138 AExpression.call(this);
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700139
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700140 this._properties["clauses"] = [];
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700141 this._properties["minSize"] = 0;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700142
143 // Bind options and return
144 this.bind(options);
145 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700146}
147
148
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700149FLWOGRExpression.prototype = Object.create(AExpression.prototype);
150FLWOGRExpression.prototype.constructor = FLWOGRExpression;
151
152
153FLWOGRExpression.prototype.bind = function(options) {
154 AExpression.prototype.bind.call(this, options);
155
156 var options = options || {};
157
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700158 if (options instanceof SetStatement) {
159 this._properties["clauses"].push(options);
160 this._properties["minSize"] += 1;
161 }
162
163 if (this._properties["clauses"].length <= this._properties["minSize"]) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700164 // Needs to start with for or let clause
165 if (options instanceof ForClause || options instanceof LetClause) {
166 this._properties["clauses"].push(options);
167 }
168 } else {
169 if (options instanceof AQLClause) {
170 this._properties["clauses"].push(options);
171 }
172 }
173
174 return this;
175};
176
177
178FLWOGRExpression.prototype.val = function() {
179 var value = AExpression.prototype.val.call(this);
180
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700181 var clauseValues = [];
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700182 for (var c in this._properties["clauses"]) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700183 clauseValues.push(this._properties["clauses"][c].val());
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700184 }
185
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700186 return value + clauseValues.join("\n");// + ";";
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700187};
188
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700189
genia.likes.science@gmail.com5f425342013-06-13 13:51:26 -0700190FLWOGRExpression.prototype.ReturnClause = function(expression) {
191 return this.bind(new ReturnClause(expression));
192};
193
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700194// AQLClause
195//
196// Base Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
197function AQLClause() {
198 this._properties = {};
199 this._properties["clause"] = "";
200}
201
202AQLClause.prototype.val = function() {
203 var value = this._properties["clause"];
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700204
205 return value;
206};
207
208AQLClause.prototype.bind = function(options) {
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700209
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700210 if (options instanceof AQLClause) {
211 this._properties["clause"] += " " + options.val();
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700212 }
213
214 return this;
215};
216
genia.likes.science@gmail.com39578302013-05-31 04:42:26 -0700217AQLClause.prototype.set = function(value) {
218 this._properties["clause"] = value;
219 return this;
220};
221
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700222
223// ForClause
224//
225// Grammar:
226// "for" Variable ( "at" Variable )? "in" ( Expression )
227//
228// @param for_variable [String], REQUIRED, first variable in clause
229// @param at_variable [String], NOT REQUIRED, first variable in clause
230// @param expression [AsterixExpression], REQUIRED, expression to evaluate
231//
232// TODO Error Checking
233function ForClause(for_variable, at_variable, expression) {
234 AQLClause.call(this);
235
236 // at_variable is optional, check if defined
237 var at = typeof at_variable ? at_variable : null;
238
239 // Prepare clause
240 this._properties["clause"] = "for $" + for_variable;
241 if (at != null) {
242 this._properties["clause"] += " at $" + at_variable;
243 }
244 this._properties["clause"] += " in " + expression.val();
245 return this;
246}
247
248ForClause.prototype = Object.create(AQLClause.prototype);
249ForClause.prototype.constructor = ForClause;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700250
251
252// LetClause
253//
254// Grammar:
255// LetClause ::= "let" Variable ":=" Expression
256//
257// @param let_variable [String]
258// @param expression [AExpression]
259//
260// TODO Vigorous error checking
261function LetClause(let_variable, expression) {
262 AQLClause.call(this);
263
264 this._properties["clause"] = "let $" + let_variable + " := ";
265 this._properties["clause"] += expression.val();
266
267 return this;
268}
269
270LetClause.prototype = Object.create(AQLClause.prototype);
271LetClause.prototype.constructor = LetClause;
272
273
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700274// ReturnClause
275//
276// Grammar:
277// return [AQLExpression]
278function ReturnClause(expression) {
279 AQLClause.call(this);
280
281 this._properties["clause"] = "return ";
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700282
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700283 if (expression instanceof AExpression || expression instanceof AQLClause) {
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700284 this._properties["clause"] += expression.val();
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700285
286 } else if ( typeof expression == "object" && Object.getPrototypeOf( expression ) === Object.prototype ) {
287
288 // TODO Null object check
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700289
290 this._properties["clause"] += "{";
291 var returnStatements = [];
292 for (returnValue in expression) {
293
294 if (expression[returnValue] instanceof AExpression) {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700295 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700296 } else if (typeof expression[returnValue] == "string") {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700297 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700298 }
299 }
300 this._properties["clause"] += returnStatements.join(",\n");
genia.likes.science@gmail.comf7929d82013-06-12 11:30:01 -0700301 this._properties["clause"] += "\n}";
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700302
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700303 } else {
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700304 this._properties["clause"] += new AQLClause().set(expression).val();
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700305 }
306
307 return this;
308}
309
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700310
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700311ReturnClause.prototype = Object.create(AQLClause.prototype);
312ReturnClause.prototype.constructor = ReturnClause;
313
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700314
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700315// WhereClause
316//
317// Grammar:
318// ::= "where" Expression
319//
320// @param expression [BooleanExpression], pushes this expression onto the stack
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700321function WhereClause(expression) {
322 AQLClause.call(this);
323
324 this._properties["stack"] = [];
325
326 this.bind(expression);
327
328 return this;
329}
330
331
332WhereClause.prototype = Object.create(AQLClause.prototype);
333WhereClause.prototype.constructor = WhereClause;
334
335
336WhereClause.prototype.bind = function(expression) {
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700337 if (expression instanceof AExpression) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700338 this._properties["stack"].push(expression);
339 }
340};
341
342
343WhereClause.prototype.val = function() {
344 var value = "where ";
345
346 var count = this._properties["stack"].length - 1;
347 while (count >= 0) {
348 value += this._properties["stack"][count].val() + " ";
349 count -= 1;
350 }
351
352 return value;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700353};
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700354
355
genia.likes.science@gmail.comd2f753e2013-06-12 13:51:03 -0700356WhereClause.prototype.and = function() {
357
358 var andClauses = [];
359 for (var expression in arguments) {
360
361 if (arguments[expression] instanceof AExpression) {
362 andClauses.push(arguments[expression].val());
363 }
364 }
365
366 if (andClauses.length > 0) {
367 this._properties["stack"].push(new AExpression().set(andClauses.join(" and ")));
368 }
369
370 return this;
371};
372
373
374WhereClause.prototype.or = function() {
375 var orClauses = [];
376 for (var expression in arguments) {
377
378 if (arguments[expression] instanceof AExpression) {
379 orClauses.push(arguments[expression].val());
380 }
381 }
382
383 if (andClauses.length > 0) {
384 this._properties["stack"].push(new AExpression().set(orClauses.join(" and ")));
385 }
386
387 return this;
388};
389
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700390// LimitClause
391// Grammar:
392// LimitClause ::= "limit" Expression ( "offset" Expression )?
393//
394// @param limitExpression [REQUIRED, AQLExpression]
395// @param offsetExpression [OPTIONAL, AQLExpression]
396function LimitClause(limitExpression, offsetExpression) {
397
398 AQLClause.call(this);
399
400 // limitExpression required
401 this._properties["clause"] = "limit " + limitExpression.val();
402
403 // Optional: Offset
404 var offset = typeof offsetExpression ? offsetExpression : null;
405 if (offset != null) {
406 this._properties["clause"] += " offset " + offsetExpression.val();
407 }
408
409 return this;
410}
411
412LimitClause.prototype = Object.create(AQLClause.prototype);
413LimitClause.prototype.constructor = LimitClause;
414
415
416// OrderbyClause
417//
418// Grammar:
419// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
420//
421// @params AQLExpressions and asc/desc strings, in any quantity. At least one required.
422function OrderbyClause() {
423
424 AQLClause.call(this);
425
426 // At least one argument expression is required, and first should be expression
427 if (arguments.length == 0 || !(arguments[0] instanceof AExpression)) {
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700428
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700429 // TODO Not sure which error to throw for an empty OrderBy but this should fail.
430 alert("Order By Error");
431 this._properties["clause"] = null;
432 return this;
433 }
434
435 var expc = 0;
436 var expressions = [];
437
438 while (expc < arguments.length) {
439
440 var expression = "";
441
442 if (arguments[expc] instanceof AExpression) {
443 expression += arguments[expc].val();
444 }
445
446 var next = expc + 1;
447 if (next < arguments.length && (arguments[next] == "asc" || arguments[next] == "desc")) {
448 expc++;
449 expression += " " + arguments[expc];
450 }
451
452 expressions.push(expression);
453
454 expc++;
455 }
456
457 this._properties["clause"] = "order by " + expressions.join(", ");
458 return this;
459}
460
461OrderbyClause.prototype = Object.create(AQLClause.prototype);
462OrderbyClause.prototype.constructor = OrderbyClause;
463
464
genia.likes.science@gmail.com6e392912013-05-31 03:46:59 -0700465// GroupClause
466//
467// Grammar:
468// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
469function GroupClause() {
470 AQLClause.call(this);
471
472 if (arguments.length == 0) {
473 // TODO Not sure which error to throw for an empty GroupBy but this should fail.
474 alert("Group Error");
475 this._properties["clause"] = null;
476 return this;
477 }
478
479 var expc = 0;
480 var expressions = [];
481 var variableRefs = [];
482 var isDecor = false;
genia.likes.science@gmail.com5f425342013-06-13 13:51:26 -0700483
genia.likes.science@gmail.com6e392912013-05-31 03:46:59 -0700484 while (expc < arguments.length) {
485
486 if (arguments[expc] instanceof AExpression) {
487
488 isDecor = false;
489 expressions.push(arguments[expc].val());
490
491 } else if (typeof arguments[expc] == "string") {
492
493 // Special keywords, decor & with
494 if (arguments[expc] == "decor") {
495 isDecor = true;
496 } else if (arguments[expc] == "with") {
497 isDecor = false;
498 expc++;
499 while (expc < arguments.length) {
500 variableRefs.push("$" + arguments[expc]);
501 expc++;
502 }
503
504 // Variables and variable refs
505 } else {
506
507 var nextc = expc + 1;
508 var expression = "";
509
510 if (isDecor) {
511 expression += "decor ";
512 isDecor = false;
513 }
514
515 expression += "$" + arguments[expc] + " := " + arguments[nextc].val();
516 expressions.push(expression);
517 expc++;
518 }
519 }
520
521 expc++;
522 }
523
524 this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
525 return this;
526}
527
528GroupClause.prototype = Object.create(AQLClause.prototype);
529GroupClause.prototype.constructor = GroupClause;
530
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700531
532// SetStatement
533//
534// Grammar
535// "set" Identifier StringLiteral
536function SetStatement (identifier, stringLiteral) {
537 AExpression.call(this);
538
539 var statement = "set " + identifier + ' "' + stringLiteral + '";';
540
541 AExpression.prototype.set.call(this, statement);
542
543 return this;
544}
545
546SetStatement.prototype = Object.create(AExpression.prototype);
547SetStatement.prototype.constructor = SetStatement;
genia.likes.science@gmail.come34c57b2013-05-31 10:15:49 -0700548
549
550// Quantified Expression
551//
552// Grammar
553// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
554//
555// @param String some/every
556// @param [AExpression]
557// @param [Aexpression] satisfiesExpression
558function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
559 AExpression.call(this);
560
561 var expression = keyword + " ";
562 var varsInExpressions = [];
563
564 for (var varInExpression in expressions) {
565 varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val());
566 }
567 expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();
568
569 AExpression.prototype.set.call(this, expression);
570
571 return this;
572}
573
574QuantifiedExpression.prototype = Object.create(AExpression.prototype);
575QuantifiedExpression.prototype.constructor = QuantifiedExpression;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700576
577QuantifiedExpression.prototype.val = function() {
578 var value = AExpression.prototype.val.call(this);
579 return "(" + value + ")";
580};