blob: 33b8e3c4589f02cbf93b747cc114b1993baab5a0 [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("dataverse")) {
14 this._properties["dataverse"] = options["dataverse"];
15 }
16
17 if (options.hasOwnProperty("success")) {
18 this._success = options["success"];
19 }
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070020
21 if (options.hasOwnProperty("return")) {
22 this._properties["return"] = " return " + options["return"].val();
23 }
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070024};
25
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070026
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070027AExpression.prototype.run = function() {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070028 var success_fn = this._success;
29
30 $.ajax({
31 type : 'GET',
genia.likes.science@gmail.comfc5f5092013-06-12 00:49:46 -070032 url : "http://localhost:19002/query",
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -070033 data : {"query" : this.val()},
34 dataType : "json",
35 success : function(data) {
36 success_fn(data);
37 }
38 });
39
40 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070041};
42
43
44AExpression.prototype.val = function() {
45
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070046 var value = "";
47
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070048 // If there is a dataverse defined, provide it.
49 if (this._properties.hasOwnProperty("dataverse")) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070050 value += "use dataverse " + this._properties["dataverse"] + ";\n";
51 };
52
53 if (this._properties.hasOwnProperty("value")) {
54 value += this._properties["value"];
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070055 }
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070056
57 return value;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070058};
59
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070060// @param expressionValue [String]
61AExpression.prototype.set = function(expressionValue) {
62 this._properties["value"] = expressionValue;
63 return this;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070064};
65
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -070066
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070067AExpression.prototype.error = function(msg) {
68 return "Asterix FunctionExpression Error: " + msg;
69};
70
71
72// FunctionExpression
73// Parent: AsterixExpression
74//
75// @param options [Various],
76// @key function [String], a function to be applid to the expression
77// @key expression [AsterixExpression or AsterixClause] an AsterixExpression/Clause to which the fn will be applied
78function FunctionExpression(options) {
79
80 // Initialize superclass
81 AExpression.call(this);
82
83 // Possible to initialize a function epxression without inputs, or with them
84 this.bind(options);
85
86 // Return object
87 return this;
88}
89
90
91FunctionExpression.prototype = Object.create(AExpression.prototype);
92FunctionExpression.prototype.constructor = FunctionExpression;
93
94
95FunctionExpression.prototype.bind = function(options) {
96
97 AExpression.prototype.bind.call(this, options);
98
99 var options = options || {};
100
101 if (options.hasOwnProperty("function")) {
102 this._properties["function"] = options["function"];
103 }
104
105 if (options.hasOwnProperty("expression")) {
106 this._properties["expression"] = options["expression"];
107 }
108
109 return this;
110};
111
112FunctionExpression.prototype.val = function () {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700113 return this._properties["function"] + "(" + this._properties["expression"].val() + ")";
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700114};
115
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700116
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700117// FLWOGR ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
118// Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700119//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700120// WhereClause ::= "where" Expression
121// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
genia.likes.science@gmail.comb4cb6b32013-05-29 04:30:38 -0700122//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700123// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
124// LimitClause ::= "limit" Expression ( "offset" Expression )?
125// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700126
127
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700128// FLWOGRExpression
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700129//
130// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700131function FLWOGRExpression (options) {
132 // Initialize superclass
133 AExpression.call(this);
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700134
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700135 this._properties["clauses"] = [];
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700136 this._properties["minSize"] = 0;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700137
138 // Bind options and return
139 this.bind(options);
140 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700141}
142
143
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700144FLWOGRExpression.prototype = Object.create(AExpression.prototype);
145FLWOGRExpression.prototype.constructor = FLWOGRExpression;
146
147
148FLWOGRExpression.prototype.bind = function(options) {
149 AExpression.prototype.bind.call(this, options);
150
151 var options = options || {};
152
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700153 if (options instanceof SetStatement) {
154 this._properties["clauses"].push(options);
155 this._properties["minSize"] += 1;
156 }
157
158 if (this._properties["clauses"].length <= this._properties["minSize"]) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700159 // Needs to start with for or let clause
160 if (options instanceof ForClause || options instanceof LetClause) {
161 this._properties["clauses"].push(options);
162 }
163 } else {
164 if (options instanceof AQLClause) {
165 this._properties["clauses"].push(options);
166 }
167 }
168
169 return this;
170};
171
172
173FLWOGRExpression.prototype.val = function() {
174 var value = AExpression.prototype.val.call(this);
175
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700176 var clauseValues = [];
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700177 for (var c in this._properties["clauses"]) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700178 clauseValues.push(this._properties["clauses"][c].val());
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700179 }
180
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700181 return value + clauseValues.join("\n");// + ";";
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700182};
183
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700184
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700185// AQLClause
186//
187// Base Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
188function AQLClause() {
189 this._properties = {};
190 this._properties["clause"] = "";
191}
192
193AQLClause.prototype.val = function() {
194 var value = this._properties["clause"];
195
196 if (this._properties.hasOwnProperty("return")) {
197 value += " return " + this._properties["return"].val();
198 }
199
200 return value;
201};
202
203AQLClause.prototype.bind = function(options) {
204 var options = options || {};
205
206 if (options.hasOwnProperty("return")) {
207 this._properties["return"] = options["return"];
208 }
209
210 return this;
211};
212
genia.likes.science@gmail.com39578302013-05-31 04:42:26 -0700213AQLClause.prototype.set = function(value) {
214 this._properties["clause"] = value;
215 return this;
216};
217
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700218
219// ForClause
220//
221// Grammar:
222// "for" Variable ( "at" Variable )? "in" ( Expression )
223//
224// @param for_variable [String], REQUIRED, first variable in clause
225// @param at_variable [String], NOT REQUIRED, first variable in clause
226// @param expression [AsterixExpression], REQUIRED, expression to evaluate
227//
228// TODO Error Checking
229function ForClause(for_variable, at_variable, expression) {
230 AQLClause.call(this);
231
232 // at_variable is optional, check if defined
233 var at = typeof at_variable ? at_variable : null;
234
235 // Prepare clause
236 this._properties["clause"] = "for $" + for_variable;
237 if (at != null) {
238 this._properties["clause"] += " at $" + at_variable;
239 }
240 this._properties["clause"] += " in " + expression.val();
241 return this;
242}
243
244ForClause.prototype = Object.create(AQLClause.prototype);
245ForClause.prototype.constructor = ForClause;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700246
247
248// LetClause
249//
250// Grammar:
251// LetClause ::= "let" Variable ":=" Expression
252//
253// @param let_variable [String]
254// @param expression [AExpression]
255//
256// TODO Vigorous error checking
257function LetClause(let_variable, expression) {
258 AQLClause.call(this);
259
260 this._properties["clause"] = "let $" + let_variable + " := ";
261 this._properties["clause"] += expression.val();
262
263 return this;
264}
265
266LetClause.prototype = Object.create(AQLClause.prototype);
267LetClause.prototype.constructor = LetClause;
268
269
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700270// ReturnClause
271//
272// Grammar:
273// return [AQLExpression]
274function ReturnClause(expression) {
275 AQLClause.call(this);
276
277 this._properties["clause"] = "return ";
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700278 if (expression instanceof AExpression || expression instanceof AQLClause) {
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700279 this._properties["clause"] += expression.val();
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700280 } else if ( Object.getPrototypeOf( expression ) === Object.prototype ) {
281
282 this._properties["clause"] += "{";
283 var returnStatements = [];
284 for (returnValue in expression) {
285
286 if (expression[returnValue] instanceof AExpression) {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700287 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700288 } else if (typeof expression[returnValue] == "string") {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700289 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700290 }
291 }
292 this._properties["clause"] += returnStatements.join(",\n");
293 this._properties["clause"] += "}";
294
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700295 } else {
genia.likes.science@gmail.com44ff94a2013-05-31 11:09:34 -0700296 this._properties["clause"] += new AExpression().set(expression).val();
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700297 }
298
299 return this;
300}
301
302ReturnClause.prototype = Object.create(AQLClause.prototype);
303ReturnClause.prototype.constructor = ReturnClause;
304
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700305ReturnClause.prototype.val = function () {
306 return this._properties["clause"];
307};
308
309
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700310// WhereClause
311//
312// Grammar:
313// ::= "where" Expression
314//
315// @param expression [BooleanExpression], pushes this expression onto the stack
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700316function WhereClause(expression) {
317 AQLClause.call(this);
318
319 this._properties["stack"] = [];
320
321 this.bind(expression);
322
323 return this;
324}
325
326
327WhereClause.prototype = Object.create(AQLClause.prototype);
328WhereClause.prototype.constructor = WhereClause;
329
330
331WhereClause.prototype.bind = function(expression) {
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700332 if (expression instanceof AExpression) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700333 this._properties["stack"].push(expression);
334 }
335};
336
337
338WhereClause.prototype.val = function() {
339 var value = "where ";
340
341 var count = this._properties["stack"].length - 1;
342 while (count >= 0) {
343 value += this._properties["stack"][count].val() + " ";
344 count -= 1;
345 }
346
347 return value;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700348};
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700349
350
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700351// LimitClause
352// Grammar:
353// LimitClause ::= "limit" Expression ( "offset" Expression )?
354//
355// @param limitExpression [REQUIRED, AQLExpression]
356// @param offsetExpression [OPTIONAL, AQLExpression]
357function LimitClause(limitExpression, offsetExpression) {
358
359 AQLClause.call(this);
360
361 // limitExpression required
362 this._properties["clause"] = "limit " + limitExpression.val();
363
364 // Optional: Offset
365 var offset = typeof offsetExpression ? offsetExpression : null;
366 if (offset != null) {
367 this._properties["clause"] += " offset " + offsetExpression.val();
368 }
369
370 return this;
371}
372
373LimitClause.prototype = Object.create(AQLClause.prototype);
374LimitClause.prototype.constructor = LimitClause;
375
376
377// OrderbyClause
378//
379// Grammar:
380// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
381//
382// @params AQLExpressions and asc/desc strings, in any quantity. At least one required.
383function OrderbyClause() {
384
385 AQLClause.call(this);
386
387 // At least one argument expression is required, and first should be expression
388 if (arguments.length == 0 || !(arguments[0] instanceof AExpression)) {
389 // TODO Not sure which error to throw for an empty OrderBy but this should fail.
390 alert("Order By Error");
391 this._properties["clause"] = null;
392 return this;
393 }
394
395 var expc = 0;
396 var expressions = [];
397
398 while (expc < arguments.length) {
399
400 var expression = "";
401
402 if (arguments[expc] instanceof AExpression) {
403 expression += arguments[expc].val();
404 }
405
406 var next = expc + 1;
407 if (next < arguments.length && (arguments[next] == "asc" || arguments[next] == "desc")) {
408 expc++;
409 expression += " " + arguments[expc];
410 }
411
412 expressions.push(expression);
413
414 expc++;
415 }
416
417 this._properties["clause"] = "order by " + expressions.join(", ");
418 return this;
419}
420
421OrderbyClause.prototype = Object.create(AQLClause.prototype);
422OrderbyClause.prototype.constructor = OrderbyClause;
423
424
genia.likes.science@gmail.com6e392912013-05-31 03:46:59 -0700425// GroupClause
426//
427// Grammar:
428// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
429function GroupClause() {
430 AQLClause.call(this);
431
432 if (arguments.length == 0) {
433 // TODO Not sure which error to throw for an empty GroupBy but this should fail.
434 alert("Group Error");
435 this._properties["clause"] = null;
436 return this;
437 }
438
439 var expc = 0;
440 var expressions = [];
441 var variableRefs = [];
442 var isDecor = false;
443
444 while (expc < arguments.length) {
445
446 if (arguments[expc] instanceof AExpression) {
447
448 isDecor = false;
449 expressions.push(arguments[expc].val());
450
451 } else if (typeof arguments[expc] == "string") {
452
453 // Special keywords, decor & with
454 if (arguments[expc] == "decor") {
455 isDecor = true;
456 } else if (arguments[expc] == "with") {
457 isDecor = false;
458 expc++;
459 while (expc < arguments.length) {
460 variableRefs.push("$" + arguments[expc]);
461 expc++;
462 }
463
464 // Variables and variable refs
465 } else {
466
467 var nextc = expc + 1;
468 var expression = "";
469
470 if (isDecor) {
471 expression += "decor ";
472 isDecor = false;
473 }
474
475 expression += "$" + arguments[expc] + " := " + arguments[nextc].val();
476 expressions.push(expression);
477 expc++;
478 }
479 }
480
481 expc++;
482 }
483
484 this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
485 return this;
486}
487
488GroupClause.prototype = Object.create(AQLClause.prototype);
489GroupClause.prototype.constructor = GroupClause;
490
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700491// BooleanExpression
492//
493// TODO
494function BooleanExpression(expression) {
495 this.value = expression;
genia.likes.science@gmail.com6fd7b2e2013-05-31 00:40:28 -0700496 alert("Debugging Bool: " + arguments.length + " " + expression);
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700497}
498
499BooleanExpression.prototype.val = function() {
500 return this.value;
501}
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700502
503
504// SetStatement
505//
506// Grammar
507// "set" Identifier StringLiteral
508function SetStatement (identifier, stringLiteral) {
509 AExpression.call(this);
510
511 var statement = "set " + identifier + ' "' + stringLiteral + '";';
512
513 AExpression.prototype.set.call(this, statement);
514
515 return this;
516}
517
518SetStatement.prototype = Object.create(AExpression.prototype);
519SetStatement.prototype.constructor = SetStatement;
genia.likes.science@gmail.come34c57b2013-05-31 10:15:49 -0700520
521
522// Quantified Expression
523//
524// Grammar
525// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
526//
527// @param String some/every
528// @param [AExpression]
529// @param [Aexpression] satisfiesExpression
530function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
531 AExpression.call(this);
532
533 var expression = keyword + " ";
534 var varsInExpressions = [];
535
536 for (var varInExpression in expressions) {
537 varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val());
538 }
539 expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();
540
541 AExpression.prototype.set.call(this, expression);
542
543 return this;
544}
545
546QuantifiedExpression.prototype = Object.create(AExpression.prototype);
547QuantifiedExpression.prototype.constructor = QuantifiedExpression;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700548
549QuantifiedExpression.prototype.val = function() {
550 var value = AExpression.prototype.val.call(this);
551 return "(" + value + ")";
552};
genia.likes.science@gmail.com44ff94a2013-05-31 11:09:34 -0700553
554
555// Functions that can be used to call core expressions/clauses more cleanly
556function AFLWOGR () {
557
558}
559
560function AClause () {
561
562}
563
564function ALetClause () {
565
566}
567
568function AWhereClause () {
569
570}
571
572function AOrderbyClause () {
573
574}
575
576function AGroupClause () {
577
578}
579
580function ALimitClause () {
581
582}
583
584function ADistinctClause () {
585
586}
587
588function AVariable () {
589
590}