diff --git a/js/db/dbQ.js b/js/db/dbQ.js new file mode 100644 index 0000000..01d530e --- /dev/null +++ b/js/db/dbQ.js @@ -0,0 +1,357 @@ +/** + ** ============================== + ** O O O OOOO + ** O O O O O O + ** O O O O O O + ** OOOO OOOO O OOO OOOO + ** O O O O O O O + ** O O O O O O O + ** OOOO OOOO O O OOOO + ** ============================== + ** Dr. Stefan Bosse http://www.bsslab.de + ** + ** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED + ** BY THE AUTHOR(S). + ** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED, + ** MODIFIED, OR OTHERWISE USED IN A CONTEXT + ** OUTSIDE OF THE SOFTWARE SYSTEM. + ** + ** $AUTHORS: Stefan Bosse + ** $INITIAL: (C) 2006-2019 bLAB + ** $CREATED: 08/05/19 by sbosse. + ** $VERSION: 1.1.2 + ** + ** $INFO: + ** + ** Embedded SQL API for AIOS - requires sqlite3.js (Database wrapper) and + ** sqlite3C.js (emscripten compiled sqlite3.c) in CURRENT directory + ** + ** Synchronous IO + ** + ** + ** $ENDOFINFO + */ +var Io = Require('com/io'); +var Comp = Require('com/compat'); +var Fs = Require('fs'); +var current={}; +var Aios=none; +var NL='\n'; + +var sql = function (path) { + try { this.sqlite3 = require('./sqlite3') } catch (e) {}; + console.log('[SQL] Database: '+this.sqlite3); + if (this.sqlite3) this.db = this.sqlite3(path); + this.id='SQL'; + this.log=function (msg) { + ((Aios && Aios.print)||Io.log)('[SQL] '+path+': '+msg); + } + this.todo=[]; +} + +sql.prototype.close = function () { + if (this.db) return this.db.close(); + else return -1; +} + +/** Create a generic table + * + * typeof @header = {} is type and name interface provider for all rows; + * + */ +sql.prototype.createTable = function (tblname,header,callback) { + var repl, + intf='', sep='', self=this; + if (!this.db || !header) return -1; + Comp.obj.iter(header,function (attr,key) { + intf += (sep+key+' '+attr); sep=','; + }); + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + else return 1; + } + return this.seq([ + ['exec','drop table if exists '+tblname, done], + ['exec','create table '+tblname+' ('+intf+')', done], + ],callback); +} + +/** Drop table operation + * + */ +sql.prototype.drop = function (tblname,callback) { + var repl,self=this, + line, + sep=''; + if (!this.db) return false; + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + else return 1; + } + return this.seq([ + ['exec','drop table if exists '+tblname, done] + ], callback); +} + +/** Insert operation + * + */ +sql.prototype.insert = function (tblname,row,callback) { + var repl,self=this, + line='', + sep=''; + if (!this.db) return false; + Comp.array.iter(row,function (col,i) { + line += sep+(Comp.obj.isNumber(col)?int(col):"'"+col+"'"); sep=','; + }); + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + else return 1; + } + return this.seq([ + ['exec','insert into '+tblname+' values ('+line+')', done] + ], callback); +} + +/** Insert a row in a matrix table + * + */ +sql.prototype.insertMatrix = function (matname,row,callback) { + var repl,self=this, + line='', + sep=''; + if (!this.db) return false; + Comp.array.iter(row,function (col,i) { + line += sep+(Comp.obj.isNumber(col)?int(col):"'"+col+"'"); sep=','; + }); + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + else return 1; + } + return this.seq([ + ['exec','insert into '+matname+' values ('+line+')', done] + ], callback); +} + +sql.prototype.insertTable = sql.prototype.insert; + +sql.prototype.open = function () { + if (this.db) return this.db.open(); + else return -1; +} + +/** Read a matrix + * + */ +sql.prototype.readMatrix = function (matname,callback) { + var mat=[],self=this; + + if (!this.db) return false; + + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + if (repl.result) { + mat=repl.result.map(function (row) { + var cols=[]; + for(var p in row) cols.push(Number(row[p])); + return cols; + }) + } + return 1; + } + + this.seq([ + ['exec','select * from '+matname,done], + ], callback?function (res) { if (res) callback(mat); else callback(none);}:undefined); + if (callback) return; else return mat; +} + +sql.prototype.readTable = function (tblname,callback) { + var tbl=[],self=this; + + if (!this.db) return false; + + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + if (repl.result) { + tbl=repl.result.map(function (row) { + var cols=[]; + for(var p in row) cols.push(Number(row[p])); + return cols; + }) + } + return 1; + } + + this.seq([ + ['exec','select * from '+tblname, done], + ], callback?function (res) { if (res) callback(tbl); else callback(none);}:undefined); + if (callback) return; else return tbl; +} + +/** SELECT operation + * tbl: string + * vars?: string | string [] + * cond: string | undefined + * callback: function (result) + * + */ +sql.prototype.select = function (tblname,vars,cond,callback) { + var self=this,result; + if (!this.db) return false; + + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + if (repl.result) result=repl.result; + return 1; + } + if (vars==undefined) vars='*'; + return this.seq([ + ['exec',Comp.printf.sprintf('select %s from %s%s', + Comp.obj.isArray(vars)?Comp.printf.list(vars):vars, + tblname, + cond?(' WHERE '+cond):''),done] + ], callback?function (res) { if (res) callback(result); else callback(none);}:undefined); + if (callback) return; else return result; +} + + +/** Execute an SQL operation sequence + ** todo format: [op: string, + ** args?: string, + ** result: function returning number (0: break (error), 1: next, -1:loop)] + ** callback: function () -> status + */ +sql.prototype.seq = function (todo,callback) { + var l=todo,self=this,status,res, + next; + if (callback) { // Async non.block. + function Todo() { + if (self.todo.length>0) { + var f = Comp.array.head(self.todo); + self.error=undefined; + f(_,function () { + self.todo = Comp.array.tail(self.todo); + Todo(); + }); + } + } + next=function (loop,finalize) { + var hd,repl; + if (l.length==0 && !loop) { callback(status); if (finalize) finalize() } + else { + if (!loop) { + hd= Comp.array.head(l); + l = Comp.array.tail(l); + } else hd=loop; + switch (hd[0]) { + case 'exec': + repl=self.db.exec(hd[1]) + status=hd[2](repl); + if (status==1) next(_,finalize); + else if (status==-1) next(hd,finalize); + else callback(status); + break; + } + } + } + self.todo.push(next); + if (self.todo.length==1) Todo(); + return; + } else { // Sync block. + next=function (loop) { + if (l.length==0 && !loop) return status; + else { + if (!loop) { + hd= Comp.array.head(l); + l = Comp.array.tail(l); + } else hd=loop; + switch (hd[0]) { + case 'exec': + res=self.db.exec(hd[1]); + status=hd[2](res); + if (status==1) return next(); + else if (status==-1) return next(hd); + else return status; + break; + } + } + } + return next(); + } +}; + +/** Write matrix values + * + */ +sql.prototype.writeMatrix = function (matname,matrix,callback) { + var repl, line='', seq=[], self=this, + intf='', sep='', i=0, row; + + if (!this.db) return false; + if (matrix.length==0) return false; + + row=matrix[0]; + Comp.array.iter(row,function (col,i) { + intf += sep+'c'+(i+1)+(Comp.obj.isNumber(col)?' integer':' varchar(32)'); sep=','; + }); + function done(repl) { + if (!repl || !repl.ok) {self.error=repl.code;return 0;} + else return 1; + } + seq=[ + ['exec','drop table if exists '+matname, done], + ['exec','create table '+matname+' ('+intf+')', done] + ]; + for(i=0;i