UNPKG

alasql

Version:

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

409 lines (350 loc) 11.5 kB
/* // // Select run-time part for Alasql.js // Date: 03.11.2014 // (c) 2014, Andrey Gershun // */ // // Main part of SELECT procedure // yy.Select = function (params) { return yy.extend(this, params); } yy.Select.prototype.toString = function() { var s = ''; if(this.explain) s+= K('EXPLAIN')+' '; s += K('SELECT')+' '; if(this.modifier) s += K(this.modifier)+' '; if(this.top) { s += K('TOP')+' '+N(this.top.value)+' '; if(this.percent) s += K('PERCENT')+' '; } s += this.columns.map(function(col){ var s = col.toString(); // console.log(col); if(typeof col.as != "undefined") s += ' '+K('AS')+' '+L(col.as); return s; }).join(', '); if(this.from) { s += NL()+ID()+K('FROM')+' '+this.from.map(function(f){ // console.log(f); var ss = f.toString(); if(f.as) ss += ' '+K('AS')+' '+f.as; return ss; }).join(','); }; if(this.joins) { s += this.joins.map(function(jn){ var ss = NL()+ID(); if(jn.joinmode) ss += K(jn.joinmode)+' '; if(jn.table) ss += K('JOIN')+' '+jn.table.toString(); else if(jn instanceof yy.Apply) ss += jn.toString(); else { throw new Error('Wrong type in JOIN mode'); } if(jn.using) ss += ' '+K('USING')+' '+jn.using.toString(); if(jn.on) ss += ' '+K('ON')+' '+jn.on.toString(); return ss; }); } if(this.where) s += NL()+ID()+K('WHERE')+' '+this.where.toString(); if(this.group && this.group.length>0) { s += NL()+ID()+K('GROUP BY')+' '+this.group.map(function(grp){ return grp.toString(); }).join(', '); }; if(this.having) s += NL()+ID()+K('HAVING')+' '+this.having.toString(); if(this.order && this.order.length>0) { s += NL()+ID()+K('ORDER BY')+' '+this.order.map(function(ord){ return ord.toString(); }).join(', '); }; if(this.limit) s += NL()+ID()+K('LIMIT')+' '+this.limit.value; if(this.offset) s += NL()+ID()+K('OFFSET')+' '+this.offset.value; if(this.union) s += NL()+K('UNION')+(this.corresponding?(' '+K('CORRESPONDING')):'')+NL()+this.union.toString(); if(this.unionall) s += NL()+K('UNION ALL')+(this.corresponding?(' '+K('CORRESPONDING')):'')+NL()+this.unionall.toString(); if(this.except) s += NL()+K('EXCEPT')+(this.corresponding?(' '+K('CORRESPONDING')):'')+NL()+this.except.toString(); if(this.intersect) s += NL()+K('INTERSECT')+(this.corresponding?(' '+K('CORRESPONDING')):'')+NL()+this.intersect.toString(); return s; }; /** Select statement in expression */ yy.Select.prototype.toJavaScript = function(context, tableid, defcols) { // console.log('Expression',this); // if(this.expression.reduced) return 'true'; // return this.expression.toJavaScript(context, tableid, defcols); // console.log('Select.toJS', 81, this.queriesidx); // var s = 'this.queriesdata['+(this.queriesidx-1)+'][0]'; var s = 'alasql.utils.flatArray(this.queriesfn['+(this.queriesidx-1)+'](this.params,null,'+context+'))[0]'; // s = '(console.log(this.queriesfn[0]),'+s+')'; return s; }; // Compile SELECT statement yy.Select.prototype.compile = function(databaseid) { var db = alasql.databases[databaseid]; // Create variable for query var query = new Query(); // Array with columns to be removed query.removeKeys = []; query.explain = this.explain; // Explain query.explaination = []; query.explid = 1; query.modifier = this.modifier; query.database = db; // 0. Precompile whereexists this.compileWhereExists(query); // 0. Precompile queries for IN, NOT IN, ANY and ALL operators this.compileQueries(query); query.defcols = this.compileDefCols(query, databaseid); // 1. Compile FROM clause query.fromfn = this.compileFrom(query); // 2. Compile JOIN clauses if(this.joins) this.compileJoins(query); // 3. Compile SELECT clause this.compileSelectGroup0(query); if(this.group || query.selectGroup.length>0) { query.selectgfns = this.compileSelectGroup1(query); } else { query.selectfns = this.compileSelect1(query); } // Remove columns clause this.compileRemoveColumns(query); // 5. Optimize WHERE and JOINS if(this.where) this.compileWhereJoins(query); // 4. Compile WHERE clause query.wherefn = this.compileWhere(query); // 6. Compile GROUP BY if(this.group || query.selectGroup.length>0) query.groupfn = this.compileGroup(query); // 6. Compile HAVING if(this.having) query.havingfn = this.compileHaving(query); if(this.group || query.selectGroup.length>0) { query.selectgfn = this.compileSelectGroup2(query); } else { query.selectfn = this.compileSelect2(query); } // 7. Compile DISTINCT, LIMIT and OFFSET query.distinct = this.distinct; // 8. Compile ORDER BY clause if(this.order) query.orderfn = this.compileOrder(query); // TOP if(this.top) { query.limit = this.top.value; } else if(this.limit) { query.limit = this.limit.value; if(this.offset) { query.offset = this.offset.value; } }; query.percent = this.percent; // 9. Compile ordering function for UNION and UNIONALL query.corresponding = this.corresponding; // If CORRESPONDING flag exists if(this.union) { query.unionfn = this.union.compile(databaseid); if(this.union.order) { query.orderfn = this.union.compileOrder(query); } else { query.orderfn = null; } } else if(this.unionall) { query.unionallfn = this.unionall.compile(databaseid); if(this.unionall.order) { query.orderfn = this.unionall.compileOrder(query); } else { query.orderfn = null; } } else if(this.except) { query.exceptfn = this.except.compile(databaseid); if(this.except.order) { query.orderfn = this.except.compileOrder(query); } else { query.orderfn = null; } } else if(this.intersect) { query.intersectfn = this.intersect.compile(databaseid); if(this.intersect.order) { query.intersectfn = this.intersect.compileOrder(query); } else { query.orderfn = null; } }; // SELECT INTO if(this.into) { if(this.into instanceof yy.Table) { // // Save into the table in database // if(alasql.options.autocommit && alasql.databases[this.into.databaseid||databaseid].engineid) { // For external database when AUTOCOMMIT is ONs query.intoallfns = 'return alasql.engines["'+alasql.databases[this.into.databaseid||databaseid].engineid+'"]'+ '.intoTable("'+(this.into.databaseid||databaseid)+'","'+this.into.tableid+'",this.data, columns, cb);'; } else { // Into AlaSQL tables query.intofns = 'alasql.databases[\''+(this.into.databaseid||databaseid)+'\'].tables'+ '[\''+this.into.tableid+'\'].data.push(r);'; } } else if(this.into instanceof yy.VarValue) { // // Save into local variable // SELECT * INTO @VAR1 FROM ? // query.intoallfns = 'alasql.vars["'+this.into.variable+'"]=this.data;res=this.data.length;if(cb)res=cb(res);return res;'; } else if (this.into instanceof yy.FuncValue) { // // If this is INTO() function, then call it // with one or two parameters // var qs = 'return alasql.into[\''+this.into.funcid.toUpperCase()+'\']('; if(this.into.args && this.into.args.length>0 ) { qs += this.into.args[0].toJavaScript()+','; if(this.into.args.length > 1) { qs += this.into.args[1].toJavaScript()+','; } else { qs += 'undefined,'; } } else { qs += 'undefined, undefined,' } query.intoallfns = qs+'this.data,columns,cb)'; //console.log('999'); } else if (this.into instanceof yy.ParamValue) { // // Save data into parameters array // like alasql('SELECT * INTO ? FROM ?',[outdata,srcdata]); // query.intofns = "params['"+this.into.param+"'].push(r)"; }; if(query.intofns) { // Create intofn function query.intofn = new Function("r,i,params,alasql",query.intofns); } else if(query.intoallfns) { // Create intoallfn function query.intoallfn = new Function("columns,cb,params,alasql",query.intoallfns); } } //console.log(query); // Now, compile all togeather into one function with query object in scope var statement = function(params, cb, oldscope) { query.params = params; var res1 = queryfn(query,oldscope,function(res){ //console.log(res[0].schoolid); //console.log(184,res); var res2 = modify(query, res); if(cb) cb(res2); //console.log(8888,res2); return res2; }); //console.log(9999,res1); // if(typeof res1 != 'undefined') res1 = modify(query,res1); return res1; }; // statement.dbversion = ; // console.log(statement.query); //console.log(202,statement); statement.query = query; return statement; }; function modify(query, res) { var modifier = query.modifier || alasql.options.modifier; var columns = query.columns; if(typeof columns == 'undefined' || columns.length == 0) { // Try to create columns if(res.length > 0) { var allcol = {}; for(var i=0;i<Math.min(res.length,alasql.options.columnlookup||10);i++) { for(var key in res[i]) { allcol[key] = true; } } columns = Object.keys(allcol).map(function(columnid){ return {columnid:columnid}; }); } else { // Cannot recognize columns columns = []; } } // console.log(columns); if(modifier == 'VALUE') { // console.log(222,res); if(res.length > 0) { var key; if(columns && columns.length > 0) key = columns[0].columnid; else key = Object.keys(res[0])[0]; res = res[0][key]; } else { res = undefined; } } if(modifier == 'ROW') { if(res.length > 0) { var key; var a = []; for(var key in res[0]) { a.push(res[0][key]); }; res = a; } else { res = undefined; } } if(modifier == 'COLUMN') { var ar = []; if(res.length > 0) { var key; if(columns && columns.length > 0) key = columns[0].columnid; else key = Object.keys(res[0])[0]; for(var i=0, ilen=res.length; i<ilen; i++){ ar.push(res[i][key]); } }; res = ar; } if(modifier == 'MATRIX') { // Returns square matrix of rows var ar = []; for(var i=0;i<res.length;i++) { var a = []; var r = res[i]; for(var j=0;j<columns.length;j++) { a.push(r[columns[j].columnid]); } ar.push(a); } res = ar; } if(modifier == 'INDEX') { var ar = {}; var key,val; if(columns && columns.length > 0) { key = columns[0].columnid; val = columns[1].columnid; } else { var okeys = Object.keys(res[0]); key = okeys[0]; val = okeys[1]; } for(var i=0, ilen=res.length; i<ilen; i++){ ar[res[i][key]] = res[i][val]; } res = ar; // res = arrayOfArrays(res); } if(modifier == 'RECORDSET') { res = new alasql.Recordset({data:res, columns:columns}); // res = arrayOfArrays(res); } if(modifier == 'TEXTSTRING') { var key; if(columns && columns.length > 0) key = columns[0].columnid; else key = Object.keys(res[0])[0]; var s = ''; for(var i=0, ilen=res.length; i<ilen; i++){ res[i] = res[i][key]; } res = res.join('\n'); // res = arrayOfArrays(res); } return res; }; // yy.Select.prototype.exec = function(databaseid) { // throw new Error('Select statement should be precompiled'); // }; yy.Select.prototype.execute = function (databaseid, params, cb) { return this.compile(databaseid)(params,cb); // throw new Error('Insert statement is should be compiled') }