/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var database_server_exports = {};
__export(database_server_exports, {
  DatabaseServerModel: () => DatabaseServerModel
});
module.exports = __toCommonJS(database_server_exports);
var import_database = __toESM(require("@nocobase/database"));
var import_remote_local_bridge = require("../bridges/remote-local-bridge");
class DatabaseServerModel extends import_database.MagicAttributeModel {
  app;
  setApp(app) {
    this.app = app;
  }
  renderJsonTemplate(options) {
    var _a;
    if (!((_a = this.app) == null ? void 0 : _a.environment)) {
      return options;
    }
    return this.app.environment.renderJsonTemplate(options);
  }
  getRemoteDatabaseInstance() {
    return new import_database.default(
      this.renderJsonTemplate({
        ...this.toJSON()
      })
    );
  }
  getOptions() {
    return this.renderJsonTemplate({
      ...this.toJSON()
    });
  }
  async listRemoteTables() {
    const remoteDB = this.getRemoteDatabaseInstance();
    if (remoteDB.inDialect("postgres")) {
      const results = await remoteDB.sequelize.query(
        `
          SELECT table_name as name, table_schema as schema
          FROM information_schema.tables
          WHERE table_schema NOT IN ('information_schema', 'pg_catalog')
        `,
        {
          type: "SELECT"
        }
      );
      await remoteDB.close();
      return results;
    } else {
      const options = this.getOptions();
      const results = await remoteDB.sequelize.query(
        `
          SELECT table_name as name
          FROM information_schema.tables
          WHERE table_schema = '${options.database}'
        `,
        {
          type: "SELECT"
        }
      );
      await remoteDB.close();
      return results;
    }
  }
  async describeTable(table) {
    const remoteDB = this.getRemoteDatabaseInstance();
    const columns = await remoteDB.sequelize.getQueryInterface().describeTable(table);
    await remoteDB.close();
    return columns;
  }
  async showIndexes(table) {
    const remoteDB = this.getRemoteDatabaseInstance();
    const queryOptions = (() => {
      if (remoteDB.inDialect("postgres")) {
        return table;
      }
      return table.tableName;
    })();
    const constraints = await remoteDB.sequelize.getQueryInterface().showIndex(queryOptions);
    await remoteDB.close();
    return constraints;
  }
  async showTableDefinition(tableInfo) {
    const remoteDB = this.getRemoteDatabaseInstance();
    const def = await remoteDB.queryInterface.showTableDefinition(tableInfo);
    await remoteDB.close();
    return def;
  }
  async updateServer(options) {
    const { transaction } = options;
    const db = this.app.db;
    const remoteInstance = this.getRemoteDatabaseInstance();
    try {
      await remoteInstance.sequelize.authenticate();
    } catch (error) {
      throw new Error(`Unable to connect to the remote database: ${error.message}`);
    }
    const replacements = this.renderJsonTemplate({
      serverName: this.get("name"),
      host: this.get("host"),
      port: this.get("port"),
      database: this.get("database"),
      user: this.get("username"),
      password: this.get("password")
    });
    if (db.inDialect("postgres")) {
      await db.sequelize.query(
        `
        ALTER SERVER ${this.get("name")}
        OPTIONS (SET host :host, SET port :port, SET dbname :database);

        ALTER USER MAPPING FOR ${db.options.username}
        SERVER ${this.get("name")}
        OPTIONS (SET user :user, SET password :password);
        `,
        {
          replacements,
          type: "RAW",
          transaction
        }
      );
    }
    if (db.inDialect("mysql", "mariadb")) {
      await db.sequelize.query(
        `
        ALTER SERVER ${this.get("name")}
        OPTIONS (USER :user, HOST :host, PORT ${replacements.port}, DATABASE :database, PASSWORD :password);
        `,
        {
          replacements,
          transaction
        }
      );
    }
  }
  async destroyServer(options) {
    const { transaction } = options;
    const db = this.app.db;
    if (db.inDialect("postgres")) {
      await db.sequelize.query(
        `
        DROP SERVER IF EXISTS ${this.get("name")} CASCADE;
        `,
        {
          transaction,
          type: "RAW"
        }
      );
    }
    if (db.inDialect("mysql", "mariadb")) {
      await db.sequelize.query(
        `
        DROP SERVER IF EXISTS ${this.get("name")};
        `,
        {
          transaction,
          type: "RAW"
        }
      );
    }
  }
  async createServer(options) {
    const { transaction } = options;
    const db = this.app.db;
    const remoteInstance = this.getRemoteDatabaseInstance();
    try {
      await remoteInstance.sequelize.authenticate();
    } catch (error) {
      throw new Error(`Unable to connect to the remote database: ${error.message}`);
    }
    const remoteLocalBridge = import_remote_local_bridge.RemoteLocalBridgeFactory.createBridge({
      remoteDatabase: remoteInstance,
      localDatabase: db
    });
    const opts = this.renderJsonTemplate({
      serverName: this.get("name"),
      host: this.get("host"),
      port: this.get("port"),
      database: this.get("database"),
      user: this.get("username"),
      password: this.get("password")
    });
    await remoteLocalBridge.createServer({
      ...opts,
      transaction
    });
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  DatabaseServerModel
});
