drizzle_core/
params.rs

1use std::{borrow::Cow, fmt};
2
3use crate::traits::SQLParam;
4
5/// Various styles of SQL parameter placeholders.
6#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum PlaceholderStyle {
8    /// Colon style placeholders (:param)
9    Colon,
10    /// At-sign style placeholders (@param)
11    AtSign,
12    /// Dollar style placeholders ($param)
13    Dollar,
14    #[default]
15    Positional,
16}
17
18/// A SQL parameter placeholder.
19#[derive(Default, Debug, Clone, Hash, Copy, PartialEq, Eq)]
20pub struct Placeholder {
21    /// The name of the parameter.
22    pub name: Option<&'static str>,
23    /// The style of the placeholder.
24    pub style: PlaceholderStyle,
25}
26
27impl Placeholder {
28    /// Creates a new placeholder with the given name and style.
29    pub const fn with_style(name: &'static str, style: PlaceholderStyle) -> Self {
30        Placeholder {
31            name: Some(name),
32            style,
33        }
34    }
35
36    /// Creates a new colon-style placeholder.
37    pub const fn colon(name: &'static str) -> Self {
38        Self::with_style(name, PlaceholderStyle::Colon)
39    }
40
41    /// Creates a new at-sign-style placeholder.
42    pub const fn at(name: &'static str) -> Self {
43        Self::with_style(name, PlaceholderStyle::AtSign)
44    }
45
46    /// Creates a new dollar-style placeholder.
47    pub const fn dollar(name: &'static str) -> Self {
48        Self::with_style(name, PlaceholderStyle::Dollar)
49    }
50
51    /// Creates a positional placeholder ('?').
52    pub const fn positional() -> Self {
53        Placeholder {
54            name: None,
55            style: PlaceholderStyle::Positional,
56        }
57    }
58}
59
60impl fmt::Display for Placeholder {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        match self.style {
63            PlaceholderStyle::Colon => write!(f, ":{}", self.name.unwrap_or_default()),
64            PlaceholderStyle::AtSign => write!(f, "@{}", self.name.unwrap_or_default()),
65            PlaceholderStyle::Dollar => write!(f, "${}", self.name.unwrap_or_default()),
66            PlaceholderStyle::Positional => write!(f, "?"),
67        }
68    }
69}
70
71/// A SQL parameter that associates a value with a placeholder.
72/// Designed to be const-friendly and zero-cost when possible.
73#[derive(Debug, Clone)]
74pub struct Param<'a, V: SQLParam> {
75    /// The placeholder to use in the SQL
76    pub placeholder: Placeholder,
77    /// The value to bind
78    pub value: Option<Cow<'a, V>>,
79}
80
81impl<'a, V: SQLParam> Param<'a, V> {
82    pub fn new(placeholder: Placeholder, value: Option<Cow<'a, V>>) -> Self {
83        Self { placeholder, value }
84    }
85}
86
87impl<'a, V: SQLParam> From<OwnedParam<V>> for Param<'a, V> {
88    fn from(value: OwnedParam<V>) -> Self {
89        Self {
90            placeholder: value.placeholder,
91            value: value.value.map(|v| Cow::Owned(v)),
92        }
93    }
94}
95
96impl<'a, V: SQLParam> From<&'a OwnedParam<V>> for Param<'a, V> {
97    fn from(value: &'a OwnedParam<V>) -> Self {
98        Self {
99            placeholder: value.placeholder,
100            value: value.value.as_ref().map(|v| Cow::Borrowed(v)),
101        }
102    }
103}
104
105#[derive(Debug, Clone)]
106pub struct OwnedParam<V: SQLParam> {
107    /// The placeholder to use in the SQL
108    pub placeholder: Placeholder,
109    /// The value to bind
110    pub value: Option<V>,
111}
112
113impl<'a, V: SQLParam> From<Param<'a, V>> for OwnedParam<V> {
114    fn from(value: Param<'a, V>) -> Self {
115        Self {
116            placeholder: value.placeholder,
117            value: value.value.map(|v| v.into_owned()),
118        }
119    }
120}
121
122impl<'a, V: SQLParam> From<&Param<'a, V>> for OwnedParam<V> {
123    fn from(value: &Param<'a, V>) -> Self {
124        Self {
125            placeholder: value.placeholder,
126            value: value.value.clone().map(|v| v.into_owned()),
127        }
128    }
129}
130
131impl<'a, T: SQLParam> Param<'a, T> {
132    /// Creates a new parameter with a positional placeholder
133    pub const fn positional(value: T) -> Self {
134        Self {
135            placeholder: Placeholder::positional(),
136            value: Some(Cow::Owned(value)),
137        }
138    }
139
140    /// Creates a new parameter with a specific placeholder and no value
141    pub const fn from_placeholder(placeholder: Placeholder) -> Self {
142        Self {
143            placeholder,
144            value: None,
145        }
146    }
147
148    /// Creates a new parameter with a named placeholder (colon style)
149    pub const fn named(name: &'static str, value: T) -> Self {
150        Self {
151            placeholder: Placeholder::colon(name),
152            value: Some(Cow::Owned(value)),
153        }
154    }
155
156    /// Creates a new parameter with a specific placeholder
157    pub const fn with_placeholder(placeholder: Placeholder, value: T) -> Self {
158        Self {
159            placeholder,
160            value: Some(Cow::Owned(value)),
161        }
162    }
163}
164
165#[derive(Debug, Clone)]
166pub struct ParamBind<'a, V: SQLParam> {
167    pub name: &'a str,
168    pub value: V,
169}
170
171impl<'a, V: SQLParam> ParamBind<'a, V> {
172    pub const fn new(name: &'a str, value: V) -> Self {
173        Self { name, value }
174    }
175}
176
177/// Utility functions for creating placeholders with different styles
178pub mod placeholders {
179    use super::{Placeholder, PlaceholderStyle};
180
181    pub const fn colon(name: &'static str) -> Placeholder {
182        Placeholder::with_style(name, PlaceholderStyle::Colon)
183    }
184
185    pub const fn at(name: &'static str) -> Placeholder {
186        Placeholder::with_style(name, PlaceholderStyle::AtSign)
187    }
188
189    pub const fn dollar(name: &'static str) -> Placeholder {
190        Placeholder::with_style(name, PlaceholderStyle::Dollar)
191    }
192}