use std::ops::Mul;
use data_types::PgInterval;
pub trait IntervalDsl: Sized + From<i32> + Mul<Self, Output = Self> {
fn microseconds(self) -> PgInterval;
fn days(self) -> PgInterval;
fn months(self) -> PgInterval;
fn milliseconds(self) -> PgInterval {
(self * 1000.into()).microseconds()
}
fn seconds(self) -> PgInterval {
(self * 1000.into()).milliseconds()
}
fn minutes(self) -> PgInterval {
(self * 60.into()).seconds()
}
fn hours(self) -> PgInterval {
(self * 60.into()).minutes()
}
fn weeks(self) -> PgInterval {
(self * 7.into()).days()
}
fn years(self) -> PgInterval {
(self * 12.into()).months()
}
fn microsecond(self) -> PgInterval {
self.microseconds()
}
fn millisecond(self) -> PgInterval {
self.milliseconds()
}
fn second(self) -> PgInterval {
self.seconds()
}
fn minute(self) -> PgInterval {
self.minutes()
}
fn hour(self) -> PgInterval {
self.hours()
}
fn day(self) -> PgInterval {
self.days()
}
fn week(self) -> PgInterval {
self.weeks()
}
fn month(self) -> PgInterval {
self.months()
}
fn year(self) -> PgInterval {
self.years()
}
}
impl IntervalDsl for i32 {
fn microseconds(self) -> PgInterval {
i64::from(self).microseconds()
}
fn days(self) -> PgInterval {
PgInterval::from_days(self)
}
fn months(self) -> PgInterval {
PgInterval::from_months(self)
}
fn milliseconds(self) -> PgInterval {
i64::from(self).milliseconds()
}
fn seconds(self) -> PgInterval {
i64::from(self).seconds()
}
fn minutes(self) -> PgInterval {
i64::from(self).minutes()
}
fn hours(self) -> PgInterval {
i64::from(self).hours()
}
}
impl IntervalDsl for i64 {
fn microseconds(self) -> PgInterval {
PgInterval::from_microseconds(self)
}
fn days(self) -> PgInterval {
(self as i32).days()
}
fn months(self) -> PgInterval {
(self as i32).months()
}
}
impl IntervalDsl for f64 {
fn microseconds(self) -> PgInterval {
(self.round() as i64).microseconds()
}
fn days(self) -> PgInterval {
let fractional_days = (self.fract() * 86_400.0).seconds();
PgInterval::from_days(self.trunc() as i32) + fractional_days
}
fn months(self) -> PgInterval {
let fractional_months = (self.fract() * 30.0).days();
PgInterval::from_months(self.trunc() as i32) + fractional_months
}
fn years(self) -> PgInterval {
((self * 12.0).trunc() as i32).months()
}
}
#[cfg(test)]
mod tests {
extern crate dotenv;
extern crate quickcheck;
use self::dotenv::dotenv;
use self::quickcheck::quickcheck;
use super::*;
use data_types::PgInterval;
use dsl::sql;
use prelude::*;
use {select, sql_types};
thread_local! {
static CONN: PgConnection = {
dotenv().ok();
let connection_url = ::std::env::var("PG_DATABASE_URL")
.or_else(|_| ::std::env::var("DATABASE_URL"))
.expect("DATABASE_URL must be set in order to run tests");
PgConnection::establish(&connection_url).unwrap()
}
}
macro_rules! test_fn {
($tpe:ty, $test_name:ident, $units:ident) => {
fn $test_name(val: $tpe) -> bool {
CONN.with(|connection| {
let sql_str = format!(concat!("'{} ", stringify!($units), "'::interval"), val);
let query = select(sql::<sql_types::Interval>(&sql_str));
let val = val.$units();
query
.get_result::<PgInterval>(connection)
.map(|res| {
val.months == res.months
&& val.days == res.days
&& val.microseconds - res.microseconds.abs() <= 1
})
.unwrap_or(false)
})
}
quickcheck($test_name as fn($tpe) -> bool);
};
}
#[test]
fn intervals_match_pg_values_i32() {
test_fn!(i32, test_microseconds, microseconds);
test_fn!(i32, test_milliseconds, milliseconds);
test_fn!(i32, test_seconds, seconds);
test_fn!(i32, test_minutes, minutes);
test_fn!(i32, test_hours, hours);
test_fn!(i32, test_days, days);
test_fn!(i32, test_weeks, weeks);
test_fn!(i32, test_months, months);
test_fn!(i32, test_years, years);
}
#[test]
fn intervals_match_pg_values_i64() {
test_fn!(i64, test_microseconds, microseconds);
test_fn!(i64, test_milliseconds, milliseconds);
test_fn!(i64, test_seconds, seconds);
test_fn!(i64, test_minutes, minutes);
test_fn!(i64, test_hours, hours);
test_fn!(i64, test_days, days);
test_fn!(i64, test_weeks, weeks);
test_fn!(i64, test_months, months);
test_fn!(i64, test_years, years);
}
#[test]
fn intervals_match_pg_values_f64() {
test_fn!(f64, test_microseconds, microseconds);
test_fn!(f64, test_milliseconds, milliseconds);
test_fn!(f64, test_seconds, seconds);
test_fn!(f64, test_minutes, minutes);
test_fn!(f64, test_hours, hours);
test_fn!(f64, test_days, days);
test_fn!(f64, test_weeks, weeks);
test_fn!(f64, test_months, months);
test_fn!(f64, test_years, years);
}
}