UNPKG

carcass-couch

Version:

(Node.js) A simple wrap of cradle plus some stream APIs, in Carcass style.

134 lines (122 loc) 3.52 kB
# debug = require('debug')('carcass:plugin:modella') _ = require('lodash') carcass = require('carcass') ###* * Plugin for Modella. * * Add the ability of doing CRUD with CouchDB to a model. ### module.exports = (Model) -> ###* * Meant to be overridden. * * @return {Object} a doc that will be saved to DB. ### Model::toDoc = -> @toJSON() ###* * Meant to be overridden. * * @return {Object} an instance of CouchDB. ### Model.db = -> throw new Error('require a DB instance') ###* * Accessor. ### Model::db = carcass.helpers.accessor('_db', { getDefault: -> return @model.db() }) ###* * Shortcut to load data from DB and instantiate a new model. * * @return {Object} the loaded model. ### Model.load = (id, done = ->) -> (new Model({ _id: id })).load(done) ###* * Load. * * @return {this} ### Model::load = (done = ->) -> db = @db() db.read(@primary(), (err, doc) => return done(db.httpError(err)) if err @set(doc) # Just loaded; nothing dirty. @dirty = {} # Allow model to be changed while loading. @run('loading', (err) => # TODO: handle err? # Model can become dirty. return @save(done) if not _.isEmpty(@dirty) # After load. @model.emit('load', @) @emit('load') # Pass self with the callback; keep consistency with the other # CRUD methods. done(null, @) ) ) return @ ###* * Route save to CouchDB. * * @return {this} ### Model.save = (done = ->) -> @db().saveAndRead(@toDoc(), (err, res) => @_onSaved(err, res, done) ) return @ ###* * Route update to CouchDB. * * @return {this} ### Model.update = (done = ->) -> @db().saveAndRead(@primary(), @toDoc(), (err, res) => @_onSaved(err, res, done) ) return @ ###* * Route remove to CouchDB. ### Model.remove = (done = ->) -> db = @db() @db().remove(@primary(), (err, res) -> # TODO: handle conflict nicely. return done(db.httpError(err)) if err done(null, res) ) return @ ###* * Handle the save result. * * @return {this} ### Model::_onSaved = (err, res, done = ->) -> # Not a valid error. if not err? or not err.headers? or not err.headers.status? done(null, res) return @ self = @ db = @db() status = err.headers.status # Conflict. if status is 409 # Load the latest version. Model.load(@primary(), (err, model) -> return done(db.httpError(err)) if err # Merge, if a merge handler available. if model.mergeConflict? model.mergeConflict(self) model.save((err, model) -> return done(db.httpError(err)) if err done(null, model.toJSON()) ) # Otherwise return the latest version (so this update is dropped). else done(null, model.toJSON()) ) else done(db.httpError(err)) return @