diff --git a/.gitignore b/.gitignore index 2ed2cf7..871c8a3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules .DS_Store coverage .idea +remotedev-db.sqlite3 diff --git a/defaultDbOptions.json b/defaultDbOptions.json new file mode 100644 index 0000000..b901157 --- /dev/null +++ b/defaultDbOptions.json @@ -0,0 +1,6 @@ +{ + "connection": { "filename": "./remotedev-db.sqlite3" }, + "client": "sqlite3", + "debug": false, + "migrate": true +} diff --git a/lib/db/connector.js b/lib/db/connector.js new file mode 100644 index 0000000..a92b64e --- /dev/null +++ b/lib/db/connector.js @@ -0,0 +1,27 @@ +var path = require('path'); +var knexModule = require('knex'); + +module.exports = function connector(options) { + var dbOptions = options.dbOptions; + dbOptions.useNullAsDefault = true; + if (!dbOptions.migrate) { + return knexModule(dbOptions); + } + + dbOptions.migrations = { directory: path.resolve(__dirname, 'migrations') }; + dbOptions.seeds = { directory: path.resolve(__dirname, 'seeds') }; + var knex = knexModule(dbOptions); + + knex.migrate.latest() + .then(function() { + return knex.seed.run(); + }) + .then(function() { + console.log('Migrations are finished.'); + }) + .catch(function(error) { + console.error(error); + }); + + return knexModule(dbOptions); +}; diff --git a/lib/db/migrations/reports.js b/lib/db/migrations/reports.js new file mode 100644 index 0000000..76b721d --- /dev/null +++ b/lib/db/migrations/reports.js @@ -0,0 +1,39 @@ +exports.up = function(knex, Promise) { + return Promise.all([ + knex.schema.createTable('remotedev_reports', function(table) { + table.uuid('id').primary(); + table.string('type'); + table.string('title'); + table.string('description'); + table.string('action'); + table.text('payload'); + table.text('preloadedState'); + table.text('screenshot'); + table.string('userAgent'); + table.string('version'); + table.string('user'); + table.string('userId'); + table.string('meta'); + table.string('exception'); + table.timestamp('added'); + table.uuid('appId') + .references('id') + .inTable('remotedev_apps'); + }), + + knex.schema.createTable('remotedev_apps', function(table){ + table.uuid('id').primary(); + table.string('title'); + table.string('description'); + table.string('url'); + table.timestamps(); + }) + ]) +}; + +exports.down = function(knex, Promise) { + return Promise.all([ + knex.schema.dropTable('remotedev_reports'), + knex.schema.dropTable('remotedev_apps') + ]) +}; diff --git a/lib/db/seeds/apps.js b/lib/db/seeds/apps.js new file mode 100644 index 0000000..d437153 --- /dev/null +++ b/lib/db/seeds/apps.js @@ -0,0 +1,12 @@ +exports.seed = function(knex, Promise) { + return Promise.all([ + knex('remotedev_apps').del() + ]).then(function() { + return Promise.all([ + knex('remotedev_apps').insert({ + id: '78626c31-e16b-4528-b8e5-f81301b627f4', + title: 'Default' + }) + ]); + }); +}; diff --git a/lib/options.js b/lib/options.js index b970e4b..b5032bd 100644 --- a/lib/options.js +++ b/lib/options.js @@ -1,4 +1,13 @@ +var path = require('path'); + module.exports = function getOptions(argv) { + var dbOptions = argv.dbOptions; + if (typeof dbOptions === 'string') { + dbOptions = require(path.resolve(process.cwd(), argv.dbOptions)); + } else if (typeof dbOptions === 'undefined') { + dbOptions = require('../defaultDbOptions.json'); + } + return { host: argv.hostname || process.env.npm_package_remotedev_hostname || null, port: Number(argv.port || process.env.npm_package_remotedev_port) || 8000, @@ -8,8 +17,7 @@ module.exports = function getOptions(argv) { cert: argv.cert || process.env.npm_package_remotedev_cert || null, passphrase: argv.passphrase || process.env.npm_package_remotedev_passphrase || null }, - adapter: argv.adapter || process.env.npm_package_remotedev_adapter, - dbOptions: argv.dbOptions || process.env.npm_package_remotedev_db, + dbOptions: dbOptions, logLevel: argv.logLevel || 3 }; } diff --git a/lib/store.js b/lib/store.js index b350c4d..78866f7 100644 --- a/lib/store.js +++ b/lib/store.js @@ -1,11 +1,9 @@ var uuid = require('node-uuid'); var pick = require('lodash/pick'); -var JSData = require('js-data'); -var getAdapter = require('./adapter'); +var connector = require('./db/connector'); -var store; -var adapter; -var Report; +var reports = 'remotedev_reports'; +var knex; var baseFields = ['id', 'title', 'added']; @@ -15,41 +13,17 @@ function error(msg) { }); } -function map(data, fields) { - if (!fields) return data; - return data.map(function(r) { - return pick(r, fields); - }); -} - -function listEvery(query) { - if (!adapter) { - return new Promise(function(resolve) { - var report = Report.filter(query); - return resolve(report); - }); - } - return Report.findAll(query); -} - function list(query, fields) { - return new Promise(function(resolve) { - listEvery(query).then(function(data) { - return resolve(map(data, fields || baseFields)); - }); - }); + knex.select().from('remotedev_apps').then(function(r){ console.log(r) }); + var r = knex.select(fields || baseFields).from(reports); + if (query) return r.where(query); + return r; } function get(id) { if (!id) return error('No id specified.'); - if (!adapter) { - return new Promise(function(resolve) { - var report = Report.get(id); - return resolve(report); - }); - } - return Report.find(id); + return knex(reports).where('id', id); } function add(data) { @@ -75,17 +49,11 @@ function add(data) { user: data.user, userId: typeof data.user === 'object' ? data.user.id : data.user, meta: data.meta, - exception: data.exception, - added: Date.now() + exception: data.exception }; - if (!adapter) { - return new Promise(function(resolve) { - var report = Report.inject(obj); - return resolve(report); - }); - } - return Report.create(obj); + return knex.insert(obj).into(reports) + .then(function (){ return byBaseFields(obj); }) } function byBaseFields(data) { @@ -93,24 +61,12 @@ function byBaseFields(data) { } function createStore(options) { - var adapterName = options.adapter; - store = new JSData.DS(); - - if (adapterName) { - var DSAdapter = getAdapter(adapterName); - adapter = new DSAdapter(options.dbOptions); - store.registerAdapter(adapterName, adapter, { default: true }); - } - - Report = store.defineResource('report'); + knex = connector(options); return { list: list, get: get, - add: add, - selectors: { - byBaseFields: byBaseFields - } + add: add }; } diff --git a/lib/worker.js b/lib/worker.js index 4008ff0..0e2ea4f 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -26,20 +26,29 @@ module.exports.run = function(worker) { switch(req.body.op) { case 'get': store.get(req.body.id).then(function(r) { - res.send(r || {}); + res.send(r[0] || {}); + }).catch(function(error) { + console.error(error); + res.sendStatus(500) }); break; case 'list': store.list(req.body.query, req.body.fields).then(function(r) { res.send(r); + }).catch(function(error) { + console.error(error); + res.sendStatus(500) }); break; default: store.add(req.body).then(function(r) { res.send({ id: r.id, error: r.error }); scServer.exchange.publish('report', { - type: 'add', data: store.selectors.byBaseFields(r) + type: 'add', data: r }); + }).catch(function(error) { + console.error(error); + res.status(500).send({}) }); } }); @@ -60,6 +69,8 @@ module.exports.run = function(worker) { if (req.channel === 'report') { store.list().then(function(data) { req.socket.emit(req.channel, { type: 'list', data: data }); + }).catch(function(error) { + console.error(error); }); } }); @@ -79,7 +90,9 @@ module.exports.run = function(worker) { }); socket.on('getReport', function (id, respond) { store.get(id).then(function(data) { - respond(null, data); + respond(null, data[0]); + }).catch(function(error) { + console.error(error); }); }); socket.on('disconnect', function() { diff --git a/package.json b/package.json index afbab2f..d570c4b 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "files": [ "bin", "lib", - "views" + "views", + "index.js", + "defaultDbOptions.json" ], "repository": { "type": "git", @@ -33,12 +35,14 @@ "express": "^4.13.3", "getport": "^0.1.0", "js-data": "^2.9.0", + "knex": "^0.12.6", "lodash": "^4.15.0", "minimist": "^1.2.0", "node-uuid": "^1.4.0", "object-assign": "^4.0.0", "repeat-string": "^1.5.4", "semver": "^5.3.0", - "socketcluster": "^5.0.4" + "socketcluster": "^5.0.4", + "sqlite3": "^3.1.8" } }