1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Proc macros to perform type sql queries similarly to sqlx::query, but without the need
//! to run `cargo sqlx prepare`
//!
//! A schema definition must be placed in "sqlx-type-schema.sql" in the root of a using crate:
//!
//! ```sql
//! DROP TABLE IF EXISTS `t1`;
//! CREATE TABLE `t1` (
//!     `id` int(11) NOT NULL,
//!     `cbool` tinyint(1) NOT NULL,
//!     `cu8` tinyint UNSIGNED NOT NULL,
//!     `cu16` smallint UNSIGNED NOT NULL,
//!     `cu32` int UNSIGNED NOT NULL,
//!     `cu64` bigint UNSIGNED NOT NULL,
//!     `ci8` tinyint,
//!     `ci16` smallint,
//!     `ci32` int,
//!     `ci64` bigint,
//!     `ctext` varchar(100) NOT NULL,
//!     `cbytes` blob,
//!     `cf32` float,
//!     `cf64` double
//! ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
//!
//! ALTER TABLE `t1`
//!     MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
//! ```
//! See [sql_type::schema] for a detailed description.
//!
//! [sql_type::schema]: https://docs.rs/sql-type/latest/sql_type/schema/index.html
//!
//! This schema can then be used to type queries:
//!
//! ``` no_run
//! use {std::env, sqlx::MySqlPool, sqlx_type::query};
//!
//! async fn test() -> Result<(), sqlx::Error> {
//!     let pool = MySqlPool::connect(&env::var("DATABASE_URL").unwrap()).await?;
//!
//!     let id = query!("INSERT INTO `t1` (`cbool`, `cu8`, `cu16`, `cu32`, `cu64`, `ctext`)
//!         VALUES (?, ?, ?, ?, ?, ?)", true, 8, 1243, 42, 42, "Hello world")
//!         .execute(&pool).await?.last_insert_id();
//!
//!     let row = query!("SELECT `cu16`, `ctext`, `ci32` FROM `t1` WHERE `id`=?", id)
//!         .fetch_one(&pool).await?;
//!
//!     assert_eq!(row.cu16, 1234);
//!     assert_eq!(row.ctext, "Hello would");
//!     assert!(row.ci32.is_none());
//!     Ok(())
//! }
//! ```
#![forbid(unsafe_code)]
use sqlx_type_macro;

pub use crate::sqlx_type_macro::{query, query_as};

/// Tag type for integer input
#[doc(hidden)]
pub struct Integer;

/// Tag type for float input
#[doc(hidden)]
pub struct Float;

/// Tag type for timestamp input
#[doc(hidden)]
pub struct Timestamp;

/// Tag type for datetime input
#[doc(hidden)]
pub struct DateTime;

/// Tag type for date input
#[doc(hidden)]
pub struct Date;

/// Tag type for time input
#[doc(hidden)]
pub struct Time;

/// If ArgIn<T> is implemented for J, it means that J can be used as for arguments of type T
#[doc(hidden)]
pub trait ArgIn<T> {}

macro_rules! arg_in {
    ( $dst: ty, $t: ty ) => {
        impl ArgIn<$dst> for $t {}
        impl ArgIn<$dst> for &$t {}
        impl ArgIn<Option<$dst>> for $t {}
        impl ArgIn<Option<$dst>> for &$t {}
        impl ArgIn<Option<$dst>> for Option<$t> {}
        impl ArgIn<Option<$dst>> for Option<&$t> {}
        impl ArgIn<Option<$dst>> for &Option<$t> {}
        impl ArgIn<Option<$dst>> for &Option<&$t> {}
    };
}

arg_in!(Integer, u64);
arg_in!(Integer, i64);
arg_in!(Integer, u32);
arg_in!(Integer, i32);
arg_in!(Integer, u16);
arg_in!(Integer, i16);
arg_in!(Integer, u8);
arg_in!(Integer, i8);

arg_in!(Float, f64);
arg_in!(Float, f32);

arg_in!(u64, u64);
arg_in!(i64, i64);
arg_in!(u32, u32);
arg_in!(i32, i32);
arg_in!(u16, u16);
arg_in!(i16, i16);
arg_in!(u8, u8);
arg_in!(i8, i8);
arg_in!(bool, bool);
arg_in!(f32, f32);
arg_in!(f64, f64);

arg_in!(&str, &str);
arg_in!(&str, String);
arg_in!(&str, std::borrow::Cow<'_, str>);

arg_in!(&[u8], &[u8]);
arg_in!(&[u8], Vec<u8>);

arg_in!(Timestamp, chrono::NaiveDateTime);
arg_in!(DateTime, chrono::NaiveDateTime);

#[doc(hidden)]
pub fn check_arg<T, T2: ArgIn<T>>(_: &T2) {}