qbrs_core/prepare.rs
1//! `prepare!{}`: declares a named, typed parameter struct for a reusable
2//! prepared query (`select::Prepared`). See that module's doc comment for
3//! the design and its soundness caveat.
4
5/// ```ignore
6/// prepare! {
7/// struct ByEmail { email: Text }
8/// }
9///
10/// let query = select((users::id,))
11/// .from(users::Table)
12/// .filter(users::email.eq(ByEmail::email()))
13/// .prepare::<ByEmail, _>(Postgres);
14///
15/// let (sql, params) = query.resolve(ByEmail { email: "a@example.com".into() })?;
16/// ```
17#[macro_export]
18macro_rules! prepare {
19 (struct $name:ident { $($field:ident : $ty:ty),* $(,)? }) => {
20 #[derive(Debug, Clone, Default)]
21 pub struct $name {
22 $(pub $field: <$ty as $crate::expr::SqlType>::Native,)*
23 }
24
25 #[allow(dead_code, non_snake_case)]
26 impl $name {
27 $(
28 pub fn $field() -> $crate::expr::Expr<$crate::scope::Nil, $ty> {
29 // Qualified by where it was declared: `Params` is a free
30 // parameter of `.prepare()`, so two `prepare!` structs
31 // sharing a field name would otherwise fill each other's
32 // placeholders with no complaint from anyone.
33 $crate::expr::placeholder::<$ty>(::std::concat!(
34 ::std::module_path!(), "::", ::std::stringify!($name),
35 ".", ::std::stringify!($field)
36 ))
37 }
38 )*
39 }
40
41 impl $crate::select::PreparedParams for $name {
42 fn into_named_values(self) -> ::std::vec::Vec<(&'static str, $crate::expr::Value)> {
43 ::std::vec![
44 $((
45 ::std::concat!(
46 ::std::module_path!(), "::", ::std::stringify!($name),
47 ".", ::std::stringify!($field)
48 ),
49 ::std::convert::Into::into(self.$field),
50 ),)*
51 ]
52 }
53 }
54 };
55}