///|
/// Boolean predicate trees — the parameter-safe `AND` / `OR` / `NOT` grouping the flat
/// `where_` / `eq` chain (always joined by `AND`) cannot express. A `Predicate` composes
/// `Cmp`, `InList`, `Exists`, and nested `And` / `Or` / `Not`; `where_pred` ANDs it with
/// the rest of the `WHERE`. Every comparison binds its value, so `(a = ? OR b = ?)` stays
/// fully parameterised. `Predicate::build` renders one to its fragment and bound values.
///
/// moon run examples/05-predicate-trees
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 {
// (name = ? OR name = ?) AND NOT (banned = ?), ANDed with a flat eq().
let tree : @moonorm.Predicate = And([
Or([
Cmp(col="name", op="=", val=@moondb.Text("lfanke")),
Cmp(col="name", op="=", val=@moondb.Text("heke1228")),
]),
Not(Cmp(col="banned", op="=", val=@moondb.Bool(true))),
])
let (sql, params) = @moonorm.select("users")
.column("id")
.eq("active", @moondb.Bool(true))
.where_pred(tree)
.build()
println("-- and/or/not predicate tree")
println(sql)
println("params: " + params_str(params))
// InList renders a parameterised IN; an empty list constant-folds.
let inpred : @moonorm.Predicate = InList(
col="id",
vals=[@moondb.Int(233), @moondb.Int(23333), @moondb.Int(66666)],
negated=false,
)
let (isql, iparams) = inpred.build()
println("")
println("-- Predicate::build for an IN list")
println(isql)
println("params: " + params_str(iparams))
let empty_in : @moonorm.Predicate = InList(col="id", vals=[], negated=true)
let (esql, _) = empty_in.build()
println("")
println("-- empty NOT IN constant-folds to always-true")
println(esql)
}