// Oracle Schema Compiler
// -------
const SchemaCompiler = require('../../../schema/compiler');
const utils = require('../utils');
const Trigger = require('./internal/trigger');

class SchemaCompiler_Oracle extends SchemaCompiler {
  constructor() {
    super(...arguments);
  }

  // Rename a table on the schema.
  renameTable(tableName, to) {
    const trigger = new Trigger(this.client.version);
    const renameTable = trigger.renameTableAndAutoIncrementTrigger(
      this.client.logger,
      tableName,
      to
    );
    this.pushQuery(renameTable);
  }

  // Check whether a table exists on the query.
  hasTable(tableName) {
    this.pushQuery({
      sql:
        'select TABLE_NAME from USER_TABLES where TABLE_NAME = ' +
        this.client.parameter(tableName, this.builder, this.bindingsHolder),
      output(resp) {
        return resp.length > 0;
      },
    });
  }

  // Check whether a column exists on the schema.
  hasColumn(tableName, column) {
    const sql =
      `select COLUMN_NAME from ALL_TAB_COLUMNS ` +
      `where TABLE_NAME = ${this.client.parameter(
        tableName,
        this.builder,
        this.bindingsHolder
      )} ` +
      `and COLUMN_NAME = ${this.client.parameter(
        column,
        this.builder,
        this.bindingsHolder
      )}`;
    this.pushQuery({ sql, output: (resp) => resp.length > 0 });
  }

  dropSequenceIfExists(sequenceName) {
    const prefix = this.schema ? `"${this.schema}".` : '';
    this.pushQuery(
      utils.wrapSqlWithCatch(
        `drop sequence ${prefix}${this.formatter.wrap(sequenceName)}`,
        -2289
      )
    );
  }

  _dropRelatedSequenceIfExists(tableName) {
    // removing the sequence that was possibly generated by increments() column
    const nameHelper = new utils.NameHelper(this.client.version);
    const sequenceName = nameHelper.generateCombinedName(
      this.client.logger,
      'seq',
      tableName
    );
    this.dropSequenceIfExists(sequenceName);
  }

  dropTable(tableName) {
    const prefix = this.schema ? `"${this.schema}".` : '';
    this.pushQuery(`drop table ${prefix}${this.formatter.wrap(tableName)}`);

    // removing the sequence that was possibly generated by increments() column
    this._dropRelatedSequenceIfExists(tableName);
  }

  dropTableIfExists(tableName) {
    this.dropObject(tableName, 'table');
  }

  dropViewIfExists(viewName) {
    this.dropObject(viewName, 'view');
  }

  dropObject(objectName, type) {
    const prefix = this.schema ? `"${this.schema}".` : '';
    let errorCode = -942;
    if (type === 'materialized view') {
      // https://stackoverflow.com/a/1801453
      errorCode = -12003;
    }
    this.pushQuery(
      utils.wrapSqlWithCatch(
        `drop ${type} ${prefix}${this.formatter.wrap(objectName)}`,
        errorCode
      )
    );

    // removing the sequence that was possibly generated by increments() column
    this._dropRelatedSequenceIfExists(objectName);
  }

  refreshMaterializedView(viewName) {
    return this.pushQuery({
      sql: `BEGIN DBMS_MVIEW.REFRESH('${
        this.schemaNameRaw ? this.schemaNameRaw + '.' : ''
      }${viewName}'); END;`,
    });
  }

  dropMaterializedView(viewName) {
    this._dropView(viewName, false, true);
  }

  dropMaterializedViewIfExists(viewName) {
    this.dropObject(viewName, 'materialized view');
  }
}

module.exports = SchemaCompiler_Oracle;
