blob: 3f7034a5290751808fb0c0ffeb66b900752959be [file] [log] [blame]
import debug from 'debug';
import inherits from 'inherits';
import Adapter from './adapter';
import TaskQueue from './taskqueue';
import Promise from './deps/promise';
import clone from './deps/clone';
function defaultCallback(err) {
/* istanbul ignore next */
if (err && global.debug) {
console.error(err);
}
}
// OK, so here's the deal. Consider this code:
// var db1 = new PouchDB('foo');
// var db2 = new PouchDB('foo');
// db1.destroy();
// ^ these two both need to emit 'destroyed' events,
// as well as the PouchDB constructor itself.
// So we have one db object (whichever one got destroy() called on it)
// responsible for emitting the initial event, which then gets emitted
// by the constructor, which then broadcasts it to any other dbs
// that may have been created with the same name.
function prepareForDestruction(self, opts) {
var name = opts.originalName;
var ctor = self.constructor;
var destructionListeners = ctor._destructionListeners;
function onDestroyed() {
ctor.emit('destroyed', name);
//so we don't have to sift through all dbnames
ctor.emit(name, 'destroyed');
}
function onConstructorDestroyed() {
self.removeListener('destroyed', onDestroyed);
self.emit('destroyed', self);
}
self.once('destroyed', onDestroyed);
// in setup.js, the constructor is primed to listen for destroy events
if (!destructionListeners.has(name)) {
destructionListeners.set(name, []);
}
destructionListeners.get(name).push(onConstructorDestroyed);
}
inherits(PouchDB, Adapter);
function PouchDB(name, opts, callback) {
if (!(this instanceof PouchDB)) {
return new PouchDB(name, opts, callback);
}
var self = this;
if (typeof opts === 'function' || typeof opts === 'undefined') {
callback = opts;
opts = {};
}
if (name && typeof name === 'object') {
opts = name;
name = undefined;
}
if (typeof callback === 'undefined') {
callback = defaultCallback;
}
name = name || opts.name;
opts = clone(opts);
// if name was specified via opts, ignore for the sake of dependentDbs
delete opts.name;
this.__opts = opts;
var oldCB = callback;
self.auto_compaction = opts.auto_compaction;
self.prefix = PouchDB.prefix;
Adapter.call(self);
self.taskqueue = new TaskQueue();
var promise = new Promise(function (fulfill, reject) {
callback = function (err, resp) {
/* istanbul ignore if */
if (err) {
return reject(err);
}
delete resp.then;
fulfill(resp);
};
opts = clone(opts);
var originalName = opts.name || name;
var backend, error;
(function () {
try {
if (typeof originalName !== 'string') {
error = new Error('Missing/invalid DB name');
error.code = 400;
throw error;
}
backend = PouchDB.parseAdapter(originalName, opts);
opts.originalName = originalName;
opts.name = backend.name;
if (opts.prefix && backend.adapter !== 'http' &&
backend.adapter !== 'https') {
opts.name = opts.prefix + opts.name;
}
opts.adapter = opts.adapter || backend.adapter;
self._adapter = opts.adapter;
debug('pouchdb:adapter')('Picked adapter: ' + opts.adapter);
self._db_name = originalName;
if (!PouchDB.adapters[opts.adapter]) {
error = new Error('Adapter is missing');
error.code = 404;
throw error;
}
/* istanbul ignore if */
if (!PouchDB.adapters[opts.adapter].valid()) {
error = new Error('Invalid Adapter');
error.code = 404;
throw error;
}
} catch (err) {
self.taskqueue.fail(err);
}
}());
if (error) {
return reject(error); // constructor error, see above
}
self.adapter = opts.adapter;
// needs access to PouchDB;
self.replicate = {};
self.replicate.from = function (url, opts, callback) {
return self.constructor.replicate(url, self, opts, callback);
};
self.replicate.to = function (url, opts, callback) {
return self.constructor.replicate(self, url, opts, callback);
};
self.sync = function (dbName, opts, callback) {
return self.constructor.sync(self, dbName, opts, callback);
};
self.replicate.sync = self.sync;
PouchDB.adapters[opts.adapter].call(self, opts, function (err) {
/* istanbul ignore if */
if (err) {
self.taskqueue.fail(err);
callback(err);
return;
}
prepareForDestruction(self, opts);
self.emit('created', self);
PouchDB.emit('created', opts.originalName);
self.taskqueue.ready(self);
callback(null, self);
});
});
promise.then(function (resp) {
oldCB(null, resp);
}, oldCB);
self.then = promise.then.bind(promise);
self.catch = promise.catch.bind(promise);
}
PouchDB.debug = debug;
export default PouchDB;