blob: 72aafd4039a5ba4b7f818bde5a4894a7d4572c99 [file] [log] [blame]
genia.likes.science@gmail.com6d6aa8e2013-07-23 01:23:21 -07001function AsterixDBConnection(configuration) {
2 this._properties = {};
3 this._properties["dataverse"] = "";
4 this._properties["mode"] = "synchronous";
5
6 // This is a demo setup related fix. Enabled by proxy to Asterix REST API.
genia.likes.science@gmail.comd42b4022013-08-09 05:05:23 -07007 this._properties["endpoint_root"] = "/";
genia.likes.science@gmail.com6d6aa8e2013-07-23 01:23:21 -07008
9 var configuration = arguments || {};
10
11 for (var key in configuration) {
12 this._properties[key] = configuration[key];
13 }
14
15 return this;
16}
17
18
19AsterixDBConnection.prototype.dataverse = function(dataverseName) {
20 this._properties["dataverse"] = dataverseName;
21
22 return this;
23};
24
25
26AsterixDBConnection.prototype.query = function(statements, successFn, mode) {
27
28 if ( typeof statements === 'string') {
29 statements = [ statements ];
30 }
31
32 var m = typeof mode ? mode : "synchronous";
33
34 var query = "use dataverse " + this._properties["dataverse"] + ";\n" + statements.join("\n");
35
36 this._api(
37 {
38 "query" : query,
39 "mode" : m
40 },
41 successFn,
42 "query"
43 );
44
45 return this;
46};
47
48
49AsterixDBConnection.prototype.query_status = function(data, successFn) {
50
51 this._api(
52 data,
53 successFn,
54 "query/status"
55 );
56
57 return this;
58};
59
60
61AsterixDBConnection.prototype.query_result = function(data, successFn) {
62 this._api(
63 data,
64 successFn,
65 "query/result"
66 );
67
68 return this;
69};
70
71
72AsterixDBConnection.prototype.ddl = function(statements, successFn) {
73 if ( typeof statements === 'string') {
74 statements = [ statements ];
75 }
76
77 this._api(
78 {
79 "ddl" : "use dataverse " + this._properties["dataverse"] + ";\n" + statements.join("\n")
80 },
81 successFn,
82 "ddl"
83 );
84}
85
86
87AsterixDBConnection.prototype.update = function(statements, successFn) {
88 if ( typeof statements === 'string') {
89 statements = [ statements ];
90 }
91
92 this._api(
93 {
94 "statements" : "use dataverse " + this._properties["dataverse"] + ";\n" + statements.join("\n")
95 },
96 successFn,
97 "update"
98 );
99}
100
101
102AsterixDBConnection.prototype._api = function(json, onSuccess, endpoint) {
103 var success_fn = onSuccess;
genia.likes.science@gmail.com6d6aa8e2013-07-23 01:23:21 -0700104 var endpoint_url = this._properties["endpoint_root"] + endpoint;
105
106 $.ajax({
107 type: 'GET',
108 url: endpoint_url,
109 data : json,
110 dataType: "json",
111 success: function(data) {
112 success_fn(data);
113 },
114 error: function(xhr, status, error) {
115
116 }
117 });
118
119 return this;
120};
121
122
123// Asterix Expressions - Base
124function AExpression () {
125
126 this._properties = {};
127 this._success = function() {};
128
129 if (arguments.length == 1) {
130 this._properties["value"] = arguments[0];
131 }
132
133 return this;
134}
135
136
137AExpression.prototype.bind = function(options) {
138 var options = options || {};
139
140 if (options.hasOwnProperty("success")) {
141 this._success = options["success"];
142 }
143
144 if (options.hasOwnProperty("return")) {
145 this._properties["return"] = " return " + options["return"].val();
146 }
147};
148
149
150AExpression.prototype.run = function(successFn) {
151 return this;
152};
153
154
155AExpression.prototype.val = function() {
156
157 var value = "";
158
159 // If there is a dataverse defined, provide it.
160 if (this._properties.hasOwnProperty("dataverse")) {
161 value += "use dataverse " + this._properties["dataverse"] + ";\n";
162 };
163
164 if (this._properties.hasOwnProperty("value")) {
165 value += this._properties["value"].toString();
166 }
167
168 return value;
169};
170
171
172// @param expressionValue [String]
173AExpression.prototype.set = function(expressionValue) {
174 this._properties["value"] = expressionValue;
175 return this;
176};
177
178
179// AQL Statements
180// SingleStatement ::= DataverseDeclaration
181// | FunctionDeclaration
182// | CreateStatement
183// | DropStatement
184// | LoadStatement
185// | SetStatement
186// | InsertStatement
187// | DeleteStatement
188// | Query
189function InsertStatement(quantifiedName, query) {
190 AExpression.call(this);
191
192 var innerQuery = "";
193 if (query instanceof AExpression) {
194 innerQuery = query.val();
195 } else if (typeof query == "object" && Object.getPrototypeOf( query ) === Object.prototype ) {
196
197 var insertStatements = [];
198 for (querykey in query) {
199 if (query[querykey] instanceof AExpression) {
200 insertStatements.push('"' + querykey + '" : ' + query[querykey].val());
201 } else if (typeof query[querykey] == "string") {
202 insertStatements.push('"' + querykey + '" : ' + query[querykey]);
203 } else {
204 insertStatements.push('"' + querykey + '" : ' + query[querykey].toString());
205 }
206 }
207
208 innerQuery = "{" + insertStatements.join(', ') + "}";
209 }
210
211 var statement = "insert into dataset " + quantifiedName + "(" + innerQuery + ");";
212
213 AExpression.prototype.set.call(this, statement);
214
215 return this;
216}
217
218InsertStatement.prototype = Object.create(AExpression.prototype);
219InsertStatement.prototype.constructor = InsertStatement;
220
221
222// Delete Statement
223// DeleteStatement ::= "delete" Variable "from" "dataset" QualifiedName ( "where" Expression )?
224function DeleteStatement (variable, quantifiedName, whereExpression) {
225 AExpression.call(this);
226
227 var statement = "delete " + variable + " from dataset " + quantifiedName;
228
229 if (whereExpression instanceof AExpression) {
230 statement += " where " + whereExpression.val();
231 }
232
233 AExpression.prototype.set.call(this, statement);
234
235 return this;
236}
237
238DeleteStatement.prototype = Object.create(AExpression.prototype);
239DeleteStatement.prototype.constructor = DeleteStatement;
240
241// SetStatement
242//
243// Grammar
244// "set" Identifier StringLiteral
245function SetStatement (identifier, stringLiteral) {
246 AExpression.call(this);
247
248 var statement = "set " + identifier + ' "' + stringLiteral + '";';
249
250 AExpression.prototype.set.call(this, statement);
251
252 return this;
253}
254
255SetStatement.prototype = Object.create(AExpression.prototype);
256SetStatement.prototype.constructor = SetStatement;
257
258
259// Other Expressions
260
261// FunctionExpression
262// Parent: AsterixExpression
263//
264// @param options [Various],
265// @key function [String], a function to be applid to the expression
266// @key expression [AsterixExpression or AQLClause] an AsterixExpression/Clause to which the fn will be applied
267function FunctionExpression() {
268
269 // Initialize superclass
270 AExpression.call(this);
271
272 this._properties["function"] = "";
273 this._properties["expressions"] = [];
274
275 // Check for fn/expression input
276 if (arguments.length >= 2 && typeof arguments[0] == "string") {
277
278 this._properties["function"] = arguments[0];
279
280 for (i = 1; i < arguments.length; i++) {
281 if (arguments[i] instanceof AExpression || arguments[i] instanceof AQLClause) {
282 this._properties["expressions"].push(arguments[i]);
283 } else {
284 this._properties["expressions"].push(new AExpression(arguments[i]));
285 }
286 }
287 }
288
289 // Return FunctionCallExpression object
290 return this;
291}
292
293
294FunctionExpression.prototype = Object.create(AExpression.prototype);
295FunctionExpression.prototype.constructor = FunctionExpression;
296
297
298FunctionExpression.prototype.val = function () {
299 var fn_args = [];
300 for (var i = 0; i < this._properties["expressions"].length; i++) {
301 fn_args.push(this._properties["expressions"][i].val());
302 }
303
304 return this._properties["function"] + "(" + fn_args.join(", ") + ")";
305};
306
307
308// FLWOGRExpression
309//
310// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
311function FLWOGRExpression (options) {
312 // Initialize superclass
313 AExpression.call(this);
314
315 this._properties["clauses"] = [];
316 this._properties["minSize"] = 0;
317
318 // Bind options and return
319 this.bind(options);
320 return this;
321}
322
323
324FLWOGRExpression.prototype = Object.create(AExpression.prototype);
325FLWOGRExpression.prototype.constructor = FLWOGRExpression;
326
327
328FLWOGRExpression.prototype.bind = function(options) {
329 AExpression.prototype.bind.call(this, options);
330
331 var options = options || {};
332
333 if (options instanceof SetStatement) {
334 this._properties["clauses"].push(options);
335 this._properties["minSize"] += 1;
336 }
337
338 if (this._properties["clauses"].length <= this._properties["minSize"]) {
339 // Needs to start with for or let clause
340 if (options instanceof ForClause || options instanceof LetClause) {
341 this._properties["clauses"].push(options);
342 }
343 } else {
344 if (options instanceof AQLClause) {
345 this._properties["clauses"].push(options);
346 }
347 }
348
349 return this;
350};
351
352
353FLWOGRExpression.prototype.val = function() {
354 var value = AExpression.prototype.val.call(this);
355
356 var clauseValues = [];
357 for (var c in this._properties["clauses"]) {
358 clauseValues.push(this._properties["clauses"][c].val());
359 }
360
361 return value + clauseValues.join("\n");// + ";";
362};
363
364// Pretty Expression Shorthand
365
366FLWOGRExpression.prototype.ReturnClause = function(expression) {
367 return this.bind(new ReturnClause(expression));
368};
369
370FLWOGRExpression.prototype.ForClause = function() {
371 return this.bind(new ForClause(Array.prototype.slice.call(arguments)));
372};
373
374FLWOGRExpression.prototype.LetClause = function() {
375 return this.bind(new LetClause(Array.prototype.slice.call(arguments)));
376};
377
378FLWOGRExpression.prototype.WhereClause = function() {
379 return this.bind(new WhereClause(Array.prototype.slice.call(arguments)));
380};
381
382FLWOGRExpression.prototype.and = function() {
383 var args = Array.prototype.slice.call(arguments);
384 args.push(true);
385 return this.bind(new WhereClause().and(args));
386};
387
388FLWOGRExpression.prototype.or = function() {
389 var args = Array.prototype.slice.call(arguments);
390 args.push(true);
391 return this.bind(new WhereClause().or(args));
392};
393
394FLWOGRExpression.prototype.OrderbyClause = function() {
395 return this.bind(new OrderbyClause(Array.prototype.slice.call(arguments)));
396};
397
398
399FLWOGRExpression.prototype.GroupClause = function() {
400 return this.bind(new GroupClause(Array.prototype.slice.call(arguments)));
401};
402
403FLWOGRExpression.prototype.LimitClause = function() {
404 return this.bind(new LimitClause(Array.prototype.slice.call(arguments)));
405};
406
407FLWOGRExpression.prototype.DistinctClause = function() {
408 return this.bind(new DistinctClause(Array.prototype.slice.call(arguments)));
409};
410
411FLWOGRExpression.prototype.AQLClause = function() {
412 return this.bind(new AQLClause(Array.prototype.slice.call(arguments)));
413};
414
415
416// AQLClause
417//
418// Base Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
419function AQLClause() {
420 this._properties = {};
421 this._properties["clause"] = "";
422 this._properties["stack"] = [];
423 if (typeof arguments[0] == 'string') {
424 this._properties["clause"] = arguments[0];
425 }
426 return this;
427}
428
429AQLClause.prototype.val = function() {
430 var value = this._properties["clause"];
431
432 return value;
433};
434
435AQLClause.prototype.bind = function(options) {
436
437 if (options instanceof AQLClause) {
438 this._properties["clause"] += " " + options.val();
439 }
440
441 return this;
442};
443
444AQLClause.prototype.set = function(value) {
445 this._properties["clause"] = value;
446 return this;
447};
448
449
450// ForClause
451//
452// Grammar:
453// "for" Variable ( "at" Variable )? "in" ( Expression )
454//
455// @param for_variable [String], REQUIRED, first variable in clause
456// @param at_variable [String], NOT REQUIRED, first variable in clause
457// @param expression [AsterixExpression], REQUIRED, expression to evaluate
458function ForClause(for_variable, at_variable, expression) {
459 AQLClause.call(this);
460
461 var parameters = [];
462 if (arguments[0] instanceof Array) {
463 parameters = arguments[0];
464 } else {
465 parameters = arguments;
466 }
467
468 this._properties["clause"] = "for " + parameters[0];
469
470 if (parameters.length == 3) {
471 this._properties["clause"] += " at " + parameters[1];
472 this._properties["clause"] += " in " + parameters[2].val();
473 } else if (parameters.length == 2) {
474 this._properties["clause"] += " in " + parameters[1].val();
475 }
476
477 return this;
478}
479
480ForClause.prototype = Object.create(AQLClause.prototype);
481ForClause.prototype.constructor = ForClause;
482
483
484// LetClause
485//
486// Grammar:
487// LetClause ::= "let" Variable ":=" Expression
488//
489// @param let_variable [String]
490// @param expression [AExpression]
491//
492// TODO Vigorous error checking
493function LetClause(let_variable, expression) {
494 AQLClause.call(this);
495
496 var parameters = [];
497 if (arguments[0] instanceof Array) {
498 parameters = arguments[0];
499 } else {
500 parameters = arguments;
501 }
502
503 this._properties["clause"] = "let " + parameters[0] + " := ";
504 this._properties["clause"] += parameters[1].val();
505
506 return this;
507}
508
509LetClause.prototype = Object.create(AQLClause.prototype);
510LetClause.prototype.constructor = LetClause;
511
512
513// ReturnClause
514//
515// Grammar:
516// return [AQLExpression]
517function ReturnClause(expression) {
518 AQLClause.call(this);
519
520 this._properties["clause"] = "return ";
521
522 if (expression instanceof AExpression || expression instanceof AQLClause) {
523 this._properties["clause"] += expression.val();
524
525 } else if ( typeof expression == "object" && Object.getPrototypeOf( expression ) === Object.prototype ) {
526
527 this._properties["clause"] += "\n{\n";
528 var returnStatements = [];
529 for (returnValue in expression) {
530
531 if (expression[returnValue] instanceof AExpression) {
532 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());
533 } else if (typeof expression[returnValue] == "string") {
534 returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);
535 }
536 }
537 this._properties["clause"] += returnStatements.join(",\n");
538 this._properties["clause"] += "\n}";
539
540 } else {
541 this._properties["clause"] += new AQLClause().set(expression).val();
542 }
543
544 return this;
545}
546
547
548ReturnClause.prototype = Object.create(AQLClause.prototype);
549ReturnClause.prototype.constructor = ReturnClause;
550
551
552// WhereClause
553//
554// Grammar:
555// ::= "where" Expression
556//
557// @param expression [BooleanExpression], pushes this expression onto the stack
558function WhereClause(expression) {
559 AQLClause.call(this);
560
561 this._properties["stack"] = [];
562
563 if (expression instanceof Array) {
564 this.bind(expression[0]);
565 } else {
566 this.bind(expression);
567 }
568
569 return this;
570}
571
572
573WhereClause.prototype = Object.create(AQLClause.prototype);
574WhereClause.prototype.constructor = WhereClause;
575
576
577WhereClause.prototype.bind = function(expression) {
578 if (expression instanceof AExpression) {
579 this._properties["stack"].push(expression);
580 }
581 return this;
582};
583
584
585WhereClause.prototype.val = function() {
586 var value = "";
587
588 if (this._properties["stack"].length == 0) {
589 return value;
590 }
591
592 var count = this._properties["stack"].length - 1;
593 while (count >= 0) {
594 value += this._properties["stack"][count].val() + " ";
595 count -= 1;
596 }
597
598 return "where " + value;
599};
600
601
602WhereClause.prototype.and = function() {
603
604 var parameters = [];
605 if (arguments[0] instanceof Array) {
606 parameters = arguments[0];
607 } else {
608 parameters = arguments;
609 }
610
611 var andClauses = [];
612 for (var expression in parameters) {
613
614 if (parameters[expression] instanceof AExpression) {
615 andClauses.push(parameters[expression].val());
616 }
617 }
618
619 if (andClauses.length > 0) {
620 this._properties["stack"].push(new AExpression().set(andClauses.join(" and ")));
621 }
622
623 return this;
624};
625
626
627WhereClause.prototype.or = function() {
628
629 var parameters = [];
630 if (arguments[0] instanceof Array) {
631 parameters = arguments[0];
632 } else {
633 parameters = arguments;
634 }
635
636 var orClauses = [];
637 for (var expression in parameters) {
638
639 if (parameters[expression] instanceof AExpression) {
640 orClauses.push(parameters[expression].val());
641 }
642 }
643
644 if (andClauses.length > 0) {
645 this._properties["stack"].push(new AExpression().set(orClauses.join(" and ")));
646 }
647
648 return this;
649};
650
651// LimitClause
652// Grammar:
653// LimitClause ::= "limit" Expression ( "offset" Expression )?
654//
655// @param limitExpression [REQUIRED, AQLExpression]
656// @param offsetExpression [OPTIONAL, AQLExpression]
657function LimitClause(limitExpression, offsetExpression) {
658
659 AQLClause.call(this);
660
661 var parameters = [];
662 if (arguments[0] instanceof Array) {
663 parameters = arguments[0];
664 } else {
665 parameters = arguments;
666 }
667
668 // limitExpression required
669 this._properties["clause"] = "limit " + parameters[0].val();
670
671 // Optional: Offset
672 if (parameters.length == 2) {
673 this._properties["clause"] += " offset " + parameters[1].val();
674 }
675
676 return this;
677}
678
679LimitClause.prototype = Object.create(AQLClause.prototype);
680LimitClause.prototype.constructor = LimitClause;
681
682
683// OrderbyClause
684//
685// Grammar:
686// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
687//
688// @params AQLExpressions and asc/desc strings, in any quantity. At least one required.
689function OrderbyClause() {
690
691 AQLClause.call(this);
692
693 // At least one argument expression is required, and first should be expression
694 if (arguments.length == 0) {
695 this._properties["clause"] = null;
696 return this;
697 }
698
699 var parameters = [];
700 if (arguments[0] instanceof Array) {
701 parameters = arguments[0];
702 } else {
703 parameters = arguments;
704 }
705
706 var expc = 0;
707 var expressions = [];
708
709 while (expc < parameters.length) {
710
711 var expression = "";
712
713 if (parameters[expc] instanceof AExpression) {
714 expression += parameters[expc].val();
715 }
716
717 var next = expc + 1;
718 if (next < parameters.length && (parameters[next] == "asc" || parameters[next] == "desc")) {
719 expc++;
720 expression += " " + parameters[expc];
721 }
722
723 expressions.push(expression);
724
725 expc++;
726 }
727
728 this._properties["clause"] = "order by " + expressions.join(", ");
729 return this;
730}
731
732OrderbyClause.prototype = Object.create(AQLClause.prototype);
733OrderbyClause.prototype.constructor = OrderbyClause;
734
735
736// GroupClause
737//
738// Grammar:
739// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
740function GroupClause() {
741 AQLClause.call(this);
742
743 if (arguments.length == 0) {
744 this._properties["clause"] = null;
745 return this;
746 }
747
748 var parameters = [];
749 if (arguments[0] instanceof Array) {
750 parameters = arguments[0];
751 } else {
752 parameters = arguments;
753 }
754
755 var expc = 0;
756 var expressions = [];
757 var variableRefs = [];
758 var isDecor = false;
759
760 while (expc < parameters.length) {
761
762 if (parameters[expc] instanceof AExpression) {
763
764 isDecor = false;
765 expressions.push(parameters[expc].val());
766
767 } else if (typeof parameters[expc] == "string") {
768
769 // Special keywords, decor & with
770 if (parameters[expc] == "decor") {
771 isDecor = true;
772 } else if (parameters[expc] == "with") {
773 isDecor = false;
774 expc++;
775 while (expc < parameters.length) {
776 variableRefs.push(parameters[expc]);
777 expc++;
778 }
779
780 // Variables and variable refs
781 } else {
782
783 var nextc = expc + 1;
784 var expression = "";
785
786 if (isDecor) {
787 expression += "decor ";
788 isDecor = false;
789 }
790
791 expression += parameters[expc] + " := " + parameters[nextc].val();
792 expressions.push(expression);
793 expc++;
794 }
795 }
796
797 expc++;
798 }
799
800 this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
801 return this;
802}
803
804GroupClause.prototype = Object.create(AQLClause.prototype);
805GroupClause.prototype.constructor = GroupClause;
806
807
808// Quantified Expression
809//
810// Grammar
811// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
812//
813// @param String some/every
814// @param [AExpression]
815// @param [Aexpression] satisfiesExpression
816function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
817 AExpression.call(this);
818
819 var expression = keyword + " ";
820 var varsInExpressions = [];
821
822 for (var varInExpression in expressions) {
823 varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val());
824 }
825 expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();
826
827 AExpression.prototype.set.call(this, expression);
828
829 return this;
830}
831
832QuantifiedExpression.prototype = Object.create(AExpression.prototype);
833QuantifiedExpression.prototype.constructor = QuantifiedExpression;
834
835QuantifiedExpression.prototype.val = function() {
836 var value = AExpression.prototype.val.call(this);
837 return "(" + value + ")";
838};