Files
pawctioneer-bot/src/db/bind_fields.rs
2025-08-29 23:25:12 +00:00

65 lines
1.5 KiB
Rust

use std::iter::repeat;
use sqlx::{prelude::*, query::Query, sqlite::SqliteArguments, Encode, Sqlite};
type BindFn = Box<
dyn for<'q> FnOnce(
Query<'q, Sqlite, SqliteArguments<'q>>,
) -> Query<'q, Sqlite, SqliteArguments<'q>>
+ Send,
>;
fn make_bind_fn<T>(value: T) -> BindFn
where
T: for<'q> Encode<'q, Sqlite> + Type<Sqlite> + Send + 'static,
{
Box::new(move |query| query.bind(value))
}
pub struct BindFields {
binds: Vec<(&'static str, BindFn)>,
}
impl Default for BindFields {
fn default() -> Self {
Self { binds: vec![] }
}
}
impl BindFields {
#[must_use]
pub fn push<'a>(
mut self,
field: &'static str,
value: &'a (impl for<'q> Encode<'q, Sqlite> + Type<Sqlite> + Send + 'static + Clone),
) -> Self {
self.binds.push((field, make_bind_fn(value.clone())));
self
}
#[must_use]
pub fn extend(mut self, other: Self) -> Self {
self.binds.extend(other.binds);
self
}
pub fn bind_to_query<'q>(
self,
query: Query<'q, Sqlite, SqliteArguments<'q>>,
) -> Query<'q, Sqlite, SqliteArguments<'q>> {
let mut query = query;
for (_, bind_fn) in self.binds {
query = bind_fn(query);
}
query
}
pub fn bind_names(&self) -> impl Iterator<Item = &'static str> + '_ {
self.binds.iter().map(|(name, _)| *name)
}
pub fn bind_placeholders(&self) -> impl Iterator<Item = &'static str> + '_ {
repeat("?").take(self.binds.len())
}
}