Make time support optional

This commit is contained in:
Steven Fackler 2014-11-17 19:11:32 -08:00
parent 22f4be2b8c
commit 9a87c6e18a
11 changed files with 219 additions and 175 deletions

View File

@ -13,7 +13,7 @@ name = "test"
path = "tests/test.rs"
[features]
default = ["uuid"]
default = ["uuid", "time"]
[dependencies.openssl]
git = "https://github.com/sfackler/rust-openssl"
@ -30,6 +30,7 @@ optional = true
[dependencies.time]
git = "https://github.com/rust-lang/time"
optional = true
[dev-dependencies.url]
git = "https://github.com/servo/rust-url"

View File

@ -297,8 +297,14 @@ traits.
### UUID type
[UUID](http://www.postgresql.org/docs/9.4/static/datatype-uuid.html) support is
provided optionally by the `uuid` feature. It is enabled by default. To disable
`UUID` support, add `default-features = false` to your Cargo manifest:
provided optionally by the `uuid` feature. It is enabled by default.
### Time types
[Time](http://www.postgresql.org/docs/9.3/static/datatype-datetime.html)
support is provided optionally by the `time` feature. It is enabled by default.
To disable support for optional features, add `default-features = false` to
your Cargo manifest:
```toml
[dependencies.postgres]

View File

@ -4,8 +4,11 @@
//!
//! ```rust,no_run
//! extern crate postgres;
//! # #[cfg(feature = "time")]
//! extern crate time;
//!
//! # #[cfg(not(feature = "time"))] fn main() {}
//! # #[cfg(feature = "time")] fn main() {
//! use time::Timespec;
//!
//! use postgres::{Connection, SslMode};
@ -49,6 +52,7 @@
//! println!("Found person {}", person.name);
//! }
//! }
//! # }
//! ```
#![doc(html_root_url="https://sfackler.github.io/doc")]
#![feature(globs, macro_rules, phase, unsafe_destructor, slicing_syntax, default_type_params, if_let)]
@ -56,7 +60,6 @@
extern crate openssl;
extern crate serialize;
extern crate time;
extern crate phf;
#[phase(plugin)]
extern crate phf_mac;

View File

@ -3,20 +3,17 @@
use serialize::json;
use std::collections::HashMap;
use std::io::{AsRefReader, MemWriter, BufReader};
use std::io::util::LimitReader;
use time::Timespec;
use std::io::{ByRefReader, MemWriter, BufReader};
use Result;
use error::{PgWrongType, PgWasNull, PgBadData};
use types::array::{Array, ArrayBase, DimensionInfo};
use types::range::{RangeBound, Inclusive, Exclusive, Range};
use types::range::{Inclusive, Exclusive, Range};
macro_rules! check_types(
($($expected:pat)|+, $actual:ident) => (
match $actual {
$(&$expected)|+ => {}
actual => return Err(PgWrongType(actual.clone()))
actual => return Err(::Error::PgWrongType(actual.clone()))
}
)
)
@ -33,8 +30,14 @@ macro_rules! raw_from_impl(
macro_rules! from_range_impl(
($t:ty) => (
impl RawFromSql for Range<$t> {
impl ::types::RawFromSql for ::types::range::Range<$t> {
fn raw_from_sql<R: Reader>(rdr: &mut R) -> Result<Range<$t>> {
use std::io::ByRefReader;
use std::io::util::LimitReader;
use types::{RANGE_EMPTY, RANGE_LOWER_UNBOUNDED, RANGE_LOWER_INCLUSIVE,
RANGE_UPPER_UNBOUNDED, RANGE_UPPER_INCLUSIVE};
use types::range::{BoundType, Range, RangeBound};
let t = try!(rdr.read_i8());
if t & RANGE_EMPTY != 0 {
@ -43,8 +46,8 @@ macro_rules! from_range_impl(
let lower = match t & RANGE_LOWER_UNBOUNDED {
0 => {
let type_ = match t & RANGE_LOWER_INCLUSIVE {
0 => Exclusive,
_ => Inclusive
0 => BoundType::Exclusive,
_ => BoundType::Inclusive
};
let len = try!(rdr.read_be_i32()) as uint;
let mut limit = LimitReader::new(rdr.by_ref(), len);
@ -58,8 +61,8 @@ macro_rules! from_range_impl(
let upper = match t & RANGE_UPPER_UNBOUNDED {
0 => {
let type_ = match t & RANGE_UPPER_INCLUSIVE {
0 => Exclusive,
_ => Inclusive
0 => BoundType::Exclusive,
_ => BoundType::Inclusive
};
let len = try!(rdr.read_be_i32()) as uint;
let mut limit = LimitReader::new(rdr.by_ref(), len);
@ -81,9 +84,8 @@ macro_rules! from_range_impl(
macro_rules! from_map_impl(
($($expected:pat)|+, $t:ty, $blk:expr $(, $a:meta)*) => (
$(#[$a])*
impl FromSql for Option<$t> {
fn from_sql(ty: &Type, raw: &Option<Vec<u8>>)
-> Result<Option<$t>> {
impl ::types::FromSql for Option<$t> {
fn from_sql(ty: &Type, raw: &Option<Vec<u8>>) -> Result<Option<$t>> {
check_types!($($expected)|+, ty)
match *raw {
Some(ref buf) => ($blk)(buf).map(|ok| Some(ok)),
@ -93,14 +95,16 @@ macro_rules! from_map_impl(
}
$(#[$a])*
impl FromSql for $t {
fn from_sql(ty: &Type, raw: &Option<Vec<u8>>)
-> Result<$t> {
impl ::types::FromSql for $t {
fn from_sql(ty: &Type, raw: &Option<Vec<u8>>) -> Result<$t> {
use Error;
use types::FromSql;
// FIXME when you can specify Self types properly
let ret: Result<Option<$t>> = FromSql::from_sql(ty, raw);
match ret {
Ok(Some(val)) => Ok(val),
Ok(None) => Err(PgWasNull),
Ok(None) => Err(Error::PgWasNull),
Err(err) => Err(err)
}
}
@ -111,6 +115,9 @@ macro_rules! from_map_impl(
macro_rules! from_raw_from_impl(
($($expected:pat)|+, $t:ty $(, $a:meta)*) => (
from_map_impl!($($expected)|+, $t, |buf: &Vec<u8>| {
use std::io::BufReader;
use types::RawFromSql;
let mut reader = BufReader::new(buf[]);
RawFromSql::raw_from_sql(&mut reader)
} $(, $a)*)
@ -119,7 +126,12 @@ macro_rules! from_raw_from_impl(
macro_rules! from_array_impl(
($($oid:pat)|+, $t:ty $(, $a:meta)*) => (
from_map_impl!($($oid)|+, ArrayBase<Option<$t>>, |buf: &Vec<u8>| {
from_map_impl!($($oid)|+, ::types::array::ArrayBase<Option<$t>>, |buf: &Vec<u8>| {
use std::io::{BufReader, ByRefReader};
use std::io::util::LimitReader;
use types::{Oid, RawFromSql};
use types::array::{ArrayBase, DimensionInfo};
let mut rdr = BufReader::new(buf[]);
let ndim = try!(rdr.read_be_i32()) as uint;
@ -164,20 +176,29 @@ macro_rules! raw_to_impl(
macro_rules! to_range_impl(
($t:ty) => (
impl RawToSql for Range<$t> {
impl ::types::RawToSql for ::types::range::Range<$t> {
fn raw_to_sql<W: Writer>(&self, buf: &mut W) -> Result<()> {
use std::io::MemWriter;
use types::{RANGE_EMPTY, RANGE_LOWER_UNBOUNDED, RANGE_LOWER_INCLUSIVE,
RANGE_UPPER_UNBOUNDED, RANGE_UPPER_INCLUSIVE};
use types::range::{BoundType, RangeBound};
let mut tag = 0;
if self.is_empty() {
tag |= RANGE_EMPTY;
} else {
match self.lower() {
None => tag |= RANGE_LOWER_UNBOUNDED,
Some(&RangeBound { type_: Inclusive, .. }) => tag |= RANGE_LOWER_INCLUSIVE,
Some(&RangeBound { type_: BoundType::Inclusive, .. }) => {
tag |= RANGE_LOWER_INCLUSIVE
}
_ => {}
}
match self.upper() {
None => tag |= RANGE_UPPER_UNBOUNDED,
Some(&RangeBound { type_: Inclusive, .. }) => tag |= RANGE_UPPER_INCLUSIVE,
Some(&RangeBound { type_: BoundType::Inclusive, .. }) => {
tag |= RANGE_UPPER_INCLUSIVE
}
_ => {}
}
}
@ -214,7 +235,7 @@ macro_rules! to_range_impl(
macro_rules! to_option_impl(
($($oid:pat)|+, $t:ty $(,$a:meta)*) => (
$(#[$a])*
impl ToSql for Option<$t> {
impl ::types::ToSql for Option<$t> {
fn to_sql(&self, ty: &Type) -> Result<Option<Vec<u8>>> {
check_types!($($oid)|+, ty)
@ -245,8 +266,10 @@ macro_rules! to_option_impl_lifetime(
macro_rules! to_raw_to_impl(
($($oid:pat)|+, $t:ty $(, $a:meta)*) => (
$(#[$a])*
impl ToSql for $t {
impl ::types::ToSql for $t {
fn to_sql(&self, ty: &Type) -> Result<Option<Vec<u8>>> {
use std::io::MemWriter;
check_types!($($oid)|+, ty)
let mut writer = MemWriter::new();
@ -262,8 +285,11 @@ macro_rules! to_raw_to_impl(
macro_rules! to_array_impl(
($($oid:pat)|+, $t:ty $(, $a:meta)*) => (
$(#[$a])*
impl ToSql for ArrayBase<Option<$t>> {
impl ::types::ToSql for ::types::array::ArrayBase<Option<$t>> {
fn to_sql(&self, ty: &Type) -> Result<Option<Vec<u8>>> {
use std::io::MemWriter;
use types::array::Array;
check_types!($($oid)|+, ty)
let mut buf = MemWriter::new();
@ -293,7 +319,7 @@ macro_rules! to_array_impl(
}
}
to_option_impl!($($oid)|+, ArrayBase<Option<$t>> $(, $a)*)
to_option_impl!($($oid)|+, ::types::array::ArrayBase<Option<$t>> $(, $a)*)
)
)
@ -301,6 +327,8 @@ pub mod array;
pub mod range;
#[cfg(feature = "uuid")]
mod uuid;
#[cfg(feature = "time")]
mod time;
/// A Postgres OID
pub type Oid = u32;
@ -347,12 +375,6 @@ const TSTZRANGEARRAYOID: Oid = 3911;
const INT8RANGEOID: Oid = 3926;
const INT8RANGEARRAYOID: Oid = 3927;
const USEC_PER_SEC: i64 = 1_000_000;
const NSEC_PER_USEC: i64 = 1_000;
// Number of seconds from 1970-01-01 to 2000-01-01
const TIME_SEC_CONVERSION: i64 = 946684800;
const RANGE_UPPER_UNBOUNDED: i8 = 0b0001_0000;
const RANGE_LOWER_UNBOUNDED: i8 = 0b0000_1000;
const RANGE_UPPER_INCLUSIVE: i8 = 0b0000_0100;
@ -528,24 +550,8 @@ raw_from_impl!(i64, read_be_i64)
raw_from_impl!(f32, read_be_f32)
raw_from_impl!(f64, read_be_f64)
impl RawFromSql for Timespec {
fn raw_from_sql<R: Reader>(raw: &mut R) -> Result<Timespec> {
let t = try!(raw.read_be_i64());
let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION;
let mut usec = t % USEC_PER_SEC;
if usec < 0 {
sec -= 1;
usec = USEC_PER_SEC + usec;
}
Ok(Timespec::new(sec, (usec * NSEC_PER_USEC) as i32))
}
}
from_range_impl!(i32)
from_range_impl!(i64)
from_range_impl!(Timespec)
impl RawFromSql for json::Json {
fn raw_from_sql<R: Reader>(raw: &mut R) -> Result<json::Json> {
@ -564,10 +570,8 @@ from_raw_from_impl!(Float4, f32)
from_raw_from_impl!(Float8, f64)
from_raw_from_impl!(Json, json::Json)
from_raw_from_impl!(Timestamp | TimestampTZ, Timespec)
from_raw_from_impl!(Int4Range, Range<i32>)
from_raw_from_impl!(Int8Range, Range<i64>)
from_raw_from_impl!(TsRange | TstzRange, Range<Timespec>)
from_array_impl!(BoolArray, bool)
from_array_impl!(ByteAArray, Vec<u8>)
@ -576,12 +580,10 @@ from_array_impl!(Int2Array, i16)
from_array_impl!(Int4Array, i32)
from_array_impl!(TextArray | CharNArray | VarcharArray | NameArray, String)
from_array_impl!(Int8Array, i64)
from_array_impl!(TimestampArray | TimestampTZArray, Timespec)
from_array_impl!(JsonArray, json::Json)
from_array_impl!(Float4Array, f32)
from_array_impl!(Float8Array, f64)
from_array_impl!(Int4RangeArray, Range<i32>)
from_array_impl!(TsRangeArray | TstzRangeArray, Range<Timespec>)
from_array_impl!(Int8RangeArray, Range<i64>)
impl FromSql for Option<HashMap<String, Option<String>>> {
@ -678,16 +680,8 @@ raw_to_impl!(i64, write_be_i64)
raw_to_impl!(f32, write_be_f32)
raw_to_impl!(f64, write_be_f64)
impl RawToSql for Timespec {
fn raw_to_sql<W: Writer>(&self, w: &mut W) -> Result<()> {
let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC;
Ok(try!(w.write_be_i64(t)))
}
}
to_range_impl!(i32)
to_range_impl!(i64)
to_range_impl!(Timespec)
impl RawToSql for json::Json {
fn raw_to_sql<W: Writer>(&self, raw: &mut W) -> Result<()> {
@ -707,7 +701,6 @@ to_raw_to_impl!(Float4, f32)
to_raw_to_impl!(Float8, f64)
to_raw_to_impl!(Int4Range, Range<i32>)
to_raw_to_impl!(Int8Range, Range<i64>)
to_raw_to_impl!(TsRange | TstzRange, Range<Timespec>)
impl<'a> ToSql for &'a str {
fn to_sql(&self, ty: &Type) -> Result<Option<Vec<u8>>> {
@ -727,8 +720,6 @@ impl<'a> ToSql for &'a [u8] {
to_option_impl_lifetime!(ByteA, &'a [u8])
to_raw_to_impl!(Timestamp | TimestampTZ, Timespec)
to_array_impl!(BoolArray, bool)
to_array_impl!(ByteAArray, Vec<u8>)
to_array_impl!(CharArray, i8)
@ -736,11 +727,9 @@ to_array_impl!(Int2Array, i16)
to_array_impl!(Int4Array, i32)
to_array_impl!(Int8Array, i64)
to_array_impl!(TextArray | CharNArray | VarcharArray | NameArray, String)
to_array_impl!(TimestampArray | TimestampTZArray, Timespec)
to_array_impl!(Float4Array, f32)
to_array_impl!(Float8Array, f64)
to_array_impl!(Int4RangeArray, Range<i32>)
to_array_impl!(TsRangeArray | TstzRangeArray, Range<Timespec>)
to_array_impl!(Int8RangeArray, Range<i64>)
to_array_impl!(JsonArray, json::Json)

View File

@ -4,7 +4,6 @@
use std::fmt;
use std::i32;
use std::i64;
use time::Timespec;
/// The `range!` macro can make it easier to create ranges. It roughly mirrors
/// traditional mathematic range syntax.
@ -131,12 +130,6 @@ macro_rules! bounded_normalizable(
bounded_normalizable!(i32)
bounded_normalizable!(i64)
impl Normalizable for Timespec {
fn normalize<S: BoundSided>(bound: RangeBound<S, Timespec>) -> RangeBound<S, Timespec> {
bound
}
}
/// The possible sides of a bound
#[deriving(PartialEq, Eq)]
pub enum BoundSide {

53
src/types/time.rs Normal file
View File

@ -0,0 +1,53 @@
extern crate time;
use self::time::Timespec;
use Result;
use types::{RawFromSql, Type, RawToSql};
use types::range::{Range, RangeBound, BoundSided, Normalizable};
const USEC_PER_SEC: i64 = 1_000_000;
const NSEC_PER_USEC: i64 = 1_000;
// Number of seconds from 1970-01-01 to 2000-01-01
const TIME_SEC_CONVERSION: i64 = 946684800;
impl RawFromSql for Timespec {
fn raw_from_sql<R: Reader>(raw: &mut R) -> Result<Timespec> {
let t = try!(raw.read_be_i64());
let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION;
let mut usec = t % USEC_PER_SEC;
if usec < 0 {
sec -= 1;
usec = USEC_PER_SEC + usec;
}
Ok(Timespec::new(sec, (usec * NSEC_PER_USEC) as i32))
}
}
from_range_impl!(Timespec)
from_raw_from_impl!(Type::Timestamp | Type::TimestampTZ, Timespec)
from_raw_from_impl!(Type::TsRange | Type::TstzRange, Range<Timespec>)
from_array_impl!(Type::TimestampArray | Type::TimestampTZArray, Timespec)
from_array_impl!(Type::TsRangeArray | Type::TstzRangeArray, Range<Timespec>)
impl RawToSql for Timespec {
fn raw_to_sql<W: Writer>(&self, w: &mut W) -> Result<()> {
let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC;
Ok(try!(w.write_be_i64(t)))
}
}
to_range_impl!(Timespec)
to_raw_to_impl!(Type::TsRange | Type::TstzRange, Range<Timespec>)
to_raw_to_impl!(Type::Timestamp | Type::TimestampTZ, Timespec)
to_array_impl!(Type::TimestampArray | Type::TimestampTZArray, Timespec)
to_array_impl!(Type::TsRangeArray | Type::TstzRangeArray, Range<Timespec>)
impl Normalizable for Timespec {
fn normalize<S: BoundSided>(bound: RangeBound<S, Timespec>) -> RangeBound<S, Timespec> {
bound
}
}

View File

@ -1,13 +1,8 @@
extern crate uuid;
use std::io::{MemWriter, BufReader};
use std::io::util::LimitReader;
use std::io::ByRefReader;
use self::uuid::Uuid;
use types::{RawFromSql, FromSql, ToSql, RawToSql, Type, Oid};
use Error::{PgWasNull, PgWrongType, PgBadData};
use types::array::{ArrayBase, DimensionInfo, Array};
use types::{RawFromSql, ToSql, RawToSql, Type};
use Error::{PgWasNull, PgBadData};
use Result;
impl RawFromSql for Uuid {

View File

@ -3,7 +3,6 @@
#[phase(plugin, link)]
extern crate postgres;
extern crate serialize;
extern crate time;
extern crate url;
extern crate openssl;

View File

@ -2,16 +2,16 @@ use serialize::json;
use std::collections::HashMap;
use std::f32;
use std::f64;
use time;
use time::Timespec;
use std::num::Float;
use postgres::{Connection, SslMode};
use postgres::types::array::ArrayBase;
use postgres::types::{ToSql, FromSql};
macro_rules! test_array_params(
($name:expr, $v1:expr, $s1:expr, $v2:expr, $s2:expr, $v3:expr, $s3:expr) => ({
use postgres::types::array::ArrayBase;
use types::test_type;
let tests = [(Some(ArrayBase::from_vec(vec!(Some($v1), Some($v2), None), 1)),
format!("'{{{},{},NULL}}'", $s1, $s2).into_string()),
(None, "NULL".to_string())];
@ -25,10 +25,33 @@ macro_rules! test_array_params(
})
)
macro_rules! test_range(
($name:expr, $t:ty, $low:expr, $low_str:expr, $high:expr, $high_str:expr) => ({
let tests = [(Some(range!('(', ')')), "'(,)'".to_string()),
(Some(range!('[' $low, ')')), format!("'[{},)'", $low_str)),
(Some(range!('(' $low, ')')), format!("'({},)'", $low_str)),
(Some(range!('(', $high ']')), format!("'(,{}]'", $high_str)),
(Some(range!('(', $high ')')), format!("'(,{})'", $high_str)),
(Some(range!('[' $low, $high ']')),
format!("'[{},{}]'", $low_str, $high_str)),
(Some(range!('[' $low, $high ')')),
format!("'[{},{})'", $low_str, $high_str)),
(Some(range!('(' $low, $high ']')),
format!("'({},{}]'", $low_str, $high_str)),
(Some(range!('(' $low, $high ')')),
format!("'({},{})'", $low_str, $high_str)),
(Some(range!(empty)), "'empty'".to_string()),
(None, "NULL".to_string())];
test_type($name, tests);
})
)
mod array;
mod range;
#[cfg(feature = "uuid")]
mod uuid;
#[cfg(feature = "time")]
mod time;
fn test_type<T: PartialEq+FromSql+ToSql, S: Str>(sql_type: &str, checks: &[(T, S)]) {
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
@ -140,44 +163,6 @@ fn test_json_params() {
(None, "NULL")])
}
#[test]
fn test_tm_params() {
fn make_check<'a>(time: &'a str) -> (Option<Timespec>, &'a str) {
(Some(time::strptime(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap().to_timespec()), time)
}
test_type("TIMESTAMP",
[make_check("'1970-01-01 00:00:00.01'"),
make_check("'1965-09-25 11:19:33.100314'"),
make_check("'2010-02-09 23:11:45.1202'"),
(None, "NULL")]);
test_type("TIMESTAMP WITH TIME ZONE",
[make_check("'1970-01-01 00:00:00.01'"),
make_check("'1965-09-25 11:19:33.100314'"),
make_check("'2010-02-09 23:11:45.1202'"),
(None, "NULL")]);
}
macro_rules! test_range(
($name:expr, $t:ty, $low:expr, $low_str:expr, $high:expr, $high_str:expr) => ({
let tests = [(Some(range!('(', ')')), "'(,)'".to_string()),
(Some(range!('[' $low, ')')), format!("'[{},)'", $low_str)),
(Some(range!('(' $low, ')')), format!("'({},)'", $low_str)),
(Some(range!('(', $high ']')), format!("'(,{}]'", $high_str)),
(Some(range!('(', $high ')')), format!("'(,{})'", $high_str)),
(Some(range!('[' $low, $high ']')),
format!("'[{},{}]'", $low_str, $high_str)),
(Some(range!('[' $low, $high ')')),
format!("'[{},{})'", $low_str, $high_str)),
(Some(range!('(' $low, $high ']')),
format!("'({},{}]'", $low_str, $high_str)),
(Some(range!('(' $low, $high ')')),
format!("'({},{})'", $low_str, $high_str)),
(Some(range!(empty)), "'empty'".to_string()),
(None, "NULL".to_string())];
test_type($name, tests);
})
)
#[test]
fn test_int4range_params() {
test_range!("INT4RANGE", i32, 100i32, "100", 200i32, "200")
@ -188,25 +173,6 @@ fn test_int8range_params() {
test_range!("INT8RANGE", i64, 100i64, "100", 200i64, "200")
}
fn test_timespec_range_params(sql_type: &str) {
fn t(time: &str) -> Timespec {
time::strptime(time, "%Y-%m-%d").unwrap().to_timespec()
}
let low = "1970-01-01";
let high = "1980-01-01";
test_range!(sql_type, Timespec, t(low), low, t(high), high);
}
#[test]
fn test_tsrange_params() {
test_timespec_range_params("TSRANGE");
}
#[test]
fn test_tstzrange_params() {
test_timespec_range_params("TSTZRANGE");
}
#[test]
fn test_boolarray_params() {
test_array_params!("BOOL", false, "f", true, "t", true, "t");
@ -263,18 +229,6 @@ fn test_int8array_params() {
test_array_params!("INT8", 0i64, "0", 1i64, "1", 2i64, "2");
}
#[test]
fn test_timestamparray_params() {
fn make_check<'a>(time: &'a str) -> (Timespec, &'a str) {
(time::strptime(time, "%Y-%m-%d %H:%M:%S.%f").unwrap().to_timespec(), time)
}
let (v1, s1) = make_check("1970-01-01 00:00:00.01");
let (v2, s2) = make_check("1965-09-25 11:19:33.100314");
let (v3, s3) = make_check("2010-02-09 23:11:45.1202");
test_array_params!("TIMESTAMP", v1, s1, v2, s2, v3, s3);
test_array_params!("TIMESTAMPTZ", v1, s1, v2, s2, v3, s3);
}
#[test]
fn test_float4array_params() {
test_array_params!("FLOAT4", 0f32, "0", 1.5f32, "1.5", 0.009f32, ".009");
@ -293,23 +247,6 @@ fn test_int4rangearray_params() {
range!('(', 10i32 ')'), "\"(,10)\"");
}
#[test]
fn test_tsrangearray_params() {
fn make_check<'a>(time: &'a str) -> (Timespec, &'a str) {
(time::strptime(time, "%Y-%m-%d").unwrap().to_timespec(), time)
}
let (v1, s1) = make_check("1970-10-11");
let (v2, s2) = make_check("1990-01-01");
let r1 = range!('(', ')');
let rs1 = "\"(,)\"";
let r2 = range!('[' v1, ')');
let rs2 = format!("\"[{},)\"", s1);
let r3 = range!('(', v2 ')');
let rs3 = format!("\"(,{})\"", s2);
test_array_params!("TSRANGE", r1, rs1, r2, rs2, r3, rs3);
test_array_params!("TSTZRANGE", r1, rs1, r2, rs2, r3, rs3);
}
#[test]
fn test_int8rangearray_params() {
test_array_params!("INT8RANGE",

70
tests/types/time.rs Normal file
View File

@ -0,0 +1,70 @@
extern crate time;
use self::time::Timespec;
use types::test_type;
#[test]
fn test_tm_params() {
fn make_check<'a>(time: &'a str) -> (Option<Timespec>, &'a str) {
(Some(time::strptime(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap().to_timespec()), time)
}
test_type("TIMESTAMP",
[make_check("'1970-01-01 00:00:00.01'"),
make_check("'1965-09-25 11:19:33.100314'"),
make_check("'2010-02-09 23:11:45.1202'"),
(None, "NULL")]);
test_type("TIMESTAMP WITH TIME ZONE",
[make_check("'1970-01-01 00:00:00.01'"),
make_check("'1965-09-25 11:19:33.100314'"),
make_check("'2010-02-09 23:11:45.1202'"),
(None, "NULL")]);
}
fn test_timespec_range_params(sql_type: &str) {
fn t(time: &str) -> Timespec {
time::strptime(time, "%Y-%m-%d").unwrap().to_timespec()
}
let low = "1970-01-01";
let high = "1980-01-01";
test_range!(sql_type, Timespec, t(low), low, t(high), high);
}
#[test]
fn test_tsrange_params() {
test_timespec_range_params("TSRANGE");
}
#[test]
fn test_tstzrange_params() {
test_timespec_range_params("TSTZRANGE");
}
#[test]
fn test_timestamparray_params() {
fn make_check<'a>(time: &'a str) -> (Timespec, &'a str) {
(time::strptime(time, "%Y-%m-%d %H:%M:%S.%f").unwrap().to_timespec(), time)
}
let (v1, s1) = make_check("1970-01-01 00:00:00.01");
let (v2, s2) = make_check("1965-09-25 11:19:33.100314");
let (v3, s3) = make_check("2010-02-09 23:11:45.1202");
test_array_params!("TIMESTAMP", v1, s1, v2, s2, v3, s3);
test_array_params!("TIMESTAMPTZ", v1, s1, v2, s2, v3, s3);
}
#[test]
fn test_tsrangearray_params() {
fn make_check<'a>(time: &'a str) -> (Timespec, &'a str) {
(time::strptime(time, "%Y-%m-%d").unwrap().to_timespec(), time)
}
let (v1, s1) = make_check("1970-10-11");
let (v2, s2) = make_check("1990-01-01");
let r1 = range!('(', ')');
let rs1 = "\"(,)\"";
let r2 = range!('[' v1, ')');
let rs2 = format!("\"[{},)\"", s1);
let r3 = range!('(', v2 ')');
let rs3 = format!("\"(,{})\"", s2);
test_array_params!("TSRANGE", r1, rs1, r2, rs2, r3, rs3);
test_array_params!("TSTZRANGE", r1, rs1, r2, rs2, r3, rs3);
}

View File

@ -1,7 +1,5 @@
extern crate uuid;
use postgres::types::array::ArrayBase;
use types::test_type;
#[test]