diesel/pg/types/
ranges.rs
1use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
2use std::collections::Bound;
3use std::io::Write;
4
5use crate::deserialize::{self, FromSql, Queryable};
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
13bitflags::bitflags! {
15 struct RangeFlags: u8 {
16 const EMPTY = 0x01;
17 const LB_INC = 0x02;
18 const UB_INC = 0x04;
19 const LB_INF = 0x08;
20 const UB_INF = 0x10;
21 const LB_NULL = 0x20;
22 const UB_NULL = 0x40;
23 const CONTAIN_EMPTY = 0x80;
24 }
25}
26
27#[cfg(feature = "postgres_backend")]
28impl<ST: 'static, T> AsExpression<Range<ST>> for (Bound<T>, Bound<T>) {
29 type Expression = SqlBound<Range<ST>, Self>;
30
31 fn as_expression(self) -> Self::Expression {
32 SqlBound::new(self)
33 }
34}
35
36#[cfg(feature = "postgres_backend")]
37impl<ST: 'static, T> AsExpression<Range<ST>> for &(Bound<T>, Bound<T>) {
38 type Expression = SqlBound<Range<ST>, Self>;
39
40 fn as_expression(self) -> Self::Expression {
41 SqlBound::new(self)
42 }
43}
44
45#[cfg(feature = "postgres_backend")]
46impl<ST: 'static, T> AsExpression<Nullable<Range<ST>>> for (Bound<T>, Bound<T>) {
47 type Expression = SqlBound<Nullable<Range<ST>>, Self>;
48
49 fn as_expression(self) -> Self::Expression {
50 SqlBound::new(self)
51 }
52}
53
54#[cfg(feature = "postgres_backend")]
55impl<ST: 'static, T> AsExpression<Nullable<Range<ST>>> for &(Bound<T>, Bound<T>) {
56 type Expression = SqlBound<Nullable<Range<ST>>, Self>;
57
58 fn as_expression(self) -> Self::Expression {
59 SqlBound::new(self)
60 }
61}
62
63#[cfg(feature = "postgres_backend")]
64impl<T, ST> FromSql<Range<ST>, Pg> for (Bound<T>, Bound<T>)
65where
66 T: FromSql<ST, Pg>,
67{
68 fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
69 let mut bytes = value.as_bytes();
70 let flags: RangeFlags = RangeFlags::from_bits_truncate(bytes.read_u8()?);
71 let mut lower_bound = Bound::Unbounded;
72 let mut upper_bound = Bound::Unbounded;
73
74 if !flags.contains(RangeFlags::LB_INF) {
75 let elem_size = bytes.read_i32::<NetworkEndian>()?;
76 let (elem_bytes, new_bytes) = bytes.split_at(elem_size.try_into()?);
77 bytes = new_bytes;
78 let value = T::from_sql(PgValue::new_internal(elem_bytes, &value))?;
79
80 lower_bound = if flags.contains(RangeFlags::LB_INC) {
81 Bound::Included(value)
82 } else {
83 Bound::Excluded(value)
84 };
85 }
86
87 if !flags.contains(RangeFlags::UB_INF) {
88 let _size = bytes.read_i32::<NetworkEndian>()?;
89 let value = T::from_sql(PgValue::new_internal(bytes, &value))?;
90
91 upper_bound = if flags.contains(RangeFlags::UB_INC) {
92 Bound::Included(value)
93 } else {
94 Bound::Excluded(value)
95 };
96 }
97
98 Ok((lower_bound, upper_bound))
99 }
100}
101
102#[cfg(feature = "postgres_backend")]
103impl<T, ST> Queryable<Range<ST>, Pg> for (Bound<T>, Bound<T>)
104where
105 T: FromSql<ST, Pg>,
106{
107 type Row = Self;
108
109 fn build(row: Self) -> deserialize::Result<Self> {
110 Ok(row)
111 }
112}
113
114#[cfg(feature = "postgres_backend")]
115impl<ST, T> ToSql<Range<ST>, Pg> for (Bound<T>, Bound<T>)
116where
117 T: ToSql<ST, Pg>,
118{
119 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
120 let mut flags = match self.0 {
121 Bound::Included(_) => RangeFlags::LB_INC,
122 Bound::Excluded(_) => RangeFlags::empty(),
123 Bound::Unbounded => RangeFlags::LB_INF,
124 };
125
126 flags |= match self.1 {
127 Bound::Included(_) => RangeFlags::UB_INC,
128 Bound::Excluded(_) => RangeFlags::empty(),
129 Bound::Unbounded => RangeFlags::UB_INF,
130 };
131
132 out.write_u8(flags.bits())?;
133
134 let mut buffer = Vec::new();
135
136 match self.0 {
137 Bound::Included(ref value) | Bound::Excluded(ref value) => {
138 {
139 let mut inner_buffer =
140 Output::new(ByteWrapper(&mut buffer), out.metadata_lookup());
141 value.to_sql(&mut inner_buffer)?;
142 }
143 out.write_u32::<NetworkEndian>(buffer.len().try_into()?)?;
144 out.write_all(&buffer)?;
145 buffer.clear();
146 }
147 Bound::Unbounded => {}
148 }
149
150 match self.1 {
151 Bound::Included(ref value) | Bound::Excluded(ref value) => {
152 {
153 let mut inner_buffer =
154 Output::new(ByteWrapper(&mut buffer), out.metadata_lookup());
155 value.to_sql(&mut inner_buffer)?;
156 }
157 out.write_u32::<NetworkEndian>(buffer.len().try_into()?)?;
158 out.write_all(&buffer)?;
159 }
160 Bound::Unbounded => {}
161 }
162
163 Ok(IsNull::No)
164 }
165}
166
167#[cfg(feature = "postgres_backend")]
168impl<ST, T> ToSql<Nullable<Range<ST>>, Pg> for (Bound<T>, Bound<T>)
169where
170 ST: 'static,
171 (Bound<T>, Bound<T>): ToSql<Range<ST>, Pg>,
172{
173 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
174 ToSql::<Range<ST>, Pg>::to_sql(self, out)
175 }
176}
177
178#[cfg(feature = "postgres_backend")]
179impl HasSqlType<Int4range> for Pg {
180 fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
181 PgTypeMetadata::new(3904, 3905)
182 }
183}
184
185#[cfg(feature = "postgres_backend")]
186impl HasSqlType<Numrange> for Pg {
187 fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
188 PgTypeMetadata::new(3906, 3907)
189 }
190}
191
192impl HasSqlType<Tsrange> for Pg {
193 fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
194 PgTypeMetadata::new(3908, 3909)
195 }
196}
197
198#[cfg(feature = "postgres_backend")]
199impl HasSqlType<Tstzrange> for Pg {
200 fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
201 PgTypeMetadata::new(3910, 3911)
202 }
203}
204
205#[cfg(feature = "postgres_backend")]
206impl HasSqlType<Daterange> for Pg {
207 fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
208 PgTypeMetadata::new(3912, 3913)
209 }
210}
211
212#[cfg(feature = "postgres_backend")]
213impl HasSqlType<Int8range> for Pg {
214 fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
215 PgTypeMetadata::new(3926, 3927)
216 }
217}