mysql.js
* MySQL Database Backend Adapter
* @module greppy/db/adapter/mysql
* @author Hermann Mayer <hermann.mayer92@gmail.com>
var prettify = require('pretty-data').pd;
* @param {String} name - Name of the connection
* @param {Object} config - Config of the connection
var MySQL = function(name, config)
* Establish the connection and do some configurations for it.
* @param {Function} callback - Function to call on finish
MySQL.prototype.configure = function(callback)
* Setup the plain MySQL connection, pooling enabled
var setupPlain = function(callback)
self.pool = (require('mysql')).createPool({
password : self.config.password,
// Initiate a connection - just to proof configuration
self.pool.getConnection(function(err, connection) {
// The connection can be closed immediately
return callback && callback(null, self.pool);
var setupOrm = function(callback)
self.orm.instance = new (require('sequelize'))(
pool: { maxConnections: 5, maxIdleTime: 30 },
msg = msg.replace(/^executing: /i, '');
'MySQL ' + self.name.green.bold + ' executing:\n' +
prettify.sql(msg).yellow + '\n'
self.orm.utils = (require('sequelize')).Utils;
// List all models for all modules
var modules = (new (require('../../helper/project'))()).listModelsForAllModules(
var connectionName = 'mysql.' + self.name;
Object.keys(modules).forEach(function(module) {
// Skip modules which got no models for this connection
if (!modules[module].hasOwnProperty(connectionName)) {
modules[module][connectionName].forEach(function(model) {
var path = process.cwd() + '/modules/' +
module + '/models/' + connectionName + '/' + model;
if ('Associations' === model) {
return associations.push(path);
// Import the current model and add it to the model map
self.orm.models[model] = self.orm.instance.import(path);
// Load all found associations
associations.forEach(function(path) {
require(path)(self.orm.instance, self.orm.models);
callback && callback(null, self.orm);
// Prepare default config values
this.config.plain = ('undefined' === typeof this.config.plain) ? true : this.config.plain;
this.config.orm = ('undefined' === typeof this.config.orm) ? true : this.config.orm;
if (this.config.plain && this.config.orm) {
async.map([setupPlain, setupOrm], function(method, callback) {
callback && callback(null, results[0], results[1]);
setupPlain(function(err, instance) {
callback && callback(err, instance);
callback && callback(err, undefined, orm);
callback && callback('Neither "plain" nor "orm" were selected.');
* Prepare a connection to auto reconnect on close events.
* @param {Object} connection - Connection to prepare
MySQL.prototype.prepare = function(connection)
if (!connection || connection.listeners('error').length > 0) {
connection.on('error', function(err) {
if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
' (' + self.name.green.bold + ') is reconnected on ' +
self.pool.getConnection(function(err, connection) {
* Close the connection(s) which where established.
* @param {Function} callback - Function to call on finish
MySQL.prototype.close = function(callback)
if (this.config.plain && this.config.orm) {
self.orm.instance.connectorManager.disconnect();
return this.pool.end(callback);
this.orm.instance.connectorManager.disconnect();
return callback && callback();
* Management method - will create the database for the configured
* @param {Function} callback - Function to call on finish
MySQL.prototype.create = function(callback)
// If we specify no db name we connect global
this.configure.call(this, function(err) {
// Rewrite db name to the configuration
return callback && callback(err);
'CREATE DATABASE IF NOT EXISTS ' + dbName +
' CHARACTER SET utf8 COLLATE utf8_general_ci;'
* Management method - will drop the database for the configured
* @param {Function} callback - Function to call on finish
MySQL.prototype.drop = function(callback)
// If we specify no db name we connect global
this.configure.call(this, function(err) {
// Rewrite db name to the configuration
return callback && callback(err);
'DROP DATABASE IF EXISTS ' + dbName + ';'
* Management method - will run all migrations for the configured
* @param {Function} callback - Function to call on finish
MySQL.prototype.migrate = function(callback)
this.configure.call(this, function(err) {
return callback && callback(err);
var migationsPath = process.cwd() + '/database/migrations/mysql.' + self.name + '/';
// No migrations found for the current connection
if (!(require('fs').existsSync(migationsPath))) {
global.async = require('async');
global.greppy = require('../../greppy');
global.orm = self.orm.instance;
global.models = self.orm.models;
var migrator = self.orm.instance.getMigrator({
migrator.migrate().success(function() {
* Management method - will run all migrations for the configured
* @param {Function} callback - Function to call on finish
MySQL.prototype.fill = function(callback)
this.configure.call(this, function(err) {
return callback && callback(err);
var fixtures = (new (require('../../helper/project'))()).listFixturesForConnection(
process.cwd(), 'mysql.' + self.name
// No fixtures found for the current connection
if ('undefined' === typeof fixtures.fixtures || 0 === fixtures.fixtures.length) {
global.async = require('async');
global.greppy = require('../../greppy');
var utils = (require('sequelize')).Utils;
utils.content = greppy.helper.get('db.fixture');
async.eachSeries(fixtures.fixtures, function(file, callback) {
console.log('\033[0;34mExecuting fixture: ' + file + '\033[0m\n');
require(fixtures.path + file)(
self.orm.instance, self.orm.models, share, utils, function(err) {
return self.close(function() {
* Management method - will clear all data from all tables.
* @param {Function} callback - Function to call on finish
MySQL.prototype.clear = function(callback)
var runOnAllTables = managementHelper.runOnAllTables.bind(
* Management method - will remove all tables.
* @param {Function} callback - Function to call on finish
MySQL.prototype.purge = function(callback)
this.orm.models.SequelizeMeta = {
var runOnAllTables = managementHelper.runOnAllTables.bind(
this, 'DROP TABLE IF EXISTS %s', callback
* Management helper method - will run a command on all tables.
* @param {String} command - Command to run
* @param {Function} callback - Function to call on finish
managementHelper.runOnAllTables = function(command, callback)
this.configure.call(this, function(err, db, orm) {
return callback && callback(err);
async.eachSeries(Object.keys(orm.models), function(model, callback) {
orm.instance.query(util.format(command, model.tableName)).success(function() {