UNPKG

alasql

Version:

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

410 lines (353 loc) 13.4 kB
/* // // Select compiler part for Alasql.js // Date: 03.11.2014 // (c) 2014, Andrey Gershun // */ // SELECT Compile functions // Compile JOIN caluese yy.Select.prototype.compileJoins = function(query) { // console.log(this); // debugger; var self = this; this.joins.forEach(function(jn){ // Test CROSS-JOIN if(jn.joinmode == "CROSS") { if(jn.using || jn.on) { throw new Error('CROSS JOIN cannot have USING or ON clauses'); } else { jn.joinmode == "INNER"; } } var source; var tq; if(jn instanceof yy.Apply) { // console.log('APPLY',jn.applymode); source = { alias: jn.as, applymode: jn.applymode, onmiddlefn: returnTrue, srcwherefns: '', // for optimization srcwherefn: returnTrue, columns: [] // TODO check this }; source.applyselect = jn.select.compile(query.database.databaseid); source.columns = source.applyselect.query.columns; source.datafn = function(query,params,cb,idx, alasql) { var res; if(cb) res = cb(res,idx,query); return res; } query.sources.push(source); } else { if(jn.table) { tq = jn.table; source = { alias: jn.as||tq.tableid, databaseid: tq.databaseid || query.database.databaseid, tableid: tq.tableid, joinmode: jn.joinmode, onmiddlefn: returnTrue, srcwherefns: '', // for optimization srcwherefn: returnTrue, columns: [] }; // // console.log(source.databaseid, source.tableid); if(!alasql.databases[source.databaseid].tables[source.tableid]) { throw new Error('Table \''+source.tableid+ '\' is not exists in database \''+source.databaseid)+'\''; }; source.columns = alasql.databases[source.databaseid].tables[source.tableid].columns; // source.data = query.database.tables[source.tableid].data; if(alasql.options.autocommit && alasql.databases[source.databaseid].engineid) { // console.log(997,alasql.databases[source.databaseid].engineid); source.datafn = function(query,params, cb, idx, alasql) { // console.log(777,arguments); return alasql.engines[alasql.databases[source.databaseid].engineid].fromTable( source.databaseid, source.tableid, cb, idx,query); } } else if(alasql.databases[source.databaseid].tables[source.tableid].view){ source.datafn = function(query,params,cb,idx, alasql) { var res = alasql.databases[source.databaseid].tables[source.tableid].select(params); if(cb) res = cb(res,idx,query); return res; } } else { source.datafn = function(query,params,cb, idx, alasql) { var res = alasql.databases[source.databaseid].tables[source.tableid].data; if(cb) res = cb(res,idx,query); return res; } }; // var alias = jn.as || tq.tableid; // if(tq) { query.aliases[source.alias] = {tableid: tq.tableid, databaseid: tq.databaseid || query.database.databaseid}; // } } else if(jn.select) { var tq = jn.select; source = { alias: jn.as, // databaseid: jn.databaseid || query.database.databaseid, // tableid: tq.tableid, joinmode: jn.joinmode, onmiddlefn: returnTrue, srcwherefns: '', // for optimization srcwherefn: returnTrue, columns: [] }; source.subquery = tq.compile(query.database.databaseid); if(typeof source.subquery.query.modifier == 'undefined') { source.subquery.query.modifier = 'RECORDSET'; // Subqueries always return recordsets } source.columns = source.subquery.query.columns; // if(jn instanceof yy.Apply) { source.datafn = function(query, params, cb, idx, alasql) { // return cb(null,idx,alasql); return source.subquery(query.params, null, cb, idx).data; } // } else { // source.datafn = function(query, params, cb, idx, alasql) { // return source.subquery(query.params, null, cb, idx); // } // } query.aliases[source.alias] = {type:'subquery'}; } else if(jn.param) { source = { alias: jn.as, // databaseid: jn.databaseid || query.database.databaseid, // tableid: tq.tableid, joinmode: jn.joinmode, onmiddlefn: returnTrue, srcwherefns: '', // for optimization srcwherefn: returnTrue }; // source.data = ; var jnparam = jn.param.param; // console.log(jn, jnparam); var ps = "var res=alasql.prepareFromData(params['"+jnparam+"']"; if(jn.array) ps += ",true"; ps += ");if(cb)res=cb(res, idx, query);return res"; source.datafn = new Function('query,params,cb,idx, alasql',ps); query.aliases[source.alias] = {type:'paramvalue'}; } else if(jn.variable) { source = { alias: jn.as, // databaseid: jn.databaseid || query.database.databaseid, // tableid: tq.tableid, joinmode: jn.joinmode, onmiddlefn: returnTrue, srcwherefns: '', // for optimization srcwherefn: returnTrue }; // source.data = ; // var jnparam = jn.param.param; // console.log(jn, jnparam); var ps = "var res=alasql.prepareFromData(alasql.vars['"+jn.variable+"']"; if(jn.array) ps += ",true"; ps += ");if(cb)res=cb(res, idx, query);return res"; source.datafn = new Function('query,params,cb,idx, alasql',ps); query.aliases[source.alias] = {type:'varvalue'}; } else if(jn.funcid) { source = { alias: jn.as, // databaseid: jn.databaseid || query.database.databaseid, // tableid: tq.tableid, joinmode: jn.joinmode, onmiddlefn: returnTrue, srcwherefns: '', // for optimization srcwherefn: returnTrue }; // source.data = ; /* var jnparam = jn.param.param; source.datafn = new Function('query,params,cb,idx', "var res=alasql.prepareFromData(params['"+jnparam+"']);if(cb)res=cb(res, idx, query);return res"); */ var s = "var res=alasql.from['"+js.funcid.toUpperCase()+"']("; // if(tq.args && tq.args.length>0) { // s += tq.args.map(function(arg){ // return arg.toJavaScript(); // }).concat('cb,idx,query').join(','); // } // if(tq.args && tq.args.length>0) { // s += tq.args.map(function(arg){ // return arg.toJavaScript(); // }).concat().join(','); // } if(jn.args && jn.args.length>0) { if(jn.args[0]) { s += jn.args[0].toJavaScript('query.oldscope')+','; } else { s += 'null,'; }; if(jn.args[1]) { s += jn.args[1].toJavaScript('query.oldscope')+','; } else { s += 'null,'; }; } else { s += 'null,null,' } s += 'cb,idx,query'; s += ');/*if(cb)res=cb(res,idx,query);*/return res'; // console.log(s); source.datafn = new Function('query, params, cb, idx, alasql',s); query.aliases[source.alias] = {type:'funcvalue'}; } /* } else if(tq instanceof yy.Select) { query.aliases[alias] = {type:'subquery'}; } else if(tq instanceof yy.ParamValue) { query.aliases[alias] = {type:'paramvalue'}; } else if(tq instanceof yy.FuncValue) { query.aliases[alias] = {type:'paramvalue'}; } else { throw new Error('Wrong table at FROM'); } */ var alias = source.alias; // Test NATURAL-JOIN if(jn.natural) { if(jn.using || jn.on) { throw new Error('NATURAL JOIN cannot have USING or ON clauses'); } else { // source.joinmode == "INNER"; if(query.sources.length > 0) { var prevSource = query.sources[query.sources.length-1]; var prevTable = alasql.databases[prevSource.databaseid].tables[prevSource.tableid]; var table = alasql.databases[source.databaseid].tables[source.tableid]; if(prevTable && table) { var c1 = prevTable.columns.map(function(col){return col.columnid}); var c2 = table.columns.map(function(col){return col.columnid}); jn.using = arrayIntersect(c1,c2).map(function(colid){return {columnid:colid}}); // console.log(jn.using); } else { throw new Error('In this version of Alasql NATURAL JOIN '+ 'works for tables with predefined columns only'); }; } } } if(jn.using) { var prevSource = query.sources[query.sources.length-1]; // console.log(query.sources[0],prevSource,source); source.onleftfns = jn.using.map(function(col){ // console.log(141,colid); return "p['"+(prevSource.alias||prevSource.tableid)+"']['"+col.columnid+"']"; }).join('+"`"+'); source.onleftfn = new Function('p,params,alasql','return '+source.onleftfns); source.onrightfns = jn.using.map(function(col){ return "p['"+(source.alias||source.tableid)+"']['"+col.columnid+"']"; }).join('+"`"+'); source.onrightfn = new Function('p,params,alasql','return '+source.onrightfns); source.optimization = 'ix'; // console.log(151,source.onleftfns, source.onrightfns); // console.log(source); } else if(jn.on) { //console.log(jn.on); if(jn.on instanceof yy.Op && jn.on.op == '=' && !jn.on.allsome) { // console.log('ix optimization', jn.on.toJavaScript('p',query.defaultTableid) ); source.optimization = 'ix'; // source.onleftfns = jn.on.left.toJavaScript('p',query.defaultTableid); // source.onleftfn = new Function('p', 'return '+source.onleftfns); // source.onrightfns = jn.on.right.toJavaScript('p',query.defaultTableid); // source.onrightfn = new Function('p', 'return '+source.onrightfns); var lefts = ''; var rights = ''; var middles = ''; var middlef = false; // Test right and left sides var ls = jn.on.left.toJavaScript('p',query.defaultTableid,query.defcols); var rs = jn.on.right.toJavaScript('p',query.defaultTableid,query.defcols); if((ls.indexOf("p['"+alias+"']")>-1) && !(rs.indexOf("p['"+alias+"']")>-1)){ if((ls.match(/p\[\'.*?\'\]/g)||[]).every(function(s){ return s == "p['"+alias+"']"})) { rights = ls; } else { middlef = true }; } else if(!(ls.indexOf("p['"+alias+"']")>-1) && (rs.indexOf("p['"+alias+"']")>-1)){ if((rs.match(/p\[\'.*?\'\]/g)||[]).every(function(s){ return s == "p['"+alias+"']"})) { lefts = ls; } else { middlef = true }; } else { middlef = true; } // console.log(alias, 1,lefts, rights, middlef); if((rs.indexOf("p['"+alias+"']")>-1) && !(ls.indexOf("p['"+alias+"']")>-1)){ if((rs.match(/p\[\'.*?\'\]/g)||[]).every(function(s){ return s == "p['"+alias+"']"})) { rights = rs; } else { middlef = true }; } else if(!(rs.indexOf("p['"+alias+"']")>-1) && (ls.indexOf("p['"+alias+"']")>-1)){ if((ls.match(/p\[\'.*?\'\]/g)||[]).every(function(s){ return s == "p['"+alias+"']"})) { lefts = rs; } else { middlef = true }; } else { middlef = true; } // console.log(alias, 2,lefts, rights, middlef); if(middlef) { // middles = jn.on.toJavaScript('p',query.defaultTableid); // } else { rights = ''; lefts = ''; middles = jn.on.toJavaScript('p',query.defaultTableid,query.defcols); source.optimization = 'no'; // What to here? } source.onleftfns = lefts; source.onrightfns = rights; source.onmiddlefns = middles || 'true'; // console.log(source.onleftfns, '-',source.onrightfns, '-',source.onmiddlefns); source.onleftfn = new Function('p,params,alasql', 'return '+source.onleftfns); source.onrightfn = new Function('p,params,alasql', 'return '+source.onrightfns); source.onmiddlefn = new Function('p,params,alasql', 'return '+source.onmiddlefns); // } else if(jn.on instanceof yy.Op && jn.on.op == 'AND') { // console.log('join on and ',jn); } else { // console.log('no optimization'); source.optimization = 'no'; // source.onleftfn = returnTrue; // source.onleftfns = "true"; source.onmiddlefns = jn.on.toJavaScript('p',query.defaultTableid,query.defcols); source.onmiddlefn = new Function('p,params,alasql','return '+jn.on.toJavaScript('p',query.defaultTableid,query.defcols)); }; // console.log(source.onleftfns, source.onrightfns, source.onmiddlefns); // Optimization function }; // source.data = alasql.databases[source.databaseid].tables[source.tableid].data; //console.log(source, jn); // TODO SubQueries /* if(source.joinmode == 'RIGHT') { var prevSource = query.sources.pop(); if(prevSource.joinmode == 'INNER') { prevSource.joinmode = 'LEFT'; var onleftfn = prevSource.onleftfn; var onleftfns = prevSource.onleftfns; var onrightfn = prevSource.onrightfn; var onrightfns = prevSource.onrightfns; var optimization = prevSource.optimization; prevSource.onleftfn = source.onrightfn; prevSource.onleftfns = source.onrightfns; prevSource.onrightfn = source.onleftfn; prevSource.onrightfns = source.onleftfns; prevSource.optimization = source.optimization; source.onleftfn = onleftfn; source.onleftfns = onleftfns; source.onrightfn = onrightfn; source.onrightfns = onrightfns; source.optimization = optimization; source.joinmode = 'INNER'; query.sources.push(source); query.sources.push(prevSource); } else { throw new Error('Do not know how to process this SQL'); } } else { query.sources.push(source); } */ query.sources.push(source); }; }); // console.log('sources',query.sources); }