Skip to content

Commit dbcc1d2

Browse files
committed
Add support for SystemTime from the standard library
This feature is still unstable, but I think we can manage to keep up support for it. We should point back at released quickcheck after BurntSushi/quickcheck#110 is merged and released.
1 parent 53ff5b1 commit dbcc1d2

File tree

10 files changed

+107
-23
lines changed

10 files changed

+107
-23
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
2121
in the standard library, a dumb struct has been provided which mirrors what
2222
Postgres provides, which can be converted into whatever crate you are using.
2323

24+
* Timestamp columns can now be used with `std::time::SystemTime` when compiled
25+
with `--features unstable`
26+
2427
## [0.2.0] - 2015-11-30
2528

2629
### Added

bin/test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/bin/sh
2-
(cd diesel && cargo test) &&
2+
(cd diesel && cargo test --features unstable) &&
33
(cd diesel_tests && cargo test --features unstable --no-default-features)

diesel/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ keywords = ["orm", "database", "postgres", "postgresql", "sql"]
1313
libc = "0.2.*"
1414
pq-sys = "0.2.*"
1515
byteorder = "0.3.*"
16-
quickcheck = { version = "^0.2.24", optional = true }
16+
quickcheck = { git = "https://github.com/sgrif/quickcheck.git", rev = "7020692b18196d9d29718b31d8b2c7d1c4df3190", optional = true }
1717

1818
[dev-dependencies]
19-
quickcheck = "^0.2.24"
19+
quickcheck = { git = "https://github.com/sgrif/quickcheck.git", rev = "7020692b18196d9d29718b31d8b2c7d1c4df3190" }
2020
dotenv = "0.4.0"
2121

2222
[features]

diesel/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! interactions. [A getting started guide](https://github.com/sgrif/diesel#getting-started) can be
33
//! found in the README.
44
#![deny(warnings)]
5+
#![cfg_attr(feature = "unstable", feature(time2))]
56
pub mod expression;
67
#[doc(hidden)]
78
pub mod persistable;

diesel/src/types/impls/date_and_time/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
extern crate byteorder;
2-
31
use std::error::Error;
42
use std::io::Write;
53
use std::ops::Add;
@@ -12,6 +10,8 @@ use types::{self, NativeSqlType, FromSql, ToSql, IsNull};
1210

1311
#[cfg(feature = "quickcheck")]
1412
mod quickcheck_impls;
13+
#[cfg(feature = "unstable")]
14+
mod std_time;
1515

1616
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1717
/// Timestamps are represented in Postgres as a 32 bit signed integer representing the number of
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use std::error::Error;
2+
use std::io::Write;
3+
use std::time::{Duration, SystemTime, UNIX_EPOCH};
4+
5+
use expression::bound::Bound;
6+
use expression::{Expression, AsExpression};
7+
use types::{self, ToSql, FromSql, IsNull, Nullable, Timestamp, NativeSqlType};
8+
use query_source::Queriable;
9+
10+
expression_impls! {
11+
Timestamp -> SystemTime,
12+
}
13+
14+
queriable_impls! {
15+
Timestamp -> SystemTime,
16+
}
17+
18+
fn pg_epoch() -> SystemTime {
19+
let thirty_years = Duration::from_secs(946684800);
20+
UNIX_EPOCH + thirty_years
21+
}
22+
23+
impl ToSql<types::Timestamp> for SystemTime {
24+
fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error>> {
25+
let (before_epoch, duration) = match self.duration_from_earlier(pg_epoch()) {
26+
Ok(duration) => (false, duration),
27+
Err(time_err) => (true, time_err.duration()),
28+
};
29+
let time_since_epoch = if before_epoch {
30+
-(duration_to_usecs(duration) as i64)
31+
} else {
32+
duration_to_usecs(duration) as i64
33+
};
34+
ToSql::<types::BigInt>::to_sql(&time_since_epoch, out)
35+
}
36+
}
37+
38+
impl FromSql<types::Timestamp> for SystemTime {
39+
fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error>> {
40+
let usecs_passed = try!(<i64 as FromSql<types::BigInt>>::from_sql(bytes));
41+
let before_epoch = usecs_passed < 0;
42+
let time_passed = usecs_to_duration(usecs_passed.abs() as u64);
43+
44+
if before_epoch {
45+
Ok(pg_epoch() - time_passed)
46+
} else {
47+
Ok(pg_epoch() + time_passed)
48+
}
49+
}
50+
}
51+
52+
const USEC_PER_SEC: u64 = 1_000_000;
53+
const NANO_PER_USEC: u32 = 1_000;
54+
55+
fn usecs_to_duration(usecs_passed: u64) -> Duration {
56+
let usecs_passed = usecs_passed;
57+
let seconds = usecs_passed / USEC_PER_SEC;
58+
let subsecond_usecs = usecs_passed % USEC_PER_SEC;
59+
let subseconds = subsecond_usecs as u32 * NANO_PER_USEC;
60+
Duration::new(seconds, subseconds)
61+
}
62+
63+
fn duration_to_usecs(duration: Duration) -> u64 {
64+
let seconds = duration.as_secs() * USEC_PER_SEC;
65+
let subseconds = duration.subsec_nanos() / NANO_PER_USEC;
66+
seconds + subseconds as u64
67+
}

diesel/src/types/impls/mod.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ macro_rules! expression_impls {
5353
}
5454
}
5555

56+
macro_rules! queriable_impls {
57+
($($Source:ident -> $Target:ty),+,) => {$(
58+
impl Queriable<types::$Source> for $Target {
59+
type Row = Self;
60+
61+
fn build(row: Self::Row) -> Self {
62+
row
63+
}
64+
}
65+
)+}
66+
}
67+
5668
macro_rules! primitive_impls {
5769
($($Source:ident -> ($Target:ty, $oid:expr)),+,) => {
5870
$(
@@ -65,15 +77,8 @@ macro_rules! primitive_impls {
6577
types::$Source
6678
}
6779
}
68-
69-
impl Queriable<types::$Source> for $Target {
70-
type Row = Self;
71-
72-
fn build(row: Self::Row) -> Self {
73-
row
74-
}
75-
}
7680
)+
81+
queriable_impls!($($Source -> $Target),+,);
7782
expression_impls!($($Source -> $Target),+,);
7883
}
7984
}

diesel_tests/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ syntex = { version = "^0.22.0", optional = true }
1818
syntex_syntax = { version = "^0.22.0", optional = true }
1919

2020
[dev-dependencies]
21-
quickcheck = "*"
21+
quickcheck = { git = "https://github.com/sgrif/quickcheck.git", rev = "7020692b18196d9d29718b31d8b2c7d1c4df3190" }
2222
dotenv = "0.4.0"
2323

2424
[features]
2525
default = ["syntex", "syntex_syntax", "diesel_codegen/with-syntex"]
26-
unstable = ["compiletest_rs", "diesel_codegen/nightly"]
26+
unstable = ["compiletest_rs", "diesel_codegen/nightly", "diesel/unstable", "quickcheck/unstable"]
2727

2828
[[test]]
2929
name = "compile_tests"

diesel_tests/tests/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![cfg_attr(feature = "unstable", feature(custom_derive, plugin, custom_attribute))]
1+
#![cfg_attr(feature = "unstable", feature(custom_derive, plugin, custom_attribute, time2))]
22
#![cfg_attr(feature = "unstable", plugin(diesel_codegen))]
33

44
extern crate quickcheck;

diesel_tests/tests/types_roundtrip.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use quickcheck::quickcheck;
1+
pub use quickcheck::quickcheck;
22

3-
use schema::connection;
4-
use diesel::*;
5-
use diesel::result::Error;
6-
use diesel::data_types::*;
7-
use diesel::types::{NativeSqlType, ToSql, Nullable, Array};
3+
pub use schema::connection;
4+
pub use diesel::*;
5+
pub use diesel::result::Error;
6+
pub use diesel::data_types::*;
7+
pub use diesel::types::{NativeSqlType, ToSql, Nullable, Array};
88

9-
fn test_type_round_trips<ST, T>(value: T, type_name: &str) -> bool where
9+
pub fn test_type_round_trips<ST, T>(value: T, type_name: &str) -> bool where
1010
ST: NativeSqlType,
1111
T: ToSql<ST> + Queriable<ST> + PartialEq,
1212
{
@@ -58,3 +58,11 @@ test_round_trip!(time_roundtrips, Time, PgTime, "time");
5858
test_round_trip!(timestamp_roundtrips, Timestamp, PgTimestamp, "timestamp");
5959
test_round_trip!(interval_roundtrips, Interval, PgInterval, "interval");
6060
test_round_trip!(numeric_roundtrips, Numeric, PgNumeric, "numeric");
61+
62+
#[cfg(feature = "unstable")]
63+
mod unstable_types {
64+
use super::*;
65+
use std::time::SystemTime;
66+
67+
test_round_trip!(systemtime_roundtrips, Timestamp, SystemTime, "timestamp");
68+
}

0 commit comments

Comments
 (0)