///|
/// Window functions: ` OVER (PARTITION BY … ORDER BY …)`, optionally aliased.
/// A window computes over a frame of rows without collapsing them, so each `window`
/// call adds one more projected column. The expression, partitions, and ordering are
/// identifier-level SQL — they name columns and functions, never bound values, so they
/// render verbatim and carry no params.
///
///     moon run examples/04-window-functions
fn render(v : @moondb.Value) -> String {
  match v {
    Null => "Null"
    Bool(b) => "Bool(\{b})"
    Int(n) => "Int(\{n})"
    Int64(n) => "Int64(\{n})"
    Double(d) => "Double(\{d})"
    Text(s) => "Text(\"\{s}\")"
    Blob(b) => "Blob(\{b.length()} bytes)"
    Time(s) => "Time(\"\{s}\")"
    Numeric(s) => "Numeric(\{s})"
    Uuid(b) => "Uuid(\{b.length()} bytes)"
    Json(s) => "Json(\{s})"
    Array(items) => "Array(\{items.length()} items)"
  }
}

///|
fn params_str(vals : Array[@moondb.Value]) -> String {
  "[" + vals.map(render).join(", ") + "]"
}

///|
#coverage.skip
fn main {
  // ROW_NUMBER over a partition, aliased, alongside a running SUM.
  let (sql, params) = @moonorm.select("sales")
    .column("region")
    .column("amount")
    .window(
      "ROW_NUMBER()",
      partition_by=["region"],
      order_by=[("amount", Desc)],
      as_="rn",
    )
    .window("SUM(amount)", partition_by=["region"], as_="region_total")
    .where_("amount", ">", @moondb.Int(233))
    .build()
  println("-- partitioned window functions")
  println(sql)
  println("params: " + params_str(params))

  // An empty partition/order yields one unordered window over the whole result.
  let (gsql, _) = @moonorm.select("sales")
    .raw("amount")
    .window("RANK()")
    .build()
  println("")
  println("-- window over the whole result")
  println(gsql)
}