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