<commit_before>import _ from 'lodash';
import { escapeValue, template, quote, applyType, applyTypeAdapters } from '../utils';

function parseColumns(columns, table, extending_type_shorthands = {}) {
  let columnsWithOptions = _.mapValues(
    columns,
    column => applyType(column, extending_type_shorthands)
  );

  const table_name = typeof table === 'object' ? table.name : table;

  const primaryColumns = _.chain(columnsWithOptions)
    .map((options, column_name) => (options.primaryKey ? column_name : null))
    .filter()
    .value();
  const multiplePrimaryColumns = primaryColumns.length > 1;

  if (multiplePrimaryColumns) {
    columnsWithOptions = _.mapValues(
      columnsWithOptions,
      options => ({ ...options, primaryKey: false })
    );
  }

  return _.map(columnsWithOptions, (options, column_name) => {
    const constraints = [];
    if (options.unique) {
      constraints.push('UNIQUE');
    }
    if (options.primaryKey) {
      constraints.push('PRIMARY KEY');
    }
    if (options.notNull) {
      constraints.push('NOT NULL');
    }
    if (options.check) {
      constraints.push(`CHECK (${options.check})`);
    }
    if (options.references) {
      constraints.push(
        typeof options.references === 'string'
          ? `REFERENCES ${options.references}`
          : template`REFERENCES "${options.references}"`
      );
      if (options.onDelete) {
        constraints.push(`ON DELETE ${options.onDelete}`);
      }
      if (options.onUpdate) {
        constraints.push(`ON UPDATE ${options.onUpdate}`);
      }
    }

    const defaultValue = options.default !== undefined ? ` DEFAULT ${escapeValue(options.default)}` : '';
    const constraintsString = constraints.length ? ` ${constraints.join(' ')}` : '';

    return template`"${column_name}" ${options.type}${defaultValue}${constraintsString}`;
  })
    .concat(multiplePrimaryColumns
      ? [`CONSTRAINT "${table_name}_pkey" PRIMARY KEY (${quote(primaryColumns).join(', ')})`]
      : []
    )
    .join(',\n');
}

export const drop = table_name =>
  template`DROP TABLE "${table_name}";`;

export const create = (type_shorthands) => {
  const _create = (table_name, columns, options = {}) => {
    /*
     columns - hash of columns

     Options
     table_name - the name of the table
     columns - see column options
     options.inherits - table to inherit from (optional)
     */
    const columnsString = parseColumns(columns, table_name, type_shorthands).replace(/^/gm, '  ');
    const inherits = options.inherits ? ` INHERITS ${options.inherits}` : '';
    return template`CREATE TABLE "${table_name}" (\n${columnsString}\n)${inherits};`;
  };
  _create.reverse = drop;
  return _create;
};

export const addColumns = type_shorthands => (table_name, columns) =>
  template`ALTER TABLE "${table_name}"\n${parseColumns(columns, table_name, type_shorthands).replace(/^/gm, '  ADD ')};`;

export const dropColumns = (table_name, columns) => {
  if (typeof columns === 'string') {
    columns = [columns]; // eslint-disable-line no-param-reassign
  } else if (!_.isArray(columns) && typeof columns === 'object') {
    columns = _.keys(columns); // eslint-disable-line no-param-reassign
  }
  return template`ALTER TABLE "${table_name}"\n${quote(columns).join(',\n').replace(/^/gm, '  DROP ')};`;
};

export const alterColumn = (table_name, column_name, options) => {
  const actions = [];
  if (options.default === null) {
    actions.push('DROP DEFAULT');
  } else if (options.default !== undefined) {
    actions.push(`SET DEFAULT ${escapeValue(options.default)}`);
  }
  if (options.type) {
    const action = `SET DATA TYPE ${applyTypeAdapters(options.type)}`;
    actions.push(
      options.using
        ? `${action} USING ${options.using}`
        : action
    );
  }
  if (options.notNull) {
    actions.push('SET NOT NULL');
  } else if (options.notNull === false || options.allowNull) {<commit_msg>Fix automatic reversal of addColumns (#110)<commit_after>import _ from 'lodash';
import { escapeValue, template, quote, applyType, applyTypeAdapters } from '../utils';

function parseColumns(columns, table, extending_type_shorthands = {}) {
  let columnsWithOptions = _.mapValues(
    columns,
    column => applyType(column, extending_type_shorthands)
  );

  const table_name = typeof table === 'object' ? table.name : table;

  const primaryColumns = _.chain(columnsWithOptions)
    .map((options, column_name) => (options.primaryKey ? column_name : null))
    .filter()
    .value();
  const multiplePrimaryColumns = primaryColumns.length > 1;

  if (multiplePrimaryColumns) {
    columnsWithOptions = _.mapValues(
      columnsWithOptions,
      options => ({ ...options, primaryKey: false })
    );
  }

  return _.map(columnsWithOptions, (options, column_name) => {
    const constraints = [];
    if (options.unique) {
      constraints.push('UNIQUE');
    }
    if (options.primaryKey) {
      constraints.push('PRIMARY KEY');
    }
    if (options.notNull) {
      constraints.push('NOT NULL');
    }
    if (options.check) {
      constraints.push(`CHECK (${options.check})`);
    }
    if (options.references) {
      constraints.push(
        typeof options.references === 'string'
          ? `REFERENCES ${options.references}`
          : template`REFERENCES "${options.references}"`
      );
      if (options.onDelete) {
        constraints.push(`ON DELETE ${options.onDelete}`);
      }
      if (options.onUpdate) {
        constraints.push(`ON UPDATE ${options.onUpdate}`);
      }
    }

    const defaultValue = options.default !== undefined ? ` DEFAULT ${escapeValue(options.default)}` : '';
    const constraintsString = constraints.length ? ` ${constraints.join(' ')}` : '';

    return template`"${column_name}" ${options.type}${defaultValue}${constraintsString}`;
  })
    .concat(multiplePrimaryColumns
      ? [`CONSTRAINT "${table_name}_pkey" PRIMARY KEY (${quote(primaryColumns).join(', ')})`]
      : []
    )
    .join(',\n');
}

export const drop = table_name =>
  template`DROP TABLE "${table_name}";`;

export const create = (type_shorthands) => {
  const _create = (table_name, columns, options = {}) => {
    /*
     columns - hash of columns

     Options
     table_name - the name of the table
     columns - see column options
     options.inherits - table to inherit from (optional)
     */
    const columnsString = parseColumns(columns, table_name, type_shorthands).replace(/^/gm, '  ');
    const inherits = options.inherits ? ` INHERITS ${options.inherits}` : '';
    return template`CREATE TABLE "${table_name}" (\n${columnsString}\n)${inherits};`;
  };
  _create.reverse = drop;
  return _create;
};

export const dropColumns = (table_name, columns) => {
  if (typeof columns === 'string') {
    columns = [columns]; // eslint-disable-line no-param-reassign
  } else if (!_.isArray(columns) && typeof columns === 'object') {
    columns = _.keys(columns); // eslint-disable-line no-param-reassign
  }
  return template`ALTER TABLE "${table_name}"\n${quote(columns).join(',\n').replace(/^/gm, '  DROP ')};`;
};

export const addColumns = (type_shorthands) => {
  const _add = (table_name, columns) =>
    template`ALTER TABLE "${table_name}"\n${parseColumns(columns, table_name, type_shorthands).replace(/^/gm, '  ADD ')};`;
  _add.reverse = dropColumns;
  return _add;
};

export const alterColumn = (table_name, column_name, options) => {
  const actions = [];
  if (options.default === null) {
    actions.push('DROP DEFAULT');
  } else if (options.default !== undefined) {
    actions.push(`SET DEFAULT ${escapeValue(options.default)}`);
  }
  if (options.type) {
    const action = `SET DATA TYPE ${applyTypeAdapters(options.type)}`;
    actions.push(
      options.using
        ? `${action} USING ${options.using}`
        : action
    );
  }
  if (options.notNull) {
    actions.push('SET NOT NULL');
  } else if (options.notNull === false || options.allowNull) {
{'fraction_non_alphanumeric': 0.159088046353445, 'fraction_numerical': 0.0006298022420959819, 'mean_word_length': 3.4382336500838457, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3361180', 'n_tokens_mistral': 2428, 'n_tokens_neox': 2414, 'n_words': 517}