UNPKG

alasql

Version:

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

421 lines (373 loc) 10.4 kB
/* // // Database class for Alasql.js // Date: 03.11.2014 // (c) 2014, Andrey Gershun // */ // Initial parameters /** Jison parser */ alasql.parser = parser; /** Jison parser @param {string} sql SQL statement @return {object} AST (Abstract Syntax Tree) */ alasql.parse = function(sql) { return parser.parse(alasql.utils.uncomment(sql)); }; // Shortcut // Database Engines /** List of engines of external databases */ alasql.engines = {}; // Databases /** List of databases */ alasql.databases = {}; /** Number of databases */ alasql.databasenum = 0; // Current database // Deafult options /** Alasql options object */ alasql.options = {}; alasql.options.errorlog = false; // Log or throw error alasql.options.valueof = false; // Use valueof in orderfn alasql.options.dropifnotexists = false; // DROP database in any case alasql.options.datetimeformat = 'sql'; // How to handle DATE and DATETIME types // Another value is 'javascript' alasql.options.casesensitive = true; // Table and column names are case sensitive and converted to lower-case alasql.options.logtarget = 'output'; // target for log. Values: 'console', 'output', 'id' of html tag alasql.options.logprompt = true; // Print SQL at log // Default modifier // values: RECORDSET, VALUE, ROW, COLUMN, MATRIX, TEXTSTRING, INDEX alasql.options.modifier = undefined; // How many rows to lookup to define columns alasql.options.columnlookup = 10; // Create vertex if not found alasql.options.autovertex = true; // Use dbo as current database (for partial T-SQL comaptibility) alasql.options.usedbo = true; // AUTOCOMMIT ON | OFF alasql.options.autocommit = true; // Use cache alasql.options.cache = true; // Compatibility flags alasql.options.tsql = true; alasql.options.mysql = true; alasql.options.postgres = true; alasql.options.oracle = true; alasql.options.sqlite = true; alasql.options.orientdb = true; //alasql.options.worker = false; // Variables alasql.vars = {}; alasql.declares = {}; alasql.prompthistory = []; alasql.from = {}; // FROM functions alasql.into = {}; // INTO functions alasql.fn = {}; alasql.aggr = {}; alasql.busy = 0; // Cache alasql.MAXSQLCACHESIZE = 10000; alasql.DEFAULTDATABASEID = 'alasql'; /* WebWorker */ alasql.lastid = 0; alasql.buffer = {}; /** Select current database @param {string} databaseid Selected database identificator */ alasql.use = function (databaseid) { if(!databaseid) databaseid = alasql.DEFAULTDATABASEID; if(alasql.useid == databaseid) return; alasql.useid = databaseid; var db = alasql.databases[alasql.useid]; alasql.tables = db.tables; // alasql.fn = db.fn; db.resetSqlCache(); if(alasql.options.usedbo) { alasql.databases.dbo = db; // Operator??? } }; // Run one statement /** Run SQL statement on current database */ alasql.exec = function (sql, params, cb, scope) { delete alasql.error; if(alasql.options.errorlog){ try { return alasql.dexec(alasql.useid, sql, params, cb, scope); } catch(err){ alasql.error = err; if(cb) cb(null,alasql.error); } } else { return alasql.dexec(alasql.useid, sql, params, cb, scope); } } /** Run SQL statement on specific database */ alasql.dexec = function (databaseid, sql, params, cb, scope) { var db = alasql.databases[databaseid]; // if(db.databaseid != databaseid) console.trace('got!'); // console.log(3,db.databaseid,databaseid); // Create hash if(alasql.options.cache) { var hh = hash(sql); var statement = db.sqlCache[hh]; // If database structure was not changed sinse lat time return cache if(statement && db.dbversion == statement.dbversion) { return statement(params, cb); } } // Create AST var ast = alasql.parse(sql); if(!ast.statements) return; if(ast.statements.length == 0) return 0; else if(ast.statements.length == 1) { if(ast.statements[0].compile) { // Compile and Execute var statement = ast.statements[0].compile(databaseid); if(!statement) return; statement.sql = sql; statement.dbversion = db.dbversion; if(alasql.options.cache) { // Secure sqlCache size if (db.sqlCacheSize > alasql.MAXSQLCACHESIZE) { db.resetSqlCache(); } db.sqlCacheSize++; db.sqlCache[hh] = statement; } var res = alasql.res = statement(params, cb, scope); return res; } else { // console.log(ast.statements[0]); alasql.precompile(ast.statements[0],alasql.useid,params); var res = alasql.res = ast.statements[0].execute(databaseid, params, cb, scope); return res; } } else { // Multiple statements if(cb) { alasql.adrun(databaseid, ast, params, cb, scope); } else { return alasql.drun(databaseid, ast, params, cb, scope); } } }; /** Run multiple statements and return array of results sync */ alasql.drun = function (databaseid, ast, params, cb, scope) { var useid = alasql.useid; if(useid != databaseid) alasql.use(databaseid); var res = []; for (var i=0, ilen=ast.statements.length; i<ilen; i++) { if(ast.statements[i]) { if(ast.statements[i].compile) { var statement = ast.statements[i].compile(alasql.useid); res.push(alasql.res = statement(params,null,scope)); } else { alasql.precompile(ast.statements[i],alasql.useid,params); res.push(alasql.res = ast.statements[i].execute(alasql.useid, params)); } } }; if(useid != databaseid) alasql.use(useid); if(cb) cb(res); alasql.res = res; return res; }; /** Run multiple statements and return array of results async */ alasql.adrun = function (databaseid, ast, params, cb, scope) { // alasql.busy++; var useid = alasql.useid; if(useid != databaseid) alasql.use(databaseid); var res = []; adrunone(); function adrunone(data) { if(typeof data != 'undefined') res.push(data); var astatement = ast.statements.shift(); if(!astatement) { if(useid != databaseid) alasql.use(useid); cb(res); // alasql.busy--; // if(alasql.busy<0) alasql.busy = 0; } else { if(astatement.compile) { var statement = astatement.compile(alasql.useid); statement(params, adrunone, scope); } else { alasql.precompile(ast.statements[0],alasql.useid,params); astatement.execute(alasql.useid, params, adrunone); } } } }; /** Compile statement to JavaScript function @param {string} sql SQL statement @param {string} databaseid Database identificator @return {functions} Compiled statement functions */ alasql.compile = function(sql, databaseid) { if(!databaseid) databaseid = alasql.useid; var ast = alasql.parse(sql); // Create AST if(ast.statements.length == 1) { return ast.statements[0].compile(databaseid); /* if(kind == 'value') { return function(params,cb) { var res = statementfn(params); var key = Object.keys(res[0])[0]; if(cb) cb(res[0][key]); return res[0][key]; }; } else if(kind == 'single') { return function(params,cb) { var res = statementfn(params); if(cb) cb(res[0]); return res[0]; } } else if(kind == 'row') { return function(params,cb) { var res = statementfn(params,cb); var a = []; for(var key in res[0]) { a.push(res[0][key]); }; if(cb) cb(a); return a; } } else if(kind == 'column') { return function(params,cb) { var res = statementfn(params,cb); var ar = []; var key = Object.keys(res)[0]; for(var i=0, ilen=res.length; i<ilen; i++){ ar.push(res[i][key]); } if(cb) cb(ar); return ar; } } else if(kind == 'array') { return function(params,cb) { var res = statementfn(params,cb); res = flatArray(res); if(cb) cb(res); return res; }; } else if(kind == 'matrix') { return function(params,cb) { var res = statementfn(params,cb); res = arrayOfArrays(res); if(cb) cb(res); return res; }; } else if(kind == 'collection') { return statementfn; } else { return statementfn; } */ } else { throw new Error('Cannot compile, because number of statments in SQL is not equal to 1'); } } // // Default methods to exec SQL statements // alasql.run = alasql.exec = function (sql, params, cb) { // return this.currentDatabase.exec(sql, params, cb); // }; // Promised version of exec // alasql.aexec = function (sql, params) { // var self = this; // return new Promise(function(resolve, reject){ // self.exec(sql,params,resolve); // }); // }; /* // MSSQL-Like aliases alasql.query = function (sql, params, cb) { var res = this.exec(sql, params); if(cb) cb(res); return res; }; alasql.queryArray = function (sql, params, cb) { var res = flatArray(this.exec(sql, params)); if(cb) cb(res); return res; }; alasql.querySingle = function (sql, params, cb) { var res = this.exec(sql, params)[0]; if(cb) cb(res); return res; }; alasql.queryRow = function (sql, params, cb) { var res = this.querySingle(sql, params); var a = []; for(var key in res) { a.push(res[key]); }; if(cb) cb(a); return a; }; alasql.queryValue = function (sql, params, cb) { var res = this.exec(sql, params)[0]; var val = res[Object.keys(res)[0]]; if(cb) cb(val); return val; // TODO Refactor to query.columns }; alasql.queryArrayOfArrays = function (sql, params, cb) { var res = this.exec(sql, params); var keys = Object.keys(res[0]); var klen = keys.length; var aa = []; for(var i=0, ilen=res.length;i<ilen;i++) { var r = res[i]; var a = []; for(var k=0; k<klen;k++){ a.push(r[keys[k]]); } aa.push(a); } if(cb) cb(aa); return aa; }; */ /*alasql.queryColumn = function (sql, params, cb) { var res = this.exec(sql, params); var keys = Object.keys(res[0]); var klen = keys.length; var aa = []; for(var i=0, ilen=res.length;i<ilen;i++) { var r = res[i]; var a = []; for(var k=0; k<klen;k++){ a.push(r[keys[k]]); } aa.push(a); } if(cb) cb(aa); return aa; }; */ /* alasql.value = alasql.queryValue; alasql.single = alasql.querySingle; alasql.row = alasql.queryRow; alasql.column = alasql.queryArray; alasql.array = alasql.queryArray; alasql.matrix = alasql.queryArrayOfArrays; */