PageRenderTime 2ms CodeModel.GetById 4ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/design/console/vendor/backbone.couchdb.js

http://github.com/couchbaselabs/Syncpoint-API
JavaScript | 181 lines | 144 code | 26 blank | 11 comment | 22 complexity | 04e780a5601d76e8312bae10090780a0 MD5 | raw file
  1/**
  2 * @author: Thomas Rampelberg <thomas@saunter.org>
  3 *
  4 * Copyright(c) 2011 Thomas Rampelberg
  5 */
  6
  7(function($) {
  8
  9  Backbone.couch = {};
 10  Backbone.couch.options = {
 11    database: 'test',
 12    design: 'backbone'
 13  };
 14
 15  Backbone.couch.utils = {
 16    _format_row: function(row) {
 17      _.extend(row, row.value ? { value: row.value } : {}, row.doc);
 18      // if (!row.id && row._id) row.id = row._id;
 19
 20      // Since we reassigned these, remove them from the object;
 21      // delete row._id;
 22      delete row.doc;
 23
 24      // if (!row.id) row.id = k;
 25      return row;
 26    },
 27    _ignores: [ 'view', 'update', 'filter', 'show', 'list' ],
 28    _remove: function(opts) {
 29      _.each(couch._ignores, function(v) {
 30        delete opts[v];
 31      });
 32    },
 33    model: {
 34      create: function(_db, model, cb) {
 35        var opts = (model.couch && model.couch()) || {};
 36        var method = _.bind(_db.saveDoc, _db);
 37        if ('update' in opts)
 38          method = _.bind(_db.updateDoc, _db, opts.update);
 39
 40        couch._remove(opts);
 41        method(model.toJSON(), _.extend(opts, {
 42          success: function(resp) {
 43            cb.success(_.extend({
 44              _id: resp.id,
 45              _rev: resp.rev
 46            }, resp.doc));
 47          },
 48          error: cb.error
 49        }));
 50      },
 51      update: function(_db, model, cb) {
 52        this.create(_db, model, cb);
 53      },
 54      read: function(_db, model, cb) {
 55        var opts = (model.couch && model.couch()) || {};
 56        var method = _.bind(_db.openDoc, _db);
 57        if ('show' in opts)
 58          method = _.bind(_db.show, _db, opts.show);
 59
 60        method(model.id, {
 61          success: cb.success,
 62          error: cb.error
 63        });
 64      },
 65      'delete': function(_db, model, cb) {
 66        _db.removeDoc(_.extend({ _id: model.id }, model.toJSON()), {
 67          success: cb.success,
 68          error: cb.error
 69        });
 70      }
 71    },
 72    collection: {
 73      read: function(_db, model, cb) {
 74        var opts = model.couch();
 75        var method = null;
 76        if ('view' in opts)
 77          method = _.bind(_db.view, _db, opts.view);
 78        if ('list' in opts)
 79          method = _.bind(_db.list, _db, opts.list, opts.view.split('/')[1]);
 80
 81        if (!method)
 82          throw new Error("The return of `couch()` must contain the view " +
 83                          "and/or the list");
 84
 85        couch._remove(opts);
 86        method(_.extend({
 87          success: function(resp) {
 88            cb.success(_.map(resp.rows, couch._format_row));
 89          },
 90          error: cb.error
 91        }, opts));
 92      }
 93    },
 94    sync: function(method, model, cb) {
 95      // XXX - This is going to be a memory issue unless someone does the
 96      // extend trick.
 97      var _db = this._db || (this.collection && this.collection._db);
 98      if (!_db) _db = this._db = Backbone.couch.db(
 99        Backbone.couch.options.database);
100      var type = 'model' in model ? 'collection' : 'model';
101      couch[type][method](_db, model, cb);
102    }
103  };
104
105  Backbone.couch.db = function(name, db_opts) {
106    if (!db_opts) db_opts = {};
107    var old_prefix = $.couch.urlPrefix;
108    $.couch.urlPrefix = db_opts.host || $.couch.urlPrefix;
109
110    var ret = $.couch.db(name, db_opts);
111
112    var base_func = function(path, fname, handler) {
113      var current_uri = this.uri;
114      
115      var name = handler.split('/');
116      this.uri = this.uri + '_design/' + name[0] + '/_' + path + '/' + name[1] +
117        '/';
118      this[fname].apply(this, _.toArray(arguments).slice(3));
119      
120      this.uri = current_uri;
121    };
122
123    _.extend(ret, {
124      show: _.bind(base_func, ret, 'show', 'openDoc'),
125      updateDoc: _.bind(base_func, ret, 'update', 'saveDoc')
126    });
127    $.couch.urlPrefix = old_prefix;
128    return ret
129  };
130
131  var couch = Backbone.couch.utils;
132
133  Backbone.couch.sync = couch.sync;
134
135  Backbone.couch.Model = Backbone.Model.extend({
136    sync: couch.sync,
137    idAttribute: '_id'
138  });
139
140  Backbone.couch.Collection = Backbone.Collection.extend({
141    model: Backbone.couch.Model,
142    sync: couch.sync,
143    change_feed: false,
144    initialize: function() {
145      _.bindAll(this, '_init_changes', '_on_change');
146
147      if (this.change_feed)
148        this._db.info({
149          success: this._init_changes
150        });
151    },
152    _init_changes: function(state) {
153      var seq = state.update_seq || 0;
154
155      var opts = { include_docs: true };
156      var col_opts = this.couch();
157      if ('filter' in col_opts)
158        _.extend(opts, col_opts.filter);
159
160      this._changes = this._db.changes(seq, opts);
161      this._changes.onChange(this._on_change);
162    },
163    _on_change: function(changes) {
164      var _this = this;
165      _.each(changes.results, function(res) {
166        var client_model = _this.get(res.id);
167
168        if (client_model) {
169          if (res.deleted) return _this.remove(client_model);
170          if (client_model.get('_rev') == res.doc._rev) return
171
172          return client_model.set(res.doc);
173        }
174
175        if (res.deleted) return
176        _this.add(couch._format_row(res));
177      });
178    }
179  });
180
181})(jQuery);