qusql_mysql_type/lib.rs
1//! Proc macros to perform type typed mysql queries on top of qusql-mysql.
2//!
3//! The queries are typed based on a schema definition, that must be placed in "qusql-mysql-type-schema.sql"
4//! in the root of a using crate:
5//!
6//! ```sql
7//! DROP TABLE IF EXISTS `t1`;
8//! CREATE TABLE `t1` (
9//! `id` int(11) NOT NULL,
10//! `cbool` tinyint(1) NOT NULL DEFAULT false,
11//! `cu8` tinyint UNSIGNED NOT NULL DEFAULT 0,
12//! `cu16` smallint UNSIGNED NOT NULL DEFAULT 1,
13//! `cu32` int UNSIGNED NOT NULL DEFAULT 2,
14//! `cu64` bigint UNSIGNED NOT NULL DEFAULT 3,
15//! `ci8` tinyint,
16//! `ci16` smallint,
17//! `ci32` int,
18//! `ci64` bigint,
19//! `ctext` varchar(100) NOT NULL,
20//! `cbytes` blob,
21//! `cf32` float,
22//! `cf64` double
23//! ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
24//!
25//! ALTER TABLE `t1`
26//! MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
27//! ```
28//! See [qusql_type::schema] for a detailed description.
29//!
30//! [qusql_type::schema]: https://docs.rs/qusql-type/latest/qusql_type/schema/index.html
31//!
32//! This schema can then be used to type queries:
33//!
34//! ```no_run
35//! use qusql_mysql::connection::{ConnectionOptions, ConnectionError, ExecutorExt};
36//! use qusql_mysql::pool::{Pool, PoolOptions};
37//! use qusql_mysql_type::{execute, fetch_one};
38//!
39//! async fn test() -> Result<(), ConnectionError> {
40//! let pool = Pool::connect(
41//! ConnectionOptions::from_url("mysql://user:pw@127.0.0.1:3307/db").unwrap(),
42//! PoolOptions::new().max_connections(10)
43//! ).await?;
44//!
45//! let mut conn = pool.acquire().await?;
46//!
47//! let id = execute!(&mut conn, "INSERT INTO `t1` (
48//! `cbool`, `cu8`, `cu16`, `cu32`, `cu64`, `ctext`)
49//! VALUES (?, ?, ?, ?, ?, ?)",
50//! true, 8, 1243, 42, 42, "Hello world").await?.last_insert_id();
51//!
52//! let row = fetch_one!(&mut conn,
53//! "SELECT `cu16`, `ctext`, `ci32` FROM `t1` WHERE `id`=?", id).await?;
54//!
55//! assert_eq!(row.cu16, 1234);
56//! assert_eq!(row.ctext, "Hello would");
57//! assert!(row.ci32.is_none());
58//! Ok(())
59//! }
60//! ```
61#![forbid(unsafe_code)]
62#[allow(clippy::single_component_path_imports)]
63use qusql_mysql_type_macro;
64
65#[doc(hidden)]
66pub use qusql_mysql_type_macro::execute_impl;
67
68/// Statically checked execute
69///
70/// This expands into a [qusql_mysql::ExecutorExt::execute].
71///
72/// The type supplied arguments are checked against the query.
73///
74/// ```no_run
75/// use qusql_mysql_type::execute;
76///
77/// async fn run(conn: &mut qusql_mysql::Connection) {
78/// let res = execute!(
79/// conn,
80/// "INSERT INTO `t1` (`cu32`, `ctext`) VALUES (?,?)",
81/// 42, "hello").await.unwrap();
82/// println!("{}", res.last_insert_id());
83/// }
84/// ```
85#[macro_export]
86macro_rules! execute {
87 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
88 qusql_mysql_type::execute_impl!(($executor), $stmt, $(($args),)*)
89 };
90}
91
92#[doc(hidden)]
93pub use qusql_mysql_type_macro::fetch_one_impl;
94
95/// Statically checked fetch_one with borrowed values
96///
97/// This expands into a [qusql_mysql::ExecutorExt::fetch_one_map], where a Row type is generated based the columns
98/// returned by the query. Text and blob fields are reference into the parsed mysql package.
99/// The type supplied arguments are checked against the query
100///
101/// ```no_run
102/// use qusql_mysql_type::fetch_one;
103///
104/// async fn run(conn: &mut qusql_mysql::Connection) {
105/// let row = fetch_one!(
106/// conn,
107/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
108/// 42, "hello").await.unwrap();
109/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a &str
110/// }
111/// ```
112#[macro_export]
113macro_rules! fetch_one {
114 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)?) => {
115 qusql_mysql_type::fetch_one_impl!(($executor), $stmt, $($args,)*)
116 };
117}
118
119#[doc(hidden)]
120pub use qusql_mysql_type_macro::fetch_one_owned_impl;
121
122/// Statically checked fetch_one with owned values
123///
124/// This expands into a [qusql_mysql::ExecutorExt::fetch_one_map], where a Row type is generated based the columns
125/// returned by the query. Text and blob fields as represented as [String] and [`Vec<u8>`].
126/// The type supplied arguments are checked against the query
127///
128/// ```no_run
129/// use qusql_mysql_type::fetch_one_owned;
130///
131/// async fn run(conn: &mut qusql_mysql::Connection) {
132/// let row = fetch_one_owned!(
133/// conn,
134/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
135/// 42, "hello").await.unwrap();
136/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a String
137/// }
138/// ```
139#[macro_export]
140macro_rules! fetch_one_owned {
141 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
142 qusql_mysql_type::fetch_one_owned_impl!(($executor), $stmt, $($args,)*)
143 };
144}
145
146#[doc(hidden)]
147pub use qusql_mysql_type_macro::fetch_one_as_impl;
148
149/// Statically checked fetch_one with borrowed values into custom type
150///
151/// This expands into a [qusql_mysql::ExecutorExt::fetch_one_map] into a give row type, with borrowed text and blob fields.
152/// The type supplied arguments are checked against the query
153///
154/// ```no_run
155/// use qusql_mysql_type::fetch_one_as;
156///
157/// async fn run(conn: &mut qusql_mysql::Connection) {
158/// struct Row<'a> {
159/// cu32: u32,
160/// ctext: &'a str
161/// }
162/// let row = fetch_one_as!(
163/// Row,
164/// conn,
165/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
166/// 42, "hello").await.unwrap();
167/// println!("{} {}", row.cu32, row.ctext);
168/// }
169/// ```
170#[macro_export]
171macro_rules! fetch_one_as {
172 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
173 qusql_mysql_type::fetch_one_as_impl!($rt, ($executor), $stmt, $($args,)*)
174 };
175}
176
177#[doc(hidden)]
178pub use qusql_mysql_type_macro::fetch_one_as_owned_impl;
179
180/// Statically checked fetch_one with owned values into custom type
181///
182/// This expands into a [qusql_mysql::ExecutorExt::fetch_one_map] into a give row type, with owned text and blob fields.
183/// The type supplied arguments are checked against the query
184///
185/// ```no_run
186/// use qusql_mysql_type::fetch_one_as_owned;
187///
188/// async fn run(conn: &mut qusql_mysql::Connection) {
189/// struct Row {
190/// cu32: u32,
191/// ctext: String
192/// }
193/// let row = fetch_one_as_owned!(
194/// Row,
195/// conn,
196/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
197/// 42, "hello").await.unwrap();
198/// println!("{} {}", row.cu32, row.ctext);
199/// }
200/// ```
201#[macro_export]
202macro_rules! fetch_one_as_owned {
203 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
204 qusql_mysql_type::fetch_one_as_owned_impl!($rt, ($executor), $stmt, $($args,)*)
205 };
206}
207
208#[doc(hidden)]
209pub use qusql_mysql_type_macro::fetch_optional_impl;
210
211/// Statically checked fetch_optional with borrowed values
212///
213/// This expands into a [qusql_mysql::ExecutorExt::fetch_optional_map], where a Row type is generated based the columns
214/// returned by the query. Text and blob fields are reference into the parsed mysql package.
215/// The type supplied arguments are checked against the query
216///
217/// ```no_run
218/// use qusql_mysql_type::fetch_optional;
219///
220/// async fn run(conn: &mut qusql_mysql::Connection) {
221/// let row = fetch_optional!(
222/// conn,
223/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
224/// 42, "hello").await.unwrap();
225/// if let Some(row) = row {
226/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a &str
227/// }
228/// }
229/// ```
230#[macro_export]
231macro_rules! fetch_optional {
232 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)?) => {
233 qusql_mysql_type::fetch_optional_impl!(($executor), $stmt, $($args,)*)
234 };
235}
236
237#[doc(hidden)]
238pub use qusql_mysql_type_macro::fetch_optional_owned_impl;
239
240/// Statically checked fetch_optional with owned values
241///
242/// This expands into a [qusql_mysql::ExecutorExt::fetch_optional_map], where a Row type is generated based the columns
243/// returned by the query. Text and blob fields as represented as [String] and [`Vec<u8>`].
244/// The type supplied arguments are checked against the query
245///
246/// ```no_run
247/// use qusql_mysql_type::fetch_optional_owned;
248///
249/// async fn run(conn: &mut qusql_mysql::Connection) {
250/// let row = fetch_optional_owned!(
251/// conn,
252/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
253/// 42, "hello").await.unwrap();
254/// if let Some(row) = row {
255/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a String
256/// }
257/// }
258/// ```
259#[macro_export]
260macro_rules! fetch_optional_owned {
261 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
262 qusql_mysql_type::fetch_optional_owned_impl!(($executor), $stmt, $($args,)*)
263 };
264}
265
266#[doc(hidden)]
267pub use qusql_mysql_type_macro::fetch_optional_as_impl;
268
269/// Statically checked fetch_optional with borrowed values into custom type
270///
271/// This expands into a [qusql_mysql::ExecutorExt::fetch_optional_map] into a give row type, with borrowed text and blob fields.
272/// The type supplied arguments are checked against the query
273///
274/// ```no_run
275/// use qusql_mysql_type::fetch_optional_as;
276///
277/// async fn run(conn: &mut qusql_mysql::Connection) {
278/// struct Row<'a> {
279/// cu32: u32,
280/// ctext: &'a str
281/// }
282/// let row = fetch_optional_as!(
283/// Row,
284/// conn,
285/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
286/// 42, "hello").await.unwrap();
287/// if let Some(row) = row {
288/// println!("{} {}", row.cu32, row.ctext);
289/// }
290/// }
291/// ```
292#[macro_export]
293macro_rules! fetch_optional_as {
294 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
295 qusql_mysql_type::fetch_optional_as_impl!($rt, ($executor), $stmt, $($args,)*)
296 };
297}
298
299#[doc(hidden)]
300pub use qusql_mysql_type_macro::fetch_optional_as_owned_impl;
301
302/// Statically checked fetch_optional with owned values into custom type
303///
304/// This expands into a [qusql_mysql::ExecutorExt::fetch_optional_map] into a give row type, with owned text and blob fields.
305/// The type supplied arguments are checked against the query
306///
307/// ```no_run
308/// use qusql_mysql_type::fetch_optional_as_owned;
309///
310/// async fn run(conn: &mut qusql_mysql::Connection) {
311/// struct Row {
312/// cu32: u32,
313/// ctext: String
314/// }
315/// let row = fetch_optional_as_owned!(
316/// Row,
317/// conn,
318/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
319/// 42, "hello").await.unwrap();
320/// if let Some(row) = row {
321/// println!("{} {}", row.cu32, row.ctext);
322/// }
323/// }
324/// ```
325#[macro_export]
326macro_rules! fetch_optional_as_owned {
327 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
328 qusql_mysql_type::fetch_optional_as_owned_impl!($rt, ($executor), $stmt, $($args,)*)
329 };
330}
331
332#[doc(hidden)]
333pub use qusql_mysql_type_macro::fetch_all_impl;
334
335/// Statically checked fetch_all with borrowed values
336///
337/// This expands into a [qusql_mysql::ExecutorExt::fetch_all_map], where a Row type is generated based the columns
338/// returned by the query. Text and blob fields are reference into the parsed mysql package.
339/// The type supplied arguments are checked against the query
340///
341/// ```no_run
342/// use qusql_mysql_type::fetch_all;
343///
344/// async fn run(conn: &mut qusql_mysql::Connection) {
345/// let rows = fetch_all!(
346/// conn,
347/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
348/// 42, "hello").await.unwrap();
349/// for row in rows {
350/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a &str
351/// }
352/// }
353/// ```
354#[macro_export]
355macro_rules! fetch_all {
356 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
357 qusql_mysql_type::fetch_all_impl!(($executor), $stmt, $($args,)*)
358 };
359}
360
361#[doc(hidden)]
362pub use qusql_mysql_type_macro::fetch_all_owned_impl;
363
364/// Statically checked fetch_all with owned values
365///
366/// This expands into a [qusql_mysql::ExecutorExt::fetch_all_map], where a Row type is generated based the columns
367/// returned by the query. Text and blob fields as represented as [String] and [`Vec<u8>`].
368/// The type supplied arguments are checked against the query
369///
370/// ```no_run
371/// use qusql_mysql_type::fetch_all_owned;
372///
373/// async fn run(conn: &mut qusql_mysql::Connection) {
374/// let rows = fetch_all_owned!(
375/// conn,
376/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
377/// 42, "hello").await.unwrap();
378/// for row in rows {
379/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a String
380/// }
381/// }
382/// ```
383#[macro_export]
384macro_rules! fetch_all_owned {
385 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
386 qusql_mysql_type::fetch_all_owned_impl!(($executor), $stmt, $($args,)*)
387 };
388}
389
390#[doc(hidden)]
391pub use qusql_mysql_type_macro::fetch_all_as_impl;
392
393/// Statically checked fetch_all with borrowed values into custom type
394///
395/// This expands into a [qusql_mysql::ExecutorExt::fetch_all_map] into a give row type, with borrowed text and blob fields.
396/// The type supplied arguments are checked against the query
397///
398/// ```no_run
399/// use qusql_mysql_type::fetch_all_as;
400///
401/// async fn run(conn: &mut qusql_mysql::Connection) {
402/// struct Row<'a> {
403/// cu32: u32,
404/// ctext: &'a str
405/// }
406/// let rows = fetch_all_as!(
407/// Row,
408/// conn,
409/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
410/// 42, "hello").await.unwrap();
411/// for row in rows {
412/// println!("{} {}", row.r#cu32, row.r#ctext);
413/// }
414/// }
415/// ```
416#[macro_export]
417macro_rules! fetch_all_as {
418 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
419 qusql_mysql_type::fetch_all_as_impl!($rt, ($executor), $stmt, $($args,)*)
420 };
421}
422
423#[doc(hidden)]
424pub use qusql_mysql_type_macro::fetch_all_as_owned_impl;
425
426/// Statically checked fetch_all with owned values into custom type
427///
428/// This expands into a [qusql_mysql::ExecutorExt::fetch_all_map] into a give row type, with owned text and blob fields.
429/// The type supplied arguments are checked against the query
430///
431/// ```no_run
432/// use qusql_mysql_type::fetch_all_as_owned;
433///
434/// async fn run(conn: &mut qusql_mysql::Connection) {
435/// struct Row {
436/// cu32: u32,
437/// ctext: String
438/// }
439/// let rows = fetch_all_as_owned!(
440/// Row,
441/// conn,
442/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
443/// 42, "hello").await.unwrap();
444/// for row in rows {
445/// println!("{} {}", row.cu32, row.ctext);
446/// }
447/// }
448/// ```
449#[macro_export]
450macro_rules! fetch_all_as_owned {
451 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)?) => {
452 qusql_mysql_type::fetch_all_as_owned_impl!($rt, ($executor), $stmt, $($args,)*)
453 };
454}
455
456#[doc(hidden)]
457pub use qusql_mysql_type_macro::fetch_impl;
458
459/// Statically checked streaming fetch with borrowed values
460///
461/// This expands into a [qusql_mysql::ExecutorExt::fetch_map], where a Row type is generated based the columns
462/// returned by the query. Text and blob fields are reference into the parsed mysql package.
463/// The type supplied arguments are checked against the query
464///
465/// ```no_run
466/// use qusql_mysql_type::fetch;
467///
468/// async fn run(conn: &mut qusql_mysql::Connection) {
469/// let mut row_iter = fetch!(
470/// conn,
471/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
472/// 42, "hello").await.unwrap();
473/// while let Some(row) = row_iter.next().await.unwrap() {
474/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a &str
475/// }
476/// }
477/// ```
478#[macro_export]
479macro_rules! fetch {
480 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
481 qusql_mysql_type::fetch_impl!(($executor), $stmt, $($args,)*)
482 };
483}
484
485#[doc(hidden)]
486pub use qusql_mysql_type_macro::fetch_owned_impl;
487
488/// Statically checked streaming fetch with owned values
489///
490/// This expands into a [qusql_mysql::ExecutorExt::fetch_map], where a Row type is generated based the columns
491/// returned by the query. Text and blob fields as represented as [String] and [`Vec<u8>`].
492/// The type supplied arguments are checked against the query
493///
494/// ```no_run
495/// use qusql_mysql_type::fetch_owned;
496///
497/// async fn run(conn: &mut qusql_mysql::Connection) {
498/// let mut row_iter = fetch_owned!(
499/// conn,
500/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
501/// 42, "hello").await.unwrap();
502/// while let Some(row) = row_iter.next().await.unwrap() {
503/// println!("{} {}", row.cu32, row.ctext); // Here row.ctext is a String
504/// }
505/// }
506/// ```
507#[macro_export]
508macro_rules! fetch_owned {
509 ( $executor: expr, $stmt: literal $(, $args:expr )* $(,)?) => {
510 qusql_mysql_type::fetch_owned_impl!(($executor), $stmt, $($args,)*)
511 };
512}
513
514#[doc(hidden)]
515pub use qusql_mysql_type_macro::fetch_as_impl;
516
517/// Statically checked streaming fetch with borrowed values into custom type
518///
519/// This expands into a [qusql_mysql::ExecutorExt::fetch_map] into a give row type, with borrowed text and blob fields.
520/// The type supplied arguments are checked against the query
521///
522/// ```no_run
523/// use qusql_mysql_type::fetch_as;
524///
525/// async fn run(conn: &mut qusql_mysql::Connection) {
526/// struct Row<'a> {
527/// cu32: u32,
528/// ctext: &'a str
529/// }
530/// let mut row_iter = fetch_as!(
531/// Row,
532/// conn,
533/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
534/// 42, "hello").await.unwrap();
535/// while let Some(row) = row_iter.next().await.unwrap() {
536/// println!("{} {}", row.r#cu32, row.r#ctext);
537/// }
538/// }
539/// ```
540#[macro_export]
541macro_rules! fetch_as {
542 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
543 qusql_mysql_type::fetch_as_impl!($rt, ($executor), $stmt, $($args,)*)
544 };
545}
546
547#[doc(hidden)]
548pub use qusql_mysql_type_macro::fetch_as_owned_impl;
549
550/// Statically checked streaming fetch with owned values into custom type
551///
552/// This expands into a [qusql_mysql::ExecutorExt::fetch_map] into a give row type, with owned text and blob fields.
553/// The type supplied arguments are checked against the query
554///
555/// ```no_run
556/// use qusql_mysql_type::fetch_as_owned;
557///
558/// async fn run(conn: &mut qusql_mysql::Connection) {
559/// struct Row {
560/// cu32: u32,
561/// ctext: String
562/// }
563/// let mut row_iter = fetch_as_owned!(
564/// Row,
565/// conn,
566/// "SELECT `cu32`, `ctext` FROM `t1` WHERE `id` = ? AND `ctext` != ?",
567/// 42, "hello").await.unwrap();
568/// while let Some(row) = row_iter.next().await.unwrap() {
569/// println!("{} {}", row.cu32, row.ctext);
570/// }
571/// }
572/// ```
573#[macro_export]
574macro_rules! fetch_as_owned {
575 ( $rt: ty, $executor: expr, $stmt: literal $(, $args:expr )* $(,)? ) => {
576 qusql_mysql_type::fetch_as_owned_impl!($rt, ($executor), $stmt, $($args,)*)
577 };
578}
579
580/// Tag type for integer input
581#[doc(hidden)]
582pub struct Integer;
583
584/// Tag type for float input
585#[doc(hidden)]
586pub struct Float;
587
588/// Tag type for timestamp input
589#[doc(hidden)]
590pub struct Timestamp;
591
592/// Tag type for datetime input
593#[doc(hidden)]
594pub struct DateTime;
595
596/// Tag type for date input
597#[doc(hidden)]
598pub struct Date;
599
600/// Tag type for time input
601#[doc(hidden)]
602pub struct Time;
603
604/// Tag type for time input
605#[doc(hidden)]
606pub struct Any;
607
608/// If `ArgIn<T>` is implemented for `J`, it means that `J` can be used as for arguments of type `T`
609pub trait ArgIn<T> {}
610
611/// If `ArgOut<N, T>` is implemented for `J`, it means that `J` can be construct from column of type `T`
612///
613/// `N` is used used with a struct named after the column to make figuring out what column has the
614/// wrong type feasible
615pub trait ArgOut<N, T> {}
616
617/// Implement [ArgIn] and [ArgOut] for the given types
618macro_rules! arg_io {
619 ( $dst: ty, $t: ty ) => {
620 impl ArgIn<$dst> for $t {}
621 impl ArgIn<$dst> for &$t {}
622 impl ArgIn<Option<$dst>> for $t {}
623 impl ArgIn<Option<$dst>> for &$t {}
624 impl ArgIn<Option<$dst>> for Option<$t> {}
625 impl ArgIn<Option<$dst>> for Option<&$t> {}
626 impl ArgIn<Option<$dst>> for &Option<$t> {}
627 impl ArgIn<Option<$dst>> for &Option<&$t> {}
628
629 impl<N> ArgOut<N, $dst> for $t {}
630 impl<N> ArgOut<N, Option<$dst>> for Option<$t> {}
631 impl<N> ArgOut<N, $dst> for Option<$t> {}
632 };
633}
634
635arg_io!(Any, u64);
636arg_io!(Any, i64);
637arg_io!(Any, u32);
638arg_io!(Any, i32);
639arg_io!(Any, u16);
640arg_io!(Any, i16);
641arg_io!(Any, u8);
642arg_io!(Any, i8);
643arg_io!(Any, String);
644arg_io!(Any, f64);
645arg_io!(Any, f32);
646arg_io!(Any, &str);
647
648arg_io!(Integer, u64);
649arg_io!(Integer, i64);
650arg_io!(Integer, u32);
651arg_io!(Integer, i32);
652arg_io!(Integer, u16);
653arg_io!(Integer, i16);
654arg_io!(Integer, u8);
655arg_io!(Integer, i8);
656
657arg_io!(String, String);
658
659arg_io!(Float, f64);
660arg_io!(Float, f32);
661
662arg_io!(u64, u64);
663arg_io!(i64, i64);
664arg_io!(u32, u32);
665arg_io!(i32, i32);
666arg_io!(u16, u16);
667arg_io!(i16, i16);
668arg_io!(u8, u8);
669arg_io!(i8, i8);
670arg_io!(bool, bool);
671arg_io!(f32, f32);
672arg_io!(f64, f64);
673
674arg_io!(&str, &str);
675arg_io!(&str, String);
676arg_io!(&str, std::borrow::Cow<'_, str>);
677
678arg_io!(&[u8], &[u8]);
679arg_io!(&[u8], Vec<u8>);
680arg_io!(Vec<u8>, Vec<u8>);
681
682#[cfg(feature = "chrono")]
683arg_io!(Timestamp, chrono::NaiveDateTime);
684#[cfg(feature = "chrono")]
685arg_io!(DateTime, chrono::NaiveDateTime);
686#[cfg(feature = "chrono")]
687arg_io!(chrono::DateTime<chrono::Utc>, chrono::DateTime<chrono::Utc>);
688#[cfg(feature = "chrono")]
689arg_io!(Timestamp, chrono::DateTime<chrono::Utc>);
690#[cfg(feature = "chrono")]
691arg_io!(Date, chrono::NaiveDate);
692
693#[doc(hidden)]
694pub fn check_arg<T, T2: ArgIn<T>>(_: &T2) {}
695
696#[doc(hidden)]
697pub fn check_arg_list_hack<T, T2: ArgIn<T>>(_: &qusql_mysql::List<'_, T2>) {}
698
699#[doc(hidden)]
700pub fn check_arg_out<N, T, T2: ArgOut<N, T>>(_: &T2) {}
701
702#[doc(hidden)]
703pub fn convert_list_query(query: &str, list_sizes: &[usize]) -> String {
704 let mut query_iter = query.split("_LIST_");
705 let mut query = query_iter.next().expect("None empty query").to_string();
706 for size in list_sizes {
707 if *size == 0 {
708 query.push_str("NULL");
709 } else {
710 for i in 0..*size {
711 if i == 0 {
712 query.push('?');
713 } else {
714 query.push_str(", ?");
715 }
716 }
717 }
718 query.push_str(query_iter.next().expect("More _LIST_ in query"));
719 }
720 if query_iter.next().is_some() {
721 panic!("Too many _LIST_ in query");
722 }
723 query
724}
725
726#[cfg(test)]
727mod tests {
728 use super::*;
729
730 #[test]
731 fn test_convert_list_query() {
732 // This assert would fire and test will fail.
733 // Please note, that private functions can be tested too!
734 assert_eq!(
735 &convert_list_query("FOO (_LIST_) X _LIST_ O _LIST_ BAR (_LIST_)", &[0, 1, 2, 3]),
736 "FOO (NULL) X ? O ?, ? BAR (?, ?, ?)"
737 );
738 }
739}