toasty_sql/serializer/
params.rs

1use crate::serializer::ExprContext;
2
3use super::{Flavor, Formatter, ToSql};
4
5use toasty_core::stmt;
6
7/// Collects query parameter values during SQL serialization.
8///
9/// Implement this trait to control how bound parameters are stored. The
10/// serializer calls [`push`](Params::push) each time it encounters a value
11/// that should be sent as a bind parameter rather than inlined into the SQL
12/// string.
13pub trait Params {
14    /// Appends a value (with an optional type hint) and returns its [`Placeholder`].
15    fn push(&mut self, param: &stmt::Value, type_hint: Option<&stmt::Type>) -> Placeholder;
16}
17
18/// A positional bind-parameter placeholder.
19///
20/// The inner `usize` is the 1-based parameter index. The serializer renders
21/// it in the target dialect's format (`$1`, `?1`, or `?`).
22///
23/// # Example
24///
25/// ```
26/// use toasty_sql::serializer::Placeholder;
27///
28/// let p = Placeholder(3);
29/// assert_eq!(p.0, 3);
30/// ```
31pub struct Placeholder(pub usize);
32
33/// A parameter value paired with an optional type hint.
34///
35/// Type hints let drivers pick the right wire format when the value alone
36/// is ambiguous (e.g. distinguishing `INTEGER` from `BIGINT`).
37///
38/// # Example
39///
40/// ```
41/// use toasty_sql::TypedValue;
42///
43/// let tv = TypedValue {
44///     value: toasty_core::stmt::Value::Null,
45///     type_hint: None,
46/// };
47/// assert!(tv.type_hint.is_none());
48/// ```
49#[derive(Debug, Clone)]
50pub struct TypedValue {
51    /// The parameter value.
52    pub value: stmt::Value,
53    /// An optional type hint for the value.
54    pub type_hint: Option<stmt::Type>,
55}
56
57impl TypedValue {
58    /// Infers the type of this value, using the type hint if available
59    pub fn infer_ty(&self) -> stmt::Type {
60        self.type_hint
61            .clone()
62            .unwrap_or_else(|| self.value.infer_ty())
63    }
64}
65
66impl Params for Vec<stmt::Value> {
67    fn push(&mut self, value: &stmt::Value, _type_hint: Option<&stmt::Type>) -> Placeholder {
68        self.push(value.clone());
69        Placeholder(self.len())
70    }
71}
72
73impl Params for Vec<TypedValue> {
74    fn push(&mut self, value: &stmt::Value, type_hint: Option<&stmt::Type>) -> Placeholder {
75        self.push(TypedValue {
76            value: value.clone(),
77            type_hint: type_hint.cloned(),
78        });
79        Placeholder(self.len())
80    }
81}
82
83impl ToSql for Placeholder {
84    fn to_sql<P: Params>(self, _cx: &ExprContext<'_>, f: &mut Formatter<'_, P>) {
85        use std::fmt::Write;
86
87        match f.serializer.flavor {
88            Flavor::Mysql => write!(&mut f.dst, "?").unwrap(),
89            Flavor::Postgresql => write!(&mut f.dst, "${}", self.0).unwrap(),
90            Flavor::Sqlite => write!(&mut f.dst, "?{}", self.0).unwrap(),
91        }
92    }
93}