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}