1use crate::prelude::*;
4use crate::{
5 sql::{ColumnRef, SQL, TableRef, Token},
6 traits::SQLParam,
7};
8
9#[cfg(feature = "uuid")]
10use uuid::Uuid;
11
12#[diagnostic::on_unimplemented(
18 message = "`{Self}` cannot be converted to SQL",
19 label = "this type does not implement ToSQL for the current dialect",
20 note = "tuples larger than the enabled arity need a larger `colN` feature (col16, col32, col64, col128, col200) on drizzle-core"
21)]
22pub trait ToSQL<'a, V: SQLParam> {
23 fn to_sql(&self) -> SQL<'a, V>;
24
25 fn into_sql(self) -> SQL<'a, V>
29 where
30 Self: Sized,
31 {
32 self.to_sql()
33 }
34}
35
36#[derive(Debug, Clone)]
48pub struct SQLBytes<'a>(pub Cow<'a, [u8]>);
49
50#[derive(Debug, Clone, Copy, Default)]
52pub struct SQLNull;
53
54impl<'a> SQLBytes<'a> {
55 #[inline]
56 pub fn new(bytes: impl Into<Cow<'a, [u8]>>) -> Self {
57 Self(bytes.into())
58 }
59}
60
61impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for SQLNull {
62 fn to_sql(&self) -> SQL<'a, V> {
63 SQL::raw("NULL")
64 }
65}
66
67impl<'a, T, V> From<&T> for SQL<'a, V>
68where
69 T: ToSQL<'a, V>,
70 V: SQLParam,
71{
72 fn from(value: &T) -> Self {
73 value.to_sql()
74 }
75}
76
77impl<'a, V: SQLParam, T> ToSQL<'a, V> for &T
78where
79 T: ToSQL<'a, V>,
80{
81 fn to_sql(&self) -> SQL<'a, V> {
82 (**self).to_sql()
83 }
84}
85
86impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for () {
87 fn to_sql(&self) -> SQL<'a, V> {
88 SQL::empty()
89 }
90}
91
92impl<'a, V, T> ToSQL<'a, V> for Vec<T>
93where
94 V: SQLParam + 'a,
95 T: ToSQL<'a, V>,
96{
97 fn to_sql(&self) -> SQL<'a, V> {
98 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
99 }
100}
101
102impl<'a, V, T> ToSQL<'a, V> for &'a [T]
103where
104 V: SQLParam + 'a,
105 T: ToSQL<'a, V>,
106{
107 fn to_sql(&self) -> SQL<'a, V> {
108 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
109 }
110}
111
112impl<'a, V, T, const N: usize> ToSQL<'a, V> for [T; N]
113where
114 V: SQLParam + 'a,
115 T: ToSQL<'a, V>,
116{
117 fn to_sql(&self) -> SQL<'a, V> {
118 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
119 }
120}
121
122impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for TableRef {
123 fn to_sql(&self) -> SQL<'a, V> {
124 SQL::table(*self)
125 }
126}
127
128impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for ColumnRef {
129 fn to_sql(&self) -> SQL<'a, V> {
130 SQL::column(*self)
131 }
132}
133
134impl<'a, V> ToSQL<'a, V> for &'a str
136where
137 V: SQLParam + 'a + From<&'a str> + Into<Cow<'a, V>>,
138{
139 fn to_sql(&self) -> SQL<'a, V> {
140 SQL::param(V::from(self))
141 }
142}
143
144impl<'a, V> ToSQL<'a, V> for Box<str>
145where
146 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
147{
148 fn to_sql(&self) -> SQL<'a, V> {
149 SQL::param(V::from(self.to_string()))
150 }
151
152 fn into_sql(self) -> SQL<'a, V> {
153 SQL::param(V::from(self.into_string()))
154 }
155}
156
157#[cfg(any(feature = "std", feature = "alloc"))]
158impl<'a, V> ToSQL<'a, V> for Rc<str>
159where
160 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
161{
162 fn to_sql(&self) -> SQL<'a, V> {
163 SQL::param(V::from(self.as_ref().to_string()))
164 }
165}
166
167#[cfg(any(feature = "std", feature = "alloc"))]
168impl<'a, V> ToSQL<'a, V> for Arc<str>
169where
170 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
171{
172 fn to_sql(&self) -> SQL<'a, V> {
173 SQL::param(V::from(self.as_ref().to_string()))
174 }
175}
176
177impl<'a, V, T> ToSQL<'a, V> for Box<T>
178where
179 V: SQLParam + 'a,
180 T: ToSQL<'a, V>,
181{
182 fn to_sql(&self) -> SQL<'a, V> {
183 (**self).to_sql()
184 }
185}
186
187#[cfg(any(feature = "std", feature = "alloc"))]
188impl<'a, V, T> ToSQL<'a, V> for Rc<T>
189where
190 V: SQLParam + 'a,
191 T: ToSQL<'a, V>,
192{
193 fn to_sql(&self) -> SQL<'a, V> {
194 (**self).to_sql()
195 }
196}
197
198#[cfg(any(feature = "std", feature = "alloc"))]
199impl<'a, V, T> ToSQL<'a, V> for Arc<T>
200where
201 V: SQLParam + 'a,
202 T: ToSQL<'a, V>,
203{
204 fn to_sql(&self) -> SQL<'a, V> {
205 (**self).to_sql()
206 }
207}
208
209impl<'a, V> ToSQL<'a, V> for String
210where
211 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
212{
213 fn to_sql(&self) -> SQL<'a, V> {
214 SQL::param(V::from(self.clone()))
215 }
216
217 fn into_sql(self) -> SQL<'a, V> {
218 SQL::param(V::from(self))
219 }
220}
221
222impl<'a, V> ToSQL<'a, V> for Cow<'a, str>
223where
224 V: SQLParam + 'a + From<&'a str> + From<String> + Into<Cow<'a, V>>,
225{
226 fn to_sql(&self) -> SQL<'a, V> {
227 match self {
228 Cow::Borrowed(value) => SQL::param(V::from(*value)),
229 Cow::Owned(value) => SQL::param(V::from(value.clone())),
230 }
231 }
232
233 fn into_sql(self) -> SQL<'a, V> {
234 match self {
235 Cow::Borrowed(value) => SQL::param(V::from(value)),
236 Cow::Owned(value) => SQL::param(V::from(value)),
237 }
238 }
239}
240
241impl<'a, V> ToSQL<'a, V> for Cow<'a, [u8]>
242where
243 V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
244{
245 fn to_sql(&self) -> SQL<'a, V> {
246 match self {
247 Cow::Borrowed(value) => SQL::param(V::from(*value)),
248 Cow::Owned(value) => SQL::param(V::from(value.clone())),
249 }
250 }
251
252 fn into_sql(self) -> SQL<'a, V> {
253 match self {
254 Cow::Borrowed(value) => SQL::param(V::from(value)),
255 Cow::Owned(value) => SQL::param(V::from(value)),
256 }
257 }
258}
259
260impl<'a, V> ToSQL<'a, V> for SQLBytes<'a>
261where
262 V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
263{
264 fn to_sql(&self) -> SQL<'a, V> {
265 match &self.0 {
266 Cow::Borrowed(value) => SQL::param(V::from(*value)),
267 Cow::Owned(value) => SQL::param(V::from(value.clone())),
268 }
269 }
270
271 fn into_sql(self) -> SQL<'a, V> {
272 match self.0 {
273 Cow::Borrowed(value) => SQL::param(V::from(value)),
274 Cow::Owned(value) => SQL::param(V::from(value)),
275 }
276 }
277}
278
279macro_rules! impl_tosql_param_copy {
280 ($($ty:ty),+ $(,)?) => {
281 $(
282 impl<'a, V> ToSQL<'a, V> for $ty
283 where
284 V: SQLParam + 'a + From<$ty>,
285 V: Into<Cow<'a, V>>,
286 {
287 fn to_sql(&self) -> SQL<'a, V> {
288 SQL::param(V::from(*self))
289 }
290 }
291 )+
292 };
293}
294
295impl_tosql_param_copy!(
296 i8, i16, i32, i64, f32, f64, bool, u8, u16, u32, u64, isize, usize
297);
298
299impl<'a, V, T> ToSQL<'a, V> for Option<T>
300where
301 V: SQLParam + 'a,
302 T: ToSQL<'a, V>,
303{
304 fn to_sql(&self) -> SQL<'a, V> {
305 self.as_ref()
306 .map_or_else(|| SQLNull.to_sql(), ToSQL::to_sql)
307 }
308}
309
310#[cfg(feature = "uuid")]
311impl<'a, V> ToSQL<'a, V> for Uuid
312where
313 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
314{
315 fn to_sql(&self) -> SQL<'a, V> {
316 SQL::param(V::from(*self))
317 }
318}