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