UNPKG

opendatabase

Version:

The WebSql standard for Nodejs using Sqlite3.

142 lines (111 loc) 5.12 kB
/* Copyright 2013 Robert Edward Steckroth II <RobertSteckroth@gmail.com> Bust0ut, Surgemcgee * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ var path = require('path'), spawn = require('child_process').spawn var log = function(message) { console.log("[openDatabase] "+message) } var openDatabase = function(args) { for ( var arg in args ) this[arg] = args[arg] this.queue = [] this.proceeding = false this.program = spawn( path.dirname(__filename)+'/bin/sqlite3', [this.name, '-json', '-appendRowsAffected'], { cwd: path.dirname(this.name) || process.cwd(), env: process.env, encoding: 'utf8', } ) var newThis = this var data = '' this.program.stdout.on('data', function(chunk) { data += chunk; if ( data[data.length-1] === '\n') { // newline feed can only happen at end of data transmission by our Sqlite3 module newThis.success(data.substr(0, data.length-1)) data = '' } }) this.program.stdout.on('error', function(data) { newThis.error(data.toString()) }) this.program.stderr.on('data', function(data) { newThis.error(data.toString()) }) this.program.stdin.on('error', function(data) { log('program shell write stream error: '+data+'\nMake sure file '+newThis.name+' exists and is writable by this user.') }) } module.exports = openDatabase var SQLResultSet = function(data) { results = data ? JSON.parse('['+data+']') : [] var meta_data = results.pop() || {} this.rowsAffected = meta_data['rowsAffected'] || 0 // Make sure to use -appendRowsAffected as an arg to our custom sqlite3 binaries this.insertId = meta_data['insertId'] || 'undefined' // Make sure to use -appendRowsAffected as an arg to our custom sqlite3 binaries this.rows = new SQLResultSetRowList(results||[]) } var SQLResultSetRowList = function(results) { this.length = results.length this.item = function(ind) { return results[ind] } } openDatabase.prototype = { error: function(data) { var tx_obj = this.queue.pop() proceeding = true if ( this.queue.length ) this.program.stdin.write(this.queue[this.queue.length-1].q_str) else proceeding = false tx_obj.err_cb && tx_obj.err_cb(tx_obj, {message: data, code: 1}) }, success: function(data) { var tx_obj = this.queue.pop() this.proceeding = true if ( this.queue.length ) this.program.stdin.write(this.queue[this.queue.length-1].q_str) else this.proceeding = false if ( tx_obj.error ) // Again with our added support for replacement text error tx_obj.err_cb && tx_obj.err_cb(tx_obj, (tx_obj.error)) else tx_obj.success_cb && tx_obj.success_cb(tx_obj, new SQLResultSet(data)) }, tx: function(program, queue, proceeding) { this.executeSql = function(q_str, params, success_cb, err_cb) { if ( !q_str ) return this.success_cb = success_cb || null this.err_cb = err_cb || null params = params || [] var err = null if ( params.length ) // We only care about question mark replacement if there are substitution variables sent in as an array q_str.match(/\?/g).forEach(function(val, ind, arr) { // This might do data type assignment in future releases (for now, simple string replacement into database as a string). q_str = q_str.replace(val, typeof params[ind] !== 'undefined' ? '"'+params[ind].toString()+'"' : function(){ // Only TEXT feilds are supported right now err = err || {} err.code = 5 err.message = "number of '?'s in statement string does not match argument count. \nCount "+arr.length+": "+arr.toString()+"\nCount "+params.length+": "+params.toString()+";"; return '' }() ) }) this.error = err this.q_str = q_str+='\n' queue.unshift(this) // Add this to the beginning of the queue if ( queue.length === 1 && !proceeding ) // If this is the first queue and were not in a message pump via the success/error callbacks, start the pump crank'n! program.stdin.write(this.q_str) } }, transaction: function(tx_func) { tx_func(new this.tx(this.program, this.queue, this.proceeding)) }, }