diesel/pg/types/
multirange.rs

1use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
2use std::io::Write;
3use std::ops::Bound;
4
5use crate::deserialize::{self, Defaultable, FromSql};
6use crate::expression::bound::Bound as SqlBound;
7use crate::expression::AsExpression;
8use crate::pg::{Pg, PgTypeMetadata, PgValue};
9use crate::query_builder::bind_collector::ByteWrapper;
10use crate::serialize::{self, IsNull, Output, ToSql};
11use crate::sql_types::*;
12
13// from `SELECT oid, typname FROM pg_catalog.pg_type where typname LIKE '%multirange'`;
14macro_rules! multirange_has_sql_type {
15    ($ty:ty, $oid:expr, $array_oid:expr) => {
16        #[cfg(feature = "postgres_backend")]
17        impl HasSqlType<$ty> for Pg {
18            fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
19                PgTypeMetadata::new($oid, $array_oid)
20            }
21        }
22    };
23}
24multirange_has_sql_type!(Datemultirange, 4535, 6155);
25multirange_has_sql_type!(Int4multirange, 4451, 6150);
26multirange_has_sql_type!(Int8multirange, 4536, 6157);
27multirange_has_sql_type!(Nummultirange, 4532, 6151);
28multirange_has_sql_type!(Tsmultirange, 4533, 6152);
29multirange_has_sql_type!(Tstzmultirange, 4534, 6153);
30
31macro_rules! multirange_as_expression {
32    ($ty:ty, $sql_type:ty) => {
33        #[cfg(feature = "postgres_backend")]
34        // this simplifies the macro implementation
35        // as some macro calls use this lifetime
36        #[allow(clippy::extra_unused_lifetimes)]
37        impl<'a, 'b, ST: 'static, T> AsExpression<$sql_type> for $ty {
38            type Expression = SqlBound<$sql_type, Self>;
39            fn as_expression(self) -> Self::Expression {
40                SqlBound::new(self)
41            }
42        }
43    };
44}
45
46macro_rules! multirange_as_expressions {
47    ($ty:ty) => {
48        multirange_as_expression!(&'a [$ty], Multirange<ST>);
49        multirange_as_expression!(&'a [$ty], Nullable<Multirange<ST>>);
50        multirange_as_expression!(&'a &'b [$ty], Multirange<ST>);
51        multirange_as_expression!(&'a &'b [$ty], Nullable<Multirange<ST>>);
52        multirange_as_expression!(Vec<$ty>, Multirange<ST>);
53        multirange_as_expression!(Vec<$ty>, Nullable<Multirange<ST>>);
54        multirange_as_expression!(&'a Vec<$ty>, Multirange<ST>);
55        multirange_as_expression!(&'a Vec<$ty>, Nullable<Multirange<ST>>);
56        multirange_as_expression!(&'a &'b Vec<$ty>, Multirange<ST>);
57        multirange_as_expression!(&'a &'b Vec<$ty>, Nullable<Multirange<ST>>);
58    };
59}
60
61multirange_as_expressions!((Bound<T>, Bound<T>));
62multirange_as_expressions!(std::ops::Range<T>);
63multirange_as_expressions!(std::ops::RangeInclusive<T>);
64multirange_as_expressions!(std::ops::RangeToInclusive<T>);
65multirange_as_expressions!(std::ops::RangeFrom<T>);
66multirange_as_expressions!(std::ops::RangeTo<T>);
67
68#[cfg(feature = "postgres_backend")]
69impl<T, ST> FromSql<Multirange<ST>, Pg> for Vec<(Bound<T>, Bound<T>)>
70where
71    T: FromSql<ST, Pg> + Defaultable,
72{
73    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
74        let mut bytes = value.as_bytes();
75        let len = bytes.read_u32::<NetworkEndian>()?;
76
77        (0..len)
78            .map(|_| {
79                let range_size: usize = bytes.read_i32::<NetworkEndian>()?.try_into()?;
80                let (range_bytes, new_bytes) = bytes.split_at(range_size);
81                bytes = new_bytes;
82                FromSql::from_sql(PgValue::new_internal(range_bytes, &value))
83            })
84            .collect()
85    }
86}
87
88fn to_sql<'c, ST, T, I>(iter: I, out: &mut Output<'_, '_, Pg>) -> serialize::Result
89where
90    ST: 'static,
91    T: ToSql<ST, Pg> + 'c,
92    I: Iterator<Item = (Bound<&'c T>, Bound<&'c T>)> + ExactSizeIterator,
93{
94    out.write_u32::<NetworkEndian>(iter.len().try_into()?)?;
95
96    let mut buffer = Vec::new();
97    for value in iter {
98        {
99            let mut inner_buffer = Output::new(ByteWrapper(&mut buffer), out.metadata_lookup());
100            ToSql::<Range<ST>, Pg>::to_sql(&value, &mut inner_buffer)?;
101        }
102        let buffer_len: i32 = buffer.len().try_into()?;
103        out.write_i32::<NetworkEndian>(buffer_len)?;
104        out.write_all(&buffer)?;
105        buffer.clear();
106    }
107
108    Ok(IsNull::No)
109}
110
111#[cfg(feature = "postgres_backend")]
112impl<T, ST> ToSql<Multirange<ST>, Pg> for [(Bound<T>, Bound<T>)]
113where
114    T: ToSql<ST, Pg>,
115{
116    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
117        to_sql(self.iter().map(|r| (r.0.as_ref(), r.1.as_ref())), out)
118    }
119}
120
121#[cfg(feature = "postgres_backend")]
122impl<T, ST> ToSql<Multirange<ST>, Pg> for Vec<(Bound<T>, Bound<T>)>
123where
124    T: ToSql<ST, Pg>,
125    [(Bound<T>, Bound<T>)]: ToSql<Multirange<ST>, Pg>,
126{
127    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
128        ToSql::<Multirange<ST>, Pg>::to_sql(self.as_slice(), out)
129    }
130}
131
132use std::ops::RangeBounds;
133macro_rules! multirange_std_to_sql {
134    ($ty:ty) => {
135        #[cfg(feature = "postgres_backend")]
136        impl<ST, T> ToSql<Multirange<ST>, Pg> for [$ty]
137        where
138            ST: 'static,
139            T: ToSql<ST, Pg>,
140        {
141            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
142                to_sql(
143                    self.into_iter().map(|r| (r.start_bound(), r.end_bound())),
144                    out,
145                )
146            }
147        }
148
149        #[cfg(feature = "postgres_backend")]
150        impl<T, ST> ToSql<Multirange<ST>, Pg> for Vec<$ty>
151        where
152            T: ToSql<ST, Pg>,
153            [$ty]: ToSql<Multirange<ST>, Pg>,
154        {
155            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
156                ToSql::<Multirange<ST>, Pg>::to_sql(self.as_slice(), out)
157            }
158        }
159    };
160}
161
162multirange_std_to_sql!(std::ops::Range<T>);
163multirange_std_to_sql!(std::ops::RangeInclusive<T>);
164multirange_std_to_sql!(std::ops::RangeFrom<T>);
165multirange_std_to_sql!(std::ops::RangeTo<T>);
166multirange_std_to_sql!(std::ops::RangeToInclusive<T>);
167
168macro_rules! multirange_to_sql_nullable {
169    ($ty:ty) => {
170        impl<T, ST> ToSql<Nullable<Multirange<ST>>, Pg> for [$ty]
171        where
172            ST: 'static,
173            [$ty]: ToSql<ST, Pg>,
174            T: ToSql<ST, Pg>,
175        {
176            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
177                ToSql::<Multirange<ST>, Pg>::to_sql(self, out)
178            }
179        }
180
181        impl<T, ST> ToSql<Nullable<Multirange<ST>>, Pg> for Vec<$ty>
182        where
183            ST: 'static,
184            Vec<$ty>: ToSql<ST, Pg>,
185            T: ToSql<ST, Pg>,
186        {
187            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
188                ToSql::<Multirange<ST>, Pg>::to_sql(self, out)
189            }
190        }
191    };
192}
193
194multirange_to_sql_nullable!((Bound<T>, Bound<T>));
195multirange_to_sql_nullable!(std::ops::Range<T>);
196multirange_to_sql_nullable!(std::ops::RangeInclusive<T>);
197multirange_to_sql_nullable!(std::ops::RangeFrom<T>);
198multirange_to_sql_nullable!(std::ops::RangeTo<T>);
199multirange_to_sql_nullable!(std::ops::RangeToInclusive<T>);