From 760aaa8b2a69a496860ccceff1f5efdc09242ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20Lepist=C3=B6?= Date: Thu, 2 Nov 2017 14:37:39 +0200 Subject: [PATCH 1/3] Added taksks for db create, migrate, drop and create new migration --- .travis.yml | 1 + features/objection/index.js | 83 +++++++++++++++++++++++++++++++++++++ index.js | 6 +-- package.json | 3 +- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 81e9575..ba31dd7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ node_js: - '5' - '6' - '7' + - '8' notifications: email: false diff --git a/features/objection/index.js b/features/objection/index.js index 1b35a90..84156f7 100644 --- a/features/objection/index.js +++ b/features/objection/index.js @@ -8,6 +8,9 @@ var _ = require('lodash') , knex = require('knex') , color = require('cli-color') , log = require('dodo/logger').getLogger('dodo-objection.feature') + , moment = require('moment') + , path = require('path') + , fs = require('fs') , createDbManager = require('knex-db-manager').databaseManagerFactory; /** @@ -152,6 +155,86 @@ module.exports = function(app, config) { } }; +module.exports.tasks = [{ + name: 'db-create', + run: function (featureConfig, serviceConfig, servicePath) { + const dbManager = createDbManager(featureConfig); + return dbManager.createDb() + .then(() => dbManager.close()) + .catch(err => { + dbManager.close(); + throw err; + }); + }, + description: 'Creates database for the service (and owner user if necessary)' + +}, { + name: 'db-migrate', + run: function (featureConfig, serviceConfig, servicePath) { + const dbManager = createDbManager(featureConfig); + return dbManager.migrateDb() + .then(() => dbManager.close()) + .catch(err => { + dbManager.close(); + throw err; + }); + }, + description: 'Runs migrations of the service' + +}, { + name: 'db-drop', + run: function (featureConfig, serviceConfig, servicePath) { + const dbManager = createDbManager(featureConfig); + return dbManager.dropDb() + .then(() => dbManager.close()) + .catch(err => { + dbManager.close(); + throw err; + }); + }, + description: 'Drops database of the service' + +}, { + name: 'new-migration', + run: function (featureConfig, serviceConfig, servicePath) { + const migrationName = process.env.MIGRATION_NAME || 'new_migration'; + const currentUtc = moment().utc().format("YYYYMMDDHHmmss"); + + const configuredMigrationDir = featureConfig.knex.migrations.directory || 'migrations'; + configuredMigrationDir = configuredMigrationDir.startsWith('/') ? + configuredMigrationDir : + path.join(servicePath, configuredMigrationDir); + + // TODO: add migration suffix + template to config + const migrationFileName = path.join(configuredMigrationDir, currentUtc + '_' + migrationName + '.js'); + + var template = [ + "'use strict';", + "//var _ = require('lodash');", + "", + "// see http://knexjs.org/#Schema ", + "exports.up = function (knex) {", + " return knex.schema.table('MyTable', function (table) {", + " table.timestamp('createTime').notNullable().defaultTo(knex.raw('now()'));", + " });", + "};", + "", + "exports.down = function (/* knex */) {", + "};" + ]; + + fs.writeFile(migrationFileName, template.join("\n"), function(err) { + if (err) { + log.error({ error: err }, 'Could not write migration file.'); + } else { + log.info(`Created new migration script: ${migrationFileName}`); + } + }); + }, + description: 'Creates new migration for the service, pass name is MIGRATION_NAME environment variable' + +}]; + /** * @private */ diff --git a/index.js b/index.js index 34f007e..7ee2a7e 100644 --- a/index.js +++ b/index.js @@ -2,10 +2,6 @@ var path = require('path'); -// TODO: how to export stuff for test helper? - module.exports = { - featurePath: path.join(__dirname, 'features'), - serviceGulpTasks: null, - globalGulpTasks: null + featurePath: path.join(__dirname, 'features') }; diff --git a/package.json b/package.json index 558d19f..a7ed923 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "bluebird": "^3.4.6", "cli-color": "^1.1.0", "knex-db-manager": "^0.4.0", - "lodash": "^4.16.2" + "lodash": "^4.16.2", + "moment": "^2.19.1" }, "peerDependencies": { "objection": ">=0.8", From 50ddde47b95846dc7ea8fc0123043564ce615526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20Lepist=C3=B6?= Date: Thu, 2 Nov 2017 16:09:25 +0200 Subject: [PATCH 2/3] Smoketests for tasks --- features/objection/index.js | 32 +++++++---- tests/feature.spec.js | 110 +++++++++++++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 14 deletions(-) diff --git a/features/objection/index.js b/features/objection/index.js index 84156f7..d928a15 100644 --- a/features/objection/index.js +++ b/features/objection/index.js @@ -160,8 +160,10 @@ module.exports.tasks = [{ run: function (featureConfig, serviceConfig, servicePath) { const dbManager = createDbManager(featureConfig); return dbManager.createDb() - .then(() => dbManager.close()) + .tap(res => dbManager.closeKnex()) + .tap(res => dbManager.close()) .catch(err => { + dbManager.closeKnex(); dbManager.close(); throw err; }); @@ -173,8 +175,10 @@ module.exports.tasks = [{ run: function (featureConfig, serviceConfig, servicePath) { const dbManager = createDbManager(featureConfig); return dbManager.migrateDb() - .then(() => dbManager.close()) + .tap(res => dbManager.closeKnex()) + .tap(res => dbManager.close()) .catch(err => { + dbManager.closeKnex(); dbManager.close(); throw err; }); @@ -186,8 +190,10 @@ module.exports.tasks = [{ run: function (featureConfig, serviceConfig, servicePath) { const dbManager = createDbManager(featureConfig); return dbManager.dropDb() - .then(() => dbManager.close()) + .tap(res => dbManager.closeKnex()) + .tap(res => dbManager.close()) .catch(err => { + dbManager.closeKnex(); dbManager.close(); throw err; }); @@ -200,7 +206,7 @@ module.exports.tasks = [{ const migrationName = process.env.MIGRATION_NAME || 'new_migration'; const currentUtc = moment().utc().format("YYYYMMDDHHmmss"); - const configuredMigrationDir = featureConfig.knex.migrations.directory || 'migrations'; + let configuredMigrationDir = featureConfig.knex.migrations.directory || 'migrations'; configuredMigrationDir = configuredMigrationDir.startsWith('/') ? configuredMigrationDir : path.join(servicePath, configuredMigrationDir); @@ -223,13 +229,17 @@ module.exports.tasks = [{ "};" ]; - fs.writeFile(migrationFileName, template.join("\n"), function(err) { - if (err) { - log.error({ error: err }, 'Could not write migration file.'); - } else { - log.info(`Created new migration script: ${migrationFileName}`); - } - }); + try { + fs.writeFileSync(migrationFileName, template.join("\n")); + log.debug(`Created new migration script: ${migrationFileName}`); + } catch (err) { + log.error({ error: err }, 'Could not write migration file.'); + throw err; + } + + return { + createdFile: migrationFileName + }; }, description: 'Creates new migration for the service, pass name is MIGRATION_NAME environment variable' diff --git a/tests/feature.spec.js b/tests/feature.spec.js index 7fe179f..b02c52a 100644 --- a/tests/feature.spec.js +++ b/tests/feature.spec.js @@ -138,7 +138,7 @@ describe('integration', function () { it('should be able to run migrations and bind models for 2 databases', function () { var mockRequest1 = { database: 'dodo-objection-test-1' }; var mockRequest2 = { database: 'dodo-objection-test-2' }; - + var manager1 = feature.dbManager(mockRequest1); var manager2 = feature.dbManager(mockRequest2); @@ -168,7 +168,7 @@ describe('integration', function () { }) .then(function () { return feature.models(mockRequest2).Model2.query().insert({}); - }) + }) ]).then(function () { var db1Knex = feature.knex(mockRequest1); var db2Knex = feature.knex(mockRequest2); @@ -188,7 +188,7 @@ describe('integration', function () { }), ]); }); - }); + }); it('should close all DB connections', function () { var mockRequest1 = { database: 'dodo-objection-test-1' }; @@ -217,6 +217,110 @@ describe('integration', function () { }); }); + describe('running tasks', () => { + let config = opts => { + return { + knex: { + client: 'postgres', + debug: false, + connection: { + host: process.env.POSTGRES_HOST || 'localhost', + port: process.env.POSTGRES_PORT || 5432, + database: opts.dbName || 'dodoobjtestdb', + user: process.env.POSTGRES_USER || 'dodoobjtestuser', + password: process.env.POSTGRES_USER_PW || undefined + }, + migrations: { + tableName: 'migrations', + directory: opts.migrationDir || path.join(__dirname, 'migrations') + } + }, + dbManager: { + superUser: process.env.POSTGRES_SUPERUSER || 'postgres', + superPassword: process.env.POSTGRES_SUPERUSER_PW || undefined + } + }; + }; + + let tasks; + let dbManager; + + before(() => { + tasks = _.keyBy(feature.constructor.tasks, 'name'); + console.log(feature.dbManager); + dbManager = feature.dbManager({ database: 'dodomigrationsteaskcreateddb' }); + return dbManager.dropDb(); + }); + + it('should create new migration to service relative path', () => { + return Promise.resolve(tasks['new-migration'].run( + config({ + migrationDir: './tempMigrations' + }), + {}, + __dirname + )).then(res => { + expect(path.dirname(res.createdFile)).to.equal(`${__dirname}/tempMigrations`); + }); + }); + + it('should create new migration to absolute path', () => { + return Promise.resolve(tasks['new-migration'].run( + config({ + migrationDir: `${__dirname}/tempMigrations` + }), + {}, + 'whatever' + )).then(res => { + expect(path.dirname(res.createdFile)).to.equal(`${__dirname}/tempMigrations`); + }); + }); + + it('should call create db', () => { + return Promise.resolve(tasks['db-create'].run( + config({ + dbName: 'dodomigrationsteaskcreateddb' + }), + {}, + 'whatever' + )) + .then(res => { + const knex = dbManager.knexInstance(); + return dbManager.knexInstance().select(knex.raw('1 as foo')); + }) + .then(res => dbManager.closeKnex().return(res)) // tap + .then(res => { + expect(res[0].foo).to.equal(1); + }); + }); + + it('should call migrate db', () => { + return Promise.resolve(tasks['db-migrate'].run( + config({ + dbName: 'dodomigrationsteaskcreateddb', + migrationDir: `${__dirname}/migrations` + }), + {}, + __dirname + )).then(res => { + expect(res).to.have.length(2); + }); + }); + + it('should call drop db', function () { + this.timeout(100000); + return Promise.resolve(tasks['db-drop'].run( + config({ + dbName: 'dodomigrationsteaskcreateddb' + }), + {}, + 'whatever' + )).then(res => { + expect(res.command).to.equal('DROP'); + }); + }); + }); + it.skip('should support mysql!', function () { expect(false).to.be.ok; // currently initialization code stuff is postrgres only }); From adf3f5742f1a82b4060b55b02c42c0ac3ce06c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20Lepist=C3=B6?= Date: Thu, 2 Nov 2017 16:10:03 +0200 Subject: [PATCH 3/3] Pushed revision up --- package.json | 2 +- tests/feature.spec.js | 4 +++- tests/tempMigrations/keepdir.txt | 0 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 tests/tempMigrations/keepdir.txt diff --git a/package.json b/package.json index a7ed923..b6dc439 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "dodo-objection", "description": "Objection.js ORM plugin for Dodo.js framework", - "version": "0.3.0", + "version": "0.4.0", "private": false, "author": { "name": "Mikael Lepistö", diff --git a/tests/feature.spec.js b/tests/feature.spec.js index b02c52a..4b0e5aa 100644 --- a/tests/feature.spec.js +++ b/tests/feature.spec.js @@ -1,3 +1,5 @@ +'use strict'; + var _ = require('lodash'); var ObjectionFeature = require('../features/objection'); var expect = require('chai').expect; @@ -91,7 +93,7 @@ describe('integration', function () { beforeEach(function () { mockApp = {}; - configFunction = function (req) { + let configFunction = function (req) { return { // normal knex config to describe db connection for app knex: { diff --git a/tests/tempMigrations/keepdir.txt b/tests/tempMigrations/keepdir.txt new file mode 100644 index 0000000..e69de29