blob: 5188d13b74f0144682cf138af1382c8e2e458a6c [file] [log] [blame]
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -07001function AsterixSDK() {
2
3 // Asterix SDK => send
4 // Posts a message containing an API endpoint, json data,
5 // and a UI callback function.
6 //
7 // @param handler [Asterix REST Controller], a handler object
8 // that provides REST request information.
9 //
10 // Anticipated Usage:
11 //
12 // var a = AsterixSDK();
13 // var e = Expression;
14 // var h = AsterixRestController.bind(e);
15 // a.send(h);
16 myThis = this;
17 this.callbacks = {
18 "sync" : function() { alert("default sync"); },
19 "async" : function() {}
20 };
21 this.send = function(handler, cb) {
22 myThis.callbacks = cb;
23 this.handler = handler;
24 this.extras = handler["extras"];
25 this.xhr.post(
26 handler["endpoint"],
27 handler["apiData"],
28 this.branch
29 );
30 };
31
32 this.branch = function(response) {
33 if (response && response["error-code"]) {
34
35 alert("Error [Code" + response["error-code"][0] + "]: " + response["error-code"][1]);
36
37 } else if (response && response["results"]) {
38 var fn_callback = myThis.callbacks["sync"];
39 fn_callback(response, myThis.extras);
40
41 } else if (response["handle"]) {
42
43 var fn_callback = this.callbacks["async"];
44 fn_callback(response, extra);
45
46 } else if (response["status"]) {
47
48 var fn_callback = this.callbacks["sync"];
49 fn_callback(response, extra);
50 }
51 }
52
53 // Asterix SDK => bindingHandler
54 // AsterixExpression form handler where a new REST API point is bound. Takes as input any
55 // AsterixExpression, each of which is bindable.
56 this.bindingHandler = new AsterixExpression();
57 this.bind = this.bindingHandler.bind;
58}
59
60function AsterixExpression() {
61 this.init();
62 return this;
63}
64
65AsterixExpression.prototype.init = function () {
66 this.dataverse = ""; // TODO This shouldn't make it to send
67 this.boundTo = {};
68 this.clauses = [];
69 this.ui_callback_on_success = function() {};
70 this.ui_callback_on_success_async = function() {};
71};
72
73AsterixExpression.prototype.bind = function(expression) {
74 // If expression is an AsterixExpression, it becomes base
75 if (expression instanceof AsterixExpression) {
76 this.boundTo = expression;
77 } else if (expression instanceof AsterixClause) {
78 this.clauses.push(expression.val());
79 }
80 return this;
81};
82
83AsterixExpression.prototype.send = function(arc) {
84 // Hackiest of hacks
85 var g = new AsterixSDK();
86 g.send(arc, arc["callback"]);
87};
88
89AsterixExpression.prototype.clear = function() {
90 this.clauses.length = 0;
91 return this;
92};
93
94AsterixExpression.prototype.val = function() {
95 return this.clauses.join("\n");
96};
97
98AsterixExpression.prototype.success = function(fn, isSync) {
99 if (isSync) {
100 this.ui_callback_on_success = fn;
101 } else {
102 this.ui_callback_on_success_async = fn;
103 }
104 return this;
105};
106
107AsterixExpression.prototype.set = function(statements_arr) {
108 for (var i = 0; i < statements_arr.length; i++) {
109 this.clauses.push(statements_arr[i]);
110 }
111 return this;
112};
113
114AsterixExpression.prototype.use_dataverse = function(dv) {
115 this.dataverse = dv;
116 this.clauses.push("use dataverse " + dv + ";");
117 return this;
118};
119
120AsterixExpression.prototype.return = function(return_object) {
121 var components = [];
122 for (var key in return_object) {
123 components.push('"' + key + '" : ' + return_object[key]);
124 }
125
126 var return_expression = 'return { ' + components.join(', ') + ' }';
127 this.clauses.push(return_expression);
128 return this;
129};
130
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700131
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700132
133
134
135
136
137
138
139
140// Temporary AsterixExpression Placeholder
141function AExpression () {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700142 this._properties = {};
143 this._success = function() {};
144
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700145 return this;
146}
147
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700148
149AExpression.prototype.bind = function(options) {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700150 var options = options || {};
151
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700152 if (options.hasOwnProperty("dataverse")) {
153 this._properties["dataverse"] = options["dataverse"];
154 }
155
156 if (options.hasOwnProperty("success")) {
157 this._success = options["success"];
158 }
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700159
160 if (options.hasOwnProperty("return")) {
161 this._properties["return"] = " return " + options["return"].val();
162 }
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700163};
164
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700165
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700166AExpression.prototype.run = function() {
genia.likes.science@gmail.com512454d2013-05-28 03:32:20 -0700167 var success_fn = this._success;
168
169 $.ajax({
170 type : 'GET',
171 url : "http://localhost:19101/query",
172 data : {"query" : this.val()},
173 dataType : "json",
174 success : function(data) {
175 success_fn(data);
176 }
177 });
178
179 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700180};
181
182
183AExpression.prototype.val = function() {
184
185 // If there is a dataverse defined, provide it.
186 if (this._properties.hasOwnProperty("dataverse")) {
187 return "use dataverse " + this._properties["dataverse"] + ";\n";
188 } else {
189 return this.error("Missing dataverse.");
190 }
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700191};
192
193
194AExpression.prototype.onReturn = function() {
195 var ret = "";
196
197 if (this._properties.hasOwnProperty("return")) {
198 ret += this._properties["return"] + ";";
199 }
200
201 return ret;
202};
203
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700204
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700205AExpression.prototype.error = function(msg) {
206 return "Asterix FunctionExpression Error: " + msg;
207};
208
209
210// FunctionExpression
211// Parent: AsterixExpression
212//
213// @param options [Various],
214// @key function [String], a function to be applid to the expression
215// @key expression [AsterixExpression or AsterixClause] an AsterixExpression/Clause to which the fn will be applied
216function FunctionExpression(options) {
217
218 // Initialize superclass
219 AExpression.call(this);
220
221 // Possible to initialize a function epxression without inputs, or with them
222 this.bind(options);
223
224 // Return object
225 return this;
226}
227
228
229FunctionExpression.prototype = Object.create(AExpression.prototype);
230FunctionExpression.prototype.constructor = FunctionExpression;
231
232
233FunctionExpression.prototype.bind = function(options) {
234
235 AExpression.prototype.bind.call(this, options);
236
237 var options = options || {};
238
239 if (options.hasOwnProperty("function")) {
240 this._properties["function"] = options["function"];
241 }
242
243 if (options.hasOwnProperty("expression")) {
244 this._properties["expression"] = options["expression"];
245 }
246
247 return this;
248};
249
250FunctionExpression.prototype.val = function () {
251
252 var value = AExpression.prototype.val.call(this);
253
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700254 return value + this._properties["function"] + "(" + this._properties["expression"].val() + ");" + AExpression.prototype.onReturn.call(this);
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700255};
256
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700257
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700258// FLWOGR ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
259// Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700260//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700261// WhereClause ::= "where" Expression
262// OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
genia.likes.science@gmail.comb4cb6b32013-05-29 04:30:38 -0700263//
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700264// GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
265// LimitClause ::= "limit" Expression ( "offset" Expression )?
266// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700267
268
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700269// FLWOGRExpression
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700270//
271// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700272function FLWOGRExpression (options) {
273 // Initialize superclass
274 AExpression.call(this);
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700275
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700276 this._properties["clauses"] = [];
277
278 // Bind options and return
279 this.bind(options);
280 return this;
genia.likes.science@gmail.com90d08722013-05-28 04:40:12 -0700281}
282
283
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700284FLWOGRExpression.prototype = Object.create(AExpression.prototype);
285FLWOGRExpression.prototype.constructor = FLWOGRExpression;
286
287
288FLWOGRExpression.prototype.bind = function(options) {
289 AExpression.prototype.bind.call(this, options);
290
291 var options = options || {};
292
293 if (this._properties["clauses"].length == 0) {
294 // Needs to start with for or let clause
295 if (options instanceof ForClause || options instanceof LetClause) {
296 this._properties["clauses"].push(options);
297 }
298 } else {
299 if (options instanceof AQLClause) {
300 this._properties["clauses"].push(options);
301 }
302 }
303
304 return this;
305};
306
307
308FLWOGRExpression.prototype.val = function() {
309 var value = AExpression.prototype.val.call(this);
310
311 for (var c in this._properties["clauses"]) {
312 value += this._properties["clauses"][c].val() + " ";
313 }
314
315 return value + AExpression.prototype.onReturn.call(this);
316};
317
genia.likes.science@gmail.com73dcc702013-05-28 04:21:28 -0700318// AQLClause
319//
320// Base Clause ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
321function AQLClause() {
322 this._properties = {};
323 this._properties["clause"] = "";
324}
325
326AQLClause.prototype.val = function() {
327 var value = this._properties["clause"];
328
329 if (this._properties.hasOwnProperty("return")) {
330 value += " return " + this._properties["return"].val();
331 }
332
333 return value;
334};
335
336AQLClause.prototype.bind = function(options) {
337 var options = options || {};
338
339 if (options.hasOwnProperty("return")) {
340 this._properties["return"] = options["return"];
341 }
342
343 return this;
344};
345
346
347// ForClause
348//
349// Grammar:
350// "for" Variable ( "at" Variable )? "in" ( Expression )
351//
352// @param for_variable [String], REQUIRED, first variable in clause
353// @param at_variable [String], NOT REQUIRED, first variable in clause
354// @param expression [AsterixExpression], REQUIRED, expression to evaluate
355//
356// TODO Error Checking
357function ForClause(for_variable, at_variable, expression) {
358 AQLClause.call(this);
359
360 // at_variable is optional, check if defined
361 var at = typeof at_variable ? at_variable : null;
362
363 // Prepare clause
364 this._properties["clause"] = "for $" + for_variable;
365 if (at != null) {
366 this._properties["clause"] += " at $" + at_variable;
367 }
368 this._properties["clause"] += " in " + expression.val();
369 return this;
370}
371
372ForClause.prototype = Object.create(AQLClause.prototype);
373ForClause.prototype.constructor = ForClause;
genia.likes.science@gmail.com38612632013-05-28 13:11:52 -0700374
375
376// LetClause
377//
378// Grammar:
379// LetClause ::= "let" Variable ":=" Expression
380//
381// @param let_variable [String]
382// @param expression [AExpression]
383//
384// TODO Vigorous error checking
385function LetClause(let_variable, expression) {
386 AQLClause.call(this);
387
388 this._properties["clause"] = "let $" + let_variable + " := ";
389 this._properties["clause"] += expression.val();
390
391 return this;
392}
393
394LetClause.prototype = Object.create(AQLClause.prototype);
395LetClause.prototype.constructor = LetClause;
396
397
398// WhereClause
399//
400// Grammar:
401// ::= "where" Expression
402//
403// @param expression [BooleanExpression], pushes this expression onto the stack
404//
405// TODO Error fixing
406function WhereClause(expression) {
407 AQLClause.call(this);
408
409 this._properties["stack"] = [];
410
411 this.bind(expression);
412
413 return this;
414}
415
416
417WhereClause.prototype = Object.create(AQLClause.prototype);
418WhereClause.prototype.constructor = WhereClause;
419
420
421WhereClause.prototype.bind = function(expression) {
422 if (expression instanceof BooleanExpression) {
423 this._properties["stack"].push(expression);
424 }
425};
426
427
428WhereClause.prototype.val = function() {
429 var value = "where ";
430
431 var count = this._properties["stack"].length - 1;
432 while (count >= 0) {
433 value += this._properties["stack"][count].val() + " ";
434 count -= 1;
435 }
436
437 return value;
438}
439
440
441// BooleanExpression
442//
443// TODO
444function BooleanExpression(expression) {
445 this.value = expression;
446}
447
448BooleanExpression.prototype.val = function() {
449 return this.value;
450}