sea_query/value/
with_array.rs

1use super::ArrayElement;
2use super::*;
3use crate::RcOrArc;
4
5// We only implement conversion from Vec<T> to Array when T is not u8.
6// This is because for u8's case, there is already conversion to Byte defined above.
7// TODO When negative trait becomes a stable feature, following code can be much shorter.
8pub trait NotU8 {}
9
10impl NotU8 for bool {}
11impl NotU8 for i8 {}
12impl NotU8 for i16 {}
13impl NotU8 for i32 {}
14impl NotU8 for i64 {}
15impl NotU8 for u16 {}
16impl NotU8 for u32 {}
17impl NotU8 for u64 {}
18impl NotU8 for f32 {}
19impl NotU8 for f64 {}
20impl NotU8 for char {}
21impl NotU8 for String {}
22impl NotU8 for Vec<u8> {}
23
24impl<T: NotU8> NotU8 for Option<T> {}
25
26#[cfg(feature = "with-json")]
27impl NotU8 for Json {}
28
29#[cfg(feature = "with-chrono")]
30impl NotU8 for NaiveDate {}
31
32#[cfg(feature = "with-chrono")]
33impl NotU8 for NaiveTime {}
34
35#[cfg(feature = "with-chrono")]
36impl NotU8 for NaiveDateTime {}
37
38#[cfg(feature = "with-chrono")]
39impl<Tz> NotU8 for chrono::DateTime<Tz> where Tz: chrono::TimeZone {}
40
41#[cfg(feature = "with-time")]
42impl NotU8 for time::Date {}
43
44#[cfg(feature = "with-time")]
45impl NotU8 for time::Time {}
46
47#[cfg(feature = "with-time")]
48impl NotU8 for PrimitiveDateTime {}
49
50#[cfg(feature = "with-time")]
51impl NotU8 for OffsetDateTime {}
52
53#[cfg(feature = "with-jiff")]
54impl NotU8 for jiff::civil::Date {}
55
56#[cfg(feature = "with-jiff")]
57impl NotU8 for jiff::civil::Time {}
58
59#[cfg(feature = "with-jiff")]
60impl NotU8 for jiff::civil::DateTime {}
61
62#[cfg(feature = "with-jiff")]
63impl NotU8 for jiff::Timestamp {}
64
65#[cfg(feature = "with-jiff")]
66impl NotU8 for jiff::Zoned {}
67
68#[cfg(feature = "with-rust_decimal")]
69impl NotU8 for rust_decimal::Decimal {}
70
71#[cfg(feature = "with-bigdecimal")]
72impl NotU8 for bigdecimal::BigDecimal {}
73
74#[cfg(feature = "with-uuid")]
75impl NotU8 for Uuid {}
76
77#[cfg(feature = "with-uuid")]
78impl NotU8 for uuid::fmt::Braced {}
79
80#[cfg(feature = "with-uuid")]
81impl NotU8 for uuid::fmt::Hyphenated {}
82
83#[cfg(feature = "with-uuid")]
84impl NotU8 for uuid::fmt::Simple {}
85
86#[cfg(feature = "with-uuid")]
87impl NotU8 for uuid::fmt::Urn {}
88
89#[cfg(feature = "with-ipnetwork")]
90impl NotU8 for IpNetwork {}
91
92#[cfg(feature = "with-mac_address")]
93impl NotU8 for MacAddress {}
94
95macro_rules! impl_value_vec {
96    ($($ty:ty => $vari:ident)*) => {
97        $(
98            impl From<Vec<$ty>> for Array {
99                fn from(x: Vec<$ty>) -> Array {
100                    let values: Vec<Option<_>> = x
101                        .into_iter()
102                        .map(Some)
103                        .collect();
104
105                    Array::$vari(values.into_boxed_slice())
106                }
107            }
108
109
110            impl From<Vec<Option<$ty>>> for Array {
111                fn from(x: Vec<Option<$ty>>) -> Array {
112                    Array::$vari(x.into_boxed_slice())
113                }
114            }
115
116            impl<const N: usize> From<[$ty; N]> for Array {
117                fn from(x: [$ty; N]) -> Array {
118                    let vec: Vec<_> = x.into_iter().collect();
119                    vec.into()
120                }
121            }
122
123            impl From<Vec<$ty>> for Value {
124                fn from(x: Vec<$ty>) -> Value {
125                    let values: Vec<Option<_>> = x
126                        .into_iter()
127                        .map(Some)
128                        .collect();
129
130                    Value::Array(
131                        Array::$vari(values.into_boxed_slice())
132                    )
133                }
134            }
135
136            impl From<Vec<Option<$ty>>> for Value {
137                fn from(x: Vec<Option<$ty>>) -> Value {
138                    Value::Array(Array::$vari(x.into()))
139                }
140            }
141
142            impl ValueType for Vec<Option<$ty>>
143            {
144                fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
145                    match v {
146                        Value::Array(Array::$vari(inner)) => {
147                            Ok(inner.into_vec())
148                        }
149                        _ => Err(ValueTypeErr),
150                    }
151                }
152
153                fn type_name() -> String {
154                    stringify!(Vec<$ty>).to_owned()
155                }
156
157                fn array_type() -> ArrayType {
158                    <$ty>::array_type()
159                }
160
161                fn column_type() -> ColumnType {
162                    use ColumnType::*;
163                    Array(RcOrArc::new(<$ty>::column_type()))
164                }
165            }
166
167
168            impl ValueType for Vec<$ty> {
169                fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
170                    match v {
171                        Value::Array(Array::$vari(inner)) => {
172                            inner.into_vec()
173                                .into_iter()
174                                // idk why the type inference failed, but this works
175                                .map(|opt| Option::ok_or(opt,ValueTypeErr))
176                                .collect()
177                        }
178                        _ => Err(ValueTypeErr),
179                    }
180                }
181
182                fn type_name() -> String {
183                    format!("Vec<{}>", stringify!($ty))
184                }
185
186                fn array_type() -> ArrayType {
187                    <$ty>::array_type()
188                }
189
190                fn column_type() -> ColumnType {
191                    ColumnType::Array(RcOrArc::new(<$ty>::column_type()))
192                }
193            }
194       )*
195    }
196}
197
198impl_value_vec! {
199    bool => Bool
200    i8 => TinyInt
201    i16 => SmallInt
202    i32 => Int
203    i64 => BigInt
204    u16 => SmallUnsigned
205    u32 => Unsigned
206    u64 => BigUnsigned
207    f32 => Float
208    f64 => Double
209    std::string::String => String
210    char => Char
211    Vec<u8> => Bytes
212}
213
214// Impls for u8
215// because Vec<u8> is already defined as Bytes
216impl From<Vec<u8>> for Array {
217    fn from(x: Vec<u8>) -> Array {
218        let values: Vec<Option<_>> = x.into_iter().map(Some).collect();
219
220        Array::TinyUnsigned(values.into_boxed_slice())
221    }
222}
223
224impl From<Vec<Option<u8>>> for Array {
225    fn from(x: Vec<Option<u8>>) -> Array {
226        Array::TinyUnsigned(x.into_boxed_slice())
227    }
228}
229
230impl From<Vec<Option<u8>>> for Value {
231    fn from(x: Vec<Option<u8>>) -> Value {
232        Value::Array(Array::TinyUnsigned(x.into_boxed_slice()))
233    }
234}
235
236impl ValueType for Vec<Option<u8>> {
237    fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
238        match v {
239            Value::Array(Array::TinyUnsigned(inner)) => Ok(inner.into_vec()),
240            _ => Err(ValueTypeErr),
241        }
242    }
243
244    fn type_name() -> String {
245        stringify!(Vec<u8>).to_owned()
246    }
247
248    fn array_type() -> ArrayType {
249        <u8>::array_type()
250    }
251
252    fn column_type() -> ColumnType {
253        use ColumnType::*;
254        Array(RcOrArc::new(<u8>::column_type()))
255    }
256}
257
258#[cfg(feature = "with-json")]
259impl_value_vec! {
260    serde_json::Value => Json
261}
262
263impl From<(Arc<str>, Vec<Option<Arc<Enum>>>)> for Value {
264    fn from(x: (Arc<str>, Vec<Option<Arc<Enum>>>)) -> Value {
265        Value::Array(Array::Enum(Box::new((x.0, x.1.into_boxed_slice()))))
266    }
267}
268
269#[cfg(feature = "with-chrono")]
270impl_value_vec! {
271    NaiveDate => ChronoDate
272    NaiveTime => ChronoTime
273    NaiveDateTime => ChronoDateTime
274    chrono::DateTime<chrono::Utc> => ChronoDateTimeUtc
275    chrono::DateTime<chrono::Local> => ChronoDateTimeLocal
276    chrono::DateTime<chrono::FixedOffset> => ChronoDateTimeWithTimeZone
277}
278
279#[cfg(feature = "with-time")]
280impl_value_vec! {
281    time::Date => TimeDate
282    time::Time => TimeTime
283    PrimitiveDateTime => TimeDateTime
284    OffsetDateTime => TimeDateTimeWithTimeZone
285}
286
287#[cfg(feature = "with-jiff")]
288impl_value_vec! {
289    jiff::civil::Date => JiffDate
290    jiff::civil::Time => JiffTime
291    jiff::civil::DateTime => JiffDateTime
292    jiff::Timestamp => JiffTimestamp
293    jiff::Zoned => JiffZoned
294}
295
296#[cfg(feature = "with-rust_decimal")]
297impl_value_vec! {
298    rust_decimal::Decimal => Decimal
299}
300
301#[cfg(feature = "with-bigdecimal")]
302impl_value_vec! {
303    bigdecimal::BigDecimal => BigDecimal
304}
305
306#[cfg(feature = "with-uuid")]
307impl_value_vec! {
308    uuid::Uuid => Uuid
309}
310
311// uuid::fmt::* types use UUID arrays
312macro_rules! impl_uuid_fmt_pg_array_element {
313    ($ty:ty, $method:ident) => {
314        #[cfg(feature = "with-uuid")]
315        impl ArrayElement for $ty {
316            type ArrayValueType = Uuid;
317
318            fn into_array_value(self) -> Self::ArrayValueType {
319                self.into_uuid()
320            }
321
322            fn try_from_value(v: Value) -> Result<Vec<Option<Self>>, ValueTypeErr> {
323                match v {
324                    Value::Array(Array::Uuid(inner)) => Ok(inner
325                        .into_vec()
326                        .into_iter()
327                        .map(|opt| opt.map(Self::from))
328                        .collect()),
329                    Value::Array(Array::Null(_)) => Ok(vec![]),
330                    _ => Err(ValueTypeErr),
331                }
332            }
333        }
334    };
335}
336
337impl_uuid_fmt_pg_array_element!(uuid::fmt::Braced, braced);
338impl_uuid_fmt_pg_array_element!(uuid::fmt::Hyphenated, hyphenated);
339impl_uuid_fmt_pg_array_element!(uuid::fmt::Simple, simple);
340impl_uuid_fmt_pg_array_element!(uuid::fmt::Urn, urn);
341
342#[cfg(feature = "with-ipnetwork")]
343impl_value_vec! {
344    IpNetwork => IpNetwork
345}
346
347#[cfg(feature = "with-mac_address")]
348impl_value_vec! {
349    MacAddress => MacAddress
350}
351
352impl<T> Nullable for Vec<T>
353where
354    T: Into<Value> + NotU8 + ValueType,
355{
356    fn null() -> Value {
357        Value::Array(Array::Null(T::array_type()))
358    }
359}
360
361impl Value {
362    pub fn is_array(&self) -> bool {
363        matches!(self, Self::Array(_))
364    }
365
366    pub fn as_ref_array(&self) -> Option<&Array> {
367        match self {
368            Self::Array(v) if !v.is_null() => Some(v),
369            Self::Array(_) => None,
370            _ => panic!("not Value::Array"),
371        }
372    }
373}