Skip to main content

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}