opendatabase
Version:
The WebSql standard for Nodejs using Sqlite3.
142 lines (111 loc) • 5.12 kB
JavaScript
/* 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))
},
}