--- Revision None +++ Revision 363439666262 @@ -0,0 +1,232 @@ +var IDBWrapper = require("idb-wrapper") + , extend = require("xtend") + , getCallback = require("./utils/getCallback") + , getOptions = require("./utils/getOptions") + + , defaultOptions = { + encoding: 'utf8' + , keys: true + , values: true + } + +module.exports = idbup + +function idbup(path, defaults, callback) { + var db = extend(new Object(), { + put: onOpen(put) + , del: onOpen(del) + , get: onOpen(get) + , batch: onOpen(batch) + , open: open + , close: close + , isOpen: isOpen + , isClosed: isClosed + }) + , idb + , status = "new" + + if (typeof defaults === "function") { + callback = defaults + defaults = {} + } + + defaults = extend({}, defaultOptions, defaults || {}) + + + open(callback) + + return db + + function put(key, value, options, callback) { + callback = getCallback(options, callback) + options = getOptions(defaults, options) + + idb.put({ + value: value + , id: key + }, function () { + callback && callback(null) + }, callback) + } + + function del(key, options, callback) { + callback = getCallback(options, callback) + options = getOptions(defaults, options) + + idb.remove(key, function () { + callback && callback(null) + }, callback) + } + + function get(key, options, callback) { + callback = getCallback(options, callback) + options = getOptions(defaults, options) + + idb.get(key, function (result) { + callback && callback(null, result, key) + }, callback) + } + + function batch(arr, options, callback) { + callback = getCallback(options, callback) + options = getOptions(defaults, options) + var _arr = arr.map(function (item) { + var result = {} + , key = item.key + + if (item.type === "del") { + result.type = "remove" + } else if (item.type === "put") { + result.type = "put" + result.value = { + value: item.value + , id: key + } + } + + result.key = key + + return result + }) + + idbBatch.call(idb, _arr, function () { + callback && callback() + }, callback) + } + + function open(options, callback) { + if (!options) callback = options + if (status === "opening") { + db.on("ready", callback) + } else if (status === "opened") { + close(_open) + } else { + _open() + } + + function _open(err) { + if (err) { + return callback(err) + } + + status = "opening" + + idb = new IDBWrapper(extend({ + storeName: path + }, defaults), function () { + status = "opened" + callback && callback(null, db) + }) + } + } + + function close(callback) { + if (status === "opened") { + _close() + } else if (status === "opening") { + db.on("ready", _close) + } else if (status === "closed") { + callback && callback() + } else if (status === "new") { + var err = new Error("cannot close unopened db") + if (callback) { + return callback(err) + } + } + + function _close() { + idb.db.close() + idb = null + status = "closed" + callback && callback() + } + } + + function isOpen() { + return status === "opened" + } + + function isClosed() { + return status === "closed" + } + + function onReady(callback) { + if (status === "opened") { + callback(idb) + } else { + db.on("ready", callback) + } + } + + function onOpen(operation) { + return function opened() { + var args = arguments + + onReady(function () { + operation.apply(null, args) + }) + } + } + + // IDBWrapper batch implementation inlined. + // Waiting for pull request + function idbBatch(arr, onSuccess, onError) { + onError || (onError = function (error) { + console.error('Could not apply batch.', error); + }); + onSuccess = onSuccess || noop; + var batchTransaction = this.db.transaction( + [this.storeName] , this.consts.READ_WRITE); + var count = arr.length; + var called = false; + + arr.forEach(function (operation) { + var type = operation.type; + var key = operation.key; + var value = operation.value; + + if (type === "remove") { + var deleteRequest = batchTransaction + .objectStore(this.storeName).delete(key); + deleteRequest.onsuccess = function (event) { + count--; + if (count === 0 && !called) { + called = true; + onSuccess(); + } + }; + deleteRequest.onerror = function (err) { + batchTransaction.abort(); + if (!called) { + called = true; + onError(err); + } + }; + } else if (type === "put") { + if (typeof value[this.keyPath] === 'undefined' && + !this.features.hasAutoIncrement + ) { + value[this.keyPath] = this._getUID() + } + var putRequest = batchTransaction + .objectStore(this.storeName).put(value) + putRequest.onsuccess = function (event) { + count--; + if (count === 0 && !called) { + called = true; + onSuccess(); + } + }; + putRequest.onerror = function (err) { + batchTransaction.abort(); + if (!called) { + called = true; + onError(err); + } + }; + } + }, this); + } + + function noop() {} +}