blob: 473919cfcf4a5cd5379cea1bd031fe9ca362321b [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);
33 }
34 });
35
36 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070037};
38
39
40AExpression.prototype.val = function() {
41
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070042 var value = "";
43
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070044 // If there is a dataverse defined, provide it.
45 if (this._properties.hasOwnProperty("dataverse")) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070046 value += "use dataverse " + this._properties["dataverse"] + ";\n";
47 };
48
49 if (this._properties.hasOwnProperty("value")) {
50 value += this._properties["value"];
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070051 }
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070052
53 return value;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070054};
55
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -070056// @param expressionValue [String]
57AExpression.prototype.set = function(expressionValue) {
58 this._properties["value"] = expressionValue;
59 return this;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -070060};
61
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -070062
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070063AExpression.prototype.error = function(msg) {
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070064 //return "Asterix FunctionExpression Error: " + msg;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070065};
66
67
68// FunctionExpression
69// Parent: AsterixExpression
70//
71// @param options [Various],
72// @key function [String], a function to be applid to the expression
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070073// @key expression [AsterixExpression or AQLClause] an AsterixExpression/Clause to which the fn will be applied
74function FunctionExpression() {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070075
76 // Initialize superclass
77 AExpression.call(this);
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070078
79 this._properties["function"] = "";
80 this._properties["expression"] = new AExpression().set("");
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070081
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -070082 // Check for fn/expression input
83 if (arguments.length == 2 && typeof arguments[0] == "string" &&
84 (arguments[1] instanceof AExpression || arguments[1] instanceof AQLClause)) {
85
86 this._properties["function"] = arguments[0];
87 this._properties["expression"] = arguments[1];
88
89 }
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -070090
91 // Return object
92 return this;
93}
94
95
96FunctionExpression.prototype = Object.create(AExpression.prototype);
97FunctionExpression.prototype.constructor = FunctionExpression;
98
99
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700100FunctionExpression.prototype.fn = function(fnName) {
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700101
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700102 if (typeof fnName == "string") {
103 this._properties["function"] = fnName;
104 }
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700105
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700106 return this;
107};
108
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700109
110FunctionExpression.prototype.expression = function(expression) {
111 if (expression instanceof AExpression || expression instanceof AQLClause) {
112 this._properties["expression"] = expression;
113 }
114
115 return this;
116};
117
118
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700119FunctionExpression.prototype.val = function () {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700120 return this._properties["function"] + "(" + this._properties["expression"].val() + ")";
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700121};
122
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700123
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700124// FLWOGR ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
125// Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700126//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700127// WhereClause ::= "where" Expression
128// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
genia.likes.science@gmail.comb4cb6b32013-05-29 04:30:38 -0700129//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700130// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
131// LimitClause ::= "limit" Expression ( "offset" Expression )?
132// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700133
134
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700135// FLWOGRExpression
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700136//
137// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700138function FLWOGRExpression (options) {
139 // Initialize superclass
140 AExpression.call(this);
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700141
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700142 this._properties["clauses"] = [];
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700143 this._properties["minSize"] = 0;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700144
145 // Bind options and return
146 this.bind(options);
147 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700148}
149
150
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700151FLWOGRExpression.prototype = Object.create(AExpression.prototype);
152FLWOGRExpression.prototype.constructor = FLWOGRExpression;
153
154
155FLWOGRExpression.prototype.bind = function(options) {
156 AExpression.prototype.bind.call(this, options);
157
158 var options = options || {};
159
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700160 if (options instanceof SetStatement) {
161 this._properties["clauses"].push(options);
162 this._properties["minSize"] += 1;
163 }
164
165 if (this._properties["clauses"].length <= this._properties["minSize"]) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700166 // Needs to start with for or let clause
167 if (options instanceof ForClause || options instanceof LetClause) {
168 this._properties["clauses"].push(options);
169 }
170 } else {
171 if (options instanceof AQLClause) {
172 this._properties["clauses"].push(options);
173 }
174 }
175
176 return this;
177};
178
179
180FLWOGRExpression.prototype.val = function() {
181 var value = AExpression.prototype.val.call(this);
182
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700183 var clauseValues = [];
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700184 for (var c in this._properties["clauses"]) {
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700185 clauseValues.push(this._properties["clauses"][c].val());
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700186 }
187
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700188 return value + clauseValues.join("\n");// + ";";
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700189};
190
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700191
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700192// AQLClause
193//
194// Base Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
195function AQLClause() {
196 this._properties = {};
197 this._properties["clause"] = "";
198}
199
200AQLClause.prototype.val = function() {
201 var value = this._properties["clause"];
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700202
203 return value;
204};
205
206AQLClause.prototype.bind = function(options) {
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700207
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700208 if (options instanceof AQLClause) {
209 this._properties["clause"] += " " + options.val();
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700210 }
211
212 return this;
213};
214
genia.likes.science@gmail.com39578302013-05-31 04:42:26 -0700215AQLClause.prototype.set = function(value) {
216 this._properties["clause"] = value;
217 return this;
218};
219
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700220
221// ForClause
222//
223// Grammar:
224// "for" Variable ( "at" Variable )? "in" ( Expression )
225//
226// @param for_variable [String], REQUIRED, first variable in clause
227// @param at_variable [String], NOT REQUIRED, first variable in clause
228// @param expression [AsterixExpression], REQUIRED, expression to evaluate
229//
230// TODO Error Checking
231function ForClause(for_variable, at_variable, expression) {
232 AQLClause.call(this);
233
234 // at_variable is optional, check if defined
235 var at = typeof at_variable ? at_variable : null;
236
237 // Prepare clause
238 this._properties["clause"] = "for $" + for_variable;
239 if (at != null) {
240 this._properties["clause"] += " at $" + at_variable;
241 }
242 this._properties["clause"] += " in " + expression.val();
243 return this;
244}
245
246ForClause.prototype = Object.create(AQLClause.prototype);
247ForClause.prototype.constructor = ForClause;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700248
249
250// LetClause
251//
252// Grammar:
253// LetClause ::= "let" Variable ":=" Expression
254//
255// @param let_variable [String]
256// @param expression [AExpression]
257//
258// TODO Vigorous error checking
259function LetClause(let_variable, expression) {
260 AQLClause.call(this);
261
262 this._properties["clause"] = "let $" + let_variable + " := ";
263 this._properties["clause"] += expression.val();
264
265 return this;
266}
267
268LetClause.prototype = Object.create(AQLClause.prototype);
269LetClause.prototype.constructor = LetClause;
270
271
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700272// ReturnClause
273//
274// Grammar:
275// return [AQLExpression]
276function ReturnClause(expression) {
277 AQLClause.call(this);
278
279 this._properties["clause"] = "return ";
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700280
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700281 if (expression instanceof AExpression || expression instanceof AQLClause) {
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700282 this._properties["clause"] += expression.val();
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700283
284 } else if ( typeof expression == "object" && Object.getPrototypeOf( expression ) === Object.prototype ) {
285
286 // TODO Null object check
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700287
288 this._properties["clause"] += "{";
289 var returnStatements = [];
290 for (returnValue in expression) {
291
292 if (expression[returnValue] instanceof AExpression) {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700293 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700294 } else if (typeof expression[returnValue] == "string") {
genia.likes.science@gmail.comfba7cc82013-05-31 04:04:08 -0700295 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700296 }
297 }
298 this._properties["clause"] += returnStatements.join(",\n");
genia.likes.science@gmail.comf7929d82013-06-12 11:30:01 -0700299 this._properties["clause"] += "\n}";
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700300
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700301 } else {
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700302 this._properties["clause"] += new AQLClause().set(expression).val();
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700303 }
304
305 return this;
306}
307
genia.likes.science@gmail.com5749ef92013-06-12 07:59:25 -0700308
genia.likes.science@gmail.com5ca104c2013-05-29 05:39:26 -0700309ReturnClause.prototype = Object.create(AQLClause.prototype);
310ReturnClause.prototype.constructor = ReturnClause;
311
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700312
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700313// WhereClause
314//
315// Grammar:
316// ::= "where" Expression
317//
318// @param expression [BooleanExpression], pushes this expression onto the stack
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700319function WhereClause(expression) {
320 AQLClause.call(this);
321
322 this._properties["stack"] = [];
323
324 this.bind(expression);
325
326 return this;
327}
328
329
330WhereClause.prototype = Object.create(AQLClause.prototype);
331WhereClause.prototype.constructor = WhereClause;
332
333
334WhereClause.prototype.bind = function(expression) {
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700335 if (expression instanceof AExpression) {
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700336 this._properties["stack"].push(expression);
337 }
338};
339
340
341WhereClause.prototype.val = function() {
342 var value = "where ";
343
344 var count = this._properties["stack"].length - 1;
345 while (count >= 0) {
346 value += this._properties["stack"][count].val() + " ";
347 count -= 1;
348 }
349
350 return value;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700351};
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700352
353
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700354// LimitClause
355// Grammar:
356// LimitClause ::= "limit" Expression ( "offset" Expression )?
357//
358// @param limitExpression [REQUIRED, AQLExpression]
359// @param offsetExpression [OPTIONAL, AQLExpression]
360function LimitClause(limitExpression, offsetExpression) {
361
362 AQLClause.call(this);
363
364 // limitExpression required
365 this._properties["clause"] = "limit " + limitExpression.val();
366
367 // Optional: Offset
368 var offset = typeof offsetExpression ? offsetExpression : null;
369 if (offset != null) {
370 this._properties["clause"] += " offset " + offsetExpression.val();
371 }
372
373 return this;
374}
375
376LimitClause.prototype = Object.create(AQLClause.prototype);
377LimitClause.prototype.constructor = LimitClause;
378
379
380// OrderbyClause
381//
382// Grammar:
383// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
384//
385// @params AQLExpressions and asc/desc strings, in any quantity. At least one required.
386function OrderbyClause() {
387
388 AQLClause.call(this);
389
390 // At least one argument expression is required, and first should be expression
391 if (arguments.length == 0 || !(arguments[0] instanceof AExpression)) {
genia.likes.science@gmail.com18f3bf22013-06-12 07:45:02 -0700392
genia.likes.science@gmail.com2ba32242013-05-31 03:10:48 -0700393 // TODO Not sure which error to throw for an empty OrderBy but this should fail.
394 alert("Order By Error");
395 this._properties["clause"] = null;
396 return this;
397 }
398
399 var expc = 0;
400 var expressions = [];
401
402 while (expc < arguments.length) {
403
404 var expression = "";
405
406 if (arguments[expc] instanceof AExpression) {
407 expression += arguments[expc].val();
408 }
409
410 var next = expc + 1;
411 if (next < arguments.length && (arguments[next] == "asc" || arguments[next] == "desc")) {
412 expc++;
413 expression += " " + arguments[expc];
414 }
415
416 expressions.push(expression);
417
418 expc++;
419 }
420
421 this._properties["clause"] = "order by " + expressions.join(", ");
422 return this;
423}
424
425OrderbyClause.prototype = Object.create(AQLClause.prototype);
426OrderbyClause.prototype.constructor = OrderbyClause;
427
428
genia.likes.science@gmail.com6e392912013-05-31 03:46:59 -0700429// GroupClause
430//
431// Grammar:
432// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
433function GroupClause() {
434 AQLClause.call(this);
435
436 if (arguments.length == 0) {
437 // TODO Not sure which error to throw for an empty GroupBy but this should fail.
438 alert("Group Error");
439 this._properties["clause"] = null;
440 return this;
441 }
442
443 var expc = 0;
444 var expressions = [];
445 var variableRefs = [];
446 var isDecor = false;
447
448 while (expc < arguments.length) {
449
450 if (arguments[expc] instanceof AExpression) {
451
452 isDecor = false;
453 expressions.push(arguments[expc].val());
454
455 } else if (typeof arguments[expc] == "string") {
456
457 // Special keywords, decor & with
458 if (arguments[expc] == "decor") {
459 isDecor = true;
460 } else if (arguments[expc] == "with") {
461 isDecor = false;
462 expc++;
463 while (expc < arguments.length) {
464 variableRefs.push("$" + arguments[expc]);
465 expc++;
466 }
467
468 // Variables and variable refs
469 } else {
470
471 var nextc = expc + 1;
472 var expression = "";
473
474 if (isDecor) {
475 expression += "decor ";
476 isDecor = false;
477 }
478
479 expression += "$" + arguments[expc] + " := " + arguments[nextc].val();
480 expressions.push(expression);
481 expc++;
482 }
483 }
484
485 expc++;
486 }
487
488 this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
489 return this;
490}
491
492GroupClause.prototype = Object.create(AQLClause.prototype);
493GroupClause.prototype.constructor = GroupClause;
494
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700495// BooleanExpression
496//
497// TODO
498function BooleanExpression(expression) {
499 this.value = expression;
genia.likes.science@gmail.com6fd7b2e2013-05-31 00:40:28 -0700500 alert("Debugging Bool: " + arguments.length + " " + expression);
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700501}
502
503BooleanExpression.prototype.val = function() {
504 return this.value;
505}
genia.likes.science@gmail.com79e603a2013-05-31 10:03:23 -0700506
507
508// SetStatement
509//
510// Grammar
511// "set" Identifier StringLiteral
512function SetStatement (identifier, stringLiteral) {
513 AExpression.call(this);
514
515 var statement = "set " + identifier + ' "' + stringLiteral + '";';
516
517 AExpression.prototype.set.call(this, statement);
518
519 return this;
520}
521
522SetStatement.prototype = Object.create(AExpression.prototype);
523SetStatement.prototype.constructor = SetStatement;
genia.likes.science@gmail.come34c57b2013-05-31 10:15:49 -0700524
525
526// Quantified Expression
527//
528// Grammar
529// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
530//
531// @param String some/every
532// @param [AExpression]
533// @param [Aexpression] satisfiesExpression
534function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
535 AExpression.call(this);
536
537 var expression = keyword + " ";
538 var varsInExpressions = [];
539
540 for (var varInExpression in expressions) {
541 varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val());
542 }
543 expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();
544
545 AExpression.prototype.set.call(this, expression);
546
547 return this;
548}
549
550QuantifiedExpression.prototype = Object.create(AExpression.prototype);
551QuantifiedExpression.prototype.constructor = QuantifiedExpression;
genia.likes.science@gmail.com64ca88e2013-05-31 10:40:39 -0700552
553QuantifiedExpression.prototype.val = function() {
554 var value = AExpression.prototype.val.call(this);
555 return "(" + value + ")";
556};
genia.likes.science@gmail.com44ff94a2013-05-31 11:09:34 -0700557
558
559// Functions that can be used to call core expressions/clauses more cleanly
560function AFLWOGR () {
561
562}
563
564function AClause () {
565
566}
567
568function ALetClause () {
569
570}
571
572function AWhereClause () {
573
574}
575
576function AOrderbyClause () {
577
578}
579
580function AGroupClause () {
581
582}
583
584function ALimitClause () {
585
586}
587
588function ADistinctClause () {
589
590}
591
592function AVariable () {
593
594}