Skip to content

Commit 744681e

Browse files
committed
feat(*): update to rust 2018 and new postgres types
1 parent 0e27945 commit 744681e

File tree

14 files changed

+69
-86
lines changed

14 files changed

+69
-86
lines changed

Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[package]
22
name = "pg_interval"
3-
version = "0.3.0"
3+
version = "0.4.1"
4+
edition = "2018"
45
authors = ["Ryan Piper <[email protected]>"]
56
license = "MIT"
67
description = "A native PostgreSQL interval type"
@@ -11,9 +12,9 @@ include = ["src/*", "Cargo.toml", "LICENSE", "README.md"]
1112
categories = ["date-and-time"]
1213

1314
[features]
14-
default = ["postgres"]
15+
default = ["postgres-types"]
1516

1617
[dependencies]
17-
postgres = { version = "^0.15", optional=true }
18-
byteorder = { version = "1.2.4" }
19-
chrono = { version = "^0.4" }
18+
chrono = { version = "^0.4" }
19+
bytes = { version = "^1" }
20+
postgres-types = { version = "^0.2", optional = true }

src/integrations/duration.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use pg_interval::Interval;
2-
use interval_norm::IntervalNorm;
1+
use crate::{interval_norm::IntervalNorm, Interval};
32
use chrono::Duration;
43

54
const NANOS_PER_SEC: i64 = 1_000_000_000;
@@ -30,10 +29,10 @@ impl Interval {
3029
years: 0,
3130
months: 0,
3231
days: days as i32,
33-
hours: hours,
34-
minutes: minutes,
35-
seconds: seconds,
36-
microseconds: microseconds,
32+
hours,
33+
minutes,
34+
seconds,
35+
microseconds,
3736
};
3837
norm_interval.try_into_interval().ok()
3938
}
@@ -47,7 +46,7 @@ fn reduce_by_units(nano_secs: i64, unit: i64) -> (i64, i64) {
4746

4847
#[cfg(test)]
4948
mod tests {
50-
use pg_interval::Interval;
49+
use super::*;
5150
use chrono::Duration;
5251

5352

src/integrations/rust_postgres.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2-
use postgres::types::{FromSql, IsNull, ToSql, Type, INTERVAL};
3-
use std::error::Error;
4-
use Interval;
1+
use crate::Interval;
2+
use bytes::{Buf, BufMut, BytesMut};
3+
use postgres_types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
54

6-
impl FromSql for Interval {
7-
fn from_sql(_: &Type, mut raw: &[u8]) -> Result<Interval, Box<Error + Sync + Send>> {
5+
impl<'a> FromSql<'a> for Interval {
6+
fn from_sql(_: &Type, mut raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
87
let microseconds: i64 = raw.read_i64::<BigEndian>()?;
98
let days: i32 = raw.read_i32::<BigEndian>()?;
109
let months: i32 = raw.read_i32::<BigEndian>()?;
@@ -17,27 +16,20 @@ impl FromSql for Interval {
1716
}
1817

1918
fn accepts(ty: &Type) -> bool {
20-
match *ty {
21-
INTERVAL => true,
22-
_ => false,
23-
}
19+
matches!(*ty, Type::INTERVAL)
2420
}
2521
}
2622

2723
impl ToSql for Interval {
28-
fn to_sql(&self, _: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
29-
out.write_i64::<BigEndian>(self.microseconds)?;
30-
out.write_i32::<BigEndian>(self.days)?;
31-
out.write_i32::<BigEndian>(self.months)?;
32-
24+
fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
25+
out.put_i64(self.microseconds);
26+
out.put_i32(self.days);
27+
out.put_i32(self.months);
3328
Ok(IsNull::No)
3429
}
3530

3631
fn accepts(ty: &Type) -> bool {
37-
match *ty {
38-
INTERVAL => true,
39-
_ => false,
40-
}
32+
matches!(*ty, Type::INTERVAL)
4133
}
4234

4335
to_sql_checked!();

src/interval_fmt/iso_8601.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use interval_norm::IntervalNorm;
1+
use crate::interval_norm::IntervalNorm;
22

33
impl IntervalNorm {
44
/// Produces a iso 8601 compliant interval string.

src/interval_fmt/postgres.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use interval_norm::IntervalNorm;
1+
use crate::interval_norm::IntervalNorm;
22

33
impl IntervalNorm {
44
/// Produces a postgres compliant interval string.

src/interval_fmt/sql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use interval_norm::IntervalNorm;
1+
use crate::interval_norm::IntervalNorm;
22

33
impl IntervalNorm {
44
pub fn into_sql(self) -> String {

src/interval_norm.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use interval_parse::parse_error::ParseError;
2-
use pg_interval::Interval;
1+
use crate::{interval_parse::parse_error::ParseError, Interval};
32

43
pub struct IntervalNorm {
54
pub years: i32,
@@ -58,13 +57,12 @@ impl IntervalNorm {
5857
.and_then(|seconds| seconds.checked_mul(1_000_000))
5958
.and_then(|microseconds| self.microseconds.checked_add(microseconds));
6059
Ok(Interval {
61-
months: months.ok_or(ParseError::from_year_month(
62-
"Invalid year/month interval overflow detected.",
63-
))?,
60+
months: months.ok_or_else(|| {
61+
ParseError::from_year_month("Invalid year/month interval overflow detected.")
62+
})?,
6463
days: self.days,
65-
microseconds: microseconds.ok_or(ParseError::from_time(
66-
"Invalid time interval overflow detected.",
67-
))?,
64+
microseconds: microseconds
65+
.ok_or_else(|| ParseError::from_time("Invalid time interval overflow detected."))?,
6866
})
6967
}
7068

src/interval_parse/iso_8601.rs

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
1-
use super::parse_error::ParseError;
21
use super::{
32
scale_date, scale_time, DAYS_PER_MONTH, HOURS_PER_DAY, MICROS_PER_SECOND, MINUTES_PER_HOUR,
43
MONTHS_PER_YEAR, SECONDS_PER_MIN,
54
};
6-
use interval_norm::IntervalNorm;
7-
use pg_interval::Interval;
5+
use super::parse_error::ParseError;
6+
use crate::{interval_norm::IntervalNorm, Interval};
87

98
enum ParserCode {
10-
BADFORMAT,
11-
GOOD,
12-
DELIMFOUND,
9+
BadFormat,
10+
Good,
11+
DelimFound,
1312
}
1413

1514
impl Interval {
16-
pub fn from_iso<'a>(iso_str: &'a str) -> Result<Interval, ParseError> {
15+
pub fn from_iso(iso_str: &str) -> Result<Interval, ParseError> {
1716
let mut date_part = true;
1817
let delim = vec!['Y', 'M', 'D', 'H', 'S'];
19-
let mut number = "".to_owned();
18+
let mut number = String::new();
2019
let mut interval_norm = IntervalNorm::default();
2120
if iso_str.rfind('P').map_or(false, |v| v == 1) {
2221
Err(ParseError::from_invalid_interval(
@@ -37,13 +36,13 @@ impl Interval {
3736
}
3837
let code = consume_number(&x, &mut number, &delim);
3938
match code {
40-
ParserCode::BADFORMAT => {
39+
ParserCode::BadFormat => {
4140
return Err(ParseError::from_invalid_interval("Invalid format."));
4241
}
43-
ParserCode::GOOD => {
42+
ParserCode::Good => {
4443
continue;
4544
}
46-
ParserCode::DELIMFOUND => {
45+
ParserCode::DelimFound => {
4746
let val = parse_number(&mut number)?;
4847
match x {
4948
'Y' => {
@@ -91,7 +90,7 @@ impl Interval {
9190
}
9291
}
9392
}
94-
if number != "" {
93+
if !number.is_empty() {
9594
Err(ParseError::from_invalid_interval(
9695
"Invalid format could not parse whole interval.",
9796
))
@@ -102,24 +101,20 @@ impl Interval {
102101
}
103102
}
104103

105-
fn consume_number<'a>(val: &'a char, number: &'a mut String, delim: &'a Vec<char>) -> ParserCode {
106-
if val.is_digit(10) {
107-
number.push(*val);
108-
ParserCode::GOOD
109-
} else if number.len() == 0 && *val == '-' {
110-
number.push(*val);
111-
ParserCode::GOOD
112-
} else if number.len() != 0 && *val == '.' {
104+
fn consume_number<'a>(val: &'a char, number: &'a mut String, delim: &[char]) -> ParserCode {
105+
let is_first_char = number.is_empty() && *val == '-';
106+
let is_period_char = !number.is_empty() && *val == '.';
107+
if val.is_digit(10) || is_first_char || is_period_char {
113108
number.push(*val);
114-
ParserCode::GOOD
115-
} else if delim.contains(&val) {
116-
ParserCode::DELIMFOUND
109+
ParserCode::Good
110+
} else if delim.contains(val) {
111+
ParserCode::DelimFound
117112
} else {
118-
ParserCode::BADFORMAT
113+
ParserCode::BadFormat
119114
}
120115
}
121116

122-
fn parse_number<'a>(number: &'a mut String) -> Result<f64, ParseError> {
117+
fn parse_number(number: &mut String) -> Result<f64, ParseError> {
123118
let parse_num = number.parse::<f64>()?;
124119
if parse_num > i32::max_value() as f64 {
125120
Err(ParseError::from_invalid_interval("Exceeded max value"))
@@ -131,7 +126,7 @@ fn parse_number<'a>(number: &'a mut String) -> Result<f64, ParseError> {
131126

132127
#[cfg(test)]
133128
mod tests {
134-
use pg_interval::Interval;
129+
use super::*;
135130

136131
#[test]
137132
fn test_from_iso_1() {

src/interval_parse/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ static MICROS_PER_SECOND: i32 = 1_000_000;
1111

1212
fn scale_date(val: f64, scale: i32) -> (i32, i32) {
1313
if val.fract() == 0.0 {
14-
return (val.trunc() as i32, 0);
14+
(val.trunc() as i32, 0)
1515
} else {
1616
// matches postgres implementation of just truncating.
1717
let sub_value = (val.fract() * scale as f64).round() as i32;
@@ -21,7 +21,7 @@ fn scale_date(val: f64, scale: i32) -> (i32, i32) {
2121

2222
fn scale_time(val: f64, scale: i32) -> (i64, i64) {
2323
if val.fract() == 0.0 {
24-
return (val.trunc() as i64, 0);
24+
(val.trunc() as i64, 0)
2525
} else {
2626
// matches postgres implementation of just truncating.
2727
let sub_value = (val.fract() * scale as f64).round() as i64;

src/interval_parse/postgres.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
use super::parse_error::ParseError;
2-
use interval_norm::IntervalNorm;
3-
use pg_interval::Interval;
2+
use crate::{interval_norm::IntervalNorm, Interval};
43

54
use super::{
65
scale_date, scale_time, DAYS_PER_MONTH, HOURS_PER_DAY, MICROS_PER_SECOND, MINUTES_PER_HOUR,
76
MONTHS_PER_YEAR, SECONDS_PER_MIN,
87
};
98

109
impl Interval {
11-
pub fn from_postgres<'a>(iso_str: &'a str) -> Result<Interval, ParseError> {
10+
pub fn from_postgres(iso_str: &str) -> Result<Interval, ParseError> {
1211
let mut delim = vec![
1312
"years", "months", "mons", "days", "hours", "minutes", "seconds",
1413
];
15-
let mut time_tokens = iso_str.split(" ").collect::<Vec<&str>>();
16-
// clean up empty values caused by n spaces between values.
17-
time_tokens.retain(|&token| token != "");
14+
let mut time_tokens = iso_str.split(' ').collect::<Vec<&str>>(); // clean up empty values caused by n spaces between values.
15+
time_tokens.retain(|&token| !token.is_empty());
1816
// since there might not be space between the delim and the
1917
// value we need to scan each token.
2018
let mut final_tokens = Vec::with_capacity(time_tokens.len());
@@ -51,7 +49,7 @@ impl Interval {
5149
}
5250

5351
/// Does the token contain both alphabetic and numeric characters?
54-
fn is_token_alphanumeric<'a>(val: &'a str) -> Result<bool, ParseError> {
52+
fn is_token_alphanumeric(val: &str) -> Result<bool, ParseError> {
5553
let mut has_numeric = false;
5654
let mut has_alpha = false;
5755
for character in val.chars() {
@@ -70,7 +68,7 @@ fn is_token_alphanumeric<'a>(val: &'a str) -> Result<bool, ParseError> {
7068

7169
/// Split the token into two tokens as they might of not been
7270
/// seperated by a space.
73-
fn split_token<'a>(val: &'a str) -> Result<(String, String), ParseError> {
71+
fn split_token(val: &str) -> Result<(String, String), ParseError> {
7472
let mut is_numeric_done = false;
7573
let mut value = String::new();
7674
let mut delim = String::new();
@@ -155,7 +153,7 @@ fn consume_token<'a>(
155153

156154
#[cfg(test)]
157155
mod tests {
158-
use pg_interval::Interval;
156+
use super::*;
159157

160158
#[test]
161159
fn test_from_postgres_1() {

0 commit comments

Comments
 (0)