wbyoung/maguey

View on GitHub
lib/adapters/mysql/procedures.js

Summary

Maintainability
A
2 hrs
Test Coverage
'use strict';

var _ = require('lodash');
var Adapter = require('../base');
var Statement = require('../../types/statement');
var Promise = require('bluebird');
var util = require('util');

/**
 * @protected
 * @constructor
 * @extends Adapter.Procedures
 */
var MySQLProcedures = Adapter.Procedures.extend();

MySQLProcedures.reopen(/** @lends MySQLAdapter.Procedures# */ {

  /**
   * Override of {@link Procedure#alterTable}.
   *
   * @method
   * @public
   * @see {@link Procedure#alterTable}.
   */
  alterTable: function(data) {
    /* jscs:disable jsDoc */

    // we know the phrasing is capable of handling everything other than index
    // renaming. we need to create a procedure if any index renames occur.
    var procedure;
    var operations =
      data.renamedIndexes.length;

    if (operations > 0) {
      procedure = this._inTransaction(function(query) {
        var table = data.name;
        var fmt = util.format;
        var quote = this._grammar.field.bind(this._grammar);
        var join = this._grammar.join.bind(this._grammar);
        var delimit = this._grammar.delimit.bind(this._grammar);
        var group = this._grammar.group.bind(this._grammar);
        var camelKeys = function(obj) {
          return _.transform(obj, function(obj, value, key) {
            obj[_.camelCase(key)] = value;
          });
        };

        var promise = Promise.bind({});

        // create a base statement that does not include renames of indexes.
        var statement = this._phrasing.alterTable(_.extend({}, data, {
          renamedIndexes: [],
        }));

        if (statement) {
          promise = promise.then(function() {
            return query.raw(statement);
          });
        }

        data.renamedIndexes.forEach(function(index) {

          promise = promise.then(function() {
            return query.raw(fmt('SHOW INDEX FROM %s WHERE KEY_NAME = ?',
              quote(table)), [index.from]).fetch();
          })
          .tap(function() {
            return query.raw(fmt('DROP INDEX %s ON %s', quote(index.from),
              quote(table)));
          })
          .map(camelKeys)
          .then(_).call('sortBy', 'seqInIndex').call('value')
          .then(function(info) {
            var columns = _.map(info, function(col) {
              var result = quote(col.columnName);
              if (col.subPart) {
                result += fmt('(%d)', col.subPart);
              }
              return result;
            });
            var unique = !_.all(info, 'nonUnique');
            var type = _(info).map('indexType').filter().first();

            var fragments = []
            .concat(['CREATE '])
            .concat(unique ? ['UNIQUE '] : [])
            .concat(['INDEX ', quote(index.to)])
            .concat([' USING ', type])
            .concat([' ON ', quote(table), ' '])
            .concat(group(join(delimit(columns))));

            return query.raw(Statement.create(join(fragments)));
          });
        });

        return promise;
      }.bind(this));
    }

    return procedure; /* jscs:enable jsDoc */
  },

});

module.exports = MySQLProcedures.reopenClass({ __name__: 'MySQLProcedures' });