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