mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-10-03 15:55:45 +00:00
postgres: implement text mode for chrono and clean up type tests
This commit is contained in:
parent
7fbc26de05
commit
f337f1c602
@ -86,10 +86,6 @@ required-features = [ "postgres" ]
|
|||||||
name = "postgres-types"
|
name = "postgres-types"
|
||||||
required-features = [ "postgres" ]
|
required-features = [ "postgres" ]
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "postgres-types-chrono"
|
|
||||||
required-features = [ "postgres", "chrono" ]
|
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "mysql-types"
|
name = "mysql-types"
|
||||||
required-features = [ "mysql" ]
|
required-features = [ "mysql" ]
|
||||||
|
@ -21,7 +21,7 @@ fn test_ssl_request() {
|
|||||||
use crate::io::Buf;
|
use crate::io::Buf;
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
SslRequest::encode(&mut buf);
|
SslRequest.encode(&mut buf);
|
||||||
|
|
||||||
assert_eq!(&buf, b"\x00\x00\x00\x08\x04\xd2\x16/");
|
assert_eq!(&buf, b"\x00\x00\x00\x08\x04\xd2\x16/");
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use byteorder::{NetworkEndian, ReadBytesExt};
|
||||||
use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
|
use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
|
||||||
|
|
||||||
use crate::decode::Decode;
|
use crate::decode::Decode;
|
||||||
@ -10,6 +11,7 @@ use crate::postgres::row::PgValue;
|
|||||||
use crate::postgres::types::PgTypeInfo;
|
use crate::postgres::types::PgTypeInfo;
|
||||||
use crate::postgres::Postgres;
|
use crate::postgres::Postgres;
|
||||||
use crate::types::Type;
|
use crate::types::Type;
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
impl Type<Postgres> for NaiveTime {
|
impl Type<Postgres> for NaiveTime {
|
||||||
fn type_info() -> PgTypeInfo {
|
fn type_info() -> PgTypeInfo {
|
||||||
@ -67,10 +69,16 @@ where
|
|||||||
|
|
||||||
impl<'de> Decode<'de, Postgres> for NaiveTime {
|
impl<'de> Decode<'de, Postgres> for NaiveTime {
|
||||||
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
|
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
|
||||||
let micros: i64 = Decode::<Postgres>::decode(value)?;
|
match value.try_into()? {
|
||||||
|
PgValue::Binary(mut buf) => {
|
||||||
|
let micros = buf.read_i64::<NetworkEndian>().map_err(Error::decode)?;
|
||||||
|
|
||||||
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(micros))
|
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(micros))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PgValue::Text(s) => NaiveTime::parse_from_str(s, "%H:%M:%S%.f").map_err(Error::decode),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode<Postgres> for NaiveTime {
|
impl Encode<Postgres> for NaiveTime {
|
||||||
@ -89,10 +97,16 @@ impl Encode<Postgres> for NaiveTime {
|
|||||||
|
|
||||||
impl<'de> Decode<'de, Postgres> for NaiveDate {
|
impl<'de> Decode<'de, Postgres> for NaiveDate {
|
||||||
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
|
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
|
||||||
let days: i32 = Decode::<Postgres>::decode(value)?;
|
match value.try_into()? {
|
||||||
|
PgValue::Binary(mut buf) => {
|
||||||
|
let days: i32 = buf.read_i32::<NetworkEndian>().map_err(Error::decode)?;
|
||||||
|
|
||||||
Ok(NaiveDate::from_ymd(2000, 1, 1) + Duration::days(days as i64))
|
Ok(NaiveDate::from_ymd(2000, 1, 1) + Duration::days(days as i64))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PgValue::Text(s) => NaiveDate::parse_from_str(s, "%Y-%m-%d").map_err(Error::decode),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode<Postgres> for NaiveDate {
|
impl Encode<Postgres> for NaiveDate {
|
||||||
@ -114,7 +128,9 @@ impl Encode<Postgres> for NaiveDate {
|
|||||||
|
|
||||||
impl<'de> Decode<'de, Postgres> for NaiveDateTime {
|
impl<'de> Decode<'de, Postgres> for NaiveDateTime {
|
||||||
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
|
fn decode(value: Option<PgValue<'de>>) -> crate::Result<Self> {
|
||||||
let micros: i64 = Decode::<Postgres>::decode(value)?;
|
match value.try_into()? {
|
||||||
|
PgValue::Binary(mut buf) => {
|
||||||
|
let micros = buf.read_i64::<NetworkEndian>().map_err(Error::decode)?;
|
||||||
|
|
||||||
postgres_epoch()
|
postgres_epoch()
|
||||||
.naive_utc()
|
.naive_utc()
|
||||||
@ -129,6 +145,23 @@ impl<'de> Decode<'de, Postgres> for NaiveDateTime {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PgValue::Text(s) => {
|
||||||
|
NaiveDateTime::parse_from_str(
|
||||||
|
s,
|
||||||
|
if s.contains('+') {
|
||||||
|
// Contains a time-zone specifier
|
||||||
|
// This is given for timestamptz for some reason
|
||||||
|
// Postgres already guarantees this to always be UTC
|
||||||
|
"%Y-%m-%d %H:%M:%S%.f%#z"
|
||||||
|
} else {
|
||||||
|
"%Y-%m-%d %H:%M:%S%.f"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map_err(Error::decode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode<Postgres> for NaiveDateTime {
|
impl Encode<Postgres> for NaiveDateTime {
|
||||||
@ -205,15 +238,15 @@ fn test_encode_datetime() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_decode_datetime() {
|
fn test_decode_datetime() {
|
||||||
let buf = [0u8; 8];
|
let buf = [0u8; 8];
|
||||||
let date: NaiveDateTime = Decode::<Postgres>::decode(&buf).unwrap();
|
let date: NaiveDateTime = Decode::<Postgres>::decode(Some(PgValue::Binary(&buf))).unwrap();
|
||||||
assert_eq!(date.to_string(), "2000-01-01 00:00:00");
|
assert_eq!(date.to_string(), "2000-01-01 00:00:00");
|
||||||
|
|
||||||
let buf = 3_600_000_000i64.to_be_bytes();
|
let buf = 3_600_000_000i64.to_be_bytes();
|
||||||
let date: NaiveDateTime = Decode::<Postgres>::decode(&buf).unwrap();
|
let date: NaiveDateTime = Decode::<Postgres>::decode(Some(PgValue::Binary(&buf))).unwrap();
|
||||||
assert_eq!(date.to_string(), "2000-01-01 01:00:00");
|
assert_eq!(date.to_string(), "2000-01-01 01:00:00");
|
||||||
|
|
||||||
let buf = 629_377_265_000_000i64.to_be_bytes();
|
let buf = 629_377_265_000_000i64.to_be_bytes();
|
||||||
let date: NaiveDateTime = Decode::<Postgres>::decode(&buf).unwrap();
|
let date: NaiveDateTime = Decode::<Postgres>::decode(Some(PgValue::Binary(&buf))).unwrap();
|
||||||
assert_eq!(date.to_string(), "2019-12-11 11:01:05");
|
assert_eq!(date.to_string(), "2019-12-11 11:01:05");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,14 +274,14 @@ fn test_encode_date() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_decode_date() {
|
fn test_decode_date() {
|
||||||
let buf = [0; 4];
|
let buf = [0; 4];
|
||||||
let date: NaiveDate = Decode::<Postgres>::decode(&buf).unwrap();
|
let date: NaiveDate = Decode::<Postgres>::decode(Some(PgValue::Binary(&buf))).unwrap();
|
||||||
assert_eq!(date.to_string(), "2000-01-01");
|
assert_eq!(date.to_string(), "2000-01-01");
|
||||||
|
|
||||||
let buf = 366i32.to_be_bytes();
|
let buf = 366i32.to_be_bytes();
|
||||||
let date: NaiveDate = Decode::<Postgres>::decode(&buf).unwrap();
|
let date: NaiveDate = Decode::<Postgres>::decode(Some(PgValue::Binary(&buf))).unwrap();
|
||||||
assert_eq!(date.to_string(), "2001-01-01");
|
assert_eq!(date.to_string(), "2001-01-01");
|
||||||
|
|
||||||
let buf = 7284i32.to_be_bytes();
|
let buf = 7284i32.to_be_bytes();
|
||||||
let date: NaiveDate = Decode::<Postgres>::decode(&buf).unwrap();
|
let date: NaiveDate = Decode::<Postgres>::decode(Some(PgValue::Binary(&buf))).unwrap();
|
||||||
assert_eq!(date.to_string(), "2019-12-11");
|
assert_eq!(date.to_string(), "2019-12-11");
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ where
|
|||||||
macro_rules! test_type {
|
macro_rules! test_type {
|
||||||
($name:ident($db:ident, $ty:ty, $($text:literal == $value:expr),+)) => {
|
($name:ident($db:ident, $ty:ty, $($text:literal == $value:expr),+)) => {
|
||||||
$crate::test_prepared_type!($name($db, $ty, $($text == $value),+));
|
$crate::test_prepared_type!($name($db, $ty, $($text == $value),+));
|
||||||
// $crate::test_unprepared_type!($name($db, $ty, $($text == $value),+));
|
$crate::test_unprepared_type!($name($db, $ty, $($text == $value),+));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +33,8 @@ macro_rules! test_unprepared_type {
|
|||||||
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
||||||
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
||||||
async fn [< test_unprepared_type_ $name >] () -> anyhow::Result<()> {
|
async fn [< test_unprepared_type_ $name >] () -> anyhow::Result<()> {
|
||||||
|
use sqlx::prelude::*;
|
||||||
|
|
||||||
let mut conn = sqlx_test::new::<$db>().await?;
|
let mut conn = sqlx_test::new::<$db>().await?;
|
||||||
|
|
||||||
$(
|
$(
|
||||||
|
@ -59,6 +59,13 @@ pub mod decode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
pub use super::Connect as _;
|
||||||
|
pub use super::Connection as _;
|
||||||
|
pub use super::Cursor as _;
|
||||||
|
pub use super::Executor as _;
|
||||||
|
pub use super::FromRow as _;
|
||||||
|
pub use super::Row as _;
|
||||||
|
|
||||||
#[cfg(feature = "postgres")]
|
#[cfg(feature = "postgres")]
|
||||||
pub use super::postgres::PgQueryAs as _;
|
pub use super::postgres::PgQueryAs as _;
|
||||||
}
|
}
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
use sqlx::types::chrono::{DateTime, NaiveDate, NaiveTime, Utc};
|
|
||||||
use sqlx::{Connection, PgConnection, Row};
|
|
||||||
|
|
||||||
async fn connect() -> anyhow::Result<PgConnection> {
|
|
||||||
Ok(PgConnection::open(dotenv::var("DATABASE_URL")?).await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
|
||||||
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
|
||||||
async fn postgres_chrono_date() -> anyhow::Result<()> {
|
|
||||||
let mut conn = connect().await?;
|
|
||||||
|
|
||||||
let value = NaiveDate::from_ymd(2019, 1, 2);
|
|
||||||
|
|
||||||
let row = sqlx::query("SELECT DATE '2019-01-02' = $1, $1")
|
|
||||||
.bind(&value)
|
|
||||||
.fetch_one(&mut conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
assert!(row.get::<bool, _>(0));
|
|
||||||
assert_eq!(value, row.get(1));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
|
||||||
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
|
||||||
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);
|
|
||||||
|
|
||||||
let row = sqlx::query("SELECT '2019-01-02 05:10:20' = $1, $1")
|
|
||||||
.bind(&value)
|
|
||||||
.fetch_one(&mut conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
assert!(row.get::<bool, _>(0));
|
|
||||||
assert_eq!(value, row.get(1));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
|
||||||
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
|
||||||
async fn postgres_chrono_time() -> anyhow::Result<()> {
|
|
||||||
let mut conn = connect().await?;
|
|
||||||
|
|
||||||
let value = NaiveTime::from_hms_micro(5, 10, 20, 115100);
|
|
||||||
|
|
||||||
let row = sqlx::query("SELECT TIME '05:10:20.115100' = $1, TIME '05:10:20.115100'")
|
|
||||||
.bind(&value)
|
|
||||||
.fetch_one(&mut conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
assert!(row.get::<bool, _>(0));
|
|
||||||
assert_eq!(value, row.get(1));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
|
||||||
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
|
||||||
async fn postgres_chrono_timestamp_tz() -> anyhow::Result<()> {
|
|
||||||
let mut conn = connect().await?;
|
|
||||||
|
|
||||||
let value = DateTime::<Utc>::from_utc(
|
|
||||||
NaiveDate::from_ymd(2019, 1, 2).and_hms_micro(5, 10, 20, 115100),
|
|
||||||
Utc,
|
|
||||||
);
|
|
||||||
|
|
||||||
let row = sqlx::query(
|
|
||||||
"SELECT TIMESTAMPTZ '2019-01-02 05:10:20.115100' = $1, TIMESTAMPTZ '2019-01-02 05:10:20.115100'",
|
|
||||||
)
|
|
||||||
.bind(&value)
|
|
||||||
.fetch_one(&mut conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
assert!(row.get::<bool, _>(0));
|
|
||||||
|
|
||||||
let out: DateTime<Utc> = row.get(1);
|
|
||||||
assert_eq!(value, out);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -26,25 +26,83 @@ test_type!(string(
|
|||||||
"''" == ""
|
"''" == ""
|
||||||
));
|
));
|
||||||
|
|
||||||
// TODO: BYTEA
|
test_type!(bytea(
|
||||||
// TODO: UUID
|
Postgres,
|
||||||
// TODO: CHRONO
|
Vec<u8>,
|
||||||
|
"E'\\\\xDEADBEEF'::bytea"
|
||||||
|
== vec![0xDE_u8, 0xAD, 0xBE, 0xEF],
|
||||||
|
"E'\\\\x'::bytea"
|
||||||
|
== Vec::<u8>::new(),
|
||||||
|
"E'\\\\x0000000052'::bytea"
|
||||||
|
== vec![0_u8, 0, 0, 0, 0x52]
|
||||||
|
));
|
||||||
|
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
test_type!(uuid(
|
||||||
|
Postgres,
|
||||||
|
sqlx::types::Uuid,
|
||||||
|
"'b731678f-636f-4135-bc6f-19440c13bd19'::uuid"
|
||||||
|
== sqlx::types::Uuid::parse_str("b731678f-636f-4135-bc6f-19440c13bd19").unwrap(),
|
||||||
|
"'00000000-0000-0000-0000-000000000000'::uuid"
|
||||||
|
== sqlx::types::Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap()
|
||||||
|
));
|
||||||
|
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
mod chrono {
|
||||||
|
use super::*;
|
||||||
|
use sqlx::types::chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
|
||||||
|
|
||||||
|
test_type!(chrono_date(
|
||||||
|
Postgres,
|
||||||
|
NaiveDate,
|
||||||
|
"DATE '2001-01-05'" == NaiveDate::from_ymd(2001, 1, 5),
|
||||||
|
"DATE '2050-11-23'" == NaiveDate::from_ymd(2050, 11, 23)
|
||||||
|
));
|
||||||
|
|
||||||
|
test_type!(chrono_time(
|
||||||
|
Postgres,
|
||||||
|
NaiveTime,
|
||||||
|
"TIME '05:10:20.115100'" == NaiveTime::from_hms_micro(5, 10, 20, 115100)
|
||||||
|
));
|
||||||
|
|
||||||
|
test_type!(chrono_date_time(
|
||||||
|
Postgres,
|
||||||
|
NaiveDateTime,
|
||||||
|
"'2019-01-02 05:10:20'" == NaiveDate::from_ymd(2019, 1, 2).and_hms(5, 10, 20)
|
||||||
|
));
|
||||||
|
|
||||||
|
test_type!(chrono_date_time_tz(
|
||||||
|
Postgres,
|
||||||
|
DateTime::<Utc>,
|
||||||
|
"TIMESTAMPTZ '2019-01-02 05:10:20.115100'"
|
||||||
|
== DateTime::<Utc>::from_utc(
|
||||||
|
NaiveDate::from_ymd(2019, 1, 2).and_hms_micro(5, 10, 20, 115100),
|
||||||
|
Utc,
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// #[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
// #[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
||||||
// #[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
// #[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
||||||
// async fn postgres_bytes() -> anyhow::Result<()> {
|
// async fn postgres_chrono_timestamp_tz() -> anyhow::Result<()> {
|
||||||
// let mut conn = connect().await?;
|
// let mut conn = connect().await?;
|
||||||
//
|
//
|
||||||
// let value = b"Hello, World";
|
// let value = DateTime::<Utc>::from_utc(
|
||||||
|
// NaiveDate::from_ymd(2019, 1, 2).and_hms_micro(5, 10, 20, 115100),
|
||||||
|
// Utc,
|
||||||
|
// );
|
||||||
//
|
//
|
||||||
// let rec: (bool, Vec<u8>) = sqlx::query("SELECT E'\\\\x48656c6c6f2c20576f726c64' = $1, $1")
|
// let row = sqlx::query(
|
||||||
// .bind(&value[..])
|
// "SELECT TIMESTAMPTZ '2019-01-02 05:10:20.115100' = $1, TIMESTAMPTZ '2019-01-02 05:10:20.115100'",
|
||||||
// .map(|row: PgRow| Ok((row.get(0)?, row.get(1)?)))
|
// )
|
||||||
|
// .bind(&value)
|
||||||
// .fetch_one(&mut conn)
|
// .fetch_one(&mut conn)
|
||||||
// .await?;
|
// .await?;
|
||||||
//
|
//
|
||||||
// assert!(rec.0);
|
// assert!(row.get::<bool, _>(0));
|
||||||
// assert_eq!(&value[..], &*rec.1);
|
//
|
||||||
|
// let out: DateTime<Utc> = row.get(1);
|
||||||
|
// assert_eq!(value, out);
|
||||||
//
|
//
|
||||||
// Ok(())
|
// Ok(())
|
||||||
// }
|
// }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user