diff --git a/js/sql/sqlite3.js b/js/sql/sqlite3.js new file mode 100644 index 0000000..23ac832 --- /dev/null +++ b/js/sql/sqlite3.js @@ -0,0 +1,103 @@ +/** JavaScript Sqlite3 Implementation with raw file system access + * (sqlite3C compiled with emscripten from C source) + * Usage: + * + * db = Database(fileName:string) + * db.open() + * ret=db.exec('CREATE TABLE ?? (id INTEGER PRIMARY KEY, name TEXT NOT NULL);', tableName) + * ret=db.exec('INSERT INTO ?? VALUES (null, ?);', tableName, 'John')) + * ret=db.exec('SELECT * FROM ??;', tableName) + * -> + * { code: 0, + * ok: true, + * statement: 'SELECT * FROM "newtable";', + * result: + * [ { id: '1', name: 'John' }]} + * + * + * + */ + +var sql = require('./sqlite3C.js') + +var PTR_SIZE = 4; +var SQLITE_OK = 0; + +var SQLite = { + open: sql.cwrap('sqlite3_open', 'number', ['string', 'number']), + exec: sql.cwrap('sqlite3_exec', 'number', ['number', 'string', 'number']), + close: sql.cwrap('sqlite3_close', 'number', ['number']) +}; + +/* output buffer and sqlite3_exec callback function mapping to js */ +var execOutput = []; +var execCallback = sql.addFunction(function (_, colNumber, valArray, keyArray) { + var row = {}; + for (var offset = 0; offset < colNumber * PTR_SIZE; offset += PTR_SIZE) { + var key = sql.UTF8ToString(sql.getValue(keyArray + offset, '*')); + var val = sql.UTF8ToString(sql.getValue(valArray + offset, '*')); + row[key] = val; + } + execOutput.push(row); +}); + +function escapeText(t) { + return String(t).replace(/'/g, "''"); +} + +function escapeIdentifier(i) { + return String(i).replace(/"/g, '""'); +} + +function prepareStatement(statement, parameters) { + return String(statement).replace(/\?+/g, function (match) { + var param = parameters.shift() || ''; + switch (match.length) { + case 1: return `'${escapeText(param)}'`; + case 2: return `"${escapeIdentifier(param)}"`; + default: return match; + } + }); +} + +function createResult(code, statement, result) { + var o = { code: code, ok: !code }; + if (statement) o.statement=statement; + if (result) o.result=result; + return o; +} + +function Database (fileName) { + if (!(this instanceof Database)) return new Database (fileName); + this.fileName = String(fileName); + this.dbPointer = null; +} + +Database.prototype.open = function () { + var dbPointer = sql._malloc(PTR_SIZE); + var returnValue = SQLite.open(this.fileName, dbPointer); + if (returnValue === SQLITE_OK) { + this.dbPointer = sql.getValue(dbPointer, '*'); + } + return createResult(returnValue); +} + +Database.prototype.exec = function () { + var statement,parameters=[]; + for(var i in arguments) { + if (i=='0') statement=arguments[0]; + else parameters.push(arguments[i]); + } + var preparedStatement = prepareStatement(statement, parameters); + var returnValue = SQLite.exec(this.dbPointer, preparedStatement, execCallback); + var result = returnValue === SQLITE_OK ? execOutput.splice(0) : null; + return createResult(returnValue, preparedStatement, result); +} + +Database.prototype.close = function () { + var returnValue = SQLite.close(this.dbPointer); + return createResult(returnValue); +} + +module.exports = Database +