diff --git a/package.json b/package.json index 45b6e9a..3f308ad 100644 --- a/package.json +++ b/package.json @@ -16,15 +16,15 @@ "errorhandler": "^1.2.0", "express": "^4.9.5", "got": "^3.3.0", - "lodash": "^3.9.2", - "lowdb": "^0.10.0", + "lodash": "^4.11.2", + "lowdb": "^0.13.0-beta.2", "method-override": "^2.1.2", "morgan": "^1.3.1", "node-uuid": "^1.4.2", "object-assign": "^4.0.1", "pluralize": "^1.1.2", "server-destroy": "^1.0.1", - "underscore-db": "^0.9.1", + "underscore-db": "^0.10.0", "update-notifier": "^0.5.0", "yargs": "^4.2.0" }, diff --git a/src/cli/run.js b/src/cli/run.js index 3987306..d35e1de 100644 --- a/src/cli/run.js +++ b/src/cli/run.js @@ -136,8 +136,12 @@ module.exports = function (argv) { if (chunk.trim().toLowerCase() === 's') { var filename = 'db-' + Date.now() + '.json' var file = path.join(argv.snapshots, filename) - app.db.saveSync(file) - console.log(' Saved snapshot to ' + path.relative(process.cwd(), file) + '\n') + app + .db + .write(file) + .then(function () { + console.log(' Saved snapshot to ' + path.relative(process.cwd(), file) + '\n') + }) } }) diff --git a/src/cli/utils/load.js b/src/cli/utils/load.js index 5b1dcfa..5fd15f9 100644 --- a/src/cli/utils/load.js +++ b/src/cli/utils/load.js @@ -1,6 +1,7 @@ var path = require('path') var got = require('got') var low = require('lowdb') +var fileAsync = require('lowdb/lib/file-async') var is = require('./is') module.exports = function (source, cb) { @@ -27,7 +28,7 @@ module.exports = function (source, cb) { } else if (is.JSON(source)) { - data = low(source).object + data = low(source, { storage: fileAsync }).object cb(null, data) } else { diff --git a/src/server/mixins.js b/src/server/mixins.js index b2dca69..43dab7f 100644 --- a/src/server/mixins.js +++ b/src/server/mixins.js @@ -41,7 +41,7 @@ function createId (coll) { if (_.isEmpty(coll)) { return 1 } else { - var id = _.max(coll, function (doc) { + var id = _.maxBy(coll, function (doc) { return doc[idProperty] })[idProperty] diff --git a/src/server/router/index.js b/src/server/router/index.js index cfa9859..9fcb3cb 100644 --- a/src/server/router/index.js +++ b/src/server/router/index.js @@ -4,6 +4,7 @@ var bodyParser = require('body-parser') var _ = require('lodash') var _db = require('underscore-db') var low = require('lowdb') +var fileAsync = require('lowdb/lib/file-async') var plural = require('./plural') var nested = require('./nested') var singular = require('./singular') @@ -23,9 +24,9 @@ module.exports = function (source) { var db if (_.isObject(source)) { db = low() - db.object = source + db.state(source) } else { - db = low(source) + db = low(source, { storage: fileAsync }) } // Add underscore-db methods to db @@ -44,7 +45,7 @@ module.exports = function (source) { // GET /db function showDatabase (req, res, next) { - res.locals.data = db.object + res.locals.data = db.state() next() } @@ -53,26 +54,24 @@ module.exports = function (source) { router.use(nested()) // Create routes - for (var prop in db.object) { - var val = db.object[prop] - - if (_.isPlainObject(val)) { - router.use('/' + prop, singular(db, prop)) - continue + db.forEach(function (value, key) { + if (_.isPlainObject(value)) { + router.use('/' + key, singular(db, key)) + return } - if (_.isArray(val)) { - router.use('/' + prop, plural(db, prop)) - continue + if (_.isArray(value)) { + router.use('/' + key, plural(db, key)) + return } var msg = - 'Type of "' + prop + '" (' + typeof val + ') ' + + 'Type of "' + key + '" (' + typeof value + ') ' + (_.isObject(source) ? '' : 'in ' + source) + ' is not supported. ' + 'Use objects or arrays of objects.' throw new Error(msg) - } + }).value() router.use(function (req, res) { if (!res.locals.data) { @@ -83,5 +82,10 @@ module.exports = function (source) { router.render(req, res) }) + router.use(function (err, req, res, next) { + console.error(err.stack) + res.status(500).send(err.stack) + }) + return router } diff --git a/src/server/router/plural.js b/src/server/router/plural.js index 706dc39..acdc1dd 100644 --- a/src/server/router/plural.js +++ b/src/server/router/plural.js @@ -12,11 +12,11 @@ module.exports = function (db, name) { function embed (resource, e) { e && [].concat(e) .forEach(function (externalResource) { - if (db.object[externalResource]) { + if (db.get(externalResource).value) { var query = {} var singularResource = pluralize.singular(name) query[singularResource + 'Id'] = resource.id - resource[externalResource] = db(externalResource).where(query) + resource[externalResource] = db.get(externalResource).filter(query).value() } }) } @@ -26,9 +26,9 @@ module.exports = function (db, name) { e && [].concat(e) .forEach(function (innerResource) { var plural = pluralize(innerResource) - if (db.object[plural]) { + if (db.get(plural).value()) { var prop = innerResource + 'Id' - resource[innerResource] = db(plural).getById(resource[prop]) + resource[innerResource] = db.get(plural).getById(resource[prop]).value() } }) } @@ -42,7 +42,7 @@ module.exports = function (db, name) { function list (req, res, next) { // Resource chain - var chain = db(name).chain() + var chain = db.get(name) // Remove q, _start, _end, ... from req.query to avoid filtering using those // parameters @@ -66,7 +66,7 @@ module.exports = function (db, name) { // Automatically delete query parameters that can't be found // in the database Object.keys(req.query).forEach(function (query) { - var arr = db(name).value() + var arr = db.get(name).value() for (var i in arr) { if ( _.has(arr[i], query) || @@ -183,7 +183,7 @@ module.exports = function (db, name) { var _embed = req.query._embed var _expand = req.query._expand var id = utils.toNative(req.params.id) - var resource = db(name).getById(id) + var resource = db.get(name).getById(id).value() if (resource) { // Clone resource to avoid making changes to the underlying object @@ -209,8 +209,9 @@ module.exports = function (db, name) { req.body[key] = utils.toNative(req.body[key]) } - var resource = db(name) + var resource = db.get(name) .insert(req.body) + .value() res.status(201) res.locals.data = resource @@ -225,10 +226,13 @@ module.exports = function (db, name) { } var id = utils.toNative(req.params.id) + var chain = db.get(name) - var resource = req.method === 'PATCH' ? - db(name).updateById(id, req.body) : - db(name).replaceById(id, req.body) + chain = req.method === 'PATCH' ? + chain.updateById(id, req.body) : + chain.replaceById(id, req.body) + + var resource = chain.value() if (resource) { res.locals.data = resource @@ -239,13 +243,13 @@ module.exports = function (db, name) { // DELETE /name/:id function destroy (req, res, next) { - var resource = db(name).removeById(utils.toNative(req.params.id)) + var resource = db.get(name).removeById(utils.toNative(req.params.id)).value() // Remove dependents documents - var removable = db._.getRemovable(db.object) + var removable = db._.getRemovable(db.state()) _.each(removable, function (item) { - db(item.name).removeById(item.id) + db.get(item.name).removeById(item.id).value() }) if (resource) { diff --git a/src/server/router/singular.js b/src/server/router/singular.js index 1bb8815..151abb9 100644 --- a/src/server/router/singular.js +++ b/src/server/router/singular.js @@ -5,27 +5,28 @@ module.exports = function (db, name) { var router = express.Router() function show (req, res, next) { - res.locals.data = db.object[name] + res.locals.data = db.get(name).value() next() } function create (req, res, next) { - res.locals.data = db.object[name] = req.body + db.set(name, req.body).value() + res.locals.data = db.get(name).value() res.status(201) next() } function update (req, res, next) { if (req.method === 'PUT') { - delete db.object[name] - db.object[name] = {} + db.set(name, req.body) + .value() + } else { + db.get(name) + .assign(req.body) + .value() } - for (var prop in req.body) { - db.object[name][prop] = req.body[prop] - } - - res.locals.data = db.object[name] + res.locals.data = db.get(name).value() next() } diff --git a/test/server/plural.js b/test/server/plural.js index 9db3f45..6b609a2 100644 --- a/test/server/plural.js +++ b/test/server/plural.js @@ -554,9 +554,9 @@ describe('Server', function () { }) - describe('Database #object', function () { + describe('Database state', function () { it('should be accessible', function () { - assert(router.db.object) + assert(router.db.state()) }) }) @@ -614,11 +614,11 @@ describe('Server', function () { describe('router.db._.id', function (done) { beforeEach(function () { - router.db.object = { + router.db.state({ posts: [ { _id: 1 } ] - } + }) router.db._.id = '_id' }) @@ -627,7 +627,7 @@ describe('Server', function () { request(server) .get('/posts/1') .expect('Content-Type', /json/) - .expect(router.db.object.posts[0]) + .expect(router.db.state().posts[0]) .expect(200, done) })