Skip to content

Commit

Permalink
Merge pull request #18 from jamplify/master
Browse files Browse the repository at this point in the history
Adds lean option to allow for returning virtuals
  • Loading branch information
florianholzapfel committed Nov 4, 2013
2 parents a7b9c84 + 02a1537 commit 3156f9b
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 43 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ serve(app, model, [options])
* postProcess - A middleware to be called after the response has been sent.
It is only executed on success. If an error is sent to the client,
this is not executed.

* lean - If ```false```, will not convert to returned values to plain old javascript
objects. This is bad for performance, but it allows for returning virtuals, getters and setters.

## Contributors
* Enric León (https://github.com/nothingbuttumbleweed)
* David Higginbotham (https://github.com/dhigginbotham)
Expand Down
71 changes: 40 additions & 31 deletions lib/express-restify-mongoose.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,29 @@ function filterjson(json, excludedkeys) {
}

function filterItem(item, model, excludedkeys) {
// just deleting the excluded keys from item does
// not modify the object. therefore we build a copy
var excludedarr = excludedkeys.split(',');
var it = {};

for (var key in item) {
if ((model.schema.options.versionKey &&
key === model.schema.options.versionKey) ||
// just deleting the excluded keys from item does
// not modify the object. therefore we build a copy
var excludedarr = excludedkeys.split(',');
var it = {};

for (var key in item) {
if ((model.schema.options.versionKey &&
key === model.schema.options.versionKey) ||
key === '_id') {
it[key] = item[key];
} else if (model.schema.paths.hasOwnProperty(key)) {
if (excludedarr.indexOf(key) === -1) {
it[key] = item[key];
}
}
}
return it;
it[key] = item[key];
} else if (model.schema.paths.hasOwnProperty(key)) {
if (excludedarr.indexOf(key) === -1) {
it[key] = item[key];
}
}
}
return it;
}

function filterItems(items, model, excludedKeys) {
return items.map(function (item) {
return filterItem(item, model, excludedKeys);
});
}

function outputExpress(res, result) {
Expand All @@ -63,10 +69,10 @@ function outputRestify(res, result) {
}

var restify = function (app, model, options) {
var postProcess, exclude,
var postProcess, exclude, lean,
usingExpress = true,
queryOptions = {
protected: ['skip', 'limit', 'sort', 'populate', 'select'],
protected: ['skip', 'limit', 'sort', 'populate', 'select', 'lean'],
current: {}
};

Expand All @@ -75,6 +81,7 @@ var restify = function (app, model, options) {
options.version = options.version || '/v1';
postProcess = options.postProcess || function () {};
exclude = options.exclude;
lean = typeof options.lean === 'undefined' ? true : options.lean;

if (options.plural !== false) {
options.plural = true;
Expand Down Expand Up @@ -103,7 +110,7 @@ var restify = function (app, model, options) {
}

options.middleware.unshift(cleanQuery);

var outputFn = options.restify ? outputRestify : outputExpress;
app.delete = app.del;

Expand Down Expand Up @@ -195,9 +202,9 @@ var restify = function (app, model, options) {
if (model.schema.options.versionKey) {
delete req.body[model.schema.options.versionKey];
}

var key, path;

if (Array.isArray(req.body)) {
for (var i = 0; i < req.body.length; ++i) {
for (key in req.body[i]) {
Expand Down Expand Up @@ -227,7 +234,7 @@ var restify = function (app, model, options) {
res.send(400, JSON.stringify(err));
} else {
var result = null;

if (Array.isArray(req.body)) {
var items = Array.prototype.slice.call(arguments, 1);

Expand All @@ -242,7 +249,7 @@ var restify = function (app, model, options) {
} else {
result = exclude ? filterItem(item, model, exclude) : item;
}

outputFn(res, result);
next();
}
Expand Down Expand Up @@ -271,9 +278,9 @@ var restify = function (app, model, options) {
if (err) {
res.send(404);
} else {
if (exclude) {
item = filterItem(item, model, exclude);
}
if (exclude) {
item = filterItem(item, model, exclude);
}
outputFn(res, item);
next();
}
Expand All @@ -284,12 +291,14 @@ var restify = function (app, model, options) {
write_middleware.push(ensureContentType);

app.get(uri_items, options.middleware, function (req, res, next) {
buildQuery(model.find(), req.query).lean().exec(function (err, items) {
buildQuery(model.find(), req.query).lean(lean)
.exec(function (err, items) {
if (err) {
res.send(400, 'Bad request');
} else {
if (exclude) {
items = filterjson(items, exclude);
items = lean ? filterjson(items, exclude) :
filterItems(items, model, exclude);
}
outputFn(res, items);
next();
Expand Down Expand Up @@ -329,9 +338,9 @@ var restify = function (app, model, options) {
if (err || !item) {
res.send(404);
} else {
if (exclude) {
item = filterItem(item, model, exclude);
}
if (exclude) {
item = filterItem(item, model, exclude);
}
outputFn(res, item);
next();
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"readmeFilename": "README.md",
"dependencies": {
"express": "~3.3.5",
"mongoose": "~3.6.13"
"mongoose": "~3.8.0"
},
"devDependencies": {
"jshint": "~2.1.4",
Expand Down
16 changes: 12 additions & 4 deletions test/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@ var mongoose = require('mongoose'),
Schema = mongoose.Schema;

var assert = require('assertmessage');
var opts = {
toObject: { virtuals: true },
toJSON: { virtuals: true }
};

var Customer = new Schema({
name: { type: String, required: true },
comment: { type: String }
});
}, opts);
var Invoice = new Schema({
customer: { type: Schema.Types.ObjectId, ref: 'Customer' },
amount: { type: Number }
customer: { type: Schema.Types.ObjectId, ref: 'Customer' },
amount: { type: Number }
}, {
versionKey: '__version'
}, opts);

Customer.virtual('info').get(function () {
return this.name + ' is awesome';
});

var setup = module.exports = function () {
Expand Down Expand Up @@ -40,4 +48,4 @@ var setup = module.exports = function () {
};

setup.customerModel = {};
setup.invoiceModel = {};
setup.invoiceModel = {};
63 changes: 57 additions & 6 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,21 @@ function Restify() {

[Express, Restify].each(function (createFn) {
describe(createFn.name, function () {
describe('General', function () {
describe.only('General', function () {
var savedCustomer, savedInvoice, server,
app = createFn();

setup();

before(function (done) {
erm.serve(app, setup.customerModel, { restify: app.isRestify });
erm.serve(app, setup.invoiceModel, { restify: app.isRestify });
erm.serve(app, setup.customerModel, {
restify: app.isRestify,
lean: false
});
erm.serve(app, setup.invoiceModel, {
restify: app.isRestify,
lean: false
});
server = app.listen(testPort, done);
});

Expand All @@ -50,7 +56,7 @@ function Restify() {
}
server.close(done);
});

it('200 GET Customers should return no objects', function (done) {
request.get({
url: util.format('%s/api/v1/Customers', testUrl),
Expand Down Expand Up @@ -120,7 +126,7 @@ function Restify() {
done();
});
});

it('200 GET Customers/count should return 3', function (done) {
request.get({
url: util.format('%s/api/v1/Customers/count', testUrl),
Expand All @@ -131,7 +137,7 @@ function Restify() {
done();
});
});

it('200 POST Invoice using pre-defined version', function (done) {
request.post({
url: util.format('%s/api/v1/Invoices', testUrl),
Expand Down Expand Up @@ -260,6 +266,7 @@ function Restify() {

it('200 PUT Customers/:id', function (done) {
savedCustomer.name = 'Test 2';
savedCustomer.info = savedCustomer.name + ' is awesome';
request.put({
url: util.format('%s/api/v1/Customers/%s', testUrl,
savedCustomer._id),
Expand Down Expand Up @@ -306,6 +313,50 @@ function Restify() {
});
});

describe('Return virtuals', function () {
var savedCustomer, server,
app = createFn();

setup();

before(function (done) {
erm.serve(app, setup.customerModel, {
lean: false,
restify: app.isRestify
});
server = app.listen(testPort, function () {
request.post({
url: util.format('%s/api/v1/Customers', testUrl),
json: {
name: 'Bob'
}
}, function (err, res, body) {
savedCustomer = body;
done();
});
});
});

after(function (done) {
if (app.close) {
return app.close(done);
}
server.close(done);
});

it('200 GET Customers', function (done) {
var info = savedCustomer.name + ' is awesome';
request.get({
url: util.format('%s/api/v1/Customers', testUrl),
json: true
}, function (err, res, body) {
assert.equal(res.statusCode, 200, 'Wrong status code');
assert.equal(body[0].info, info, 'info is not defined');
done();
});
});
});

describe('Excluded comment field', function () {
var savedCustomer, server,
app = createFn();
Expand Down

0 comments on commit 3156f9b

Please sign in to comment.