blob: 1d8d6ee2305c2203c02c5a7a6deed7ac54e40342 [file] [log] [blame]
// FIXME: Review this module to see if we can do these casts in a more backend agnostic way
#[cfg(any(feature = "postgres", feature = "mysql"))]
extern crate bigdecimal;
extern crate chrono;
use diesel::deserialize::FromSql;
#[cfg(feature = "postgres")]
use diesel::pg::Pg;
use diesel::sql_types::*;
use diesel::*;
use schema::*;
use quickcheck::quickcheck;
table! {
has_timestamps {
id -> Integer,
ts -> Timestamp,
}
}
table! {
has_time_types(datetime) {
datetime -> Timestamp,
date -> Date,
time -> Time,
}
}
#[test]
#[cfg(feature = "postgres")]
fn errors_during_deserialization_do_not_panic() {
use self::chrono::NaiveDateTime;
use self::has_timestamps::dsl::*;
use diesel::result::Error::DeserializationError;
let connection = connection();
connection
.execute(
"CREATE TABLE has_timestamps (
id SERIAL PRIMARY KEY,
ts TIMESTAMP NOT NULL
)",
)
.unwrap();
let valid_pg_date_too_large_for_chrono = "'294276/01/01'";
connection
.execute(&format!(
"INSERT INTO has_timestamps (ts) VALUES ({})",
valid_pg_date_too_large_for_chrono
))
.unwrap();
let values = has_timestamps.select(ts).load::<NaiveDateTime>(&connection);
match values {
Err(DeserializationError(_)) => {}
v => panic!("Expected a deserialization error, got {:?}", v),
}
}
#[test]
#[cfg(feature = "sqlite")]
fn errors_during_deserialization_do_not_panic() {
use self::chrono::NaiveDateTime;
use self::has_timestamps::dsl::*;
use diesel::result::Error::DeserializationError;
let connection = connection();
connection
.execute(
"CREATE TABLE has_timestamps (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ts VARCHAR NOT NULL
)",
)
.unwrap();
let valid_sqlite_date_too_large_for_chrono = "'294276-01-01 00:00:00'";
connection
.execute(&format!(
"INSERT INTO has_timestamps (ts) VALUES ({})",
valid_sqlite_date_too_large_for_chrono
))
.unwrap();
let values = has_timestamps.select(ts).load::<NaiveDateTime>(&connection);
match values {
Err(DeserializationError(_)) => {}
v => panic!("Expected a deserialization error, got {:?}", v),
}
}
#[test]
#[cfg(feature = "sqlite")]
fn test_chrono_types_sqlite() {
use self::chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use self::has_time_types;
#[derive(Queryable, Insertable)]
#[table_name = "has_time_types"]
struct NewTimeTypes {
datetime: NaiveDateTime,
date: NaiveDate,
time: NaiveTime,
}
let connection = connection();
connection
.execute(
"CREATE TABLE has_time_types (
datetime DATETIME PRIMARY KEY,
date DATE,
time TIME
)",
)
.unwrap();
let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11);
let new_time_types = NewTimeTypes {
datetime: dt,
date: dt.date(),
time: dt.time(),
};
insert_into(has_time_types::table)
.values(&new_time_types)
.execute(&connection)
.unwrap();
let result = has_time_types::table
.first::<NewTimeTypes>(&connection)
.unwrap();
assert_eq!(result.datetime, dt);
assert_eq!(result.date, dt.date());
assert_eq!(result.time, dt.time());
}
#[test]
#[cfg(feature = "postgres")]
fn boolean_from_sql() {
assert_eq!(true, query_single_value::<Bool, bool>("'t'::bool"));
assert_eq!(false, query_single_value::<Bool, bool>("'f'::bool"));
}
#[test]
#[cfg(feature = "postgres")]
fn boolean_treats_null_as_false_when_predicates_return_null() {
let connection = connection();
let one = Some(1).into_sql::<Nullable<Integer>>();
let query = select(one.eq(None::<i32>));
assert_eq!(Ok(false), query.first(&connection));
}
#[test]
#[cfg(feature = "postgres")]
fn boolean_to_sql() {
assert!(query_to_sql_equality::<Bool, bool>("'t'::bool", true));
assert!(query_to_sql_equality::<Bool, bool>("'f'::bool", false));
assert!(!query_to_sql_equality::<Bool, bool>("'t'::bool", false));
assert!(!query_to_sql_equality::<Bool, bool>("'f'::bool", true));
}
#[test]
#[cfg(feature = "postgres")]
fn i16_from_sql() {
assert_eq!(0, query_single_value::<SmallInt, i16>("0::int2"));
assert_eq!(-1, query_single_value::<SmallInt, i16>("-1::int2"));
assert_eq!(1, query_single_value::<SmallInt, i16>("1::int2"));
}
#[test]
#[cfg(feature = "postgres")]
fn i16_to_sql_smallint() {
assert!(query_to_sql_equality::<SmallInt, i16>("0::int2", 0));
assert!(query_to_sql_equality::<SmallInt, i16>("-1::int2", -1));
assert!(query_to_sql_equality::<SmallInt, i16>("1::int2", 1));
assert!(!query_to_sql_equality::<SmallInt, i16>("0::int2", 1));
assert!(!query_to_sql_equality::<SmallInt, i16>("-1::int2", 1));
}
#[test]
fn i32_from_sql() {
assert_eq!(0, query_single_value::<Integer, i32>("0"));
assert_eq!(-1, query_single_value::<Integer, i32>("-1"));
assert_eq!(70_000, query_single_value::<Integer, i32>("70000"));
}
#[test]
fn i32_to_sql_integer() {
assert!(query_to_sql_equality::<Integer, i32>("0", 0));
assert!(query_to_sql_equality::<Integer, i32>("-1", -1));
assert!(query_to_sql_equality::<Integer, i32>("70000", 70_000));
assert!(!query_to_sql_equality::<Integer, i32>("0", 1));
assert!(!query_to_sql_equality::<Integer, i32>("70000", 69_999));
}
#[test]
#[cfg(feature = "mysql")]
fn u16_to_sql_integer() {
assert!(query_to_sql_equality::<Unsigned<SmallInt>, u16>(
"65535", 65535
));
assert!(query_to_sql_equality::<Unsigned<SmallInt>, u16>("0", 0));
assert!(query_to_sql_equality::<Unsigned<SmallInt>, u16>("1", 1));
assert!(query_to_sql_equality::<Unsigned<SmallInt>, u16>(
"7000", 7000
));
assert!(!query_to_sql_equality::<Unsigned<SmallInt>, u16>("0", 1));
assert!(!query_to_sql_equality::<Unsigned<SmallInt>, u16>(
"50000", 49999
));
assert!(!query_to_sql_equality::<Unsigned<SmallInt>, u16>(
"64435", 64434
));
}
#[test]
#[cfg(feature = "mysql")]
fn u16_from_sql() {
assert_eq!(0, query_single_value::<Unsigned<SmallInt>, u16>("0"));
assert_eq!(
65535,
query_single_value::<Unsigned<SmallInt>, u16>("65535")
);
assert_ne!(
65534,
query_single_value::<Unsigned<SmallInt>, u16>("65535")
);
assert_eq!(7000, query_single_value::<Unsigned<SmallInt>, u16>("7000"));
}
#[test]
#[cfg(feature = "mysql")]
fn u32_to_sql_integer() {
assert!(query_to_sql_equality::<Unsigned<Integer>, u32>(
"4294967295",
4294967295
));
assert!(query_to_sql_equality::<Unsigned<Integer>, u32>("0", 0));
assert!(query_to_sql_equality::<Unsigned<Integer>, u32>("1", 1));
assert!(query_to_sql_equality::<Unsigned<Integer>, u32>(
"70000", 70000
));
assert!(!query_to_sql_equality::<Unsigned<Integer>, u32>("0", 1));
assert!(!query_to_sql_equality::<Unsigned<Integer>, u32>(
"70000", 69999
));
assert!(!query_to_sql_equality::<Unsigned<Integer>, u32>(
"4294967295",
4294967294
));
}
#[test]
#[cfg(feature = "mysql")]
fn u32_from_sql() {
assert_eq!(0, query_single_value::<Unsigned<Integer>, u32>("0"));
assert_eq!(
4294967295,
query_single_value::<Unsigned<Integer>, u32>("4294967295")
);
assert_ne!(
4294967294,
query_single_value::<Unsigned<Integer>, u32>("4294967295")
);
assert_eq!(70000, query_single_value::<Unsigned<Integer>, u32>("70000"));
}
#[test]
#[cfg(feature = "mysql")]
fn u64_to_sql_integer() {
assert!(query_to_sql_equality::<Unsigned<BigInt>, u64>(
"18446744073709551615",
18446744073709551615
));
assert!(query_to_sql_equality::<Unsigned<BigInt>, u64>("0", 0));
assert!(query_to_sql_equality::<Unsigned<BigInt>, u64>("1", 1));
assert!(query_to_sql_equality::<Unsigned<BigInt>, u64>(
"700000", 700000
));
assert!(!query_to_sql_equality::<Unsigned<BigInt>, u64>("0", 1));
assert!(!query_to_sql_equality::<Unsigned<BigInt>, u64>(
"70000", 69999
));
assert!(!query_to_sql_equality::<Unsigned<BigInt>, u64>(
"18446744073709551615",
18446744073709551614
));
}
#[test]
#[cfg(feature = "mysql")]
fn u64_from_sql() {
assert_eq!(0, query_single_value::<Unsigned<BigInt>, u64>("0"));
assert_eq!(
18446744073709551615,
query_single_value::<Unsigned<BigInt>, u64>("18446744073709551615")
);
assert_ne!(
18446744073709551614,
query_single_value::<Unsigned<BigInt>, u64>("18446744073709551615")
);
assert_eq!(
700000,
query_single_value::<Unsigned<BigInt>, u64>("700000")
);
}
#[test]
#[cfg(feature = "postgres")]
fn i64_from_sql() {
assert_eq!(0, query_single_value::<BigInt, i64>("0::int8"));
assert_eq!(-1, query_single_value::<BigInt, i64>("-1::int8"));
assert_eq!(
283_745_982_374,
query_single_value::<BigInt, i64>("283745982374::int8")
);
}
#[test]
#[cfg(feature = "postgres")]
fn i64_to_sql_bigint() {
assert!(query_to_sql_equality::<BigInt, i64>("0::int8", 0));
assert!(query_to_sql_equality::<BigInt, i64>("-1::int8", -1));
assert!(query_to_sql_equality::<BigInt, i64>(
"283745982374::int8",
283_745_982_374
));
assert!(!query_to_sql_equality::<BigInt, i64>("0::int8", 1));
assert!(!query_to_sql_equality::<BigInt, i64>(
"283745982374::int8",
283_745_982_373
));
}
use std::{f32, f64};
#[test]
#[cfg(feature = "postgres")]
fn f32_from_sql() {
assert_eq!(0.0, query_single_value::<Float, f32>("0.0::real"));
assert_eq!(0.5, query_single_value::<Float, f32>("0.5::real"));
let nan = query_single_value::<Float, f32>("'NaN'::real");
assert!(nan.is_nan());
assert_eq!(
f32::INFINITY,
query_single_value::<Float, f32>("'Infinity'::real")
);
assert_eq!(
-f32::INFINITY,
query_single_value::<Float, f32>("'-Infinity'::real")
);
}
#[test]
#[cfg(feature = "postgres")]
fn f32_to_sql_float() {
assert!(query_to_sql_equality::<Float, f32>("0.0::real", 0.0));
assert!(query_to_sql_equality::<Float, f32>("0.5::real", 0.5));
assert!(query_to_sql_equality::<Float, f32>("'NaN'::real", f32::NAN));
assert!(query_to_sql_equality::<Float, f32>(
"'Infinity'::real",
f32::INFINITY
));
assert!(query_to_sql_equality::<Float, f32>(
"'-Infinity'::real",
-f32::INFINITY
));
assert!(!query_to_sql_equality::<Float, f32>("0.0::real", 0.5));
assert!(!query_to_sql_equality::<Float, f32>("'NaN'::real", 0.0));
assert!(!query_to_sql_equality::<Float, f32>(
"'Infinity'::real",
-f32::INFINITY
));
assert!(!query_to_sql_equality::<Float, f32>(
"'-Infinity'::real",
1.0
));
}
#[test]
#[cfg(feature = "postgres")]
fn f64_from_sql() {
assert_eq!(
0.0,
query_single_value::<Double, f64>("0.0::double precision")
);
assert_eq!(
0.5,
query_single_value::<Double, f64>("0.5::double precision")
);
let nan = query_single_value::<Double, f64>("'NaN'::double precision");
assert!(nan.is_nan());
assert_eq!(
f64::INFINITY,
query_single_value::<Double, f64>("'Infinity'::double precision")
);
assert_eq!(
-f64::INFINITY,
query_single_value::<Double, f64>("'-Infinity'::double precision")
);
}
#[test]
#[cfg(feature = "postgres")]
fn f64_to_sql_float() {
assert!(query_to_sql_equality::<Double, f64>(
"0.0::double precision",
0.0
));
assert!(query_to_sql_equality::<Double, f64>(
"0.5::double precision",
0.5
));
assert!(query_to_sql_equality::<Double, f64>(
"'NaN'::double precision",
f64::NAN
));
assert!(query_to_sql_equality::<Double, f64>(
"'Infinity'::double precision",
f64::INFINITY
));
assert!(query_to_sql_equality::<Double, f64>(
"'-Infinity'::double precision",
-f64::INFINITY
));
assert!(!query_to_sql_equality::<Double, f64>(
"0.0::double precision",
0.5
));
assert!(!query_to_sql_equality::<Double, f64>(
"'NaN'::double precision",
0.0
));
assert!(!query_to_sql_equality::<Double, f64>(
"'Infinity'::double precision",
-f64::INFINITY
));
assert!(!query_to_sql_equality::<Double, f64>(
"'-Infinity'::double precision",
1.0
));
}
#[test]
fn string_from_sql() {
assert_eq!("hello", &query_single_value::<VarChar, String>("'hello'"));
assert_eq!("world", &query_single_value::<VarChar, String>("'world'"));
}
#[test]
fn str_to_sql_varchar() {
assert!(query_to_sql_equality::<VarChar, &str>("'hello'", "hello"));
assert!(query_to_sql_equality::<VarChar, &str>("'world'", "world"));
assert!(!query_to_sql_equality::<VarChar, &str>("'hello'", "world"));
}
#[test]
fn string_to_sql_varchar() {
assert!(query_to_sql_equality::<VarChar, String>(
"'hello'",
"hello".to_string()
));
assert!(query_to_sql_equality::<VarChar, String>(
"'world'",
"world".to_string()
));
assert!(!query_to_sql_equality::<VarChar, String>(
"'hello'",
"world".to_string()
));
}
#[test]
#[cfg(feature = "postgres")]
fn binary_from_sql() {
let invalid_utf8_bytes = vec![0x1Fu8, 0x8Bu8];
assert_eq!(
invalid_utf8_bytes,
query_single_value::<Binary, Vec<u8>>("E'\\\\x1F8B'::bytea")
);
assert_eq!(
Vec::<u8>::new(),
query_single_value::<Binary, Vec<u8>>("''::bytea")
);
assert_eq!(
vec![0u8],
query_single_value::<Binary, Vec<u8>>("E'\\\\000'::bytea")
);
}
#[test]
#[cfg(feature = "postgres")]
fn bytes_to_sql_binary() {
let invalid_utf8_bytes = vec![0x1Fu8, 0x8Bu8];
assert!(query_to_sql_equality::<Binary, Vec<u8>>(
"E'\\\\x1F8B'::bytea",
invalid_utf8_bytes.clone()
));
assert!(query_to_sql_equality::<Binary, &[u8]>(
"E'\\\\x1F8B'::bytea",
&invalid_utf8_bytes
));
assert!(!query_to_sql_equality::<Binary, &[u8]>(
"''::bytea",
&invalid_utf8_bytes
));
assert!(query_to_sql_equality::<Binary, Vec<u8>>(
"''::bytea",
Vec::<u8>::new()
));
assert!(query_to_sql_equality::<Binary, Vec<u8>>(
"E'\\\\000'::bytea",
vec![0u8]
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_specific_option_from_sql() {
assert_eq!(
Some(true),
query_single_value::<Nullable<Bool>, Option<bool>>("'t'::bool")
);
}
#[test]
fn option_from_sql() {
assert_eq!(
None,
query_single_value::<Nullable<Bool>, Option<bool>>("NULL")
);
assert_eq!(
Some(1),
query_single_value::<Nullable<Integer>, Option<i32>>("1")
);
assert_eq!(
None,
query_single_value::<Nullable<Integer>, Option<i32>>("NULL")
);
assert_eq!(
Some("Hello!".to_string()),
query_single_value::<Nullable<VarChar>, Option<String>>("'Hello!'")
);
assert_eq!(
Some("".to_string()),
query_single_value::<Nullable<VarChar>, Option<String>>("''")
);
assert_eq!(
None,
query_single_value::<Nullable<VarChar>, Option<String>>("NULL")
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_specific_option_to_sql() {
assert!(query_to_sql_equality::<Nullable<Bool>, Option<bool>>(
"'t'::bool",
Some(true)
));
assert!(!query_to_sql_equality::<Nullable<Bool>, Option<bool>>(
"'f'::bool",
Some(true)
));
assert!(query_to_sql_equality::<Nullable<Bool>, Option<bool>>(
"NULL", None
));
assert!(!query_to_sql_equality::<Nullable<Bool>, Option<bool>>(
"NULL::bool",
Some(false)
));
}
#[test]
fn option_to_sql() {
assert!(query_to_sql_equality::<Nullable<Integer>, Option<i32>>(
"1",
Some(1)
));
assert!(query_to_sql_equality::<Nullable<Integer>, Option<i32>>(
"NULL", None
));
assert!(query_to_sql_equality::<Nullable<VarChar>, Option<String>>(
"'Hello!'",
Some("Hello!".to_string())
));
assert!(query_to_sql_equality::<Nullable<VarChar>, Option<String>>(
"''",
Some("".to_string())
));
assert!(query_to_sql_equality::<Nullable<VarChar>, Option<String>>(
"NULL", None
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_array_from_sql() {
assert_eq!(
vec![true, false, true],
query_single_value::<Array<Bool>, Vec<bool>>("ARRAY['t', 'f', 't']::bool[]")
);
assert_eq!(
vec![1, 2, 3],
query_single_value::<Array<Integer>, Vec<i32>>("ARRAY[1, 2, 3]")
);
assert_eq!(
vec!["Hello".to_string(), "".to_string(), "world".to_string()],
query_single_value::<Array<VarChar>, Vec<String>>("ARRAY['Hello', '', 'world']")
);
}
#[cfg(feature = "postgres")]
#[test]
fn pg_array_from_sql_non_one_lower_bound() {
assert_eq!(
vec![true, false, true],
query_single_value::<Array<Bool>, Vec<bool>>("'[0:2]={t, f, t}'::bool[]")
);
assert_eq!(
vec![true, false, true],
query_single_value::<Array<Bool>, Vec<bool>>("'[1:3]={t, f, t}'::bool[]")
);
assert_eq!(
vec![true, false, true],
query_single_value::<Array<Bool>, Vec<bool>>("'[2:4]={t, f, t}'::bool[]")
);
}
#[test]
#[cfg(feature = "postgres")]
fn to_sql_array() {
assert!(query_to_sql_equality::<Array<Bool>, Vec<bool>>(
"ARRAY['t', 'f', 't']::bool[]",
vec![true, false, true]
));
assert!(query_to_sql_equality::<Array<Bool>, &[bool]>(
"ARRAY['t', 'f', 't']::bool[]",
&[true, false, true]
));
assert!(!query_to_sql_equality::<Array<Bool>, &[bool]>(
"ARRAY['t', 'f', 't']::bool[]",
&[false, false, true]
));
assert!(query_to_sql_equality::<Array<Integer>, &[i32]>(
"ARRAY[1, 2, 3]",
&[1, 2, 3]
));
assert!(query_to_sql_equality::<Array<VarChar>, &[&str]>(
"ARRAY['Hello', '', 'world']::text[]",
&["Hello", "", "world"]
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_array_containing_null() {
let query = "ARRAY['Hello', '', NULL, 'world']";
let data = query_single_value::<Array<Nullable<VarChar>>, Vec<Option<String>>>(query);
let expected = vec![
Some("Hello".to_string()),
Some("".to_string()),
None,
Some("world".to_string()),
];
assert_eq!(expected, data);
}
#[test]
#[cfg(feature = "postgres")]
fn timestamp_from_sql() {
use diesel::data_types::PgTimestamp;
let query = "'2015-11-13 13:26:48.041057-07'::timestamp";
let expected_value = PgTimestamp(500_736_408_041_057);
assert_eq!(
expected_value,
query_single_value::<Timestamp, PgTimestamp>(query)
);
let query = "'2015-11-13 13:26:49.041057-07'::timestamp";
let expected_value = PgTimestamp(500_736_409_041_057);
assert_eq!(
expected_value,
query_single_value::<Timestamp, PgTimestamp>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_timestamp_to_sql_timestamp() {
use diesel::data_types::PgTimestamp;
let expected_value = "'2015-11-13 13:26:48.041057-07'::timestamp";
let value = PgTimestamp(500_736_408_041_057);
assert!(query_to_sql_equality::<Timestamp, PgTimestamp>(
expected_value,
value
));
let expected_value = "'2015-11-13 13:26:49.041057-07'::timestamp";
let value = PgTimestamp(500_736_409_041_057);
assert!(query_to_sql_equality::<Timestamp, PgTimestamp>(
expected_value,
value
));
let expected_non_equal_value = "'2015-11-13 13:26:48.041057-07'::timestamp";
assert!(!query_to_sql_equality::<Timestamp, PgTimestamp>(
expected_non_equal_value,
value
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_numeric_from_sql() {
use diesel::data_types::PgNumeric;
let query = "1.0::numeric";
let expected_value = PgNumeric::Positive {
digits: vec![1],
weight: 0,
scale: 1,
};
assert_eq!(
expected_value,
query_single_value::<Numeric, PgNumeric>(query)
);
let query = "-31.0::numeric";
let expected_value = PgNumeric::Negative {
digits: vec![31],
weight: 0,
scale: 1,
};
assert_eq!(
expected_value,
query_single_value::<Numeric, PgNumeric>(query)
);
let query = "'NaN'::numeric";
let expected_value = PgNumeric::NaN;
assert_eq!(
expected_value,
query_single_value::<Numeric, PgNumeric>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_numeric_bigdecimal_to_sql() {
use self::bigdecimal::BigDecimal;
fn correct_rep(integer: u64, decimal: u64) -> bool {
let expected = format!("{}.{}", integer, decimal);
let value: BigDecimal = expected.parse().expect("Could not parse to a BigDecimal");
query_to_sql_equality::<Numeric, BigDecimal>(&expected, value)
}
quickcheck(correct_rep as fn(u64, u64) -> bool);
let test_values = vec![
"0.1",
"1.0",
"141.0",
"-1.0",
// Larger than u64
"18446744073709551616",
// Powers of 10k (numeric is represented in base 10k)
"10000",
"100000000",
"1.100001",
"10000.100001",
"0.00001234",
"120000.00001234",
"120001.00001234",
];
for value in test_values {
let expected = format!("'{}'::numeric", value);
let value = value.parse::<BigDecimal>().unwrap();
query_to_sql_equality::<Numeric, _>(&expected, value);
}
}
#[test]
#[cfg(feature = "mysql")]
fn mysql_numeric_bigdecimal_to_sql() {
use self::bigdecimal::BigDecimal;
fn correct_rep(integer: u64, decimal: u64) -> bool {
let expected = format!("{}.{}", integer, decimal);
let value: BigDecimal = expected.parse().expect("Could not parse to a BigDecimal");
query_to_sql_equality::<Numeric, BigDecimal>(&expected, value)
}
quickcheck(correct_rep as fn(u64, u64) -> bool);
let test_values = vec![
"1.0",
"141.0",
"-1.0",
"10000",
"100000000",
"1.100001",
"10000.100001",
"0.00001234",
"120000.00001234",
"120001.00001234",
];
for value in test_values {
let expected = format!("cast('{}' as decimal(20, 10))", value);
let value = value.parse::<BigDecimal>().unwrap();
query_to_sql_equality::<Numeric, _>(&expected, value);
}
}
#[test]
#[cfg(feature = "postgres")]
fn pg_numeric_bigdecimal_from_sql() {
use self::bigdecimal::BigDecimal;
let values = vec![
"0.1",
"1.0",
"141.0",
"-1.0",
// With some more precision
"4.2000000",
// Larger than u64
"18446744073709551616",
// Powers of 10k (numeric is represented in base 10k)
"10000",
"100000000",
"1.100001",
"10000.100001",
"0.00001234",
"120000.00001234",
"120001.00001234",
];
for value in values {
let query = format!("'{}'::numeric", value);
let expected = value.parse::<BigDecimal>().unwrap();
assert_eq!(expected, query_single_value::<Numeric, BigDecimal>(&query));
assert_eq!(
format!("{}", expected),
format!("{}", query_single_value::<Numeric, BigDecimal>(&query))
);
}
}
#[test]
#[cfg(feature = "mysql")]
fn mysql_numeric_bigdecimal_from_sql() {
use self::bigdecimal::BigDecimal;
let query = "cast(1.0 as decimal)";
let expected_value: BigDecimal = "1.0".parse().expect("Could not parse to a BigDecimal");
assert_eq!(
expected_value,
query_single_value::<Numeric, BigDecimal>(query)
);
let query = "cast(141.00 as decimal)";
let expected_value: BigDecimal = "141.00".parse().expect("Could not parse to a BigDecimal");
assert_eq!(
expected_value,
query_single_value::<Numeric, BigDecimal>(query)
);
// Some non standard values:
let query = "cast(18446744073709551616 as decimal)"; // 2^64; doesn't fit in u64
// It is mysql, it will trim it even in strict mode
let expected_value: BigDecimal = "9999999999.00"
.parse()
.expect("Could not parse to a BigDecimal");
assert_eq!(
expected_value,
query_single_value::<Numeric, BigDecimal>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_uuid_from_sql() {
extern crate uuid;
let query = "'8a645207-42d6-4d17-82e7-f5e42ede0f67'::uuid";
let expected_value = uuid::Uuid::parse_str("8a645207-42d6-4d17-82e7-f5e42ede0f67").unwrap();
assert_eq!(
expected_value,
query_single_value::<Uuid, uuid::Uuid>(query)
);
let query = "'f94e0e4d-c7b0-405f-9c0e-57b97f4afb58'::uuid";
let expected_value = uuid::Uuid::parse_str("f94e0e4d-c7b0-405f-9c0e-57b97f4afb58").unwrap();
assert_eq!(
expected_value,
query_single_value::<Uuid, uuid::Uuid>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_uuid_to_sql_uuid() {
extern crate uuid;
let expected_value = "'8a645207-42d6-4d17-82e7-f5e42ede0f67'::uuid";
let value = uuid::Uuid::parse_str("8a645207-42d6-4d17-82e7-f5e42ede0f67").unwrap();
assert!(query_to_sql_equality::<Uuid, uuid::Uuid>(
expected_value,
value
));
let expected_value = "'f94e0e4d-c7b0-405f-9c0e-57b97f4afb58'::uuid";
let value = uuid::Uuid::parse_str("f94e0e4d-c7b0-405f-9c0e-57b97f4afb58").unwrap();
assert!(query_to_sql_equality::<Uuid, uuid::Uuid>(
expected_value,
value
));
let expected_non_equal_value = "'8e940686-97a5-4e8b-ac44-64cf3cceea9b'::uuid";
assert!(!query_to_sql_equality::<Uuid, uuid::Uuid>(
expected_non_equal_value,
value
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_macaddress_from_sql() {
let query = "'08:00:2b:01:02:03'::macaddr";
let expected_value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03];
assert_eq!(
expected_value,
query_single_value::<MacAddr, [u8; 6]>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_macaddress_to_sql_macaddress() {
let expected_value = "'08:00:2b:01:02:03'::macaddr";
let value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03];
assert!(query_to_sql_equality::<MacAddr, [u8; 6]>(
expected_value,
value
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_v4address_from_sql() {
extern crate ipnetwork;
use std::str::FromStr;
let query = "'192.168.1.0/24'::cidr";
let expected_value =
ipnetwork::IpNetwork::V4(ipnetwork::Ipv4Network::from_str("192.168.1.0/24").unwrap());
assert_eq!(
expected_value,
query_single_value::<Cidr, ipnetwork::IpNetwork>(query)
);
let query = "'192.168.1.0/24'::inet";
let expected_value =
ipnetwork::IpNetwork::V4(ipnetwork::Ipv4Network::from_str("192.168.1.0/24").unwrap());
assert_eq!(
expected_value,
query_single_value::<Inet, ipnetwork::IpNetwork>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_v6address_from_sql() {
extern crate ipnetwork;
use std::str::FromStr;
let query = "'2001:4f8:3:ba::/64'::cidr";
let expected_value =
ipnetwork::IpNetwork::V6(ipnetwork::Ipv6Network::from_str("2001:4f8:3:ba::/64").unwrap());
assert_eq!(
expected_value,
query_single_value::<Cidr, ipnetwork::IpNetwork>(query)
);
let query = "'2001:4f8:3:ba::/64'::inet";
let expected_value =
ipnetwork::IpNetwork::V6(ipnetwork::Ipv6Network::from_str("2001:4f8:3:ba::/64").unwrap());
assert_eq!(
expected_value,
query_single_value::<Inet, ipnetwork::IpNetwork>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_v4address_to_sql_v4address() {
extern crate ipnetwork;
use std::str::FromStr;
let expected_value = "'192.168.1'::cidr";
let value =
ipnetwork::IpNetwork::V4(ipnetwork::Ipv4Network::from_str("192.168.1.0/24").unwrap());
assert!(query_to_sql_equality::<Cidr, ipnetwork::IpNetwork>(
expected_value,
value
));
let expected_value = "'192.168.1.0/24'::inet";
let value =
ipnetwork::IpNetwork::V4(ipnetwork::Ipv4Network::from_str("192.168.1.0/24").unwrap());
assert!(query_to_sql_equality::<Inet, ipnetwork::IpNetwork>(
expected_value,
value
));
let expected_non_equal_value = "'192.168.1.0/23'::inet";
assert!(!query_to_sql_equality::<Inet, ipnetwork::IpNetwork>(
expected_non_equal_value,
value
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_v6address_to_sql_v6address() {
extern crate ipnetwork;
use std::str::FromStr;
let expected_value = "'2001:4f8:3:ba::/64'::cidr";
let value =
ipnetwork::IpNetwork::V6(ipnetwork::Ipv6Network::from_str("2001:4f8:3:ba::/64").unwrap());
assert!(query_to_sql_equality::<Cidr, ipnetwork::IpNetwork>(
expected_value,
value
));
let expected_value = "'2001:4f8:3:ba::/64'::cidr";
let value =
ipnetwork::IpNetwork::V6(ipnetwork::Ipv6Network::from_str("2001:4f8:3:ba::/64").unwrap());
assert!(query_to_sql_equality::<Inet, ipnetwork::IpNetwork>(
expected_value,
value
));
let expected_non_equal_value = "'2001:4f8:3:ba::/63'::cidr";
assert!(!query_to_sql_equality::<Inet, ipnetwork::IpNetwork>(
expected_non_equal_value,
value
));
}
#[test]
#[cfg(feature = "postgres")]
fn pg_json_from_sql() {
extern crate serde_json;
let query = "'true'::json";
let expected_value = serde_json::Value::Bool(true);
assert_eq!(
expected_value,
query_single_value::<Json, serde_json::Value>(query)
);
}
// See https://stackoverflow.com/q/32843213/12089 for why we don't have a
// pg_json_to_sql_json test. There's no `'true':json = 'true':json`
// because JSON string representations are ambiguous. We _do_ have this
// test for `jsonb` values.
#[test]
#[cfg(feature = "postgres")]
fn pg_jsonb_from_sql() {
extern crate serde_json;
let query = "'true'::jsonb";
let expected_value = serde_json::Value::Bool(true);
assert_eq!(
expected_value,
query_single_value::<Jsonb, serde_json::Value>(query)
);
}
#[test]
#[cfg(feature = "postgres")]
fn pg_jsonb_to_sql_jsonb() {
extern crate serde_json;
let expected_value = "'false'::jsonb";
let value = serde_json::Value::Bool(false);
assert!(query_to_sql_equality::<Jsonb, serde_json::Value>(
expected_value,
value
));
}
#[test]
#[cfg(feature = "postgres")]
fn text_array_can_be_assigned_to_varchar_array_column() {
let conn = connection_with_sean_and_tess_in_users_table();
let sean = find_user_by_name("Sean", &conn);
let post = insert_into(posts::table)
.values(&sean.new_post("Hello", None))
.get_result::<Post>(&conn)
.unwrap();
update(posts::table.find(post.id))
.set(posts::tags.eq(vec!["tag1", "tag2"]))
.execute(&conn)
.unwrap();
let tags_in_db = posts::table.find(post.id).select(posts::tags).first(&conn);
assert_eq!(Ok(vec!["tag1".to_string(), "tag2".to_string()]), tags_in_db);
}
#[test]
#[cfg(feature = "postgres")]
fn third_party_crates_can_add_new_types() {
#[derive(Debug, Clone, Copy, QueryId, SqlType)]
struct MyInt;
impl HasSqlType<MyInt> for Pg {
fn metadata(lookup: &Self::MetadataLookup) -> Self::TypeMetadata {
<Pg as HasSqlType<Integer>>::metadata(lookup)
}
}
impl FromSql<MyInt, Pg> for i32 {
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
FromSql::<Integer, Pg>::from_sql(bytes)
}
}
assert_eq!(0, query_single_value::<MyInt, i32>("0"));
assert_eq!(-1, query_single_value::<MyInt, i32>("-1"));
assert_eq!(70_000, query_single_value::<MyInt, i32>("70000"));
}
fn query_single_value<T, U: Queryable<T, TestBackend>>(sql_str: &str) -> U
where
TestBackend: HasSqlType<T>,
T: QueryId + SingleValue,
{
use diesel::dsl::sql;
let connection = connection();
select(sql::<T>(sql_str)).first(&connection).unwrap()
}
use diesel::expression::AsExpression;
use diesel::query_builder::{QueryFragment, QueryId};
use std::fmt::Debug;
fn query_to_sql_equality<T, U>(sql_str: &str, value: U) -> bool
where
U: AsExpression<T> + Debug + Clone,
U::Expression: SelectableExpression<(), SqlType = T>,
U::Expression: QueryFragment<TestBackend> + QueryId,
T: QueryId + SingleValue,
{
use diesel::dsl::sql;
let connection = connection();
let query = select(
sql::<T>(sql_str)
.is_null()
.and(value.clone().as_expression().is_null())
.or(sql::<T>(sql_str).eq(value.clone())),
);
query
.get_result(&connection)
.expect(&format!("Error comparing {}, {:?}", sql_str, value))
}
#[cfg(feature = "postgres")]
#[test]
#[should_panic(expected = "Received more than 4 bytes decoding i32")]
fn debug_check_catches_reading_bigint_as_i32_when_using_raw_sql() {
use diesel::dsl::sql;
use diesel::sql_types::Integer;
let connection = connection();
users::table
.select(sql::<Integer>("COUNT(*)"))
.get_result::<i32>(&connection)
.unwrap();
}
#[cfg(feature = "postgres")]
#[test]
fn test_range_from_sql() {
use diesel::dsl::sql;
use std::collections::Bound;
let connection = connection();
let query = "'[1,)'::int4range";
let expected_value = (Bound::Included(1), Bound::Unbounded);
assert_eq!(
expected_value,
query_single_value::<Range<Int4>, (Bound<i32>, Bound<i32>)>(query)
);
let query = "'(1,2]'::int4range";
let expected_value = (Bound::Included(2), Bound::Excluded(3));
assert_eq!(
expected_value,
query_single_value::<Range<Int4>, (Bound<i32>, Bound<i32>)>(query)
);
let query = "SELECT '(1,1]'::int4range";
assert!(
sql::<Range<Int4>>(query)
.load::<(Bound<i32>, Bound<i32>)>(&connection)
.is_err()
);
}
#[cfg(feature = "postgres")]
#[test]
fn test_range_to_sql() {
use std::collections::Bound;
let expected_value = "'[1,2]'::int4range";
let value = (Bound::Included(1), Bound::Excluded(3));
assert!(query_to_sql_equality::<Range<Int4>, (Bound<i32>, Bound<i32>)>(expected_value, value));
let expected_value = "'(1,2]'::int4range";
let value = (Bound::Included(2), Bound::Excluded(3));
assert!(query_to_sql_equality::<Range<Int4>, (Bound<i32>, Bound<i32>)>(expected_value, value));
}
#[cfg(feature = "postgres")]
#[test]
fn test_inserting_ranges() {
use std::collections::Bound;
let connection = connection();
connection
.execute(
"CREATE TABLE has_ranges (
id SERIAL PRIMARY KEY,
nul_range INT4RANGE,
range INT4RANGE NOT NULL)",
)
.unwrap();
table!(
has_ranges(id) {
id -> Int4,
nul_range -> Nullable<Range<Int4>>,
range -> Range<Int4>,
}
);
let value = (Bound::Included(1), Bound::Excluded(3));
let (_, v1, v2): (i32, Option<(_, _)>, (_, _)) = insert_into(has_ranges::table)
.values((has_ranges::nul_range.eq(value), has_ranges::range.eq(value)))
.get_result(&connection)
.unwrap();
assert_eq!(v1, Some(value));
assert_eq!(v2, value);
}