// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// The three SQL dialects moondb's ratified drivers speak.
///
/// A query layer that has to emit SQL — a builder, a migration runner, an ORM that
/// paginates or upserts — needs two things from the backend it is talking to: the
/// spelling of a bound parameter, and what the backend can do beyond the plain
/// `Driver` contract. Reporting the dialect through the driver itself means the
/// layer is written once and runs on all three, instead of the caller naming the
/// backend a second time at every call site.
///
/// ```moonbit check
/// test "a dialect spells its own placeholder" {
///   assert_eq(@moondb.Dialect::Postgres.placeholder(1), "$1")
///   assert_eq(@moondb.Dialect::Postgres.placeholder(7), "$7")
///   assert_eq(@moondb.Dialect::Sqlite.placeholder(1), "?")
///   assert_eq(@moondb.Dialect::Mysql.placeholder(3), "?")
/// }
/// ```
#derive(Eq, @debug.Debug)
pub(all) enum Dialect {
  Sqlite
  Postgres
  Mysql
}

///|
/// The placeholder for the `n`-th bound parameter (1-based).
///
/// PostgreSQL's extended-query protocol numbers parameters, so each one is spelled
/// `$n`; SQLite and MySQL bind positionally and spell every one `?`. The index is
/// ignored by the two positional dialects, which is why a builder can call this
/// unconditionally.
pub fn Dialect::placeholder(self : Dialect, n : Int32) -> String {
  match self {
    Postgres => "$" + n.to_string()
    Sqlite | Mysql => "?"
  }
}

///|
/// The dialect's short name in lower case — the spelling used in configuration and
/// in a driver's `Capabilities`.
pub fn Dialect::name(self : Dialect) -> String {
  match self {
    Sqlite => "sqlite"
    Postgres => "postgres"
    Mysql => "mysql"
  }
}

///|
/// Look a dialect up by its short name, ignoring case. Accepts the usual aliases
/// (`postgresql`, `pg`, `mariadb`) because a configuration file is written by a
/// person, not by this module.
pub fn Dialect::parse(name : String) -> Dialect? {
  let lower = name.to_lower()
  match lower {
    "sqlite" | "sqlite3" => Some(Sqlite)
    "postgres" | "postgresql" | "pg" => Some(Postgres)
    "mysql" | "mariadb" => Some(Mysql)
    _ => None
  }
}

///|
pub extend Dialect with Eq::{not_equal, equal}

///|
pub extend Dialect with Debug::{to_repr}