carcass-couch
Version:
(Node.js) A simple wrap of cradle plus some stream APIs, in Carcass style.
134 lines (122 loc) • 3.52 kB
text/coffeescript
# 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.
*
* {Object} a doc that will be saved to DB.
###
Model::toDoc = ->
###*
* Meant to be overridden.
*
* {Object} an instance of CouchDB.
###
Model.db = -> throw new Error('require a DB instance')
###*
* Accessor.
###
Model::db = carcass.helpers.accessor('_db', {
getDefault: -> return .db()
})
###*
* Shortcut to load data from DB and instantiate a new model.
*
* {Object} the loaded model.
###
Model.load = (id, done = ->) -> (new Model({ _id: id })).load(done)
###*
* Load.
*
* {this}
###
Model::load = (done = ->) ->
db =
db.read(, (err, doc) =>
return done(db.httpError(err)) if err
# Just loaded; nothing dirty.
= {}
# Allow model to be changed while loading.
)
return @
###*
* Route save to CouchDB.
*
* {this}
###
Model.save = (done = ->) ->
.saveAndRead(, (err, res) =>
)
return @
###*
* Route update to CouchDB.
*
* {this}
###
Model.update = (done = ->) ->
.saveAndRead(, , (err, res) =>
)
return @
###*
* Route remove to CouchDB.
###
Model.remove = (done = ->) ->
db =
.remove(, (err, res) ->
# TODO: handle conflict nicely.
return done(db.httpError(err)) if err
done(null, res)
)
return @
###*
* Handle the save result.
*
* {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 =
status = err.headers.status
# Conflict.
if status is 409
# Load the latest version.
Model.load(, (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 @