///|
/// Schema DDL from declared columns: `Model::create_table_sql` (SQLite affinities) and
/// `create_table_sql_for` for PostgreSQL and MySQL, covering autoincrement idioms
/// (`AUTOINCREMENT` / `SERIAL` / `AUTO_INCREMENT`), `UNIQUE`, `DEFAULT`, column `CHECK`,
/// foreign keys with `ON DELETE`/`ON UPDATE`, and a composite primary key rendered as a
/// table-level constraint. Also a lone `Column::ddl`, `ColumnType::sql_for` across
/// dialects, and `index_ddl`. All identifiers are trusted, declared in code — never bound.
///
///     moon run examples/10-schema-ddl
struct Hero {
  id : Int32
  name : String
  team_id : Int32
}

///|
let heroes : @moonorm.Model[Hero] = @moonorm.Model::new(
  "heroes",
  [
    @moonorm.column("id", IntType, primary_key=true, autoincrement=true),
    @moonorm.column("name", VarcharType(64), nullable=false, unique=true),
    @moonorm.column("power", IntType, default="0", checks=["power >= 0"]),
    @moonorm.column(
      "team_id",
      IntType,
      references=("teams", "id"),
      on_delete="CASCADE",
    ),
    @moonorm.column("created", DateTimeType, default="CURRENT_TIMESTAMP"),
  ],
  r => { id: r.int(0), name: r.text(1), team_id: r.int(3), },
  h => {
    [
      ("id", @moondb.Int(h.id)),
      ("name", @moondb.Text(h.name)),
      ("team_id", @moondb.Int(h.team_id)),
    ]
  },
)

///|
/// A composite-key association table: the primary key spans two columns, so it lands
/// as a table-level `PRIMARY KEY (a, b)` constraint rather than inline.
let memberships : @moonorm.Model[Hero] = @moonorm.Model::new(
  "memberships",
  [
    @moonorm.column("hero_id", IntType, primary_key=true),
    @moonorm.column("team_id", IntType, primary_key=true),
  ],
  r => { id: r.int(0), name: "", team_id: r.int(1), },
  _ => [],
)

///|
#coverage.skip
fn main {
  println("-- CREATE TABLE (SQLite affinities)")
  println(heroes.create_table_sql())
  println("")
  println("-- CREATE TABLE (PostgreSQL)")
  println(heroes.create_table_sql_for(Postgres))
  println("")
  println("-- CREATE TABLE (MySQL)")
  println(heroes.create_table_sql_for(Mysql))
  println("")
  println("-- idempotent DDL (IF NOT EXISTS)")
  println(heroes.create_table_sql(if_not_exists=true))

  // One column on its own, and the type keyword each dialect renders.
  let fk = @moonorm.column(
    "team_id",
    IntType,
    nullable=false,
    references=("teams", "id"),
    on_update="RESTRICT",
  )
  println("")
  println("-- one Column::ddl")
  println(fk.ddl())
  println("-- ColumnType::sql_for across dialects")
  let types : Array[(String, @moonorm.ColumnType)] = [
    ("uuid", UuidType),
    ("json", JsonType),
    ("bool", BoolType),
    ("real", RealType),
  ]
  for t in types {
    let name = t.0
    let ty = t.1
    println(
      "  \{name}: sqlite=\{ty.sql_for(Sqlite)} pg=\{ty.sql_for(Postgres)} mysql=\{ty.sql_for(Mysql)}",
    )
  }

  println("")
  println("-- composite primary key -> table-level constraint")
  println(memberships.create_table_sql())

  println("")
  println("-- index_ddl")
  println(@moonorm.index_ddl("idx_heroes_name", "heroes", ["name"]))
  println(
    @moonorm.index_ddl(
      "uq_membership",
      "memberships",
      ["hero_id", "team_id"],
      unique=true,
    ),
  )
}