use sqlx_oldapi::any::AnyRow; use sqlx_oldapi::{Any, Connection, Decode, Executor, Row, Type}; use sqlx_test::new; async fn get_val(expr: &str) -> anyhow::Result where for<'r> T: Decode<'r, Any> + Type + std::marker::Unpin + std::marker::Send + 'static, { let mut conn = new::().await?; let val = sqlx_oldapi::query(&format!("select {}", expr)) .try_map(|row: AnyRow| row.try_get::(0)) .fetch_one(&mut conn) .await?; conn.close().await?; Ok(val) } #[sqlx_macros::test] async fn it_has_all_the_types() -> anyhow::Result<()> { assert_eq!(6, get_val::("5 + 1").await?); assert_eq!(1234567890123, get_val::("1234567890123").await?); assert_eq!( "hello world".to_owned(), get_val::("'hello world'").await? ); assert_eq!(None, get_val::>("NULL").await?); assert_eq!(1e-40, get_val::("1e-40").await?); assert_eq!(12.5f64, get_val::("CAST(12.5 AS DECIMAL(9,2))").await?); assert_eq!( 125125.125f64, get_val::("CAST(125125.125 AS DECIMAL(10,3))").await? ); assert_eq!( -1234567890.125, get_val::("CAST(-1234567890.125 AS DECIMAL(15,3))").await? ); Ok(()) } #[cfg(feature = "chrono")] #[sqlx_macros::test] async fn it_has_chrono() -> anyhow::Result<()> { use sqlx_oldapi::types::chrono::NaiveDate; assert_eq!( NaiveDate::from_ymd_opt(2020, 1, 2).unwrap(), get_val::("CAST('20200102' AS DATE)").await? ); Ok(()) } #[cfg(feature = "chrono")] #[sqlx_macros::test] async fn it_has_chrono_fixed_offset() -> anyhow::Result<()> { use sqlx_oldapi::types::chrono::{DateTime, FixedOffset}; assert_eq!( DateTime::::parse_from_rfc3339("2020-01-02T12:00:00+02:00").unwrap(), get_val::>(if cfg!(feature = "sqlite") { "'2020-01-02 12:00:00+02:00'" } else if cfg!(feature = "mssql") { "CAST('2020-01-02 12:00:00+02:00' AS DATETIMEOFFSET)" } else if cfg!(feature = "postgres") { "'2020-01-02 12:00:00+02:00'::timestamptz" } else { eprintln!("DBMS not supported"); return Ok(()); }) .await? ); Ok(()) } #[cfg(feature = "bigdecimal")] #[sqlx_macros::test] async fn it_has_bigdecimal() -> anyhow::Result<()> { use sqlx_oldapi::types::BigDecimal; use std::str::FromStr; assert_eq!( BigDecimal::from_str("1234567.25")?, get_val::("CAST('1234567.25' AS DECIMAL(9,2))").await? ); Ok(()) } #[cfg(feature = "decimal")] #[sqlx_macros::test] async fn it_has_decimal() -> anyhow::Result<()> { use sqlx_oldapi::types::Decimal; use std::str::FromStr; assert_eq!( Decimal::from_str("1234567.25")?, get_val::("CAST('1234567.25' AS DECIMAL(9,2))").await? ); Ok(()) } #[cfg(feature = "json")] #[sqlx_macros::test] async fn it_has_json() -> anyhow::Result<()> { use serde_json::json; assert_eq!( json!({"foo": "bar"}), get_val::( // SQLite and Mssql do not have a native JSON type, strings are parsed as JSON if cfg!(any(feature = "sqlite", feature = "mssql")) { "'{\"foo\": \"bar\"}'" } else { "CAST('{\"foo\": \"bar\"}' AS JSON)" } ) .await? ); Ok(()) } #[sqlx_macros::test] async fn it_pings() -> anyhow::Result<()> { let mut conn = new::().await?; conn.ping().await?; Ok(()) } #[sqlx_macros::test] async fn it_executes_with_pool() -> anyhow::Result<()> { let pool = sqlx_test::pool::().await?; let rows = pool.fetch_all("SELECT 1; SElECT 2").await?; assert_eq!(rows.len(), 2); Ok(()) } #[sqlx_macros::test] async fn it_does_not_stop_stream_after_decoding_error() -> anyhow::Result<()> { use futures::stream::StreamExt; // see https://github.com/launchbadge/sqlx/issues/1884 let pool = sqlx_test::pool::().await?; #[derive(Debug, PartialEq)] struct MyType; impl<'a> sqlx_oldapi::FromRow<'a, AnyRow> for MyType { fn from_row(row: &'a AnyRow) -> sqlx_oldapi::Result { let n = row.try_get::(0)?; if n == 1 { Err(sqlx_oldapi::Error::RowNotFound) } else { Ok(MyType) } } } let rows = sqlx_oldapi::query_as("SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2") .fetch(&pool) .map(|r| r.ok()) .collect::>() .await; assert_eq!(rows, vec![Some(MyType), None, Some(MyType)]); Ok(()) } #[sqlx_macros::test] async fn it_gets_by_name() -> anyhow::Result<()> { let mut conn = new::().await?; let row = conn.fetch_one("SELECT 1 as _1").await?; let val: i32 = row.get("_1"); assert_eq!(val, 1); Ok(()) } #[sqlx_macros::test] async fn it_can_fail_and_recover() -> anyhow::Result<()> { let mut conn = new::().await?; for i in 0..10 { // make a query that will fail let res = conn .execute("INSERT INTO not_found (column) VALUES (10)") .await; assert!(res.is_err()); // now try and use the connection let val: i32 = conn .fetch_one(&*format!("SELECT {}", i)) .await? .get_unchecked(0); assert_eq!(val, i); } Ok(()) } #[sqlx_macros::test] async fn it_can_fail_and_recover_with_pool() -> anyhow::Result<()> { let pool = sqlx_test::pool::().await?; for i in 0..10 { // make a query that will fail let res = pool .execute("INSERT INTO not_found (column) VALUES (10)") .await; assert!(res.is_err()); // now try and use the connection let val: i32 = pool .fetch_one(&*format!("SELECT {}", i)) .await? .get_unchecked(0); assert_eq!(val, i); } Ok(()) } #[sqlx_macros::test] async fn it_has_unsigned_integers() -> anyhow::Result<()> { let max_value = 9223372036854775807; let expr = if cfg!(feature = "mysql") { format!("CAST({} AS UNSIGNED)", max_value) } else { max_value.to_string() }; assert_eq!(max_value, get_val::(&expr).await?); Ok(()) }