UNPKG

knex-db-manager

Version:

Collection of administrative database operations for knex supported databases

228 lines (209 loc) 5.72 kB
var DatabaseManager = require('./DatabaseManager').default, classUtils = require('./class-utils'), mysql = require('mysql'), Promise = require('bluebird'), _ = require('lodash'); /** * @constructor * @extends DatabaseManager * * Notes: * - Even though the method signature implicates that _masterConnectionUrl returns * an URL string, it actually returns an object because MySQL node lib * assumes that the database name is defined in the URL format. * */ function MySqlDatabaseManager() { DatabaseManager.apply(this, arguments); this._masterClient = null; this._cachedTableNames = null; } classUtils.inherits(MySqlDatabaseManager, DatabaseManager); /** * @Override */ MySqlDatabaseManager.prototype.createDbOwnerIfNotExist = function() { return this._masterQuery("CREATE USER IF NOT EXISTS ?@'%' IDENTIFIED BY ?", [ this.config.knex.connection.user, this.config.knex.connection.password, ]); }; /** * @Override */ MySqlDatabaseManager.prototype.createDb = function(databaseName) { databaseName = databaseName || this.config.knex.connection.database; var collate = this.config.dbManager.collate; var owner = this.config.knex.connection.user; var self = this; var promise = Promise.reject(new Error()); if (_.isEmpty(collate)) { promise = promise.catch(function() { return self._masterQuery( 'CREATE DATABASE ?? DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci', [databaseName] ); }); } else { // Try to create with each collate. Use the first one that works. This is kind of a hack // but seems to be the only reliable way to make this work with both windows and unix. _.each(collate, function(locale) { promise = promise.catch(function() { return self._masterQuery( 'CREATE DATABASE ?? DEFAULT CHARACTER SET utf8 DEFAULT COLLATE ?', [databaseName, locale] ); }); }); } promise = promise.then(function() { return self._masterQuery('GRANT ALL PRIVILEGES ON ??.* TO ??', [ databaseName, owner, ]); }); return promise; }; /** * Drops database with name if db exists. * * @Override */ MySqlDatabaseManager.prototype.dropDb = function(databaseName) { databaseName = databaseName || this.config.knex.connection.database; return this._masterQuery('DROP DATABASE IF EXISTS ??', [databaseName]); }; /** * @Override */ MySqlDatabaseManager.prototype.truncateDb = function(ignoreTables) { var knex = this.knexInstance(); var config = this.config; if (!this._cachedTableNames) { this._updateTableNameCache(knex, config); } return this._cachedTableNames.then(function(tableNames) { if (!_.isEmpty(tableNames)) { return knex.transaction(function(trx) { return knex .raw('SET FOREIGN_KEY_CHECKS = 0') .transacting(trx) .then(function() { // ignore the tables based on `ignoreTables` var filteredTables = _.differenceWith( tableNames, ignoreTables, _.isEqual ); return Promise.map( filteredTables, function(tableName) { return knex .table(tableName) .truncate() .transacting(trx); }, { concurrency: 1 } ); }); }); } }); }; /** * @private */ MySqlDatabaseManager.prototype._updateTableNameCache = function(knex, config) { this._cachedTableNames = knex('information_schema.tables') .select('table_name') .where('table_schema', config.knex.connection.database) .then(function(tables) { return _.without( _.map(tables, 'table_name'), config.knex.migrations.tableName ); }); }; /** * @Override */ MySqlDatabaseManager.prototype.close = function() { var disconnectAll = [this.closeKnex()]; if (this._masterClient) { disconnectAll.push( this._masterClient.then(function(client) { client.end(); }) ); this._masterClient = null; } return Promise.all(disconnectAll); }; /** * @private * @returns {Promise} */ MySqlDatabaseManager.prototype._masterQuery = function(query, params) { var self = this; if (!this._masterClient) { this._masterClient = this.create_masterClient(); } return this._masterClient.then(function(client) { return self.perform_masterQuery(client, query, params); }); }; /** * @private * @returns {Promise} */ MySqlDatabaseManager.prototype.create_masterClient = function() { var self = this; return new Promise(function(resolve, reject) { var client = mysql.createConnection(self._masterConnectionUrl()); client.connect(function(err) { if (err) { reject(err); } else { resolve(client); } }); }); }; /** * @private * @returns {Promise} */ MySqlDatabaseManager.prototype.perform_masterQuery = function( client, query, params ) { return new Promise(function(resolve, reject) { if (params) { query = mysql.format(query, params); } client.query(query, function(err, result) { if (err) { reject(err); } else { resolve(result); } }); }); }; /** * @private * @returns {String} */ MySqlDatabaseManager.prototype._masterConnectionUrl = function() { return { host: this.config.knex.connection.host, port: this.config.knex.connection.port || 3306, user: this.config.dbManager.superUser, password: this.config.dbManager.superPassword, }; }; module.exports = { default: MySqlDatabaseManager, MySqlDatabaseManager: MySqlDatabaseManager, };