blob: 9a11c75fbbb7017f8f385c9bc065a3a8446ef4a6 [file] [log] [blame]
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -07001// Functions that can be used to call core expressions/clauses more cleanly
2function AFLWOGR () {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -07003
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -07004}
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -07005
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -07006function AClause () {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -07007
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -07008}
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -07009
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070010function ALetClause () {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070011
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070012}
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070013
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070014function AWhereClause () {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070015
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070016}
17
18function AOrderbyClause () {
19
20}
21
22function AGroupClause () {
23
24}
25
26function ALimitClause () {
27
28}
29
30function ADistinctClause () {
31
32}
33
34function AVariable () {
35
36}
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070037
38// Temporary AsterixExpression Placeholder
39function AExpression () {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070040 this._properties = {};
41 this._success = function() {};
42
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070043 return this;
44}
45
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070046
47AExpression.prototype.bind = function(options) {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070048 var options = options || {};
49
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070050 if (options.hasOwnProperty("dataverse")) {
51 this._properties["dataverse"] = options["dataverse"];
52 }
53
54 if (options.hasOwnProperty("success")) {
55 this._success = options["success"];
56 }
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070057
58 if (options.hasOwnProperty("return")) {
59 this._properties["return"] = " return " + options["return"].val();
60 }
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070061};
62
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070063
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070064AExpression.prototype.run = function() {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070065 var success_fn = this._success;
66
67 $.ajax({
68 type : 'GET',
69 url : "http://localhost:19101/query",
70 data : {"query" : this.val()},
71 dataType : "json",
72 success : function(data) {
73 success_fn(data);
74 }
75 });
76
77 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070078};
79
80
81AExpression.prototype.val = function() {
82
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070083 var value = "";
84
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070085 // If there is a dataverse defined, provide it.
86 if (this._properties.hasOwnProperty("dataverse")) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070087 value += "use dataverse " + this._properties["dataverse"] + ";\n";
88 };
89
90 if (this._properties.hasOwnProperty("value")) {
91 value += this._properties["value"];
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070092 }
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070093
94 return value;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070095};
96
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070097// @param expressionValue [String]
98AExpression.prototype.set = function(expressionValue) {
99 this._properties["value"] = expressionValue;
100 return this;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700101};
102
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700103
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700104AExpression.prototype.error = function(msg) {
105 return "Asterix FunctionExpression Error: " + msg;
106};
107
108
109// FunctionExpression
110// Parent: AsterixExpression
111//
112// @param options [Various],
113// @key function [String], a function to be applid to the expression
114// @key expression [AsterixExpression or AsterixClause] an AsterixExpression/Clause to which the fn will be applied
115function FunctionExpression(options) {
116
117 // Initialize superclass
118 AExpression.call(this);
119
120 // Possible to initialize a function epxression without inputs, or with them
121 this.bind(options);
122
123 // Return object
124 return this;
125}
126
127
128FunctionExpression.prototype = Object.create(AExpression.prototype);
129FunctionExpression.prototype.constructor = FunctionExpression;
130
131
132FunctionExpression.prototype.bind = function(options) {
133
134 AExpression.prototype.bind.call(this, options);
135
136 var options = options || {};
137
138 if (options.hasOwnProperty("function")) {
139 this._properties["function"] = options["function"];
140 }
141
142 if (options.hasOwnProperty("expression")) {
143 this._properties["expression"] = options["expression"];
144 }
145
146 return this;
147};
148
149FunctionExpression.prototype.val = function () {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700150 return this._properties["function"] + "(" + this._properties["expression"].val() + ")";
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700151};
152
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700153
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700154// FLWOGR ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
155// Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700156//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700157// WhereClause ::= "where" Expression
158// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
genia.likes.science@gmail.comb4cb6b32013-05-29 04:30:38 -0700159//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700160// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
161// LimitClause ::= "limit" Expression ( "offset" Expression )?
162// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700163
164
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700165// FLWOGRExpression
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700166//
167// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700168function FLWOGRExpression (options) {
169 // Initialize superclass
170 AExpression.call(this);
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700171
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700172 this._properties["clauses"] = [];
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700173 this._properties["minSize"] = 0;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700174
175 // Bind options and return
176 this.bind(options);
177 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700178}
179
180
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700181FLWOGRExpression.prototype = Object.create(AExpression.prototype);
182FLWOGRExpression.prototype.constructor = FLWOGRExpression;
183
184
185FLWOGRExpression.prototype.bind = function(options) {
186 AExpression.prototype.bind.call(this, options);
187
188 var options = options || {};
189
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700190 if (options instanceof SetStatement) {
191 this._properties["clauses"].push(options);
192 this._properties["minSize"] += 1;
193 }
194
195 if (this._properties["clauses"].length <= this._properties["minSize"]) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700196 // Needs to start with for or let clause
197 if (options instanceof ForClause || options instanceof LetClause) {
198 this._properties["clauses"].push(options);
199 }
200 } else {
201 if (options instanceof AQLClause) {
202 this._properties["clauses"].push(options);
203 }
204 }
205
206 return this;
207};
208
209
210FLWOGRExpression.prototype.val = function() {
211 var value = AExpression.prototype.val.call(this);
212
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700213 var clauseValues = [];
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700214 for (var c in this._properties["clauses"]) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700215 clauseValues.push(this._properties["clauses"][c].val());
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700216 }
217
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700218 return value + clauseValues.join("\n");// + ";";
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700219};
220
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700221
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700222// AQLClause
223//
224// Base Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
225function AQLClause() {
226 this._properties = {};
227 this._properties["clause"] = "";
228}
229
230AQLClause.prototype.val = function() {
231 var value = this._properties["clause"];
232
233 if (this._properties.hasOwnProperty("return")) {
234 value += " return " + this._properties["return"].val();
235 }
236
237 return value;
238};
239
240AQLClause.prototype.bind = function(options) {
241 var options = options || {};
242
243 if (options.hasOwnProperty("return")) {
244 this._properties["return"] = options["return"];
245 }
246
247 return this;
248};
249
genia.likes.science@gmail.com39578302013-05-31 04:42:26 -0700250AQLClause.prototype.set = function(value) {
251 this._properties["clause"] = value;
252 return this;
253};
254
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700255
256// ForClause
257//
258// Grammar:
259// "for" Variable ( "at" Variable )? "in" ( Expression )
260//
261// @param for_variable [String], REQUIRED, first variable in clause
262// @param at_variable [String], NOT REQUIRED, first variable in clause
263// @param expression [AsterixExpression], REQUIRED, expression to evaluate
264//
265// TODO Error Checking
266function ForClause(for_variable, at_variable, expression) {
267 AQLClause.call(this);
268
269 // at_variable is optional, check if defined
270 var at = typeof at_variable ? at_variable : null;
271
272 // Prepare clause
273 this._properties["clause"] = "for $" + for_variable;
274 if (at != null) {
275 this._properties["clause"] += " at $" + at_variable;
276 }
277 this._properties["clause"] += " in " + expression.val();
278 return this;
279}
280
281ForClause.prototype = Object.create(AQLClause.prototype);
282ForClause.prototype.constructor = ForClause;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700283
284
285// LetClause
286//
287// Grammar:
288// LetClause ::= "let" Variable ":=" Expression
289//
290// @param let_variable [String]
291// @param expression [AExpression]
292//
293// TODO Vigorous error checking
294function LetClause(let_variable, expression) {
295 AQLClause.call(this);
296
297 this._properties["clause"] = "let $" + let_variable + " := ";
298 this._properties["clause"] += expression.val();
299
300 return this;
301}
302
303LetClause.prototype = Object.create(AQLClause.prototype);
304LetClause.prototype.constructor = LetClause;
305
306
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700307// ReturnClause
308//
309// Grammar:
310// return [AQLExpression]
311function ReturnClause(expression) {
312 AQLClause.call(this);
313
314 this._properties["clause"] = "return ";
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700315 if (expression instanceof AExpression || expression instanceof AQLClause) {
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700316 this._properties["clause"] += expression.val();
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700317 } else if ( Object.getPrototypeOf( expression ) === Object.prototype ) {
318
319 this._properties["clause"] += "{";
320 var returnStatements = [];
321 for (returnValue in expression) {
322
323 if (expression[returnValue] instanceof AExpression) {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700324 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700325 } else if (typeof expression[returnValue] == "string") {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700326 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700327 }
328 }
329 this._properties["clause"] += returnStatements.join(",\n");
330 this._properties["clause"] += "}";
331
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700332 } else {
genia.likes.science@gmail.com44ff94a2013-05-31 11:09:34 -0700333 this._properties["clause"] += new AExpression().set(expression).val();
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700334 }
335
336 return this;
337}
338
339ReturnClause.prototype = Object.create(AQLClause.prototype);
340ReturnClause.prototype.constructor = ReturnClause;
341
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700342ReturnClause.prototype.val = function () {
343 return this._properties["clause"];
344};
345
346
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700347// WhereClause
348//
349// Grammar:
350// ::= "where" Expression
351//
352// @param expression [BooleanExpression], pushes this expression onto the stack
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700353function WhereClause(expression) {
354 AQLClause.call(this);
355
356 this._properties["stack"] = [];
357
358 this.bind(expression);
359
360 return this;
361}
362
363
364WhereClause.prototype = Object.create(AQLClause.prototype);
365WhereClause.prototype.constructor = WhereClause;
366
367
368WhereClause.prototype.bind = function(expression) {
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700369 if (expression instanceof AExpression) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700370 this._properties["stack"].push(expression);
371 }
372};
373
374
375WhereClause.prototype.val = function() {
376 var value = "where ";
377
378 var count = this._properties["stack"].length - 1;
379 while (count >= 0) {
380 value += this._properties["stack"][count].val() + " ";
381 count -= 1;
382 }
383
384 return value;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700385};
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700386
387
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700388// LimitClause
389// Grammar:
390// LimitClause ::= "limit" Expression ( "offset" Expression )?
391//
392// @param limitExpression [REQUIRED, AQLExpression]
393// @param offsetExpression [OPTIONAL, AQLExpression]
394function LimitClause(limitExpression, offsetExpression) {
395
396 AQLClause.call(this);
397
398 // limitExpression required
399 this._properties["clause"] = "limit " + limitExpression.val();
400
401 // Optional: Offset
402 var offset = typeof offsetExpression ? offsetExpression : null;
403 if (offset != null) {
404 this._properties["clause"] += " offset " + offsetExpression.val();
405 }
406
407 return this;
408}
409
410LimitClause.prototype = Object.create(AQLClause.prototype);
411LimitClause.prototype.constructor = LimitClause;
412
413
414// OrderbyClause
415//
416// Grammar:
417// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
418//
419// @params AQLExpressions and asc/desc strings, in any quantity. At least one required.
420function OrderbyClause() {
421
422 AQLClause.call(this);
423
424 // At least one argument expression is required, and first should be expression
425 if (arguments.length == 0 || !(arguments[0] instanceof AExpression)) {
426 // TODO Not sure which error to throw for an empty OrderBy but this should fail.
427 alert("Order By Error");
428 this._properties["clause"] = null;
429 return this;
430 }
431
432 var expc = 0;
433 var expressions = [];
434
435 while (expc < arguments.length) {
436
437 var expression = "";
438
439 if (arguments[expc] instanceof AExpression) {
440 expression += arguments[expc].val();
441 }
442
443 var next = expc + 1;
444 if (next < arguments.length && (arguments[next] == "asc" || arguments[next] == "desc")) {
445 expc++;
446 expression += " " + arguments[expc];
447 }
448
449 expressions.push(expression);
450
451 expc++;
452 }
453
454 this._properties["clause"] = "order by " + expressions.join(", ");
455 return this;
456}
457
458OrderbyClause.prototype = Object.create(AQLClause.prototype);
459OrderbyClause.prototype.constructor = OrderbyClause;
460
461
genia.likes.science@gmail.com6e392912013-05-31 03:46:59 -0700462// GroupClause
463//
464// Grammar:
465// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
466function GroupClause() {
467 AQLClause.call(this);
468
469 if (arguments.length == 0) {
470 // TODO Not sure which error to throw for an empty GroupBy but this should fail.
471 alert("Group Error");
472 this._properties["clause"] = null;
473 return this;
474 }
475
476 var expc = 0;
477 var expressions = [];
478 var variableRefs = [];
479 var isDecor = false;
480
481 while (expc < arguments.length) {
482
483 if (arguments[expc] instanceof AExpression) {
484
485 isDecor = false;
486 expressions.push(arguments[expc].val());
487
488 } else if (typeof arguments[expc] == "string") {
489
490 // Special keywords, decor & with
491 if (arguments[expc] == "decor") {
492 isDecor = true;
493 } else if (arguments[expc] == "with") {
494 isDecor = false;
495 expc++;
496 while (expc < arguments.length) {
497 variableRefs.push("$" + arguments[expc]);
498 expc++;
499 }
500
501 // Variables and variable refs
502 } else {
503
504 var nextc = expc + 1;
505 var expression = "";
506
507 if (isDecor) {
508 expression += "decor ";
509 isDecor = false;
510 }
511
512 expression += "$" + arguments[expc] + " := " + arguments[nextc].val();
513 expressions.push(expression);
514 expc++;
515 }
516 }
517
518 expc++;
519 }
520
521 this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
522 return this;
523}
524
525GroupClause.prototype = Object.create(AQLClause.prototype);
526GroupClause.prototype.constructor = GroupClause;
527
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700528// BooleanExpression
529//
530// TODO
531function BooleanExpression(expression) {
532 this.value = expression;
genia.likes.science@gmail.com6fd7b2e2013-05-31 00:40:28 -0700533 alert("Debugging Bool: " + arguments.length + " " + expression);
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700534}
535
536BooleanExpression.prototype.val = function() {
537 return this.value;
538}
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700539
540
541// SetStatement
542//
543// Grammar
544// "set" Identifier StringLiteral
545function SetStatement (identifier, stringLiteral) {
546 AExpression.call(this);
547
548 var statement = "set " + identifier + ' "' + stringLiteral + '";';
549
550 AExpression.prototype.set.call(this, statement);
551
552 return this;
553}
554
555SetStatement.prototype = Object.create(AExpression.prototype);
556SetStatement.prototype.constructor = SetStatement;
genia.likes.science@gmail.come34c57b2013-05-31 10:15:49 -0700557
558
559// Quantified Expression
560//
561// Grammar
562// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
563//
564// @param String some/every
565// @param [AExpression]
566// @param [Aexpression] satisfiesExpression
567function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
568 AExpression.call(this);
569
570 var expression = keyword + " ";
571 var varsInExpressions = [];
572
573 for (var varInExpression in expressions) {
574 varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val());
575 }
576 expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();
577
578 AExpression.prototype.set.call(this, expression);
579
580 return this;
581}
582
583QuantifiedExpression.prototype = Object.create(AExpression.prototype);
584QuantifiedExpression.prototype.constructor = QuantifiedExpression;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700585
586QuantifiedExpression.prototype.val = function() {
587 var value = AExpression.prototype.val.call(this);
588 return "(" + value + ")";
589};
genia.likes.science@gmail.com44ff94a2013-05-31 11:09:34 -0700590
591
592// Functions that can be used to call core expressions/clauses more cleanly
593function AFLWOGR () {
594
595}
596
597function AClause () {
598
599}
600
601function ALetClause () {
602
603}
604
605function AWhereClause () {
606
607}
608
609function AOrderbyClause () {
610
611}
612
613function AGroupClause () {
614
615}
616
617function ALimitClause () {
618
619}
620
621function ADistinctClause () {
622
623}
624
625function AVariable () {
626
627}