blob: 9df649040a5445c77b2ec181ebb9f797dfb81f23 [file] [log] [blame]
'use strict';
import { changesHandler } from 'pouchdb-utils';
import setup from './setup';
// API implementations
import info from './info';
import get from './get';
import { getAttachment } from './getAttachment';
import bulkDocs from './bulkDocs';
import allDocs from './allDocs';
import changes from './changes';
import getRevisionTree from './getRevisionTree';
import doCompaction from './doCompaction';
import destroy from './destroy';
import {query, viewCleanup} from './find';
import { DOC_STORE } from './util';
var ADAPTER_NAME = 'indexeddb';
// TODO: Constructor should be capitalised
var idbChanges = new changesHandler();
// A shared list of database handles
var openDatabases = {};
function IdbPouch(dbOpts, callback) {
var api = this;
var metadata = {};
// Wrapper that gives you an active DB handle. You probably want $t.
var $ = function (fun) {
return function () {
var args = Array.prototype.slice.call(arguments);
setup(openDatabases, api, dbOpts).then(function (res) {
metadata = res.metadata;
args.unshift(res.idb);
fun.apply(api, args);
}).catch(function (err) {
var last = args.unshift();
if (typeof last === 'function') {
last(err);
} else {
throw err;
}
});
};
};
// the promise version of $
var $p = function (fun) {
return function () {
var args = Array.prototype.slice.call(arguments);
return new Promise(function (resolve, reject) {
setup(openDatabases, api, dbOpts).then(function (res) {
metadata = res.metadata;
args.unshift(res.idb);
return fun.apply(api, args);
}).then(resolve)
.catch(reject);
});
};
};
// Wrapper that gives you a safe transaction handle. It's important to use
// this instead of opening your own transaction from a db handle got from $,
// because in the time between getting the db handle and opening the
// transaction it may have been invalidated by index changes.
var $t = function (fun, stores, mode) {
stores = stores || [DOC_STORE];
mode = mode || 'readonly';
return function () {
var args = Array.prototype.slice.call(arguments);
var txn = {};
setup(openDatabases, api, dbOpts).then(function (res) {
metadata = res.metadata;
txn.txn = res.idb.transaction(stores, mode);
}).catch(function (err) {
console.error('Failed to establish transaction safely');
console.error(err);
txn.error = err;
}).then(function () {
args.unshift(txn);
fun.apply(api, args);
});
};
};
api._openTransactionSafely = function (stores, mode, callback) {
$t(function (txn, callback) {
callback(txn.error, txn.txn);
}, stores, mode)(callback);
};
api._remote = false;
api.type = function () { return ADAPTER_NAME; };
api._id = $(function (_, cb) {
cb(null, metadata.db_uuid);
});
api._info = $(function (_, cb) {
return info(metadata, cb);
});
api._get = $t(get);
api._bulkDocs = $(function (_, req, opts, callback) {
bulkDocs(api, req, opts, metadata, dbOpts, idbChanges, callback);
});
api._allDocs = $t(function (txn, opts, cb) {
allDocs(txn, metadata, opts, cb);
});
api._getAttachment = $t(getAttachment);
api._changes = $t(function (txn, opts) {
changes(txn, idbChanges, api, dbOpts, opts);
});
api._getRevisionTree = $t(getRevisionTree);
api._doCompaction = $t(doCompaction, [DOC_STORE], 'readwrite');
api._customFindAbstractMapper = {
query: $p(query),
viewCleanup: $p(viewCleanup)
};
api._destroy = function (opts, callback) {
return destroy(dbOpts, openDatabases, idbChanges, callback);
};
api._close = $(function (db, cb) {
delete openDatabases[dbOpts.name];
db.close();
cb();
});
// Closing and re-opening the DB re-generates native indexes
api._freshen = function () {
return new Promise(function (resolve) {
api._close(function () {
$(resolve)();
});
});
};
// TODO: this setTimeout seems nasty, if its needed lets
// figure out / explain why
setTimeout(function () {
callback(null, api);
});
}
// TODO: this isnt really valid permanently, just being lazy to start
IdbPouch.valid = function () {
return true;
};
export default function (PouchDB) {
PouchDB.adapter(ADAPTER_NAME, IdbPouch, true);
}