diff --git a/1-hello-world/package.json b/1-hello-world/package.json index 79f71fc68a..006d9b04b8 100644 --- a/1-hello-world/package.json +++ b/1-hello-world/package.json @@ -34,7 +34,7 @@ "devDependencies": { "jshint": "^2.9.1", "mocha": "^2.4.5", - "supertest": "^1.1.0" + "supertest": "^1.2.0" }, "engines": { "node": ">=0.12.7" diff --git a/2-structured-data/books/api.js b/2-structured-data/books/api.js index 0322929233..6233cc49b2 100644 --- a/2-structured-data/books/api.js +++ b/2-structured-data/books/api.js @@ -55,7 +55,7 @@ module.exports = function (model) { * * Retrieve a book. */ - router.get('/:book(\\d+)', function get(req, res, next) { + router.get('/:book', function get(req, res, next) { model.read(req.params.book, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -67,7 +67,7 @@ module.exports = function (model) { * * Update a book. */ - router.put('/:book(\\d+)', function update(req, res, next) { + router.put('/:book', function update(req, res, next) { model.update(req.params.book, req.body, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -79,7 +79,7 @@ module.exports = function (model) { * * Delete a book. */ - router.delete('/:book(\\d+)', function _delete(req, res, next) { + router.delete('/:book', function _delete(req, res, next) { model.delete(req.params.book, function (err) { if (err) { return next(err); } res.status(200).send('OK'); diff --git a/2-structured-data/books/model-mongodb.js b/2-structured-data/books/model-mongodb.js index a0978a7e5f..1dbcf92e9e 100644 --- a/2-structured-data/books/model-mongodb.js +++ b/2-structured-data/books/model-mongodb.js @@ -16,38 +16,35 @@ var MongoClient = require('mongodb').MongoClient; var ObjectID = require('mongodb').ObjectID; - -module.exports = function(config) { +module.exports = function (config) { var url = config.mongodb.url; var collectionName = config.mongodb.collection; var collection; - // [START translate] function fromMongo(item) { - if (item.length) { item = item.pop(); } + if (Array.isArray(item) && item.length) { + item = item[0]; + } item.id = item._id; delete item._id; return item; } - function toMongo(item) { delete item.id; return item; } // [END translate] - function getCollection(cb) { if (collection) { - setImmediate(function() { cb(null, collection); }); + setImmediate(function () { cb(null, collection); }); return; } - MongoClient.connect(url, function(err, db) { + MongoClient.connect(url, function (err, db) { if (err) { - console.log(err); return cb(err); } collection = db.collection(collectionName); @@ -55,16 +52,18 @@ module.exports = function(config) { }); } - // [START list] function list(limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { if (err) { return cb(err); } collection.find({}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -74,12 +73,11 @@ module.exports = function(config) { } // [END list] - // [START create] function create(data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.insert(data, {w: 1}, function(err, result) { + collection.insert(data, {w: 1}, function (err, result) { if (err) { return cb(err); } var item = fromMongo(result.ops); cb(null, item); @@ -88,13 +86,12 @@ module.exports = function(config) { } // [END create] - function read(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.findOne({ _id: new ObjectID(id) - }, function(err, result) { + }, function (err, result) { if (err) { return cb(err); } if (!result) { return cb({ @@ -107,18 +104,15 @@ module.exports = function(config) { }); } - // [START update] function update(id, data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.update({ - _id: new ObjectID(id) - }, { - '$set': toMongo(data) - }, - {w: 1}, - function(err) { + collection.update( + { _id: new ObjectID(id) }, + { '$set': toMongo(data) }, + { w: 1 }, + function (err) { if (err) { return cb(err); } return read(id, cb); } @@ -127,9 +121,8 @@ module.exports = function(config) { } // [END update] - function _delete(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.remove({ _id: new ObjectID(id) @@ -144,5 +137,4 @@ module.exports = function(config) { delete: _delete, list: list }; - }; diff --git a/2-structured-data/package.json b/2-structured-data/package.json index d7c11a96f0..a9a0474a9a 100644 --- a/2-structured-data/package.json +++ b/2-structured-data/package.json @@ -30,20 +30,20 @@ ], "license": "Apache Version 2.0", "dependencies": { - "body-parser": "^1.14.2", + "body-parser": "^1.15.0", "express": "^4.13.4", - "gcloud": "^0.27.0", + "gcloud": "^0.28.0", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.2.1", - "mongodb": "^2.1.4", + "lodash": "^4.5.1", + "mongodb": "^2.1.7", "mysql": "^2.10.2", - "prompt": "^0.2.14" + "prompt": "^1.0.0" }, "devDependencies": { "jshint": "^2.9.1", "mocha": "^2.4.5", - "supertest": "^1.1.0" + "supertest": "^1.2.0" }, "engines": { "node": ">=0.12.7" diff --git a/2-structured-data/test/crud.test.js b/2-structured-data/test/crud.test.js index a62be1c4ec..0ad65d9d81 100644 --- a/2-structured-data/test/crud.test.js +++ b/2-structured-data/test/crud.test.js @@ -48,20 +48,10 @@ describe('crud.js', function () { }); it('should handle error', function (done) { - var expected = 'Bad Request'; - if (process.version.indexOf('v0.10') !== -1) { - expected = 'Error during request.'; - } - if (require('../config')().dataBackend === 'cloudsql') { - expected = 'ER_SP_UNDECLARED_VAR: Undeclared variable: NaN'; - } request(proxyquire('../app', stubs)) .get('/books') .query({ pageToken: 'badrequest' }) .expect(500) - .expect(function (response) { - assert.ok(response.text.indexOf(expected) !== -1); - }) .end(done); }); @@ -88,7 +78,12 @@ describe('crud.js', function () { .expect(302) .expect(function (response) { var location = response.headers.location; - id = parseInt(location.replace('/books/', ''), 10); + var idPart = location.replace('/books/', ''); + if (require('../config')().dataBackend !== 'mongodb') { + id = parseInt(idPart, 10); + } else { + id = idPart; + } assert.ok(response.text.indexOf('Redirecting to /books/') !== -1); }) .end(done); diff --git a/3-binary-data/books/api.js b/3-binary-data/books/api.js index 0322929233..6233cc49b2 100644 --- a/3-binary-data/books/api.js +++ b/3-binary-data/books/api.js @@ -55,7 +55,7 @@ module.exports = function (model) { * * Retrieve a book. */ - router.get('/:book(\\d+)', function get(req, res, next) { + router.get('/:book', function get(req, res, next) { model.read(req.params.book, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -67,7 +67,7 @@ module.exports = function (model) { * * Update a book. */ - router.put('/:book(\\d+)', function update(req, res, next) { + router.put('/:book', function update(req, res, next) { model.update(req.params.book, req.body, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -79,7 +79,7 @@ module.exports = function (model) { * * Delete a book. */ - router.delete('/:book(\\d+)', function _delete(req, res, next) { + router.delete('/:book', function _delete(req, res, next) { model.delete(req.params.book, function (err) { if (err) { return next(err); } res.status(200).send('OK'); diff --git a/3-binary-data/books/model-mongodb.js b/3-binary-data/books/model-mongodb.js index fd811e45db..a8edfbb1d9 100644 --- a/3-binary-data/books/model-mongodb.js +++ b/3-binary-data/books/model-mongodb.js @@ -16,34 +16,32 @@ var MongoClient = require('mongodb').MongoClient; var ObjectID = require('mongodb').ObjectID; - -module.exports = function(config) { +module.exports = function (config) { var url = config.mongodb.url; var collectionName = config.mongodb.collection; var collection; - function fromMongo(item) { - if (item.length) { item = item.pop(); } + if (Array.isArray(item) && item.length) { + item = item[0]; + } item.id = item._id; delete item._id; return item; } - function toMongo(item) { delete item.id; return item; } - function getCollection(cb) { if (collection) { - setImmediate(function() { cb(null, collection); }); + setImmediate(function () { cb(null, collection); }); return; } - MongoClient.connect(url, function(err, db) { + MongoClient.connect(url, function (err, db) { if (err) { console.log(err); return cb(err); @@ -53,15 +51,17 @@ module.exports = function(config) { }); } - function list(limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { if (err) { return cb(err); } collection.find({}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -70,11 +70,10 @@ module.exports = function(config) { }); } - function create(data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.insert(data, {w: 1}, function(err, result) { + collection.insert(data, {w: 1}, function (err, result) { if (err) { return cb(err); } var item = fromMongo(result.ops); cb(null, item); @@ -82,13 +81,12 @@ module.exports = function(config) { }); } - function read(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.findOne({ _id: new ObjectID(id) - }, function(err, result) { + }, function (err, result) { if (err) { return cb(err); } if (!result) { return cb({ @@ -101,17 +99,14 @@ module.exports = function(config) { }); } - function update(id, data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.update({ - _id: new ObjectID(id) - }, { - '$set': toMongo(data) - }, - {w: 1}, - function(err) { + collection.update( + { _id: new ObjectID(id) }, + { '$set': toMongo(data) }, + { w: 1 }, + function (err) { if (err) { return cb(err); } return read(id, cb); } @@ -119,9 +114,8 @@ module.exports = function(config) { }); } - function _delete(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.remove({ _id: new ObjectID(id) @@ -136,5 +130,4 @@ module.exports = function(config) { delete: _delete, list: list }; - }; diff --git a/3-binary-data/package.json b/3-binary-data/package.json index bce97aa2ff..b3d783c007 100644 --- a/3-binary-data/package.json +++ b/3-binary-data/package.json @@ -30,21 +30,21 @@ ], "license": "Apache Version 2.0", "dependencies": { - "body-parser": "^1.14.2", + "body-parser": "^1.15.0", "express": "^4.13.4", - "gcloud": "^0.27.0", + "gcloud": "^0.28.0", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.2.1", - "mongodb": "^2.1.4", + "lodash": "^4.5.1", + "mongodb": "^2.1.7", "multer": "^1.1.0", "mysql": "^2.10.2", - "prompt": "^0.2.14" + "prompt": "^1.0.0" }, "devDependencies": { "jshint": "^2.9.1", "mocha": "^2.4.5", - "supertest": "^1.1.0" + "supertest": "^1.2.0" }, "engines": { "node": ">=0.12.7" diff --git a/3-binary-data/test/crud.test.js b/3-binary-data/test/crud.test.js index ed3b145fc9..95cad589a4 100644 --- a/3-binary-data/test/crud.test.js +++ b/3-binary-data/test/crud.test.js @@ -48,20 +48,10 @@ describe('crud.js', function () { }); it('should handle error', function (done) { - var expected = 'Bad Request'; - if (process.version.indexOf('v0.10') !== -1) { - expected = 'Error during request.'; - } - if (require('../config')().dataBackend === 'cloudsql') { - expected = 'ER_SP_UNDECLARED_VAR: Undeclared variable: NaN'; - } request(proxyquire('../app', stubs)) .get('/books') .query({ pageToken: 'badrequest' }) .expect(500) - .expect(function (response) { - assert.ok(response.text.indexOf(expected) !== -1); - }) .end(done); }); @@ -88,7 +78,12 @@ describe('crud.js', function () { .expect(302) .expect(function (response) { var location = response.headers.location; - id = parseInt(location.replace('/books/', ''), 10); + var idPart = location.replace('/books/', ''); + if (require('../config')().dataBackend !== 'mongodb') { + id = parseInt(idPart, 10); + } else { + id = idPart; + } assert.ok(response.text.indexOf('Redirecting to /books/') !== -1); }) .end(done); diff --git a/4-auth/books/api.js b/4-auth/books/api.js index 0322929233..6233cc49b2 100644 --- a/4-auth/books/api.js +++ b/4-auth/books/api.js @@ -55,7 +55,7 @@ module.exports = function (model) { * * Retrieve a book. */ - router.get('/:book(\\d+)', function get(req, res, next) { + router.get('/:book', function get(req, res, next) { model.read(req.params.book, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -67,7 +67,7 @@ module.exports = function (model) { * * Update a book. */ - router.put('/:book(\\d+)', function update(req, res, next) { + router.put('/:book', function update(req, res, next) { model.update(req.params.book, req.body, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -79,7 +79,7 @@ module.exports = function (model) { * * Delete a book. */ - router.delete('/:book(\\d+)', function _delete(req, res, next) { + router.delete('/:book', function _delete(req, res, next) { model.delete(req.params.book, function (err) { if (err) { return next(err); } res.status(200).send('OK'); diff --git a/4-auth/books/model-mongodb.js b/4-auth/books/model-mongodb.js index 216def4058..dfe01009ed 100644 --- a/4-auth/books/model-mongodb.js +++ b/4-auth/books/model-mongodb.js @@ -16,34 +16,32 @@ var MongoClient = require('mongodb').MongoClient; var ObjectID = require('mongodb').ObjectID; - -module.exports = function(config) { +module.exports = function (config) { var url = config.mongodb.url; var collectionName = config.mongodb.collection; var collection; - function fromMongo(item) { - if (item.length) { item = item.pop(); } + if (Array.isArray(item) && item.length) { + item = item[0]; + } item.id = item._id; delete item._id; return item; } - function toMongo(item) { delete item.id; return item; } - function getCollection(cb) { if (collection) { - setImmediate(function() { cb(null, collection); }); + setImmediate(function () { cb(null, collection); }); return; } - MongoClient.connect(url, function(err, db) { + MongoClient.connect(url, function (err, db) { if (err) { console.log(err); return cb(err); @@ -53,15 +51,17 @@ module.exports = function(config) { }); } - function list(limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { if (err) { return cb(err); } collection.find({}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -70,15 +70,17 @@ module.exports = function(config) { }); } - // [START listby] function listBy(userid, limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { collection.find({createdById: userid}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -88,11 +90,10 @@ module.exports = function(config) { } // [END listby] - function create(data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.insert(data, {w: 1}, function(err, result) { + collection.insert(data, {w: 1}, function (err, result) { if (err) { return cb(err); } var item = fromMongo(result.ops); cb(null, item); @@ -100,13 +101,12 @@ module.exports = function(config) { }); } - function read(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.findOne({ _id: new ObjectID(id) - }, function(err, result) { + }, function (err, result) { if (err) { return cb(err); } if (!result) { return cb({ @@ -119,17 +119,14 @@ module.exports = function(config) { }); } - function update(id, data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.update({ - _id: new ObjectID(id) - }, { - '$set': toMongo(data) - }, - {w: 1}, - function(err) { + collection.update( + { _id: new ObjectID(id) }, + { '$set': toMongo(data) }, + { w: 1 }, + function (err) { if (err) { return cb(err); } return read(id, cb); } @@ -137,9 +134,8 @@ module.exports = function(config) { }); } - function _delete(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.remove({ _id: new ObjectID(id) @@ -155,5 +151,4 @@ module.exports = function(config) { list: list, listBy: listBy }; - }; diff --git a/4-auth/package.json b/4-auth/package.json index a64e476378..96e651cbe4 100644 --- a/4-auth/package.json +++ b/4-auth/package.json @@ -31,23 +31,23 @@ "license": "Apache Version 2.0", "dependencies": { "async": "^1.5.2", - "body-parser": "^1.14.2", + "body-parser": "^1.15.0", "cookie-session": "^2.0.0-alpha.1", "express": "^4.13.4", - "gcloud": "^0.27.0", + "gcloud": "^0.28.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.2.1", - "mongodb": "^2.1.4", + "lodash": "^4.5.1", + "mongodb": "^2.1.7", "multer": "^1.1.0", "mysql": "^2.10.2", - "prompt": "^0.2.14" + "prompt": "^1.0.0" }, "devDependencies": { "jshint": "^2.9.1", "mocha": "^2.4.5", - "supertest": "^1.1.0" + "supertest": "^1.2.0" }, "engines": { "node": ">=0.12.7" diff --git a/4-auth/test/crud.test.js b/4-auth/test/crud.test.js index ed3b145fc9..95cad589a4 100644 --- a/4-auth/test/crud.test.js +++ b/4-auth/test/crud.test.js @@ -48,20 +48,10 @@ describe('crud.js', function () { }); it('should handle error', function (done) { - var expected = 'Bad Request'; - if (process.version.indexOf('v0.10') !== -1) { - expected = 'Error during request.'; - } - if (require('../config')().dataBackend === 'cloudsql') { - expected = 'ER_SP_UNDECLARED_VAR: Undeclared variable: NaN'; - } request(proxyquire('../app', stubs)) .get('/books') .query({ pageToken: 'badrequest' }) .expect(500) - .expect(function (response) { - assert.ok(response.text.indexOf(expected) !== -1); - }) .end(done); }); @@ -88,7 +78,12 @@ describe('crud.js', function () { .expect(302) .expect(function (response) { var location = response.headers.location; - id = parseInt(location.replace('/books/', ''), 10); + var idPart = location.replace('/books/', ''); + if (require('../config')().dataBackend !== 'mongodb') { + id = parseInt(idPart, 10); + } else { + id = idPart; + } assert.ok(response.text.indexOf('Redirecting to /books/') !== -1); }) .end(done); diff --git a/5-logging/books/api.js b/5-logging/books/api.js index 0322929233..6233cc49b2 100644 --- a/5-logging/books/api.js +++ b/5-logging/books/api.js @@ -55,7 +55,7 @@ module.exports = function (model) { * * Retrieve a book. */ - router.get('/:book(\\d+)', function get(req, res, next) { + router.get('/:book', function get(req, res, next) { model.read(req.params.book, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -67,7 +67,7 @@ module.exports = function (model) { * * Update a book. */ - router.put('/:book(\\d+)', function update(req, res, next) { + router.put('/:book', function update(req, res, next) { model.update(req.params.book, req.body, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -79,7 +79,7 @@ module.exports = function (model) { * * Delete a book. */ - router.delete('/:book(\\d+)', function _delete(req, res, next) { + router.delete('/:book', function _delete(req, res, next) { model.delete(req.params.book, function (err) { if (err) { return next(err); } res.status(200).send('OK'); diff --git a/5-logging/books/model-mongodb.js b/5-logging/books/model-mongodb.js index a0a8a98754..1280ebc3fd 100644 --- a/5-logging/books/model-mongodb.js +++ b/5-logging/books/model-mongodb.js @@ -16,36 +16,33 @@ var MongoClient = require('mongodb').MongoClient; var ObjectID = require('mongodb').ObjectID; - -module.exports = function(config) { +module.exports = function (config) { var url = config.mongodb.url; var collectionName = config.mongodb.collection; var collection; - function fromMongo(item) { - if (item.length) { item = item.pop(); } + if (Array.isArray(item) && item.length) { + item = item[0]; + } item.id = item._id; delete item._id; return item; } - function toMongo(item) { delete item.id; return item; } - function getCollection(cb) { if (collection) { - setImmediate(function() { cb(null, collection); }); + setImmediate(function () { cb(null, collection); }); return; } - MongoClient.connect(url, function(err, db) { + MongoClient.connect(url, function (err, db) { if (err) { - console.log(err); return cb(err); } collection = db.collection(collectionName); @@ -56,12 +53,15 @@ module.exports = function(config) { function list(limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { if (err) { return cb(err); } collection.find({}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -73,11 +73,14 @@ module.exports = function(config) { function listBy(userid, limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { collection.find({createdById: userid}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -88,9 +91,9 @@ module.exports = function(config) { function create(data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.insert(data, {w: 1}, function(err, result) { + collection.insert(data, {w: 1}, function (err, result) { if (err) { return cb(err); } var item = fromMongo(result.ops); cb(null, item); @@ -100,11 +103,11 @@ module.exports = function(config) { function read(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.findOne({ _id: new ObjectID(id) - }, function(err, result) { + }, function (err, result) { if (err) { return cb(err); } if (!result) { return cb({ @@ -119,15 +122,13 @@ module.exports = function(config) { function update(id, data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.update({ - _id: new ObjectID(id) - }, { - '$set': toMongo(data) - }, - {w: 1}, - function(err) { + collection.update( + { _id: new ObjectID(id) }, + { '$set': toMongo(data) }, + { w: 1 }, + function (err) { if (err) { return cb(err); } return read(id, cb); } @@ -137,7 +138,7 @@ module.exports = function(config) { function _delete(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.remove({ _id: new ObjectID(id) @@ -153,5 +154,4 @@ module.exports = function(config) { list: list, listBy: listBy }; - }; diff --git a/5-logging/package.json b/5-logging/package.json index f84fc55dfb..42fa55d8fe 100644 --- a/5-logging/package.json +++ b/5-logging/package.json @@ -31,25 +31,25 @@ "license": "Apache Version 2.0", "dependencies": { "async": "^1.5.2", - "body-parser": "^1.14.2", + "body-parser": "^1.15.0", "cookie-session": "^2.0.0-alpha.1", "express": "^4.13.4", "express-winston": "^1.2.0", - "gcloud": "^0.27.0", + "gcloud": "^0.28.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.2.1", - "mongodb": "^2.1.4", + "lodash": "^4.5.1", + "mongodb": "^2.1.7", "multer": "^1.1.0", "mysql": "^2.10.2", - "prompt": "^0.2.14", + "prompt": "^1.0.0", "winston": "^2.1.1" }, "devDependencies": { "jshint": "^2.9.1", "mocha": "^2.4.5", - "supertest": "^1.1.0" + "supertest": "^1.2.0" }, "engines": { "node": ">=0.12.7" diff --git a/5-logging/test/crud.test.js b/5-logging/test/crud.test.js index ed3b145fc9..95cad589a4 100644 --- a/5-logging/test/crud.test.js +++ b/5-logging/test/crud.test.js @@ -48,20 +48,10 @@ describe('crud.js', function () { }); it('should handle error', function (done) { - var expected = 'Bad Request'; - if (process.version.indexOf('v0.10') !== -1) { - expected = 'Error during request.'; - } - if (require('../config')().dataBackend === 'cloudsql') { - expected = 'ER_SP_UNDECLARED_VAR: Undeclared variable: NaN'; - } request(proxyquire('../app', stubs)) .get('/books') .query({ pageToken: 'badrequest' }) .expect(500) - .expect(function (response) { - assert.ok(response.text.indexOf(expected) !== -1); - }) .end(done); }); @@ -88,7 +78,12 @@ describe('crud.js', function () { .expect(302) .expect(function (response) { var location = response.headers.location; - id = parseInt(location.replace('/books/', ''), 10); + var idPart = location.replace('/books/', ''); + if (require('../config')().dataBackend !== 'mongodb') { + id = parseInt(idPart, 10); + } else { + id = idPart; + } assert.ok(response.text.indexOf('Redirecting to /books/') !== -1); }) .end(done); diff --git a/6-pubsub/books/api.js b/6-pubsub/books/api.js index 0322929233..6233cc49b2 100644 --- a/6-pubsub/books/api.js +++ b/6-pubsub/books/api.js @@ -55,7 +55,7 @@ module.exports = function (model) { * * Retrieve a book. */ - router.get('/:book(\\d+)', function get(req, res, next) { + router.get('/:book', function get(req, res, next) { model.read(req.params.book, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -67,7 +67,7 @@ module.exports = function (model) { * * Update a book. */ - router.put('/:book(\\d+)', function update(req, res, next) { + router.put('/:book', function update(req, res, next) { model.update(req.params.book, req.body, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -79,7 +79,7 @@ module.exports = function (model) { * * Delete a book. */ - router.delete('/:book(\\d+)', function _delete(req, res, next) { + router.delete('/:book', function _delete(req, res, next) { model.delete(req.params.book, function (err) { if (err) { return next(err); } res.status(200).send('OK'); diff --git a/6-pubsub/books/model-mongodb.js b/6-pubsub/books/model-mongodb.js index a5a084281b..aa2a8b0fe8 100644 --- a/6-pubsub/books/model-mongodb.js +++ b/6-pubsub/books/model-mongodb.js @@ -23,7 +23,9 @@ module.exports = function (config, background) { var collection; function fromMongo(item) { - if (item.length) { item = item.pop(); } + if (Array.isArray(item) && item.length) { + item = item[0]; + } item.id = item._id; delete item._id; return item; @@ -36,12 +38,11 @@ module.exports = function (config, background) { function getCollection(cb) { if (collection) { - setImmediate(function() { cb(null, collection); }); + setImmediate(function () { cb(null, collection); }); return; } - MongoClient.connect(url, function(err, db) { + MongoClient.connect(url, function (err, db) { if (err) { - console.log(err); return cb(err); } collection = db.collection(collectionName); @@ -51,12 +52,15 @@ module.exports = function (config, background) { function list(limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { if (err) { return cb(err); } collection.find({}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -67,11 +71,14 @@ module.exports = function (config, background) { function listBy(userid, limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { collection.find({createdById: userid}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -82,9 +89,9 @@ module.exports = function (config, background) { // [START create] function create(data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.insert(data, {w: 1}, function(err, result) { + collection.insert(data, {w: 1}, function (err, result) { if (err) { return cb(err); } var item = fromMongo(result.ops); background.queueBook(item.id); @@ -95,11 +102,11 @@ module.exports = function (config, background) { // [END create] function read(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.findOne({ _id: new ObjectID(id) - }, function(err, result) { + }, function (err, result) { if (err) { return cb(err); } if (!result) { return cb({ @@ -114,15 +121,13 @@ module.exports = function (config, background) { // [START update] function update(id, data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.update({ - _id: new ObjectID(id) - }, { - '$set': toMongo(data) - }, - {w: 1}, - function(err) { + collection.update( + { _id: new ObjectID(id) }, + { '$set': toMongo(data) }, + { w: 1 }, + function (err) { if (err) { return cb(err); } background.queueBook(id); return read(id, cb); @@ -133,7 +138,7 @@ module.exports = function (config, background) { // [END update] function _delete(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.remove({ _id: new ObjectID(id) diff --git a/6-pubsub/package.json b/6-pubsub/package.json index 6dbda5a1c2..fc88a3d9d4 100644 --- a/6-pubsub/package.json +++ b/6-pubsub/package.json @@ -31,19 +31,19 @@ "license": "Apache Version 2.0", "dependencies": { "async": "^1.5.2", - "body-parser": "^1.14.2", + "body-parser": "^1.15.0", "cookie-session": "^2.0.0-alpha.1", "express": "^4.13.4", "express-winston": "^1.2.0", - "gcloud": "^0.27.0", + "gcloud": "^0.28.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.2.1", - "mongodb": "^2.1.4", + "lodash": "^4.5.1", + "mongodb": "^2.1.7", "multer": "^1.1.0", "mysql": "^2.10.2", - "prompt": "^0.2.14", + "prompt": "^1.0.0", "request": "^2.69.0", "winston": "^2.1.1" }, @@ -52,7 +52,7 @@ "mocha": "^2.4.5", "proxyquire": "^1.7.4", "sinon": "^1.17.3", - "supertest": "^1.1.0" + "supertest": "^1.2.0" }, "engines": { "node": ">=0.12.7" diff --git a/6-pubsub/test/crud.test.js b/6-pubsub/test/crud.test.js index ed3b145fc9..95cad589a4 100644 --- a/6-pubsub/test/crud.test.js +++ b/6-pubsub/test/crud.test.js @@ -48,20 +48,10 @@ describe('crud.js', function () { }); it('should handle error', function (done) { - var expected = 'Bad Request'; - if (process.version.indexOf('v0.10') !== -1) { - expected = 'Error during request.'; - } - if (require('../config')().dataBackend === 'cloudsql') { - expected = 'ER_SP_UNDECLARED_VAR: Undeclared variable: NaN'; - } request(proxyquire('../app', stubs)) .get('/books') .query({ pageToken: 'badrequest' }) .expect(500) - .expect(function (response) { - assert.ok(response.text.indexOf(expected) !== -1); - }) .end(done); }); @@ -88,7 +78,12 @@ describe('crud.js', function () { .expect(302) .expect(function (response) { var location = response.headers.location; - id = parseInt(location.replace('/books/', ''), 10); + var idPart = location.replace('/books/', ''); + if (require('../config')().dataBackend !== 'mongodb') { + id = parseInt(idPart, 10); + } else { + id = idPart; + } assert.ok(response.text.indexOf('Redirecting to /books/') !== -1); }) .end(done); diff --git a/7-gce/books/api.js b/7-gce/books/api.js index 0322929233..6233cc49b2 100644 --- a/7-gce/books/api.js +++ b/7-gce/books/api.js @@ -55,7 +55,7 @@ module.exports = function (model) { * * Retrieve a book. */ - router.get('/:book(\\d+)', function get(req, res, next) { + router.get('/:book', function get(req, res, next) { model.read(req.params.book, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -67,7 +67,7 @@ module.exports = function (model) { * * Update a book. */ - router.put('/:book(\\d+)', function update(req, res, next) { + router.put('/:book', function update(req, res, next) { model.update(req.params.book, req.body, function (err, entity) { if (err) { return next(err); } res.json(entity); @@ -79,7 +79,7 @@ module.exports = function (model) { * * Delete a book. */ - router.delete('/:book(\\d+)', function _delete(req, res, next) { + router.delete('/:book', function _delete(req, res, next) { model.delete(req.params.book, function (err) { if (err) { return next(err); } res.status(200).send('OK'); diff --git a/7-gce/books/model-mongodb.js b/7-gce/books/model-mongodb.js index c76d5e5932..621f10b95a 100644 --- a/7-gce/books/model-mongodb.js +++ b/7-gce/books/model-mongodb.js @@ -23,7 +23,9 @@ module.exports = function (config, background) { var collection; function fromMongo(item) { - if (item.length) { item = item.pop(); } + if (Array.isArray(item) && item.length) { + item = item[0]; + } item.id = item._id; delete item._id; return item; @@ -36,12 +38,11 @@ module.exports = function (config, background) { function getCollection(cb) { if (collection) { - setImmediate(function() { cb(null, collection); }); + setImmediate(function () { cb(null, collection); }); return; } - MongoClient.connect(url, function(err, db) { + MongoClient.connect(url, function (err, db) { if (err) { - console.log(err); return cb(err); } collection = db.collection(collectionName); @@ -51,12 +52,15 @@ module.exports = function (config, background) { function list(limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { if (err) { return cb(err); } collection.find({}) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -67,11 +71,14 @@ module.exports = function (config, background) { function listBy(userid, limit, token, cb) { token = token ? parseInt(token, 10) : 0; - getCollection(function(err, collection) { - collection.find({createdById: userid}) + if (isNaN(token)) { + return cb(new Error('invalid token')); + } + getCollection(function (err, collection) { + collection.find({ createdById: userid }) .skip(token) .limit(limit) - .toArray(function(err, results) { + .toArray(function (err, results) { if (err) { return cb(err); } var hasMore = results.length === limit ? token + results.length : false; @@ -81,9 +88,9 @@ module.exports = function (config, background) { } function create(data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.insert(data, {w: 1}, function(err, result) { + collection.insert(data, {w: 1}, function (err, result) { if (err) { return cb(err); } var item = fromMongo(result.ops); background.queueBook(item.id); @@ -93,11 +100,11 @@ module.exports = function (config, background) { } function read(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.findOne({ _id: new ObjectID(id) - }, function(err, result) { + }, function (err, result) { if (err) { return cb(err); } if (!result) { return cb({ @@ -111,15 +118,13 @@ module.exports = function (config, background) { } function update(id, data, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } - collection.update({ - _id: new ObjectID(id) - }, { - '$set': toMongo(data) - }, - {w: 1}, - function(err) { + collection.update( + { _id: new ObjectID(id) }, + { '$set': toMongo(data) }, + { w: 1 }, + function (err) { if (err) { return cb(err); } background.queueBook(id); return read(id, cb); @@ -129,7 +134,7 @@ module.exports = function (config, background) { } function _delete(id, cb) { - getCollection(function(err, collection) { + getCollection(function (err, collection) { if (err) { return cb(err); } collection.remove({ _id: new ObjectID(id) diff --git a/7-gce/package.json b/7-gce/package.json index 6dbda5a1c2..fc88a3d9d4 100644 --- a/7-gce/package.json +++ b/7-gce/package.json @@ -31,19 +31,19 @@ "license": "Apache Version 2.0", "dependencies": { "async": "^1.5.2", - "body-parser": "^1.14.2", + "body-parser": "^1.15.0", "cookie-session": "^2.0.0-alpha.1", "express": "^4.13.4", "express-winston": "^1.2.0", - "gcloud": "^0.27.0", + "gcloud": "^0.28.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.2.1", - "mongodb": "^2.1.4", + "lodash": "^4.5.1", + "mongodb": "^2.1.7", "multer": "^1.1.0", "mysql": "^2.10.2", - "prompt": "^0.2.14", + "prompt": "^1.0.0", "request": "^2.69.0", "winston": "^2.1.1" }, @@ -52,7 +52,7 @@ "mocha": "^2.4.5", "proxyquire": "^1.7.4", "sinon": "^1.17.3", - "supertest": "^1.1.0" + "supertest": "^1.2.0" }, "engines": { "node": ">=0.12.7" diff --git a/7-gce/test/crud.test.js b/7-gce/test/crud.test.js index ed3b145fc9..95cad589a4 100644 --- a/7-gce/test/crud.test.js +++ b/7-gce/test/crud.test.js @@ -48,20 +48,10 @@ describe('crud.js', function () { }); it('should handle error', function (done) { - var expected = 'Bad Request'; - if (process.version.indexOf('v0.10') !== -1) { - expected = 'Error during request.'; - } - if (require('../config')().dataBackend === 'cloudsql') { - expected = 'ER_SP_UNDECLARED_VAR: Undeclared variable: NaN'; - } request(proxyquire('../app', stubs)) .get('/books') .query({ pageToken: 'badrequest' }) .expect(500) - .expect(function (response) { - assert.ok(response.text.indexOf(expected) !== -1); - }) .end(done); }); @@ -88,7 +78,12 @@ describe('crud.js', function () { .expect(302) .expect(function (response) { var location = response.headers.location; - id = parseInt(location.replace('/books/', ''), 10); + var idPart = location.replace('/books/', ''); + if (require('../config')().dataBackend !== 'mongodb') { + id = parseInt(idPart, 10); + } else { + id = idPart; + } assert.ok(response.text.indexOf('Redirecting to /books/') !== -1); }) .end(done); diff --git a/package.json b/package.json index 0833e035a5..60f4f79c0a 100644 --- a/package.json +++ b/package.json @@ -37,11 +37,11 @@ "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.5.0", + "lodash": "^4.5.1", "mongodb": "^2.1.7", "multer": "^1.1.0", "mysql": "^2.10.2", - "prompt": "^0.2.14", + "prompt": "^1.0.0", "request": "^2.69.0", "winston": "^2.1.1" }, diff --git a/test/index.js b/test/index.js index a552c1e98e..dc75e0b3e8 100644 --- a/test/index.js +++ b/test/index.js @@ -13,8 +13,10 @@ 'use strict'; - var proxyquire = require('proxyquire').noPreserveCache(); - var stubs = {}; +var proxyquire = require('proxyquire').noPreserveCache(); +var stubs = {}; + +var MongoClient = require('mongodb').MongoClient; // Test Datastore describe('using Datastore backend', function () { @@ -46,3 +48,27 @@ describe('using Cloud SQL backend', function () { proxyquire('../6-pubsub/test', stubs); proxyquire('../7-gce/test', stubs); }); + +// Test MongoDB +describe('using MongoDB backend', function () { + before(function () { + process.env.BACKEND = 'mongodb'; + }); + proxyquire('../2-structured-data/test', stubs); + proxyquire('../3-binary-data/test', stubs); + proxyquire('../4-auth/test', stubs); + proxyquire('../5-logging/test', stubs); + proxyquire('../6-pubsub/test', stubs); + proxyquire('../7-gce/test', stubs); + after(function (done) { + var config = proxyquire('../7-gce/config', stubs)(); + MongoClient.connect(config.mongodb.url, function (err, db) { + if (err) { + return done(err); + } + db.collection(config.mongodb.collection).remove(function (err) { + done(err); + }); + }); + }); +});