Skip to content

Instantly share code, notes, and snippets.

@bernharduw
Forked from christophercliff/documents.js
Last active August 29, 2015 14:16
Show Gist options
  • Save bernharduw/9f54a989171f97eaf8cc to your computer and use it in GitHub Desktop.
Save bernharduw/9f54a989171f97eaf8cc to your computer and use it in GitHub Desktop.

Base Classes for Binding Backbone.js to the CouchDB Documents API

Backbone's default service layer depends on a fairly rigid API design. In order to integrate with CouchDB's slightly irregular Documents API, we can create a set of base Document classes that override key methods to work with CouchDB. By inheriting these Document classes, Models and Collections that correspond directly to CouchDB Documents fit seamlessly into normal Backbone workflow.

This approach is advantageous for several reasons:

  • The default Backbone library remains predictably intact
  • Documents can be bound to specific CouchDB view functions or databases
(function(window, undefined){
window.Document = Backbone.Model.extend({
url: function () {
var self = this,
base = '/' + self.database;
if (self.isNew())
{
return base;
}
return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(self.id);
},
parse: function (obj) {
obj['_rev'] = obj['rev'];
delete obj.rev;
delete obj.ok;
return obj;
},
destroy: function (options) {
var self = this;
options || (options = {});
options.url = self.url() + '/?rev=' + self.get('_rev');
if (this.isNew()) return this.trigger('destroy', this, this.collection, options);
var model = this;
var success = options.success;
options.success = function(resp) {
model.trigger('destroy', model, model.collection, options);
if (success) success(model, resp);
};
options.error = wrapError(options.error, model, options);
return (this.sync || Backbone.sync).call(this, 'delete', this, options);
}
});
window.Documents = Backbone.Collection.extend({
model: Document,
parse: function (response) {
return _.map(response.rows, function(obj){
obj.value['id'] = obj.value['_id'];
delete obj.value._id;
return obj.value;
});
},
fetch: function(options) {
options || (options = {});
options.data || (options.data = {});
_.extend(options.data, {
key: '\"' + this.key + '\"'
});
var collection = this;
var success = options.success;
options.success = function(resp, status, xhr) {
collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
if (success) success(collection, resp);
};
options.error = wrapError(options.error, collection, options);
return (this.sync || Backbone.sync).call(this, 'read', this, options);
}
});
var wrapError = function(onError, model, options) {
return function(resp) {
if (onError) {
onError(model, resp, options);
} else {
model.trigger('error', model, resp, options);
}
};
};
})(window);
(function(window, undefined){
window.Apple = Document.extend({
database: 'fruit',
defaults: {
type: 'apple'
}
});
window.Apples = Documents.extend({
model: Apple,
key: 'apple',
url: '/fruit/_design/fruit/_view/by_type'
});
var apples = new Apples();
apples.fetch({
success: function () {
var apple = apples.create({}, {
success: function () {
apple.save({}, {
success: function () {
apple.destroy();
}
});
}
});
}
});
})(window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment