// PostgreSQL Schema Compiler
// -------

const SchemaCompiler = require('../../../schema/compiler');

class SchemaCompiler_PG extends SchemaCompiler {
  constructor(client, builder) {
    super(client, builder);
  }

  // Check whether the current table
  hasTable(tableName) {
    let sql = 'select * from information_schema.tables where table_name = ?';
    const bindings = [tableName];

    if (this.schema) {
      sql += ' and table_schema = ?';
      bindings.push(this.schema);
    } else {
      sql += ' and table_schema = current_schema()';
    }

    this.pushQuery({
      sql,
      bindings,
      output(resp) {
        return resp.rows.length > 0;
      },
    });
  }

  // Compile the query to determine if a column exists in a table.
  hasColumn(tableName, columnName) {
    let sql =
      'select * from information_schema.columns where table_name = ? and column_name = ?';
    const bindings = [tableName, columnName];

    if (this.schema) {
      sql += ' and table_schema = ?';
      bindings.push(this.schema);
    } else {
      sql += ' and table_schema = current_schema()';
    }

    this.pushQuery({
      sql,
      bindings,
      output(resp) {
        return resp.rows.length > 0;
      },
    });
  }

  qualifiedTableName(tableName) {
    const name = this.schema ? `${this.schema}.${tableName}` : tableName;
    return this.formatter.wrap(name);
  }

  // Compile a rename table command.
  renameTable(from, to) {
    this.pushQuery(
      `alter table ${this.qualifiedTableName(
        from
      )} rename to ${this.formatter.wrap(to)}`
    );
  }

  createSchema(schemaName) {
    this.pushQuery(`create schema ${this.formatter.wrap(schemaName)}`);
  }

  createSchemaIfNotExists(schemaName) {
    this.pushQuery(
      `create schema if not exists ${this.formatter.wrap(schemaName)}`
    );
  }

  dropSchema(schemaName, cascade = false) {
    this.pushQuery(
      `drop schema ${this.formatter.wrap(schemaName)}${
        cascade ? ' cascade' : ''
      }`
    );
  }

  dropSchemaIfExists(schemaName, cascade = false) {
    this.pushQuery(
      `drop schema if exists ${this.formatter.wrap(schemaName)}${
        cascade ? ' cascade' : ''
      }`
    );
  }

  dropExtension(extensionName) {
    this.pushQuery(`drop extension ${this.formatter.wrap(extensionName)}`);
  }

  dropExtensionIfExists(extensionName) {
    this.pushQuery(
      `drop extension if exists ${this.formatter.wrap(extensionName)}`
    );
  }

  createExtension(extensionName) {
    this.pushQuery(`create extension ${this.formatter.wrap(extensionName)}`);
  }

  createExtensionIfNotExists(extensionName) {
    this.pushQuery(
      `create extension if not exists ${this.formatter.wrap(extensionName)}`
    );
  }

  renameView(from, to) {
    this.pushQuery(
      this.alterViewPrefix +
        `${this.formatter.wrap(from)} rename to ${this.formatter.wrap(to)}`
    );
  }

  refreshMaterializedView(viewName, concurrently = false) {
    this.pushQuery({
      sql: `refresh materialized view${
        concurrently ? ' concurrently' : ''
      } ${this.formatter.wrap(viewName)}`,
    });
  }

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

  dropMaterializedViewIfExists(viewName) {
    this._dropView(viewName, true, true);
  }
}

module.exports = SchemaCompiler_PG;
