Permalink
Browse files

refactor out the storage so we can swap http / idb backends

  • Loading branch information...
1 parent 0017844 commit 1d5be03562bef6ac60f17312cefc0d986603bcde @daleharvey daleharvey committed Apr 21, 2012
View
@@ -26,20 +26,16 @@ Simply download the minified pouch.js script from https://github.com/mikeal/pouc
Most of the Pouch API is exposed as `fun(arg, [options], [callback])` Where both the options and the callback are optional. Callbacks are in the node.js idiom of `function(err, data)` Where the first argument will be undefined unless there is an error, further arguments specify the result.
-## pouch.open(name, [options], [callback])
+## new Pouch('idb://dbname', [options], [callback])
-This method gets an existing database if one exists or creates a new one if one does not exist. if you specify `{http:true}` in the options then PouchDB will act as a client to a CouchDB server with a matching API (if your database name is a url then it behaves as a client by default)
+This method gets an existing database if one exists or creates a new one if one does not exist. The protocol field denotes which backend you want to use (currently only http and indexeddb are supported)
<pre>
-pouch.open('test', function(err, db) {
+new Pouch('idb://test', function(err, db) {
// Use db to call further functions
})
</pre>
-## pouch.deleteDatabase(name, [callback])
-
-Delete method with given name
-
## db
The subject of the of pouch.open. This is primary PouchDB API.
@@ -62,22 +58,23 @@ The subject of the of pouch.open. This is primary PouchDB API.
### db.changes.removeListener(listener)
-## db.replicate
+## Pouch.destroy(name, [callback])
-### db.replicate.to(dbName, [options], [callback])
+Delete database with given name
-### db.replicate.from(dbName, [options], [callback])
+## Pouch.replicate(from, to, [callback])
+Replicate a database
## Running the tests
To run the full test suite (including replication) you'll need to run a CORS proxy
pointing to a local CouchDB.
-
- git clone https://github.com/daleharvey/CORS-Proxy.git
+
+ git clone https://github.com/daleharvey/CORS-Proxy.git
cd CORS-Proxy
node server.js
-
+
This will proxy requests to http://localhost:1234 (made by the test suite) to
your local CouchDB running on http://localhost:5984, adding the correct CORS
headers so the browser allows the requests to go through.
View
@@ -0,0 +1,229 @@
+Pouch.adapter('http', (function() {
+
+ var api = {};
+
+ api.destroy = function(name, callback) {
+ var host = getHost(name);
+ ajax({auth: host.auth, type: 'DELETE', url: genUrl(host, '')}, callback);
+ };
+
+ api.valid = function() { return true; };
+
+ api.init = function(opts, callback) {
+ var self = this;
+ this.host = getHost(opts.name);
+ ajax({
+ auth: this.host.auth,
+ type: 'PUT',
+ url: genUrl(this.host, '')
+ }, function(err, ret) {
+ if (!err || err.status === 412) {
+ call(callback, null, self);
+ }
+ });
+ };
+
+ api.id = function() {
+ return genUrl(this.host, '');
+ };
+
+ api.info = function(callback) {
+ };
+
+ api.get = function(id, opts, callback) {
+ if (opts instanceof Function) {
+ callback = opts;
+ opts = {};
+ }
+ var params = [];
+ if (opts.revs) {
+ params.push('revs=true');
+ }
+ if (opts.rev) {
+ params.push('rev=' + opts.rev);
+ }
+ if (opts.conflicts) {
+ params.push('conflicts=' + opts.conflicts);
+ }
+ params = params.join('&');
+ params = params === '' ? '' : '?' + params;
+
+ var options = {
+ auth: this.host.auth,
+ type: 'GET',
+ url: genUrl(this.host, id + params)
+ };
+
+ if (/\//.test(id) && !/^_local/.test(id)) {
+ options.dataType = false;
+ }
+
+ ajax(options, function(err, doc, xhr) {
+ if (err) {
+ return call(callback, Pouch.Errors.MISSING_DOC);
+ }
+ call(callback, null, doc, xhr);
+ });
+ };
+
+ api.remove = function(doc, opts, callback) {
+ };
+
+ api.putAttachment = function(id, rev, doc, type, callback) {
+ ajax({
+ auth: this.host.auth,
+ type:'PUT',
+ url: genUrl(this.host, id) + '?rev=' + rev,
+ headers: {'Content-Type': type},
+ data: doc
+ }, callback);
+ };
+
+ api.put = api.post = function(doc, opts, callback) {
+ if (opts instanceof Function) {
+ callback = opts;
+ opts = {};
+ }
+ ajax({
+ auth: this.host.auth,
+ type:'PUT',
+ url: genUrl(this.host, doc._id),
+ data: doc
+ }, callback);
+ };
+
+ api.bulkDocs = function(req, opts, callback) {
+ if (typeof opts.new_edits !== 'undefined') {
+ req.new_edits = opts.new_edits;
+ }
+ ajax({
+ auth: this.host.auth,
+ type:'POST',
+ url: genUrl(this.host, '_bulk_docs'),
+ data: req
+ }, callback);
+ };
+ api.allDocs = function(opts, callback) {
+ if (opts instanceof Function) {
+ callback = opts;
+ opts = {};
+ }
+ ajax({auth: this.host.auth, type:'GET', url: genUrl(this.host, '_all_docs')}, callback);
+ };
+
+ api.changes = function(opts, callback) {
+ if (opts instanceof Function) {
+ opts = {complete: opts};
+ }
+ if (callback) {
+ opts.complete = callback;
+ }
+
+ var params = '?style=all_docs'
+ if (opts.include_docs) {
+ params += '&include_docs=true'
+ }
+ if (opts.since) {
+ params += '&since=' + opts.since;
+ }
+ ajax({auth: this.host.auth, type:'GET', url: genUrl(this.host, '_changes' + params)}, function(err, res) {
+ res.results.forEach(function(c) {
+ call(opts.onChange, c);
+ });
+ call(opts.complete, null, res);
+ });
+ };
+
+ api.revsDiff = function(req, opts, callback) {
+ if (opts instanceof Function) {
+ callback = opts;
+ opts = {};
+ }
+ ajax({auth: this.host.auth, type:'POST', url: genUrl(this.host, '_revs_diff'), data: req}, function(err, res) {
+ call(callback, null, res);
+ });
+ };
+
+ // parseUri 1.2.2
+ // (c) Steven Levithan <stevenlevithan.com>
+ // MIT License
+ function parseUri (str) {
+ var o = parseUri.options;
+ var m = o.parser[o.strictMode ? "strict" : "loose"].exec(str);
+ var uri = {};
+ var i = 14;
+
+ while (i--) uri[o.key[i]] = m[i] || "";
+
+ uri[o.q.name] = {};
+ uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
+ if ($1) uri[o.q.name][$1] = $2;
+ });
+
+ return uri;
+ };
+
+ parseUri.options = {
+ strictMode: false,
+ key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
+ q: {
+ name: "queryKey",
+ parser: /(?:^|&)([^&=]*)=?([^&]*)/g
+ },
+ parser: {
+ strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
+ loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
+ }
+ };
+
+ function getHost(name) {
+ if (/http:/.test(name)) {
+ var uri = parseUri(name);
+ uri.remote = true;
+ uri.auth = {username: uri.user, password: uri.password};
+ var parts = uri.path.replace(/(^\/|\/$)/g, '').split('/');
+ uri.db = parts.pop();
+ uri.path = parts.join('/');
+ return uri;
+ }
+ return {host: '', path: '/', db: name, auth: false};
+ }
+
+ function genUrl(opts, path) {
+ if (opts.remote) {
+ var pathDel = !opts.path ? '' : '/';
+ return opts.protocol + '://' + opts.host + ':' + opts.port + '/' + opts.path
+ + pathDel + opts.db + '/' + path;
+ }
+ return '/' + opts.db + '/' + path;
+ };
+
+ function ajax(options, callback) {
+ var defaults = {
+ success: function (obj, _, xhr) {
+ callback(null, obj, xhr);
+ },
+ error: function (err) {
+ if (err) callback(err);
+ else callback(true);
+ },
+ dataType: 'json',
+ contentType: 'application/json'
+ };
+ options = $.extend({}, defaults, options);
+
+ if (options.data && typeof options.data !== 'string') {
+ options.data = JSON.stringify(options.data);
+ }
+ if (options.auth) {
+ options.beforeSend = function(xhr) {
+ var token = btoa(options.auth.username + ":" + options.auth.password);
+ xhr.setRequestHeader("Authorization", "Basic " + token);
+ }
+ }
+ $.ajax(options);
+ };
+
+ return api;
+
+})());
Oops, something went wrong.

0 comments on commit 1d5be03

Please sign in to comment.