Lawnchair.adapter('webkit-sqlite', (function () { // private methods var fail = function (e, i) { console.log('error in sqlite adaptor!', e, i) } , now = function () { return new Date() } // FIXME need to use better date fn // not entirely sure if this is needed... if (!Function.prototype.bind) { Function.prototype.bind = function( obj ) { var slice = [].slice , args = slice.call(arguments, 1) , self = this , nop = function () {} , bound = function () { return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments))) } nop.prototype = self.prototype bound.prototype = new nop() return bound } } // public methods return { //valid: function() { return !!(window.openDatabase) }, valid: function() { return !!(window.my_openDatabase) }, //valid: function() { return !!(sqlitePlugin.openDatabase) }, init: function (options, callback) { var that = this , cb = that.fn(that.name, callback) , create = "CREATE TABLE IF NOT EXISTS " + this.name + " (id NVARCHAR(32) UNIQUE PRIMARY KEY, value TEXT, timestamp REAL)" , win = function(){ return cb.call(that, that); } // open a connection and create the db if it doesn't exist //this.db = openDatabase(this.name, '1.0.0', this.name, 65536) //this.db = my_openDatabase(this.name, '1.0.0', this.name, 65536) this.db = window.my_openDatabase("Database", "1.0", "PhoneGap Demo", 200000); //this.db = sqlitePlugin.openDatabase(this.name, '1.0.0', this.name, 65536) this.db.transaction(function (t) { t.executeSql(create, [], win, fail) }) }, keys: function (callback) { var cb = this.lambda(callback) , that = this , keys = "SELECT id FROM " + this.name + " ORDER BY timestamp DESC" this.db.transaction(function(t) { var win = function (xxx, results) { if (results.rows.length == 0 ) { cb.call(that, []) } else { var r = []; for (var i = 0, l = results.rows.length; i < l; i++) { r.push(results.rows.item(i).id); } cb.call(that, r) } } t.executeSql(keys, [], win, fail) }) return this }, // you think thats air you're breathing now? save: function (obj, callback) { var that = this , id = obj.key || that.uuid() , ins = "INSERT INTO " + this.name + " (value, timestamp, id) VALUES (?,?,?)" , up = "UPDATE " + this.name + " SET value=?, timestamp=? WHERE id=?" , win = function () { if (callback) { obj.key = id; that.lambda(callback).call(that, obj) }} , val = [now(), id] // existential that.exists(obj.key, function(exists) { // transactions are like condoms that.db.transaction(function(t) { // TODO move timestamp to a plugin var insert = function (obj) { val.unshift(JSON.stringify(obj)) t.executeSql(ins, val, win, fail) } // TODO move timestamp to a plugin var update = function (obj) { delete(obj.key) val.unshift(JSON.stringify(obj)) t.executeSql(up, val, win, fail) } // pretty exists ? update(obj) : insert(obj) }) }); return this }, // FIXME this should be a batch insert / just getting the test to pass... batch: function (objs, cb) { var results = [] , done = false , that = this var updateProgress = function(obj) { results.push(obj) done = results.length === objs.length } var checkProgress = setInterval(function() { if (done) { if (cb) that.lambda(cb).call(that, results) clearInterval(checkProgress) } }, 200) for (var i = 0, l = objs.length; i < l; i++) this.save(objs[i], updateProgress) return this }, get: function (keyOrArray, cb) { var that = this , sql = '' // batch selects support if (this.isArray(keyOrArray)) { sql = 'SELECT id, value FROM ' + this.name + " WHERE id IN ('" + keyOrArray.join("','") + "')" } else { sql = 'SELECT id, value FROM ' + this.name + " WHERE id = '" + keyOrArray + "'" } // FIXME // will always loop the results but cleans it up if not a batch return at the end.. // in other words, this could be faster var win = function (xxx, results) { var o = null , r = [] if (results.rows.length) { for (var i = 0, l = results.rows.length; i < l; i++) { o = JSON.parse(results.rows.item(i).value) o.key = results.rows.item(i).id r.push(o) } } if (!that.isArray(keyOrArray)) r = r.length ? r[0] : null if (cb) that.lambda(cb).call(that, r) } this.db.transaction(function(t){ t.executeSql(sql, [], win, fail) }) return this }, exists: function (key, cb) { var is = "SELECT * FROM " + this.name + " WHERE id = ?" , that = this , win = function(xxx, results) { if (cb) that.fn('exists', cb).call(that, (results.rows.length > 0)) } this.db.transaction(function(t){ t.executeSql(is, [key], win, fail) }) return this }, all: function (callback) { var that = this , all = "SELECT * FROM " + this.name , r = [] , cb = this.fn(this.name, callback) || undefined , win = function (xxx, results) { if (results.rows.length != 0) { for (var i = 0, l = results.rows.length; i < l; i++) { var obj = JSON.parse(results.rows.item(i).value) obj.key = results.rows.item(i).id r.push(obj) } } if (cb) cb.call(that, r) } this.db.transaction(function (t) { t.executeSql(all, [], win, fail) }) return this }, remove: function (keyOrObj, cb) { var that = this , key = typeof keyOrObj === 'string' ? keyOrObj : keyOrObj.key , del = "DELETE FROM " + this.name + " WHERE id = ?" , win = function () { if (cb) that.lambda(cb).call(that) } this.db.transaction( function (t) { t.executeSql(del, [key], win, fail); }); return this; }, nuke: function (cb) { var nuke = "DELETE FROM " + this.name , that = this , win = cb ? function() { that.lambda(cb).call(that) } : function(){} this.db.transaction(function (t) { t.executeSql(nuke, [], win, fail) }) return this } ////// }})())