From c8af7e4eb500bab9f76f8ccabbecdf5b2d841370 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 22 Oct 2014 22:16:00 -0400 Subject: [PATCH] Add ToSql/FromSql for time::Timespec. Uses SQLite's default format string for `datetime()`. --- src/types.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/types.rs b/src/types.rs index 266f04a..cbad3bd 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,3 +1,5 @@ +extern crate time; + use libc::{c_int, c_double}; use std::c_str::{CString}; use std::mem; @@ -5,6 +7,8 @@ use std::vec; use super::ffi; use super::{SqliteResult, SqliteError}; +const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S"; + pub trait ToSql { unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int; } @@ -55,6 +59,13 @@ impl ToSql for Vec { } } +impl ToSql for time::Timespec { + unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int { + let time_str = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap(); + time_str.bind_parameter(stmt, col) + } +} + impl ToSql for Option { unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int { match *self { @@ -112,6 +123,20 @@ impl FromSql for Vec { } } +impl FromSql for time::Timespec { + unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, + col: c_int) -> SqliteResult { + let col_str = FromSql::column_result(stmt, col); + col_str.and_then(|txt: String| { + time::strptime(txt.as_slice(), SQLITE_DATETIME_FMT).map(|tm| { + tm.to_timespec() + }).map_err(|parse_error| { + SqliteError{ code: ffi::SQLITE_MISMATCH, message: format!("{}", parse_error) } + }) + }) + } +} + impl FromSql for Option { unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult> { if ffi::sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL { @@ -125,6 +150,7 @@ impl FromSql for Option { #[cfg(test)] mod test { use SqliteConnection; + use super::time; fn checked_memory_handle() -> SqliteConnection { let db = SqliteConnection::open(":memory:").unwrap(); @@ -154,6 +180,17 @@ mod test { assert_eq!(from.as_slice(), s); } + #[test] + fn test_timespec() { + let db = checked_memory_handle(); + + let ts = time::Timespec{sec: 10_000, nsec: 0 }; + db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]).unwrap(); + + let from: time::Timespec = db.query_row("SELECT t FROM foo", [], |r| r.unwrap().get(0)); + assert_eq!(from, ts); + } + #[test] fn test_option() { let db = checked_memory_handle();