Skip to main content

sea_query_rusqlite/
lib.rs

1#![forbid(unsafe_code)]
2
3pub use rusqlite;
4
5use rusqlite::{
6    Result, ToSql,
7    types::{Null, ToSqlOutput},
8};
9use sea_query::Value;
10use sea_query::{QueryBuilder, query::*};
11
12#[derive(Clone, Debug, PartialEq)]
13pub struct RusqliteValue(pub sea_query::Value);
14#[derive(Clone, Debug, PartialEq)]
15pub struct RusqliteValues(pub Vec<RusqliteValue>);
16
17impl RusqliteValues {
18    pub fn as_params(&self) -> Vec<&dyn ToSql> {
19        self.0
20            .iter()
21            .map(|x| {
22                let y: &dyn ToSql = x;
23                y
24            })
25            .collect()
26    }
27}
28
29pub trait RusqliteBinder {
30    fn build_rusqlite<T: QueryBuilder>(&self, query_builder: T) -> (String, RusqliteValues);
31}
32
33macro_rules! impl_rusqlite_binder {
34    ($l:ident) => {
35        impl RusqliteBinder for $l {
36            fn build_rusqlite<T: QueryBuilder>(
37                &self,
38                query_builder: T,
39            ) -> (String, RusqliteValues) {
40                let (query, values) = self.build(query_builder);
41                (
42                    query,
43                    RusqliteValues(values.into_iter().map(RusqliteValue).collect()),
44                )
45            }
46        }
47    };
48}
49
50impl_rusqlite_binder!(SelectStatement);
51impl_rusqlite_binder!(UpdateStatement);
52impl_rusqlite_binder!(InsertStatement);
53impl_rusqlite_binder!(DeleteStatement);
54impl_rusqlite_binder!(WithQuery);
55
56impl ToSql for RusqliteValue {
57    fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
58        macro_rules! opt_string_to_sql {
59            ( $v: expr ) => {
60                match $v {
61                    Some(v) => Ok(ToSqlOutput::from(v)),
62                    None => Null.to_sql(),
63                }
64            };
65        }
66
67        match &self.0 {
68            Value::Bool(v) => v.to_sql(),
69            Value::TinyInt(v) => v.to_sql(),
70            Value::SmallInt(v) => v.to_sql(),
71            Value::Int(v) => v.to_sql(),
72            Value::BigInt(v) => v.to_sql(),
73            Value::TinyUnsigned(v) => v.to_sql(),
74            Value::SmallUnsigned(v) => v.to_sql(),
75            Value::Unsigned(v) => v.to_sql(),
76            Value::BigUnsigned(v) => v.to_sql(),
77            Value::Float(v) => v.to_sql(),
78            Value::Double(v) => v.to_sql(),
79            Value::String(v) => match v {
80                Some(v) => v.as_str().to_sql(),
81                None => Null.to_sql(),
82            },
83            Value::Char(v) => opt_string_to_sql!(v.map(|v| v.to_string())),
84            Value::Bytes(v) => match v {
85                Some(v) => v.as_slice().to_sql(),
86                None => Null.to_sql(),
87            },
88            #[cfg(feature = "with-chrono")]
89            Value::ChronoDate(v) => v.to_sql(),
90            #[cfg(feature = "with-chrono")]
91            Value::ChronoTime(v) => v.to_sql(),
92            #[cfg(feature = "with-chrono")]
93            Value::ChronoDateTime(v) => v.to_sql(),
94            #[cfg(feature = "with-chrono")]
95            Value::ChronoDateTimeUtc(v) => v.to_sql(),
96            #[cfg(feature = "with-chrono")]
97            Value::ChronoDateTimeLocal(v) => v.to_sql(),
98            #[cfg(feature = "with-chrono")]
99            Value::ChronoDateTimeWithTimeZone(v) => v.to_sql(),
100            #[cfg(feature = "with-time")]
101            Value::TimeDate(v) => v.to_sql(),
102            #[cfg(feature = "with-time")]
103            Value::TimeTime(v) => v.to_sql(),
104            #[cfg(feature = "with-time")]
105            Value::TimeDateTime(v) => v.to_sql(),
106            #[cfg(feature = "with-time")]
107            Value::TimeDateTimeWithTimeZone(v) => v.to_sql(),
108            #[cfg(feature = "with-uuid")]
109            Value::Uuid(v) => v.to_sql(),
110            #[cfg(feature = "with-json")]
111            Value::Json(j) => {
112                if cfg!(feature = "sea-orm") && j.is_some() && j.as_ref().unwrap().is_null() {
113                    // rusqlite binds Json::Null as SQL NULL
114                    // which is different from sqlx
115                    return "null".to_sql();
116                }
117                match j {
118                    Some(v) => v.as_ref().to_sql(),
119                    None => Null.to_sql(),
120                }
121            }
122            #[cfg(feature = "with-rust_decimal")]
123            Value::Decimal(v) => opt_string_to_sql!(v.as_ref().map(|v| v.to_string())),
124            #[cfg(feature = "with-bigdecimal")]
125            Value::BigDecimal(v) => opt_string_to_sql!(v.as_ref().map(|v| v.to_string())),
126            #[cfg(feature = "with-ipnetwork")]
127            Value::IpNetwork(v) => opt_string_to_sql!(v.as_ref().map(|v| v.to_string())),
128            #[cfg(feature = "with-mac_address")]
129            Value::MacAddress(v) => opt_string_to_sql!(v.as_ref().map(|v| v.to_string())),
130            #[cfg(feature = "postgres-array")]
131            Value::Array(_, _) => {
132                panic!("Rusqlite doesn't support Array arguments");
133            }
134            #[cfg(feature = "postgres-vector")]
135            Value::Vector(_) => {
136                panic!("Rusqlite doesn't support Vector arguments");
137            }
138        }
139    }
140}