1#![forbid(unsafe_code)]
54#[allow(clippy::single_component_path_imports)]
55use qusql_sqlx_type_macro;
56
57pub use crate::qusql_sqlx_type_macro::{query, query_as};
58
59#[doc(hidden)]
61pub struct Integer;
62
63#[doc(hidden)]
65pub struct Float;
66
67#[doc(hidden)]
69pub struct Timestamp;
70
71#[doc(hidden)]
73pub struct DateTime;
74
75#[doc(hidden)]
77pub struct Date;
78
79#[doc(hidden)]
81pub struct Time;
82
83#[doc(hidden)]
85pub struct Any;
86
87#[doc(hidden)]
89pub struct Uuid;
90
91#[doc(hidden)]
93pub trait ArgIn<T> {}
94
95pub trait ArgOut<T, const IDX: usize> {}
97
98macro_rules! arg_io {
100 ( $dst: ty, $t: ty ) => {
101 impl ArgIn<$dst> for $t {}
102 impl ArgIn<$dst> for &$t {}
103 impl ArgIn<$dst> for Option<$t> {}
104 impl ArgIn<$dst> for Option<&$t> {}
105 impl ArgIn<$dst> for &Option<$t> {}
106 impl ArgIn<$dst> for &Option<&$t> {}
107 impl ArgIn<Option<$dst>> for $t {}
108 impl ArgIn<Option<$dst>> for &$t {}
109 impl ArgIn<Option<$dst>> for Option<$t> {}
110 impl ArgIn<Option<$dst>> for Option<&$t> {}
111 impl ArgIn<Option<$dst>> for &Option<$t> {}
112 impl ArgIn<Option<$dst>> for &Option<&$t> {}
113
114 impl<const IDX: usize> ArgOut<$dst, IDX> for $t {}
115 impl<const IDX: usize> ArgOut<Option<$dst>, IDX> for Option<$t> {}
116 impl<const IDX: usize> ArgOut<$dst, IDX> for Option<$t> {}
117 impl<const IDX: usize> ArgOut<Option<$dst>, IDX> for $t {}
118 };
119}
120
121arg_io!(Any, u64);
122arg_io!(Any, i64);
123arg_io!(Any, u32);
124arg_io!(Any, i32);
125arg_io!(Any, u16);
126arg_io!(Any, i16);
127arg_io!(Any, u8);
128arg_io!(Any, i8);
129arg_io!(Any, String);
130arg_io!(Any, f64);
131arg_io!(Any, f32);
132arg_io!(Any, &str);
133
134arg_io!(Integer, u64);
135arg_io!(Integer, i64);
136arg_io!(Integer, u32);
137arg_io!(Integer, i32);
138arg_io!(Integer, u16);
139arg_io!(Integer, i16);
140arg_io!(Integer, u8);
141arg_io!(Integer, i8);
142
143arg_io!(String, String);
144
145arg_io!(Float, f64);
146arg_io!(Float, f32);
147
148arg_io!(u64, u64);
149arg_io!(i64, i64);
150arg_io!(u32, u32);
151arg_io!(i32, i32);
152arg_io!(u16, u16);
153arg_io!(i16, i16);
154arg_io!(u8, u8);
155arg_io!(i8, i8);
156arg_io!(bool, bool);
157arg_io!(f32, f32);
158arg_io!(f64, f64);
159
160arg_io!(&str, &str);
161arg_io!(&str, String);
162arg_io!(&str, std::borrow::Cow<'_, str>);
163
164arg_io!(&[u8], &[u8]);
165arg_io!(&[u8], Vec<u8>);
166arg_io!(Vec<u8>, Vec<u8>);
167
168arg_io!(Any, Vec<u8>);
169arg_io!(Any, Vec<i32>);
170arg_io!(Any, Vec<i64>);
171arg_io!(Any, Vec<String>);
172arg_io!(Any, Vec<Vec<u8>>);
173arg_io!(Any, Vec<&[u8]>);
174arg_io!(Any, Vec<bool>);
175arg_io!(Any, Vec<f64>);
176
177impl ArgIn<Any> for &[u8] {}
179impl ArgIn<Option<Any>> for &[u8] {}
180impl ArgIn<Any> for &[i32] {}
181impl ArgIn<Option<Any>> for &[i32] {}
182impl ArgIn<Any> for &[i64] {}
183impl ArgIn<Option<Any>> for &[i64] {}
184impl ArgIn<Any> for &[String] {}
185impl ArgIn<Option<Any>> for &[String] {}
186impl ArgIn<Option<Any>> for Option<&[String]> {}
187impl ArgIn<Option<Any>> for Option<&[i32]> {}
188impl ArgIn<Option<Any>> for Option<&[i64]> {}
189impl ArgIn<Any> for &[f64] {}
190impl ArgIn<Option<Any>> for &[f64] {}
191impl ArgIn<Option<Any>> for Option<&[f64]> {}
192impl ArgIn<Any> for &[bool] {}
193impl ArgIn<Option<Any>> for &[bool] {}
194
195impl<T> ArgIn<std::convert::Infallible> for T {}
197impl<T> ArgIn<Option<std::convert::Infallible>> for T {}
198
199arg_io!(Timestamp, chrono::NaiveDateTime);
200arg_io!(DateTime, chrono::NaiveDateTime);
201arg_io!(chrono::DateTime<chrono::Utc>, chrono::DateTime<chrono::Utc>);
202arg_io!(Timestamp, chrono::DateTime<chrono::Utc>);
203arg_io!(Date, chrono::NaiveDate);
204arg_io!(Uuid, String);
205arg_io!(Uuid, &str);
206
207#[cfg(feature = "uuid")]
208mod uuid_support {
209 use super::*;
211 arg_io!(Uuid, uuid::Uuid);
212 arg_io!(uuid::Uuid, uuid::Uuid);
213 arg_io!(Any, Vec<uuid::Uuid>);
214 arg_io!(Any, Vec<Option<uuid::Uuid>>);
215 impl ArgIn<Any> for &[uuid::Uuid] {}
216 impl ArgIn<Option<Any>> for &[uuid::Uuid] {}
217 impl ArgIn<Option<Any>> for Option<&[uuid::Uuid]> {}
218}
219
220#[cfg(feature = "uuid")]
223#[doc(hidden)]
224pub type UuidValue = uuid::Uuid;
225
226#[cfg(not(feature = "uuid"))]
229#[doc(hidden)]
230pub type UuidValue = String;
231
232#[cfg(feature = "json")]
233mod json_support {
234 use super::*;
236 arg_io!(String, serde_json::Value);
237 arg_io!(serde_json::Value, serde_json::Value);
238 arg_io!(&str, serde_json::Value);
239 arg_io!(Any, serde_json::Value);
240 arg_io!(Any, Vec<serde_json::Value>);
241 impl ArgIn<Any> for &[serde_json::Value] {}
242 impl ArgIn<Option<Any>> for &[serde_json::Value] {}
243}
244
245#[cfg(feature = "json")]
247#[doc(hidden)]
248pub type JsonValue = serde_json::Value;
249
250#[cfg(not(feature = "json"))]
253#[doc(hidden)]
254pub type JsonValue = String;
255
256#[cfg(feature = "postgres")]
257mod postgres_support {
258 use super::*;
260
261 arg_io!(PgRange<i32>, PgRange<i32>);
265 arg_io!(PgRange<i64>, PgRange<i64>);
266 arg_io!(PgRange<chrono::NaiveDate>, PgRange<chrono::NaiveDate>);
267 arg_io!(
268 PgRange<chrono::NaiveDateTime>,
269 PgRange<chrono::NaiveDateTime>
270 );
271 arg_io!(
272 PgRange<chrono::DateTime<chrono::Utc>>,
273 PgRange<chrono::DateTime<chrono::Utc>>
274 );
275}
276
277#[cfg(feature = "postgres")]
281pub use sqlx::postgres::types::PgRange;
282
283#[doc(hidden)]
284pub fn check_arg<T, T2: ArgIn<T>>(_: &T2) {}
285
286#[doc(hidden)]
287pub fn check_arg_list_hack<T, T2: ArgIn<T>>(_: &[T2]) {}
288
289#[doc(hidden)]
290pub fn arg_out<T, T2: ArgOut<T, IDX>, const IDX: usize>(v: T2) -> T2 {
291 v
292}
293
294#[doc(hidden)]
295pub fn convert_list_query(query: &str, list_sizes: &[usize]) -> sqlx::AssertSqlSafe<String> {
296 let mut query_iter = query.split("_LIST_");
297 let mut query = query_iter.next().expect("None empty query").to_string();
298 for size in list_sizes {
299 if *size == 0 {
300 query.push_str("NULL");
301 } else {
302 for i in 0..*size {
303 if i == 0 {
304 query.push('?');
305 } else {
306 query.push_str(", ?");
307 }
308 }
309 }
310 query.push_str(query_iter.next().expect("More _LIST_ in query"));
311 }
312 if query_iter.next().is_some() {
313 panic!("Too many _LIST_ in query");
314 }
315 sqlx::AssertSqlSafe(query)
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn test_convert_list_query() {
324 use sqlx::SqlSafeStr;
325 assert_eq!(
328 convert_list_query("FOO (_LIST_) X _LIST_ O _LIST_ BAR (_LIST_)", &[0, 1, 2, 3])
329 .into_sql_str()
330 .as_str(),
331 "FOO (NULL) X ? O ?, ? BAR (?, ?, ?)"
332 );
333 }
334}