use crate::expr::{Expr, IntoExpr, IntoExprList};
use crate::writer::{Expression, SqlWriter};
#[derive(Debug, Clone, Default)]
pub struct Set {
pub exprs: Vec<Expr>,
}
impl Set {
pub fn append_set(&mut self, expr: impl IntoExpr) {
self.exprs.push(expr.into_expr());
}
pub fn append_sets(&mut self, exprs: impl IntoExprList) {
self.exprs.extend(exprs.into_expr_list());
}
pub fn is_empty(&self) -> bool {
self.exprs.is_empty()
}
}
impl Expression for Set {
fn write_sql(&self, w: &mut SqlWriter<'_>) {
w.write_slice(&self.exprs, "", ", ", "");
}
}
pub trait HasSet {
fn set_mut(&mut self) -> &mut Set;
}
impl HasSet for Set {
fn set_mut(&mut self) -> &mut Set {
self
}
}
#[cfg(test)]
mod tests {
use keelson_sqlcheck::testing::assert_frag_sql;
use super::*;
use crate::dialect::testing::Numbered;
use crate::expr::{Chain, arg, quote};
use crate::value::Value;
use crate::writer::build;
const FRAME: &str = "UPDATE users SET {} WHERE \"id\" = 1";
#[test]
fn an_empty_set_writes_nothing() {
assert_eq!(build(&Numbered, &Set::default()).unwrap().0, "");
assert!(Set::default().is_empty());
}
#[test]
fn assignments_are_comma_separated_and_carry_no_keyword() {
let mut s = Set::default();
s.append_set(quote("name").eq(arg("kubo")));
s.append_set(quote("age").eq(arg(3i32)));
let (sql, args) = build(&Numbered, &s).unwrap();
assert_frag_sql(
r#"SELECT {} FROM users"#,
&sql,
r#"("name" = $1), ("age" = $2)"#,
);
assert_eq!(args, vec![Value::Text("kubo".into()), Value::I32(3)]);
}
#[test]
fn a_multi_column_assignment_is_one_assignment() {
let mut s = Set::default();
s.append_sets((
Expr::binary(
Expr::group((quote("name"), quote("email"))),
"=",
Expr::group((arg("kubo"), arg("kubo@example.com"))),
),
Expr::raw(r#""age" = DEFAULT"#),
));
let (sql, args) = build(&Numbered, &s).unwrap();
assert_frag_sql(
FRAME,
&sql,
r#"("name", "email") = ($1, $2), "age" = DEFAULT"#,
);
assert_eq!(args.len(), 2);
}
}