@rill/mongoose
Version:
Resource based crud api generator for Rill and Mongoose.
157 lines (141 loc) • 4.19 kB
JavaScript
var utils = require('./utils')
var PATCH_OPTIONS = { runValidators: true, new: true }
var PUT_OPTIONS = { runValidators: true, overwrite: true, new: true }
module.exports = {
/**
* Default handler for GET requests.
*/
find: function (ctx, next) {
var req = ctx.req
var res = ctx.res
var mongoose = ctx.mongoose
var Model = ctx.Model
return Promise.all([
Model
.find(req.query)
.sort(mongoose.sort)
.skip(mongoose.skip)
.limit(mongoose.limit)
.select(mongoose.select)
.lean(),
Model.count(req.query)
])
.then(function (result) {
var docs = result[0] || []
var count = result[1]
res.set('X-Total-Count', count)
res.status = 200
res.body = docs
if (docs.length && mongoose.populate) {
return Model.populate(docs, mongoose.populate)
}
})
.then(next)
},
/**
* Default handler for GET/id requests.
*/
findById: function (ctx, next) {
var req = ctx.req
var res = ctx.res
var params = req.params
var mongoose = ctx.mongoose
var Model = ctx.Model
return Model
.findById(params._id)
.select(mongoose.select)
.lean()
.then(function (doc) {
var notFound = doc == null
var count = notFound ? 0 : 1
res.body = doc
res.status = notFound ? 204 : 200
res.set('X-Total-Count', count)
if (notFound) return
if (mongoose.populate) return Model.populate(doc, mongoose.populate)
})
.then(next)
},
/**
* Default handler for POST requests.
*/
create: function (ctx, next) {
var req = ctx.req
var res = ctx.res
var mongoose = ctx.mongoose
var Model = ctx.Model
res.body = new Model(req.body)
res.status = 201
return next().then(function () {
if (!res.body || typeof res.body.save !== 'function') return
return res.body.save().then(function (doc) {
res.body = utils.omitObj(doc.toObject(), mongoose.hidden)
}).catch(handleValidationError.bind(ctx))
})
},
/**
* Default handler for PUT/PATCH requests.
*/
save: function (ctx, next) {
var req = ctx.req
var res = ctx.res
var mongoose = ctx.mongoose
var Model = ctx.Model
var $set
var options
if (req.method === 'PUT') {
$set = req.body
options = utils.assign(PUT_OPTIONS, { fields: mongoose.select })
} else if (req.method === 'PATCH') {
$set = { $set: req.body }
options = utils.assign(PATCH_OPTIONS, { fields: mongoose.select })
}
return Model.findByIdAndUpdate(req.params._id, $set, options).then(function (doc) {
res.body = doc
res.status = doc == null ? 204 : 200
if (doc == null) return
return next().then(function () {
if (!res.body || typeof res.body.save !== 'function') return
return res.body.save().then(function (doc) {
res.body = utils.omitObj(doc.toObject(), mongoose.hidden)
})
})
}).catch(handleValidationError.bind(ctx))
},
/**
* Default handler for DELETE requests.
*/
remove: function (ctx, next) {
var res = ctx.res
var req = ctx.req
var params = req.params
var mongoose = ctx.mongoose
var Model = ctx.Model
return Model.findById(params._id, mongoose.select).then(function (doc) {
res.body = doc
res.status = doc == null ? 204 : 200
if (doc == null) return
return next().then(function () {
if (!res.body || typeof res.body.remove !== 'function') return
return res.body.remove()
})
})
}
}
/**
* Special handler for validation errors.
*/
function handleValidationError (e) {
// Handle validation errors specially.
if (e.name !== 'ValidationError') throw e
var res = this.res
// Set "Bad Request" error status.
res.status = 400
// Generate an 'x-error-message' header.
var xErrorMessage = []
for (var key in e.errors) xErrorMessage.push(e.errors[key].message)
res.set('X-Error-Message', xErrorMessage.join('\n'))
// Send the error to the client.
res.body = JSON.stringify({ error: e })
}