UNPKG

alasql

Version:

AlaSQL.js - JavaScript SQL database library for relational and graph data manipulation with support of localStorage, IndexedDB, and Excel

689 lines (588 loc) 22 kB
/* // // Expressions for Alasql.js // Date: 03.11.2014 // (c) 2014, Andrey Gershun // */ yy.ExpressionStatement = function(params) { return yy.extend(this, params); }; yy.ExpressionStatement.prototype.toString = function() { return this.expression.toString(); }; yy.ExpressionStatement.prototype.execute = function (databaseid, params, cb) { if(this.expression) { // console.log(this.expression.toJavaScript('','', null)); // console.log(this.expression.toJavaScript('','', null)); var expr = new Function("params,alasql,p",'return '+this.expression.toJavaScript('({})','', null)); var res = expr(params,alasql); if(cb) res = cb(res); return res; } } yy.Expression = function(params) { return yy.extend(this, params); }; yy.Expression.prototype.toString = function() { var s = this.expression.toString(); if(this.order) s += ' '+this.order.toString(); if(this.nocase) s += ' '+K('COLLATE')+' '+K('NOCASE'); return s; }; yy.Expression.prototype.findAggregator = function (query){ if(this.expression.findAggregator) this.expression.findAggregator(query); }; yy.Expression.prototype.toJavaScript = function(context, tableid, defcols) { // console.log('Expression',this); if(this.expression.reduced) return 'true'; return this.expression.toJavaScript(context, tableid, defcols); }; yy.Expression.prototype.compile = function(context, tableid, defcols){ // console.log('Expression',this); if(this.reduced) return returnTrue(); return new Function('p','return '+this.toJavaScript(context, tableid, defcols)); }; yy.JavaScript = function(params) { return yy.extend(this, params); }; yy.JavaScript.prototype.toString = function() { var s = '``'+this.value+'``'; return s; }; yy.JavaScript.prototype.toJavaScript = function(context, tableid, defcols) { // console.log('Expression',this); return '('+this.value+')'; }; yy.JavaScript.prototype.execute = function (databaseid, params, cb) { var res = 1; var expr = new Function("params,alasql,p",this.value); expr(params,alasql); if(cb) res = cb(res); return res; } yy.Literal = function (params) { return yy.extend(this, params); } yy.Literal.prototype.toString = function() { var s = this.value; if(this.value1) s = this.value1+'.'+s; // else s = tableid+'.'+s; return L(s); } yy.Join = function (params) { return yy.extend(this, params); } yy.Join.prototype.toString = function() { var s = NL()+ID(); if(this.joinmode) s += K(this.joinmode)+' '; s += K('JOIN')+this.table.toString(); return s; } //yy.Join.prototype.toJavaScript = function(context, tableid) { // return 'JOIN'+this.table.toString(); //} yy.Table = function (params) { return yy.extend(this, params); } yy.Table.prototype.toString = function() { var s = this.tableid; // if(this.joinmode) if(this.databaseid) s = this.databaseid+'.'+s; return L(s); }; yy.View = function (params) { return yy.extend(this, params); } yy.View.prototype.toString = function() { var s = this.viewid; // if(this.joinmode) if(this.databaseid) s = this.databaseid+'.'+s; return L(s); }; yy.Op = function (params) { return yy.extend(this, params); } yy.Op.prototype.toString = function() { if(this.op == 'IN' || this.op == 'NOT IN') { return this.left.toString()+" "+P(this.op)+" ("+this.right.toString()+")"; } if(this.allsome) { return this.left.toString()+" "+P(this.op)+" "+this.allsome+' ('+this.right.toString()+')'; } if(this.op == '->' || this.op == '!') { var s = this.left.toString()+this.op; // console.log(this.right); if(typeof this.right != 'string' && typeof this.right != 'number' ) s += '('; s += this.right.toString(); if(typeof this.right != 'string' && typeof this.right != 'number' ) s += ')'; return s; } return this.left.toString()+" "+P(this.op)+" "+(this.allsome?this.allsome+' ':'')+this.right.toString(); }; yy.Op.prototype.findAggregator = function (query){ // console.log(this.toString()); if(this.left && this.left.findAggregator) this.left.findAggregator(query); // Do not go in > ALL if(this.right && this.right.findAggregator && (!this.allsome)) { this.right.findAggregator(query); } }; yy.Op.prototype.toType = function(tableid) { if(['-','*','/','%','^'].indexOf(this.op) >-1) return 'number'; if(this.op == '+') { if(this.left.toType(tableid) == 'string' || this.right.toType(tableid) == 'string') return 'string'; if(this.left.toType(tableid) == 'number' || this.right.toType(tableid) == 'number') return 'number'; }; if(['AND','OR','NOT','=','==','===', '!=','!==','!===','>','>=','<','<=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE'].indexOf(this.op) >-1 ) return 'boolean'; if(this.op == 'BETWEEN' || this.op == 'NOT BETWEEN' || this.op == 'IS NULL' || this.op == 'IS NOT NULL') return 'boolean'; if(this.allsome) return 'boolean'; if(!this.op) return this.left.toType(); return 'unknown'; }; yy.Op.prototype.toJavaScript = function(context,tableid,defcols) { // console.log(this); var op = this.op; if(this.op == '=') op = '==='; else if(this.op == '<>') op = '!='; else if(this.op == 'OR') op = '||'; if(this.op == '->') { // console.log(this.right, typeof this.right); if(typeof this.right == "string") { return this.left.toJavaScript(context,tableid, defcols)+'["'+this.right+'"]'; } else if(typeof this.right == "number") { return this.left.toJavaScript(context,tableid, defcols)+'['+this.right+']'; } else if(this.right instanceof yy.FuncValue) { ss = []; if(!this.right.args || this.right.args.length == 0) { } else { var ss = this.right.args.map(function(arg){ return arg.toJavaScript(context,tableid, defcols); }); } return this.left.toJavaScript(context,tableid, defcols)+'[\''+this.right.funcid+'\']('+ ss.join(',')+')'; } else { return this.left.toJavaScript(context,tableid, defcols)+'['+this.right.toJavaScript(context,tableid, defcols)+']'; } }; if(this.op == '!') { if(typeof this.right == "string") { return 'alasql.databases[alasql.useid].objects['+this.left.toJavaScript(context,tableid, defcols)+']["'+this.right+'"]'; } // TODO - add other cases } if(this.op == 'IS') { return '((typeof '+this.left.toJavaScript(context,tableid, defcols)+"=='undefined') == " + '(typeof '+this.right.toJavaScript(context,tableid, defcols)+"=='undefined'))"; } if(this.op == '==') { return 'alasql.utils.deepEqual('+this.left.toJavaScript(context,tableid, defcols)+","+this.right.toJavaScript(context,tableid, defcols)+')'; } if(this.op == '===') { return "(("+this.left.toJavaScript(context,tableid, defcols)+").valueOf()===("+this.right.toJavaScript(context,tableid, defcols)+'.valueOf()))'; } if(this.op == '!===') { return "!(("+this.left.toJavaScript(context,tableid, defcols)+").valueOf()===("+this.right.toJavaScript(context,tableid, defcols)+'.valueOf()))'; } if(this.op == '!==') { return '(!alasql.utils.deepEqual('+this.left.toJavaScript(context,tableid, defcols)+","+this.right.toJavaScript(context,tableid, defcols)+'))'; } if(this.op == 'LIKE') { var s = "("+this.left.toJavaScript(context,tableid, defcols)+"+'')"+ ".toUpperCase().match(new RegExp('^'+("+this.right.toJavaScript(context,tableid, defcols)+").replace(/\\\%/g,'.*').toUpperCase()+'$','g'))" // console.log(s); return s; }; if(this.op == 'NOT LIKE') { var s = "!(("+this.left.toJavaScript(context,tableid, defcols)+"+'')"+ ".toUpperCase().match(new RegExp('^'+("+this.right.toJavaScript(context,tableid, defcols)+").replace(/\\\%/g,'.*').toUpperCase()+'$','g')))" return s; }; if(this.op == 'BETWEEN') { if(this.right instanceof yy.Op && this.right.op == 'AND') { return '(('+this.right.left.toJavaScript(context,tableid, defcols)+'<='+this.left.toJavaScript(context,tableid, defcols)+')&&'+ '('+this.left.toJavaScript(context,tableid, defcols)+'<='+this.right.right.toJavaScript(context,tableid, defcols)+'))'; } else { throw new Error('Wrong BETWEEN operator without AND part'); } }; if(this.op == 'NOT BETWEEN') { if(this.right instanceof yy.Op && this.right.op == 'AND') { return '!(('+this.right.left.toJavaScript(context,tableid, defcols)+'<='+this.left.toJavaScript(context,tableid, defcols)+')&&'+ '('+this.left.toJavaScript(context,tableid, defcols)+'<='+this.right.right.toJavaScript(context,tableid, defcols)+'))'; } else { throw new Error('Wrong NOT BETWEEN operator without AND part'); } }; if(this.op == 'IN') { if(this.right instanceof yy.Select ) { var s = '('; // s += 'this.query.queriesdata['+this.queriesidx+']'; s += 'alasql.utils.flatArray(this.query.queriesfn['+(this.queriesidx)+'](params,null,p))'; s += '.indexOf('; s += this.left.toJavaScript(context,tableid, defcols)+')>-1)'; return s; } else if(this.right instanceof Array ) { // if(this.right.length == 0) return 'false'; var s = '(['+this.right.map(function(a){return a.toJavaScript(context,tableid, defcols)}).join(',')+'].indexOf('; s += this.left.toJavaScript(context,tableid, defcols)+')>-1)'; //console.log(s); return s; } else { var s = '('+this.right.toJavaScript(context,tableid, defcols)+'.indexOf('; s += this.left.toJavaScript(context,tableid, defcols)+')>-1)'; return s; // } else { // throw new Error('Wrong IN operator without SELECT part'); } }; if(this.op == 'NOT IN') { if(this.right instanceof yy.Select ) { var s = '(' //this.query.queriesdata['+this.queriesidx+'] s += 'alasql.utils.flatArray(this.query.queriesfn['+(this.queriesidx)+'](params,null,p))'; s +='.indexOf('; s += this.left.toJavaScript(context,tableid, defcols)+')<0)'; return s; } else if(this.right instanceof Array ) { // if(this.right.length == 0) return 'true'; var s = '(['+this.right.map(function(a){return a.toJavaScript(context,tableid, defcols)}).join(',')+'].indexOf('; s += this.left.toJavaScript(context,tableid, defcols)+')<0)'; return s; } else { throw new Error('Wrong NOT IN operator without SELECT part'); } }; if(this.allsome == 'ALL') { if(this.right instanceof yy.Select ) { // var s = 'this.query.queriesdata['+this.queriesidx+']'; var s = 'alasql.utils.flatArray(this.query.queriesfn['+(this.queriesidx)+'](params,null,p))'; s +='.every(function(b){return ('; s += this.left.toJavaScript(context,tableid, defcols)+')'+op+'b})'; return s; } else if(this.right instanceof Array ) { var s = '['+this.right.map(function(a){return a.toJavaScript(context,tableid, defcols)}).join(',')+'].every(function(b){return ('; s += this.left.toJavaScript(context,tableid, defcols)+')'+op+'b})'; return s; } else { throw new Error('Wrong NOT IN operator without SELECT part'); } }; if(this.allsome == 'SOME' || this.allsome == 'ANY') { if(this.right instanceof yy.Select ) { // var s = 'this.query.queriesdata['+this.queriesidx+']'; var s = 'alasql.utils.flatArray(this.query.queriesfn['+(this.queriesidx)+'](params,null,p))'; s+='.some(function(b){return ('; s += this.left.toJavaScript(context,tableid, defcols)+')'+op+'b})'; return s; } else if(this.right instanceof Array ) { var s = '['+this.right.map(function(a){return a.toJavaScript(context,tableid, defcols)}).join(',')+'].some(function(b){return ('; s += this.left.toJavaScript(context,tableid, defcols)+')'+op+'b})'; return s; } else { throw new Error('Wrong NOT IN operator without SELECT part'); } }; // Special case for AND optimization (if reduced) if(this.op == 'AND') { if(this.left.reduced) { if(this.right.reduced) { return 'true'; } else { return this.right.toJavaScript(context,tableid, defcols); } } else if(this.right.reduced) { return this.left.toJavaScript(context,tableid, defcols); } // Otherwise process as regular operation (see below) op = '&&'; } if(this.op == '^') { return 'Math.pow('+this.left.toJavaScript(context,tableid, defcols) +','+this.right.toJavaScript(context,tableid, defcols)+')'; }; // Change names // console.log(this); return '('+this.left.toJavaScript(context,tableid, defcols)+op+this.right.toJavaScript(context,tableid, defcols)+')'; }; yy.VarValue = function (params) { return yy.extend(this, params); } yy.VarValue.prototype.toString = function() { return '@'+L(this.variable); }; yy.VarValue.prototype.toType = function() { return 'unknown'; }; yy.VarValue.prototype.toJavaScript = function() { return "alasql.vars['"+this.variable+"']"; } yy.NumValue = function (params) { return yy.extend(this, params); } yy.NumValue.prototype.toString = function() { return N(this.value.toString()); }; yy.NumValue.prototype.toType = function() { return 'number'; }; yy.NumValue.prototype.toJavaScript = function() { return ""+this.value; } yy.StringValue = function (params) { return yy.extend(this, params); } yy.StringValue.prototype.toString = function() { return "'"+S(this.value.toString())+"'"; } yy.StringValue.prototype.toType = function() { return 'string'; } yy.StringValue.prototype.toJavaScript = function() { // console.log("'"+doubleqq(this.value)+"'"); // return "'"+doubleqq(this.value)+"'"; return "'"+escapeq(this.value)+"'"; } yy.LogicValue = function (params) { return yy.extend(this, params); } yy.LogicValue.prototype.toString = function() { return this.value?'TRUE':'FALSE'; } yy.LogicValue.prototype.toType = function() { return 'boolean'; } yy.LogicValue.prototype.toJavaScript = function() { return this.value?'true':'false'; } yy.NullValue = function (params) { return yy.extend(this, params); } yy.NullValue.prototype.toString = function() { return 'NULL'; } yy.NullValue.prototype.toJavaScript = function() { return 'undefined'; } yy.ParamValue = function (params) { return yy.extend(this, params); } yy.ParamValue.prototype.toString = function() { return '$'+this.param; } yy.ParamValue.prototype.toJavaScript = function() { if(typeof this.param == "string") return "params[\'"+this.param+"\']"; else return "params["+this.param+"]"; } yy.UniOp = function (params) { return yy.extend(this, params); } yy.UniOp.prototype.toString = function() { if(this.op == '-') return this.op+this.right.toString(); if(this.op == '+') return this.op+this.right.toString(); if(this.op == '#') return this.op+this.right.toString(); if(this.op == 'NOT') return this.op+'('+this.right.toString()+')'; else if(this.op == null) return '('+this.right.toString()+')'; }; yy.UniOp.prototype.findAggregator = function (query){ if(this.right.findAggregator) this.right.findAggregator(query); }; yy.UniOp.prototype.toType = function(tableid) { if(this.op == '-') return 'number'; if(this.op == '+') return 'number'; if(this.op == 'NOT') return 'boolean'; }; yy.UniOp.prototype.toJavaScript = function(context, tableid, defcols) { if(this.op == '-') return "(-("+this.right.toJavaScript(context, tableid, defcols)+"))"; if(this.op == '+') return "("+this.right.toJavaScript(context, tableid, defcols)+")"; if(this.op == 'NOT') return '!('+this.right.toJavaScript(context, tableid, defcols)+')'; if(this.op == '#') { if(this.right instanceof yy.Column) { return "(alasql.databases[alasql.useid].objects[\'"+this.right.columnid+"\'])"; } else { return "(alasql.databases[alasql.useid].objects[" +this.right.toJavaScript(context, tableid, defcols)+"])"; }; } else if(this.op == null) return '('+this.right.toJavaScript(context, tableid, defcols)+')'; }; // yy.Star = function (params) { return yy.extend(this, params); } // yy.Star.prototype.toString = function() { // var s = this.fieldid; // if(this.tableid) { // s = this.tableid+'.'+s; // if(this.databaseid) { // s = this.databaseid+'.'+s; // } // } // if(this.alias) s += ' AS '+this.alias; // return s; // } yy.Column = function(params) { return yy.extend(this, params); } yy.Column.prototype.toString = function() { var s; if(this.columnid == +this.columnid) { s = '['+this.columnid+']'; } else { s = this.columnid; } if(this.tableid) { if(+this.columnid == this.columnid) { s = this.tableid+s; } else { s = this.tableid+'.'+s; } if(this.databaseid) { s = this.databaseid+'.'+s; } } // if(this.alias) s += ' AS '+this.alias; return s; }; yy.Column.prototype.toJavaScript = function(context, tableid, defcols) { // var s = this.value; // var s = this.columnid; // if(this.tableid) { // s = this.tableid+'.'+s; // // if(this.databaseid) { // // s = this.databaseid+'.'+s; // // } // } else { // s = tableid+'.'+s; // } //console.log('yy.Column',this, tableid); // console.log(392,this.columnid); //console.log(506,this); var s = ''; if(!this.tableid && tableid == '' && !defcols) { if(this.columnid != '_') { s = context+'[\''+this.columnid+'\']'; } else { if(context == 'g') { s = 'g[\'_\']'; } else { s = context; } } } else { if(context == 'g') { // if(this.columnid == '_') { // } else { s = 'g[\''+this.nick+'\']'; // } } else if(this.tableid) { if(this.columnid != '_') { s = context+'[\''+(this.tableid) + '\'][\''+this.columnid+'\']'; } else { if(context == 'g') { s = 'g[\'_\']'; } else { s = context+'[\''+(this.tableid) + '\']'; } } } else if(defcols) { var tbid = defcols[this.columnid]; if(tbid == '-') { throw new Error('Cannot resolve column "'+this.columnid+'" because it exists in two source tables'); } else if(tbid) { if(this.columnid != '_') { s = context+'[\''+(tbid) + '\'][\''+this.columnid+'\']'; } else { s = context+'[\''+(tbid) + '\']'; }; } else { if(this.columnid != '_') { s = context+'[\''+(this.tableid || tableid) + '\'][\''+this.columnid+'\']'; } else { s = context+'[\''+(this.tableid || tableid) + '\']'; }; } } else if(tableid == -1) { // if(this.columnid != '') { s = context+'[\''+this.columnid+'\']'; // } else { // s = context; // } } else { if(this.columnid != '_') { s = context+'[\''+(this.tableid || tableid) + '\'][\''+this.columnid+'\']'; } else { s = context+'[\''+(this.tableid || tableid) + '\']'; } } } // console.log(context,s); // console.trace(new Error()); return s; } yy.AggrValue = function(params){ return yy.extend(this, params); } yy.AggrValue.prototype.toString = function() { var s = ''; if(this.aggregatorid == 'REDUCE') s += L(this.funcid)+'('; else s += this.aggregatorid+'('; if(this.distinct) s+= K('DISTINCT')+' '; if(this.expression) s += this.expression.toString(); s += ')'; if(this.over) s += ' '+this.over.toString(); // console.log(this.over); // if(this.alias) s += ' AS '+this.alias; return s; }; yy.AggrValue.prototype.findAggregator = function (query){ // console.log('aggregator found',this.toString()); // var colas = this.as || this.toString(); var colas = escapeq(this.toString())+':'+query.selectGroup.length; // console.log('findAgg',this); /* var found = false; for(var i=0;i<query.columns.length;i++) { // THis part should be intellectual if(query.columns[i].as == colas) { found = true; break; } } */ // if(!query.selectColumns[colas]) { // } var found = false; /* for(var i=0;i<query.selectGroup.length;i++){ if(query.selectGroup[i].nick==colas) { colas = colas+':'+i; found = false; break; }; }; */ // console.log("query.selectGroup",query.selectGroup,found); if(!found) { if(!this.nick) { this.nick = colas; var found = false; for(var i=0;i<query.removeKeys.length;i++){ if(query.removeKeys[i]==colas) { found = true; break; } }; if(!found) query.removeKeys.push(colas); }; query.selectGroup.push(this); }; // console.log(query.selectGroup); //// this.reduced = true; return; }; yy.AggrValue.prototype.toType = function() { if(['SUM','COUNT','AVG','MIN', 'MAX','AGGR','VAR','STDDEV'].indexOf(this.aggregatorid)>-1) return 'number'; if(['ARRAY'].indexOf(this.aggregatorid)>-1) return 'array'; if(['FIRST','LAST' ].indexOf(this.aggregatorid)>-1) return this.expression.toType(); } yy.AggrValue.prototype.toJavaScript = function(context, tableid, defcols) { // var s = 'alasql.functions.'+this.funcid+'('; // if(this.expression) s += this.expression.toJavaScript(context, tableid); // s += ')'; // if(this.alias) s += ' AS '+this.alias; // return s; // var s = ''; //if(this.as) console.log(499,this.as); // var colas = this.as; var colas = this.nick; if(typeof colas == 'undefined') colas = this.toString(); return 'g[\''+colas+'\']'; } yy.OrderExpression = function(params){ return yy.extend(this, params); } yy.OrderExpression.prototype.toString = function() { var s = this.expression.toString(); if(this.order) s += ' '+this.order.toString(); if(this.nocase) s += ' '+K('COLLATE')+' '+K('NOCASE'); return s; } yy.GroupExpression = function(params){ return yy.extend(this, params); } yy.GroupExpression.prototype.toString = function() { return this.type+'('+this.group.toString()+')'; } yy.ColumnDef = function (params) { return yy.extend(this, params); } yy.ColumnDef.prototype.toString = function() { var s = this.columnid; if(this.dbtypeid) s += ' '+this.dbtypeid; if(this.dbsize) { s += '('+this.dbsize; if(this.dbprecision) s += ','+this.dbprecision; s += ')'; }; if(this.primarykey) s += ' PRIMARY KEY'; if(this.notnull) s += ' NOT NULL'; return s; }