sea_query_postgres/
lib.rs

1use std::error::Error;
2
3use bytes::BytesMut;
4use postgres_types::{to_sql_checked, IsNull, ToSql, Type};
5
6use sea_query::{query::*, QueryBuilder, Value};
7
8#[derive(Clone, Debug, PartialEq)]
9pub struct PostgresValue(pub Value);
10#[derive(Clone, Debug, PartialEq)]
11pub struct PostgresValues(pub Vec<PostgresValue>);
12
13impl PostgresValues {
14    pub fn as_params(&self) -> Vec<&(dyn ToSql + Sync)> {
15        self.0
16            .iter()
17            .map(|x| {
18                let y: &(dyn ToSql + Sync) = x;
19                y
20            })
21            .collect()
22    }
23}
24
25pub trait PostgresBinder {
26    fn build_postgres<T: QueryBuilder>(&self, query_builder: T) -> (String, PostgresValues);
27}
28
29macro_rules! impl_postgres_binder {
30    ($l:ident) => {
31        impl PostgresBinder for $l {
32            fn build_postgres<T: QueryBuilder>(
33                &self,
34                query_builder: T,
35            ) -> (String, PostgresValues) {
36                let (query, values) = self.build(query_builder);
37                (
38                    query,
39                    PostgresValues(values.into_iter().map(PostgresValue).collect()),
40                )
41            }
42        }
43    };
44}
45
46impl_postgres_binder!(SelectStatement);
47impl_postgres_binder!(UpdateStatement);
48impl_postgres_binder!(InsertStatement);
49impl_postgres_binder!(DeleteStatement);
50impl_postgres_binder!(WithQuery);
51
52impl ToSql for PostgresValue {
53    fn to_sql(
54        &self,
55        ty: &Type,
56        out: &mut BytesMut,
57    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
58        macro_rules! to_sql {
59            ( $v: expr, $ty: ty ) => {
60                $v.map(|v| v as $ty).as_ref().to_sql(ty, out)
61            };
62        }
63        match &self.0 {
64            Value::Bool(v) => to_sql!(v, bool),
65            Value::TinyInt(v) => to_sql!(v, i8),
66            Value::SmallInt(v) => to_sql!(v, i16),
67            Value::Int(v) => to_sql!(v, i32),
68            Value::BigInt(v) => to_sql!(v, i64),
69            Value::TinyUnsigned(v) => to_sql!(v, u32),
70            Value::SmallUnsigned(v) => to_sql!(v, u32),
71            Value::Unsigned(v) => to_sql!(v, u32),
72            Value::BigUnsigned(v) => to_sql!(v, i64),
73            Value::Float(v) => to_sql!(v, f32),
74            Value::Double(v) => to_sql!(v, f64),
75            Value::String(v) => v.as_deref().to_sql(ty, out),
76            Value::Char(v) => v.map(|v| v.to_string()).to_sql(ty, out),
77            Value::Bytes(v) => v.as_deref().to_sql(ty, out),
78            #[cfg(feature = "with-json")]
79            Value::Json(v) => v.as_deref().to_sql(ty, out),
80            #[cfg(feature = "with-chrono")]
81            Value::ChronoDate(v) => v.as_deref().to_sql(ty, out),
82            #[cfg(feature = "with-chrono")]
83            Value::ChronoTime(v) => v.as_deref().to_sql(ty, out),
84            #[cfg(feature = "with-chrono")]
85            Value::ChronoDateTime(v) => v.as_deref().to_sql(ty, out),
86            #[cfg(feature = "with-chrono")]
87            Value::ChronoDateTimeUtc(v) => v.as_deref().to_sql(ty, out),
88            #[cfg(feature = "with-chrono")]
89            Value::ChronoDateTimeLocal(v) => v.as_deref().to_sql(ty, out),
90            #[cfg(feature = "with-chrono")]
91            Value::ChronoDateTimeWithTimeZone(v) => v.as_deref().to_sql(ty, out),
92            #[cfg(feature = "with-time")]
93            Value::TimeDate(v) => v.as_deref().to_sql(ty, out),
94            #[cfg(feature = "with-time")]
95            Value::TimeTime(v) => v.as_deref().to_sql(ty, out),
96            #[cfg(feature = "with-time")]
97            Value::TimeDateTime(v) => v.as_deref().to_sql(ty, out),
98            #[cfg(feature = "with-time")]
99            Value::TimeDateTimeWithTimeZone(v) => v.as_deref().to_sql(ty, out),
100            #[cfg(feature = "with-rust_decimal")]
101            Value::Decimal(v) => v.as_deref().to_sql(ty, out),
102            #[cfg(feature = "with-bigdecimal")]
103            Value::BigDecimal(v) => {
104                use bigdecimal::ToPrimitive;
105                v.as_deref()
106                    .map(|v| v.to_f64().expect("Fail to convert bigdecimal as f64"))
107                    .to_sql(ty, out)
108            }
109            #[cfg(feature = "with-uuid")]
110            Value::Uuid(v) => v.as_deref().to_sql(ty, out),
111            #[cfg(feature = "postgres-array")]
112            Value::Array(_, Some(v)) => v
113                .iter()
114                .map(|v| PostgresValue(v.clone()))
115                .collect::<Vec<PostgresValue>>()
116                .to_sql(ty, out),
117            #[cfg(feature = "postgres-array")]
118            Value::Array(_, None) => Ok(IsNull::Yes),
119            #[cfg(feature = "postgres-vector")]
120            Value::Vector(Some(v)) => v.to_sql(ty, out),
121            #[cfg(feature = "postgres-vector")]
122            Value::Vector(None) => Ok(IsNull::Yes),
123            #[cfg(feature = "with-ipnetwork")]
124            Value::IpNetwork(v) => {
125                use cidr::IpCidr;
126                v.as_deref()
127                    .map(|v| {
128                        IpCidr::new(v.network(), v.prefix())
129                            .expect("Fail to convert IpNetwork to IpCidr")
130                    })
131                    .to_sql(ty, out)
132            }
133            #[cfg(feature = "with-mac_address")]
134            Value::MacAddress(v) => {
135                use eui48::MacAddress;
136                v.as_deref()
137                    .map(|v| MacAddress::new(v.bytes()))
138                    .to_sql(ty, out)
139            }
140        }
141    }
142
143    fn accepts(_ty: &Type) -> bool {
144        true
145    }
146
147    to_sql_checked!();
148}