#![allow(dead_code)] use sqlx::database::HasArguments; use sqlx::encode::Encode; use sqlx::types::Type; use sqlx::{Arguments, Database}; use std::fmt::Display; pub struct UpdateBuilder<'args, DB> where DB: Database, { table: Option, names: Option>, where_: Option>, values: Option<>::Arguments>, } impl<'args, DB: Database> UpdateBuilder<'args, DB> where DB: Database, { pub fn new() -> Self where >::Arguments: Default, { UpdateBuilder { table: None, names: Some(Vec::new()), where_: Some(Vec::new()), values: Some(Default::default()), } } #[inline] fn sanity_check(&self) { assert!( self.values.is_some(), "UpdateBuilder must be reset before reuse after `.build()`" ); } pub fn table(&mut self, table: impl Display) -> &mut Self { self.sanity_check(); self.table = Some(format!("{table}")); self } pub fn and_where(&mut self, name: impl Display, op: impl Display, value: T) -> &mut Self where T: 'args + Encode<'args, DB> + Send + Type, { self.sanity_check(); let values = self.values.as_mut().expect("BUG: Values taken already"); values.add(value); let mut placeholder = String::new(); values .format_placeholder(&mut placeholder) .expect("error in format_placeholder"); let where_ = self.where_.as_mut().expect("BUG: Where taken already"); where_.push((format!("{name}"), format!("{op}"), placeholder)); self } pub fn set(&mut self, name: impl Display, value: T) -> &mut Self where T: 'args + Encode<'args, DB> + Send + Type, { self.sanity_check(); assert!( self.where_.as_ref().unwrap().is_empty(), "set must not be called after add_where" ); let names = self.names.as_mut().expect("BUG: Names taken already"); let values = self.values.as_mut().expect("BUG: Values taken already"); values.add(value); let mut placeholder = String::new(); values .format_placeholder(&mut placeholder) .expect("error in format_placeholder"); names.push((format!("{name}"), placeholder)); self } pub fn build(&mut self) -> (String, >::Arguments) { self.sanity_check(); let table = self.table.take().unwrap(); let mut query = format!("UPDATE {table} SET"); let mut first = true; for (name, placeholder) in self.names.take().unwrap() { if first { first = false; } else { query.push(','); } query.push_str(&format!(" {name}={placeholder}")); } let where_ = self.where_.take().unwrap(); if !where_.is_empty() { query.push_str(" WHERE"); first = true; for (name, op, placeholder) in where_ { if first { first = false; } else { query.push_str(" AND"); } query.push_str(&format!(" {name}{op}{placeholder}")); } } // TODO: This method should return a Query, constructed by QueryBuilder, but I can't // figure out how to create QueryBuilder::with_arguments in this generic method, // where DB isn't "known". (query, self.values.take().unwrap()) } pub fn reset(&mut self) -> &mut Self { self.names = Some(Vec::new()); self.where_ = Some(Vec::new()); self.values = Some(Default::default()); self } }