diff --git a/bin/index.js b/bin/index.js index 87b7314..2f122b3 100755 --- a/bin/index.js +++ b/bin/index.js @@ -32,6 +32,10 @@ var argv = yargs routes: { alias: 'r', description: 'Load routes file' + }, + id: { + description: 'Set database id property (e.g. _id)', + default: 'id' } }) .help('help').alias('help', 'h') @@ -118,6 +122,10 @@ function start (object, filename) { } server.use(router) + + // Custom id + router.db._.id = argv.id + server.listen(port, argv.host) } diff --git a/package.json b/package.json index 1bb2738..74b4e2b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "express": "^4.9.5", "got": "^1.2.2", "lodash": "^3.9.2", - "lowdb": "^0.9.0", + "lowdb": "^0.10.0", "method-override": "^2.1.2", "morgan": "^1.3.1", "node-uuid": "^1.4.2", diff --git a/src/mixins.js b/src/mixins.js new file mode 100644 index 0000000..b43b9e4 --- /dev/null +++ b/src/mixins.js @@ -0,0 +1,77 @@ +var uuid = require('node-uuid') +var pluralize = require('pluralize') + +module.exports = { + getRemovable: getRemovable, + createId: createId, + deepQuery: deepQuery +} + +// Returns document ids that have unsatisfied relations +// Example: a comment that references a post that doesn't exist +function getRemovable (db) { + var _ = this + var removable = [] + _.each(db, function (coll, collName) { + _.each(coll, function (doc) { + _.each(doc, function (value, key) { + if (/Id$/.test(key)) { + var refName = pluralize.plural(key.slice(0, -2)) + // Test if table exists + if (db[refName]) { + // Test if references is defined in table + var ref = _.getById(db[refName], value) + if (_.isUndefined(ref)) { + removable.push({name: collName, id: doc.id}) + } + } + } + }) + }) + }) + + return removable +} + +// Return incremented id or uuid +// Used to override underscore-db's createId with utils.createId +function createId (coll) { + var _ = this + var idProperty = _.__id() + if (_.isEmpty(coll)) { + return 1 + } else { + var id = _.max(coll, function (doc) { + return doc[idProperty] + })[idProperty] + + if (_.isFinite(id)) { + // Increment integer id + return ++id + } else { + // Generate string id + return uuid() + } + } +} + +function deepQuery (value, q) { + var _ = this + if (value && q) { + if (_.isArray(value)) { + for (var i = 0; i < value.length; i++) { + if (deepQuery(value[i], q)) { + return true + } + } + } else if (_.isObject(value) && !_.isArray(value)) { + for (var k in value) { + if (deepQuery(value[k], q)) { + return true + } + } + } else if (value.toString().toLowerCase().indexOf(q) !== -1) { + return true + } + } +} diff --git a/src/router.js b/src/router.js index 1b71942..5521180 100644 --- a/src/router.js +++ b/src/router.js @@ -6,6 +6,7 @@ var _db = require('underscore-db') var low = require('lowdb') var pluralize = require('pluralize') var utils = require('./utils') +var mixins = require('./mixins') module.exports = function (source) { // Create router @@ -26,11 +27,10 @@ module.exports = function (source) { } // Add underscore-db methods to db - db.mixin(_db) + db._.mixin(_db) - // Override underscore-db's createId with utils.createId - // utils.createId can generate incremental id or uuid - db.mixin({createId: utils.createId}) + // Add specific mixins + db._.mixin(mixins) // Expose database router.db = db @@ -86,7 +86,7 @@ module.exports = function (source) { array = db(req.params.resource).filter(function (obj) { for (var key in obj) { var value = obj[key] - if (utils.deepQuery(value, q)) { + if (db._.deepQuery(value, q)) { return true } } @@ -226,7 +226,7 @@ module.exports = function (source) { db(req.params.resource).removeById(utils.toNative(req.params.id)) // Remove dependents documents - var removable = utils.getRemovable(db.object) + var removable = db._.getRemovable(db.object) _.each(removable, function (item) { db(item.name).removeById(item.id) diff --git a/src/utils.js b/src/utils.js index 53a7811..397e2ff 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,6 +1,6 @@ -var _ = require('lodash') -var uuid = require('node-uuid') -var pluralize = require('pluralize') +module.exports = { + toNative: toNative +} // Turns string to native. // Example: @@ -20,74 +20,3 @@ function toNative (value) { } return value } - -// Return incremented id or uuid -function createId (coll) { - if (_.isEmpty(coll)) { - return 1 - } else { - var id = _.max(coll, function (doc) { - return doc.id - }).id - - if (_.isFinite(id)) { - // Increment integer id - return ++id - } else { - // Generate string id - return uuid() - } - } -} - -// Returns document ids that have unsatisfied relations -// Example: a comment that references a post that doesn't exist -function getRemovable (db) { - var removable = [] - _.each(db, function (coll, collName) { - _.each(coll, function (doc) { - _.each(doc, function (value, key) { - if (/Id$/.test(key)) { - var refName = pluralize.plural(key.slice(0, -2)) - // Test if table exists - if (db[refName]) { - // Test if references is defined in table - var ref = _.findWhere(db[refName], {id: value}) - if (_.isUndefined(ref)) { - removable.push({name: collName, id: doc.id}) - } - } - } - }) - }) - }) - - return removable -} - -function deepQuery (value, q) { - if (value && q) { - if (_.isArray(value)) { - for (var i = 0; i < value.length; i++) { - if (deepQuery(value[i], q)) { - return true - } - } - } else if (_.isObject(value) && !_.isArray(value)) { - for (var k in value) { - if (deepQuery(value[k], q)) { - return true - } - } - } else if (value.toString().toLowerCase().indexOf(q) !== -1) { - return true - } - } -} - -module.exports = { - toNative: toNative, - createId: createId, - getRemovable: getRemovable, - deepQuery: deepQuery -} diff --git a/test/index.js b/test/index.js index b7498a3..e793e8a 100644 --- a/test/index.js +++ b/test/index.js @@ -405,4 +405,26 @@ describe('Server', function () { }) }) + + describe('router.db._.id', function (done) { + + beforeEach(function () { + router.db.object = { + posts: [ + { _id: 1 } + ] + } + + router.db._.id = '_id' + }) + + it('should be possible to override id property', function (done) { + request(server) + .get('/posts/1') + .expect('Content-Type', /json/) + .expect(router.db.object.posts[0]) + .expect(200, done) + }) + + }) }) diff --git a/test/mixins.js b/test/mixins.js new file mode 100644 index 0000000..88210fb --- /dev/null +++ b/test/mixins.js @@ -0,0 +1,38 @@ +var assert = require('assert') +var mixins = require('../src/mixins') +var _ = require('lodash') +var _db = require('underscore-db') + +/* global describe, it */ + +describe('mixins', function () { + + describe('getRemovable', function () { + + it('should return removable documents', function () { + + var db = { + posts: [ + {id: 1, comment: 1} + ], + comments: [ + {id: 1, postId: 1}, + // Comments below references a post that doesn't exist + {id: 2, postId: 2}, + {id: 3, postId: 2} + ] + } + + var expected = [ + {name: 'comments', id: 2}, + {name: 'comments', id: 3} + ] + + _.mixin(_db) + _.mixin(mixins) + + assert.deepEqual(_.getRemovable(db), expected) + + }) + }) +}) diff --git a/test/utils.js b/test/utils.js index 0e7bfdd..13c7d0a 100644 --- a/test/utils.js +++ b/test/utils.js @@ -5,32 +5,6 @@ var utils = require('../src/utils') describe('utils', function () { - describe('getRemovable', function () { - - it('should return removable documents', function () { - - var db = { - posts: [ - {id: 1, comment: 1} - ], - comments: [ - {id: 1, postId: 1}, - // Comments below references a post that doesn't exist - {id: 2, postId: 2}, - {id: 3, postId: 2} - ] - } - - var expected = [ - {name: 'comments', id: 2}, - {name: 'comments', id: 3} - ] - - assert.deepEqual(utils.getRemovable(db), expected) - - }) - }) - describe('toNative', function () { it('should convert string to native type', function () {