Skip to content

Commit 5e197e8

Browse files
committed
Use postgres_protocol
1 parent 0a23f49 commit 5e197e8

File tree

3 files changed

+67
-82
lines changed

3 files changed

+67
-82
lines changed

Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ documentation = "https://sfackler.github.io/rust-postgres-range/doc/v0.8.2/postg
1010
[dependencies]
1111
time = "0.1"
1212
postgres = "0.11"
13-
byteorder = "0.5"
13+
postgres-protocol = { git = "https://github.com/sfackler/rust-postgres-protocol" }
1414

1515
[dev-dependencies]
16-
postgres = { version = "0.11", features = ["time"] }
16+
postgres = { version = "0.11", features = ["with-time"] }
17+
18+
[replace]
19+
"postgres:0.11.11" = { git = "https://github.com/sfackler/rust-postgres" }
20+
"fallible-iterator:0.1.2" = { git = "https://github.com/sfackler/rust-fallible-iterator" }

src/impls.rs

Lines changed: 60 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,24 @@
1-
use std::io::prelude::*;
2-
use std::error;
3-
use postgres;
1+
use std::error::Error;
42
use postgres::types::{Type, Kind, ToSql, FromSql, IsNull, SessionInfo};
5-
use postgres::error::Error;
6-
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
3+
use postgres_protocol::types;
74

85
use {Range, RangeBound, BoundType, BoundSided, Normalizable};
96

10-
const RANGE_UPPER_UNBOUNDED: i8 = 0b0001_0000;
11-
const RANGE_LOWER_UNBOUNDED: i8 = 0b0000_1000;
12-
const RANGE_UPPER_INCLUSIVE: i8 = 0b0000_0100;
13-
const RANGE_LOWER_INCLUSIVE: i8 = 0b0000_0010;
14-
const RANGE_EMPTY: i8 = 0b0000_0001;
15-
167
impl<T> FromSql for Range<T> where T: PartialOrd+Normalizable+FromSql {
17-
fn from_sql<R: Read>(ty: &Type, rdr: &mut R, info: &SessionInfo)
18-
-> postgres::Result<Range<T>> {
8+
fn from_sql(ty: &Type, raw: &[u8], info: &SessionInfo) -> Result<Range<T>, Box<Error + Sync + Send>> {
199
let element_type = match ty.kind() {
2010
&Kind::Range(ref ty) => ty,
2111
_ => panic!("unexpected type {:?}", ty)
2212
};
2313

24-
let t = try!(rdr.read_i8());
25-
26-
if t & RANGE_EMPTY != 0 {
27-
return Ok(Range::empty());
28-
}
29-
30-
fn make_bound<S, T, R>(ty: &Type, rdr: &mut R, info: &SessionInfo,
31-
tag: i8, bound_flag: i8, inclusive_flag: i8)
32-
-> postgres::Result<Option<RangeBound<S, T>>>
33-
where S: BoundSided, T: PartialOrd+Normalizable+FromSql, R: Read {
34-
match tag & bound_flag {
35-
0 => {
36-
let type_ = match tag & inclusive_flag {
37-
0 => BoundType::Exclusive,
38-
_ => BoundType::Inclusive,
39-
};
40-
let len = try!(rdr.read_i32::<BigEndian>()) as u64;
41-
let mut limit = rdr.take(len);
42-
let bound = try!(FromSql::from_sql(ty, &mut limit, info));
43-
if limit.limit() != 0 {
44-
let err: Box<error::Error+Sync+Send> =
45-
"from_sql call did not consume all data".into();
46-
return Err(Error::Conversion(err));
47-
}
48-
Ok(Some(RangeBound::new(bound, type_)))
49-
}
50-
_ => Ok(None)
14+
match try!(types::range_from_sql(raw)) {
15+
types::Range::Empty => Ok(Range::empty()),
16+
types::Range::Nonempty(lower, upper) => {
17+
let lower = try!(bound_from_sql(lower, element_type, info));
18+
let upper = try!(bound_from_sql(upper, element_type, info));
19+
Ok(Range::new(lower, upper))
5120
}
5221
}
53-
54-
let lower = try!(make_bound(element_type, rdr, info, t,
55-
RANGE_LOWER_UNBOUNDED, RANGE_LOWER_INCLUSIVE));
56-
let upper = try!(make_bound(element_type, rdr, info, t,
57-
RANGE_UPPER_UNBOUNDED, RANGE_UPPER_INCLUSIVE));
58-
Ok(Range::new(lower, upper))
5922
}
6023

6124
fn accepts(ty: &Type) -> bool {
@@ -66,47 +29,44 @@ impl<T> FromSql for Range<T> where T: PartialOrd+Normalizable+FromSql {
6629
}
6730
}
6831

32+
fn bound_from_sql<T, S>(bound: types::RangeBound<Option<&[u8]>>, ty: &Type, info: &SessionInfo) -> Result<Option<RangeBound<S, T>>, Box<Error + Sync + Send>>
33+
where T: PartialOrd + Normalizable + FromSql,
34+
S: BoundSided
35+
{
36+
match bound {
37+
types::RangeBound::Exclusive(value) => {
38+
let value = match value {
39+
Some(value) => try!(T::from_sql(ty, value, info)),
40+
None => try!(T::from_sql_null(ty, info)),
41+
};
42+
Ok(Some(RangeBound::new(value, BoundType::Exclusive)))
43+
},
44+
types::RangeBound::Inclusive(value) => {
45+
let value = match value {
46+
Some(value) => try!(T::from_sql(ty, value, info)),
47+
None => try!(T::from_sql_null(ty, info)),
48+
};
49+
Ok(Some(RangeBound::new(value, BoundType::Inclusive)))
50+
},
51+
types::RangeBound::Unbounded => Ok(None),
52+
}
53+
}
54+
6955
impl<T> ToSql for Range<T> where T: PartialOrd+Normalizable+ToSql {
70-
fn to_sql<W: ?Sized+Write>(&self, ty: &Type, mut buf: &mut W, info: &SessionInfo)
71-
-> postgres::Result<IsNull> {
56+
fn to_sql(&self, ty: &Type, mut buf: &mut Vec<u8>, info: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
7257
let element_type = match ty.kind() {
7358
&Kind::Range(ref ty) => ty,
7459
_ => panic!("unexpected type {:?}", ty)
7560
};
7661

77-
let mut tag = 0;
7862
if self.is_empty() {
79-
tag |= RANGE_EMPTY;
63+
types::empty_range_to_sql(buf);
8064
} else {
81-
fn make_tag<S, T>(bound: Option<&RangeBound<S, T>>, unbounded_tag: i8,
82-
inclusive_tag: i8) -> i8 where S: BoundSided {
83-
match bound {
84-
None => unbounded_tag,
85-
Some(&RangeBound { type_: BoundType::Inclusive, .. }) => inclusive_tag,
86-
_ => 0
87-
}
88-
}
89-
tag |= make_tag(self.lower(), RANGE_LOWER_UNBOUNDED, RANGE_LOWER_INCLUSIVE);
90-
tag |= make_tag(self.upper(), RANGE_UPPER_UNBOUNDED, RANGE_UPPER_INCLUSIVE);
91-
}
92-
93-
try!(buf.write_i8(tag));
94-
95-
fn write_value<S, T, W: ?Sized>(ty: &Type, mut buf: &mut W, info: &SessionInfo,
96-
v: Option<&RangeBound<S, T>>) -> postgres::Result<()>
97-
where S: BoundSided, T: ToSql, W: Write {
98-
if let Some(bound) = v {
99-
let mut inner_buf = vec![];
100-
try!(bound.value.to_sql(ty, &mut inner_buf, info));
101-
try!(buf.write_u32::<BigEndian>(inner_buf.len() as u32));
102-
try!(buf.write_all(&*inner_buf));
103-
}
104-
Ok(())
65+
try!(types::range_to_sql(|buf| bound_to_sql(self.lower(), element_type, info, buf),
66+
|buf| bound_to_sql(self.upper(), element_type, info, buf),
67+
buf));
10568
}
10669

107-
try!(write_value(&element_type, buf, info, self.lower()));
108-
try!(write_value(&element_type, buf, info, self.upper()));
109-
11070
Ok(IsNull::No)
11171
}
11272

@@ -120,11 +80,32 @@ impl<T> ToSql for Range<T> where T: PartialOrd+Normalizable+ToSql {
12080
to_sql_checked!();
12181
}
12282

83+
fn bound_to_sql<S, T>(bound: Option<&RangeBound<S, T>>, ty: &Type, info: &SessionInfo, buf: &mut Vec<u8>) -> Result<types::RangeBound<types::IsNull>, Box<Error + Sync + Send>>
84+
where S: BoundSided,
85+
T: ToSql
86+
{
87+
match bound {
88+
Some(bound) => {
89+
let null = match try!(bound.value.to_sql(ty, buf, info)) {
90+
IsNull::Yes => types::IsNull::Yes,
91+
IsNull::No => types::IsNull::No,
92+
};
93+
94+
match bound.type_ {
95+
BoundType::Exclusive => Ok(types::RangeBound::Exclusive(null)),
96+
BoundType::Inclusive => Ok(types::RangeBound::Inclusive(null)),
97+
}
98+
}
99+
None => Ok(types::RangeBound::Unbounded),
100+
}
101+
102+
}
103+
123104
#[cfg(test)]
124105
mod test {
125106
use std::fmt;
126107

127-
use postgres::{Connection, SslMode};
108+
use postgres::{Connection, TlsMode};
128109
use postgres::types::{FromSql, ToSql};
129110
use time::{self, Timespec};
130111

@@ -150,7 +131,7 @@ mod test {
150131
}
151132

152133
fn test_type<T: PartialEq+FromSql+ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
153-
let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();
134+
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
154135
for &(ref val, ref repr) in checks {
155136
let stmt = conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)).unwrap();
156137
let result = stmt.query(&[]).unwrap().iter().next().unwrap().get(0);

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
#[macro_use(to_sql_checked)]
55
extern crate postgres;
6+
extern crate postgres_protocol;
67
extern crate time;
7-
extern crate byteorder;
88

99
use std::cmp::Ordering;
1010
use std::fmt;

0 commit comments

Comments
 (0)