import { FieldType } from './schema';

/** @noSelf */
export interface SqlCommander {
  /**
   * Execute the SQL statement contained in the sql-statement parameter.
   * @param sqlStatement Statement, which should conform to the rules for SQL grammar.
   * @param extraParameters Optional table for placeholders in the statement.
   */
  execute(sqlStatement: string, extraParameters?: unknown[]): ExecutionResult;

  /** The same as `prepared_table:execute()`. */
  execute(preparedStatementId: number): ExecutionResult;

  /**
   * Prepare the SQL statement contained in the sql-statement parameter. The syntax and requirements for box.prepare are the same as for `box.execute()`.
   * @param sqlStatement Statement, which should conform to the rules for SQL grammar.
   * @returns Prepared_table, with id and methods and metadata.
   */
  prepare(sqlStatement: string): PreparedStatementObjectTable;

  /** The same as `prepared_table:unprepare()`. */
  unprepare(preparedStatementId: number): void;
}

export interface ExecutionResult {
  rowcount?: number;

  /**
   * If `sql_full_metadata` in the `_session_settings` system table is `TRUE`,
   * then result set metadata may include these things in addition to name and type:
   * - `collation` (present only if `COLLATE` clause is specified for a STRING) = “Collation”.
   * - `is_nullable` (present only if the select list specified a base table column and nothing else) = `false` if column was defined as `NOT NULL`,
   * otherwise `true`. If this is not present, that implies that nullability is unknown.
   * - `is_autoincrement` (present only if the select list specified a base table column and nothing else) = `true` if column was defined as
   * `PRIMARY KEY AUTOINCREMENT`, otherwise `false`.
   * - `span` (always present) = the original expression in a select list,
   * which often is the same as name if the select list specifies a column name and nothing else,
   * but otherwise differs, for example, after `SELECT x+55 AS x FROM t;` the name is `X` and the span is `x+55`.
   * If span and name are the same then the content is `MP_NIL`.
   */
  metadata?: ExecutionResultMetadata;

  /** Returned values. */
  rows?: unknown[][]
}

export interface ExecutionResultMetadata {
  /** Column name. */
  name: string;
  /** Column type. */
  type: FieldType;
  collation?: string;
  is_nullable?: boolean;
  is_autoincrement?: boolean;
  span?: unknown;
}

export interface PreparedStatementObjectTable {
  /** An identifier generated by a hash of the statement string. */
  stmt_id: number;

  /** Parameter descriptions. */
  params: { name: string, type: string }[];

  /** This is present only for `SELECT` or `PRAGMA` statements and has the same contents as the result set metadata for `box.execute`. */
  metadata: { name: string, type: string}[];

  /** Number of parameters. */
  param_count: number;

  /**
   * Execute a statement that has been prepared with `box.prepare()`.
   * @param extraParameters Optional table to match placeholders or named parameters in the statement.
   */
  execute(extraParameters?: LuaTable): ExecutionResult;

  /**
   * Undo the result of an earlier `box.prepare()` request. This is equivalent to standard-SQL `DEALLOCATE PREPARE`.
   *
   * Tarantool strongly recommends using `unprepare` as soon as the immediate objective (executing a prepared statement multiple times) is done,
   * or whenever a prepared statement expires. There is no automatic eviction policy,
   * although automatic unprepare will happen when the session disconnects
   * (the session’s prepared statements will be removed from the prepared-statement cache).
   */
  unprepare(): void;
}
