Permalink
Browse files

Added CRUD middleware

  • Loading branch information...
1 parent f7d26b6 commit 3a775d72cd9b42a23c2f7401df8a383c85d31ea0 @scttnlsn committed Sep 19, 2012
Showing with 237 additions and 1 deletion.
  1. +1 −0 .gitignore
  2. +65 −0 lib/crud.js
  3. +3 −1 package.json
  4. +8 −0 test/support/model.js
  5. +160 −0 test/test_crud.js
View
1 .gitignore
@@ -0,0 +1 @@
+node_modules
View
65 lib/crud.js
@@ -0,0 +1,65 @@
+exports.create = function(options) {
+ options || (options = {});
+
+ return function(req, res, next) {
+ var data = {};
+
+ if (options.fields) {
+ options.fields.forEach(function(field) {
+ data[field] = req.body[field];
+ });
+ } else {
+ data = req.body;
+ }
+
+ req.instance = new req.model(data);
+ next();
+ };
+};
+
+exports.load = function(options) {
+ options || (options = {});
+ options.param || (options.param = 'id');
+
+ return function(req, res, next) {
+ var id = req.params[options.param];
+
+ req.model.findById(id, function(err, instance) {
+ if (err) return next(err);
+
+ req.instance = instance;
+ next();
+ });
+ };
+};
+
+exports.update = function(options) {
+ options || (options = {});
+
+ return function(req, res, next) {
+ var data = {};
+
+ options.fields || (options.fields = Object.keys(req.body));
+ options.fields.forEach(function(field) {
+ data[field] = req.body[field];
+ });
+
+ for (var field in data) {
+ req.instance[field] = data[field];
+ }
+
+ next();
+ };
+};
+
+exports.save = function() {
+ return function(req, res, next) {
+ req.instance.save(next);
+ };
+};
+
+exports.remove = function() {
+ return function(req, res, next) {
+ req.instance.remove(next);
+ };
+};
View
4 package.json
@@ -19,6 +19,8 @@
},
"devDependencies": {
- "mocha": ">= 1.4.2"
+ "mocha": ">= 1.4.2",
+ "mongoose": ">= 3.1.2",
+ "sinon": ">= 1.4.2"
}
}
View
8 test/support/model.js
@@ -0,0 +1,8 @@
+var mongoose = require('mongoose');
+
+var Test = new mongoose.Schema({
+ foo: String,
+ baz: String
+});
+
+module.exports = mongoose.model('Test', Test);
View
160 test/test_crud.js
@@ -0,0 +1,160 @@
+var assert = require('assert');
+var sinon = require('sinon');
+var Model = require('./support/model');
+var crud = require('../lib/crud');
+
+describe('CRUD', function() {
+ var req;
+
+ beforeEach(function() {
+ req = { model: Model };
+ });
+
+ describe('create', function() {
+ beforeEach(function() {
+ req.body = { foo: 'bar', baz: 'qux' };
+ });
+
+ it('creates instance of model from req body', function(done) {
+ var create = crud.create();
+
+ create(req, null, function() {
+ assert.ok(req.instance);
+ assert.ok(req.instance instanceof req.model);
+ assert.ok(req.instance.isNew);
+ var attrs = req.instance.toObject();
+ assert.equal(attrs.foo, 'bar');
+ assert.equal(attrs.baz, 'qux');
+ done();
+ });
+ });
+
+ it('accepts whitelist of fields', function(done) {
+ var create = crud.create({ fields: ['foo'] });
+
+ create(req, null, function() {
+ var attrs = req.instance.toObject();
+ assert.equal(attrs.foo, 'bar');
+ assert.ok(!attrs.baz);
+ done();
+ });
+ });
+ });
+
+ describe('load', function() {
+ var stub;
+
+ beforeEach(function() {
+ req.params = { id: '1234' };
+ stub = sinon.stub(Model, 'findById').yields(null, new Model());
+ });
+
+ afterEach(function() {
+ stub.restore();
+ });
+
+ it('finds model by id', function(done) {
+ var load = crud.load();
+
+ load(req, null, function() {
+ assert.ok(stub.calledOnce);
+ assert.equal(stub.getCall(0).args[0], '1234');
+ done();
+ });
+ });
+
+ it('sets instance in req', function(done) {
+ var load = crud.load();
+
+ load(req, null, function() {
+ assert.ok(req.instance);
+ assert.ok(req.instance instanceof Model);
+ done();
+ });
+ });
+
+ it('accepts id param', function(done) {
+ req.params = { foo: '1234' };
+
+ var load = crud.load({ param: 'foo' });
+
+ load(req, null, function() {
+ assert.equal(stub.getCall(0).args[0], '1234');
+ done();
+ });
+ });
+ });
+
+ describe('update', function() {
+ beforeEach(function() {
+ req.body = { foo: 'bar', baz: 'qux' };
+ req.instance = new Model();
+ });
+
+ it('updates model attributes from req body', function(done) {
+ var update = crud.update();
+
+ update(req, null, function() {
+ var attrs = req.instance.toObject();
+ assert.equal(attrs.foo, 'bar');
+ assert.equal(attrs.baz, 'qux');
+ done();
+ });
+ });
+
+ it('accepts whitelist of fields', function(done) {
+ var update = crud.update({ fields: ['foo'] });
+
+ update(req, null, function() {
+ var attrs = req.instance.toObject();
+ assert.equal(attrs.foo, 'bar');
+ assert.ok(!attrs.baz);
+ done();
+ });
+ });
+ });
+
+ describe('save', function() {
+ var stub;
+
+ beforeEach(function() {
+ req.instance = new Model();
+ stub = sinon.stub(req.instance, 'save').yields(null, req.model);
+ });
+
+ afterEach(function() {
+ stub.restore();
+ });
+
+ it('saves model instance', function(done) {
+ var save = crud.save();
+
+ save(req, null, function() {
+ assert.ok(stub.calledOnce);
+ done();
+ });
+ });
+ });
+
+ describe('remove', function() {
+ var stub;
+
+ beforeEach(function() {
+ req.instance = new Model();
+ stub = sinon.stub(req.instance, 'remove').yields(null, req.model);
+ });
+
+ afterEach(function() {
+ stub.restore();
+ });
+
+ it('removes model instance', function(done) {
+ var remove = crud.remove();
+
+ remove(req, null, function() {
+ assert.ok(stub.calledOnce);
+ done();
+ });
+ });
+ });
+});

0 comments on commit 3a775d7

Please sign in to comment.