postgres: fix various issues and add more tests

This commit is contained in:
Ryan Leckey 2020-03-01 02:32:37 -08:00
parent 433aab1e5b
commit 8e8cf6db20
8 changed files with 123 additions and 78 deletions

View file

@ -76,7 +76,7 @@ name = "postgres"
required-features = [ "postgres" ]
[[test]]
name = "postgres-unprepared"
name = "postgres-simple"
required-features = [ "postgres" ]
[[test]]

View file

@ -7,6 +7,7 @@ use crate::decode::Decode;
use crate::encode::Encode;
use crate::postgres::protocol::TypeId;
use crate::postgres::types::PgTypeInfo;
use crate::postgres::row::PgValue;
use crate::postgres::Postgres;
use crate::types::Type;
@ -65,8 +66,8 @@ where
}
impl<'de> Decode<'de, Postgres> for NaiveTime {
fn decode(raw: &'de [u8]) -> crate::Result<Self> {
let micros: i64 = Decode::<Postgres>::decode(raw)?;
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
let micros: i64 = Decode::<Postgres>::decode(value)?;
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(micros))
}
@ -87,8 +88,8 @@ impl Encode<Postgres> for NaiveTime {
}
impl<'de> Decode<'de, Postgres> for NaiveDate {
fn decode(raw: &'de [u8]) -> crate::Result<Self> {
let days: i32 = Decode::<Postgres>::decode(raw)?;
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
let days: i32 = Decode::<Postgres>::decode(value)?;
Ok(NaiveDate::from_ymd(2000, 1, 1) + Duration::days(days as i64))
}
@ -112,8 +113,8 @@ impl Encode<Postgres> for NaiveDate {
}
impl<'de> Decode<'de, Postgres> for NaiveDateTime {
fn decode(raw: &'de [u8]) -> crate::Result<Self> {
let micros: i64 = Decode::<Postgres>::decode(raw)?;
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
let micros: i64 = Decode::<Postgres>::decode(value)?;
postgres_epoch()
.naive_utc()
@ -146,15 +147,15 @@ impl Encode<Postgres> for NaiveDateTime {
}
impl<'de> Decode<'de, Postgres> for DateTime<Utc> {
fn decode(raw: &'de [u8]) -> crate::Result<Self> {
let date_time = Decode::<Postgres>::decode(raw)?;
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
let date_time = Decode::<Postgres>::decode(value)?;
Ok(DateTime::from_utc(date_time, Utc))
}
}
impl<'de> Decode<'de, Postgres> for DateTime<Local> {
fn decode(raw: &'de [u8]) -> crate::Result<Self> {
let date_time = Decode::<Postgres>::decode(raw)?;
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
let date_time = Decode::<Postgres>::decode(value)?;
Ok(Local.from_utc_datetime(&date_time))
}
}

View file

@ -49,6 +49,6 @@ impl Encode<Postgres> for f64 {
impl<'de> Decode<'de, Postgres> for f64 {
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
<i32 as Decode<Postgres>>::decode(value).map(|value| f64::from_bits(value as u64))
<i64 as Decode<Postgres>>::decode(value).map(|value| f64::from_bits(value as u64))
}
}

View file

@ -1,7 +1,11 @@
use std::convert::TryInto;
use std::str::FromStr;
use uuid::Uuid;
use crate::decode::Decode;
use crate::encode::Encode;
use crate::postgres::row::PgValue;
use crate::postgres::protocol::TypeId;
use crate::postgres::types::PgTypeInfo;
use crate::postgres::Postgres;
@ -26,7 +30,10 @@ impl Encode<Postgres> for Uuid {
}
impl<'de> Decode<'de, Postgres> for Uuid {
fn decode(buf: &'de [u8]) -> crate::Result<Self> {
Uuid::from_slice(buf).map_err(|err| crate::Error::Decode(Box::new(err)))
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
match value.try_into()? {
PgValue::Binary(buf) => Uuid::from_slice(buf).map_err(|err| crate::Error::decode(err)),
PgValue::Text(s) => Uuid::from_str(s).map_err(|err| crate::Error::decode(err)),
}
}
}

View file

@ -1,4 +1,5 @@
use sqlx::{Connect, Executor, Cursor, Row, PgConnection};
use sqlx::postgres::PgRow;
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
@ -19,7 +20,7 @@ async fn test_select_1() -> anyhow::Result<()> {
let mut cursor = conn.fetch("SELECT 5");
let row = cursor.next().await?.unwrap();
assert_eq!(5i32, row.get(0)?);
assert!(5i32 == row.get::<i32, _>(0)?);
Ok(())
}
@ -48,12 +49,48 @@ SELECT id, text FROM _sqlx_test_postgres_5112;
let row = cursor.next().await?.unwrap();
assert_eq!(1_i64, row.get(0)?);
assert!("this is a test" == row.get::<&str, _>(1)?);
let id: i64 = row.get(0)?;
let text: &str = row.get(1)?;
assert!(1_i64 == id);
assert!("this is a test" == text);
Ok(())
}
macro_rules! test {
($name:ident: $ty:ty: $($text:literal == $value:expr),+) => {
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
async fn $name () -> anyhow::Result<()> {
let mut conn = connect().await?;
$(
let rec: $ty = sqlx::query(&format!("SELECT $1 as _1"))
.bind($value)
.map(|row: PgRow| row.get(0))
.fetch_one(&mut conn)
.await?;
assert!($value == rec);
)+
Ok(())
}
}
}
test!(postgres_simple_bool: bool: "false::boolean" == false, "true::boolean" == true);
test!(postgres_simple_smallint: i16: "821::smallint" == 821_i16);
test!(postgres_simple_int: i32: "94101::int" == 94101_i32);
test!(postgres_simple_bigint: i64: "9358295312::bigint" == 9358295312_i64);
test!(postgres_simple_real: f32: "9419.122::real" == 9419.122_f32);
test!(postgres_simple_double: f64: "939399419.1225182::double precision" == 939399419.1225182_f64);
test!(postgres_simple_text: String: "'this is foo'" == "this is foo", "''" == "");
async fn connect() -> anyhow::Result<PgConnection> {
let _ = dotenv::dotenv();
let _ = env_logger::try_init();

View file

@ -25,7 +25,7 @@ async fn postgres_chrono_date() -> anyhow::Result<()> {
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
async fn mysql_chrono_date_time() -> anyhow::Result<()> {
async fn postgres_chrono_date_time() -> anyhow::Result<()> {
let mut conn = connect().await?;
let value = NaiveDate::from_ymd(2019, 1, 2).and_hms(5, 10, 20);

View file

@ -1,59 +1,59 @@
// use sqlx::{postgres::PgConnection, Connect as _, Connection as _, Row};
//
// async fn connect() -> anyhow::Result<PgConnection> {
// Ok(PgConnection::connect(dotenv::var("DATABASE_URL")?).await?)
// }
//
// macro_rules! test {
// ($name:ident: $ty:ty: $($text:literal == $value:expr),+) => {
// #[cfg_attr(feature = "runtime-async-std", async_std::test)]
// #[cfg_attr(feature = "runtime-tokio", tokio::test)]
// async fn $name () -> anyhow::Result<()> {
// let mut conn = connect().await?;
//
// $(
// let row = sqlx::query(&format!("SELECT {} = $1, $1 as _1", $text))
// .bind($value)
// .fetch_one(&mut conn)
// .await?;
//
// assert!(row.get::<bool, _>(0));
// assert!($value == row.get::<$ty, _>("_1"));
// )+
//
// Ok(())
// }
// }
// }
//
// test!(postgres_bool: bool: "false::boolean" == false, "true::boolean" == true);
//
// test!(postgres_smallint: i16: "821::smallint" == 821_i16);
// test!(postgres_int: i32: "94101::int" == 94101_i32);
// test!(postgres_bigint: i64: "9358295312::bigint" == 9358295312_i64);
//
// test!(postgres_real: f32: "9419.122::real" == 9419.122_f32);
// test!(postgres_double: f64: "939399419.1225182::double precision" == 939399419.1225182_f64);
//
// test!(postgres_text: String: "'this is foo'" == "this is foo", "''" == "");
//
// #[cfg_attr(feature = "runtime-async-std", async_std::test)]
// #[cfg_attr(feature = "runtime-tokio", tokio::test)]
// async fn postgres_bytes() -> anyhow::Result<()> {
// let mut conn = connect().await?;
//
// let value = b"Hello, World";
//
// let row = sqlx::query("SELECT E'\\\\x48656c6c6f2c20576f726c64' = $1, $1")
// .bind(&value[..])
// .fetch_one(&mut conn)
// .await?;
//
// assert!(row.get::<bool, _>(0));
//
// let output: Vec<u8> = row.get(1);
//
// assert_eq!(&value[..], &*output);
//
// Ok(())
// }
use sqlx::{PgConnection, Connect, Row};
use sqlx::postgres::PgRow;
async fn connect() -> anyhow::Result<PgConnection> {
Ok(PgConnection::connect(dotenv::var("DATABASE_URL")?).await?)
}
macro_rules! test {
($name:ident: $ty:ty: $($text:literal == $value:expr),+) => {
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
async fn $name () -> anyhow::Result<()> {
let mut conn = connect().await?;
$(
let rec: (bool, $ty) = sqlx::query(&format!("SELECT {} = $1, $1 as _1", $text))
.bind($value)
.map(|row: PgRow| Ok((row.get(0)?, row.get(1)?)))
.fetch_one(&mut conn)
.await?;
assert!(rec.0);
assert!($value == rec.1);
)+
Ok(())
}
}
}
test!(postgres_bool: bool: "false::boolean" == false, "true::boolean" == true);
test!(postgres_smallint: i16: "821::smallint" == 821_i16);
test!(postgres_int: i32: "94101::int" == 94101_i32);
test!(postgres_bigint: i64: "9358295312::bigint" == 9358295312_i64);
test!(postgres_real: f32: "9419.122::real" == 9419.122_f32);
test!(postgres_double: f64: "939399419.1225182::double precision" == 939399419.1225182_f64);
test!(postgres_text: String: "'this is foo'" == "this is foo", "''" == "");
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
async fn postgres_bytes() -> anyhow::Result<()> {
let mut conn = connect().await?;
let value = b"Hello, World";
let rec: (bool, Vec<u8>) = sqlx::query("SELECT E'\\\\x48656c6c6f2c20576f726c64' = $1, $1")
.bind(&value[..])
.map(|row: PgRow| Ok((row.get(0)?, row.get(1)?)))
.fetch_one(&mut conn)
.await?;
assert!(rec.0);
assert_eq!(&value[..], &*rec.1);
Ok(())
}

View file

@ -2,8 +2,8 @@ use futures::TryStreamExt;
use sqlx::{
postgres::PgConnection, Connect, Executor, Row,
};
use sqlx_core::postgres::{PgPool, PgRow};
use std::time::Duration;
use sqlx::postgres::{PgPool, PgRow};
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]