sqlx/tests/postgres-derives.rs
sid 40f11ebb77 Process keyword fields correctly in FromRow macro
This PR fixes the the incorrect handling of keywords fields of a struct in the FromRow macro.
Currently a struct with a field like 'r#type' will try to read values from a column with the exact same name with r# prefix. With this change this field will now map to a database column with the correct name 'type' without the r# prefix.
2020-03-30 19:30:50 +05:30

168 lines
4.2 KiB
Rust

use sqlx::Postgres;
use sqlx_test::{new, test_type};
use std::fmt::Debug;
// Transparent types are rust-side wrappers over DB types
#[derive(PartialEq, Debug, sqlx::Type)]
#[sqlx(transparent)]
struct Transparent(i32);
// "Weak" enums map to an integer type indicated by #[repr]
#[derive(PartialEq, Copy, Clone, Debug, sqlx::Type)]
#[repr(i32)]
enum Weak {
One = 0,
Two = 2,
Three = 4,
}
// "Strong" enums can map to TEXT (25) or a custom enum type
#[derive(PartialEq, Debug, sqlx::Type)]
#[sqlx(rename = "text")]
#[sqlx(rename_all = "lowercase")]
enum Strong {
One,
Two,
#[sqlx(rename = "four")]
Three,
}
// TODO: Figure out a good solution for custom type testing
// Records must map to a custom type
// Note that all types are types in Postgres
// #[derive(PartialEq, Debug, sqlx::Type)]
// #[sqlx(rename = "inventory_item")]
// struct InventoryItem {
// name: String,
// supplier_id: Option<i32>,
// price: Option<i64>
// }
test_type!(transparent(
Postgres,
Transparent,
"0" == Transparent(0),
"23523" == Transparent(23523)
));
test_type!(weak_enum(
Postgres,
Weak,
"0::int4" == Weak::One,
"2::int4" == Weak::Two,
"4::int4" == Weak::Three
));
test_type!(strong_enum(
Postgres,
Strong,
"'one'::text" == Strong::One,
"'two'::text" == Strong::Two,
"'four'::text" == Strong::Three
));
// TODO: Figure out a good solution for custom type testing
// test_type!(record_pg_config(
// Postgres,
// InventoryItem,
// "(SELECT ROW('fuzzy dice', 42, 199)::inventory_item)"
// == InventoryItem {
// name: "fuzzy dice".to_owned(),
// supplier_id: Some(42),
// price: Some(199),
// },
// "(SELECT '(\"fuuzy dice\",,)'::pg_config)"
// == InventoryItem {
// name: "fuzzy dice".to_owned(),
// supplier_id: None,
// price: None,
// },
// "(SELECT '(\"\",,2350)'::pg_config)"
// == InventoryItem {
// name: "".to_owned(),
// supplier_id: None,
// price: Some(2350)
// }
// ));
#[cfg(feature = "macros")]
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
async fn test_from_row() -> anyhow::Result<()> {
// Needed for PgQueryAs
use sqlx::prelude::*;
let mut conn = new::<Postgres>().await?;
#[derive(sqlx::FromRow)]
struct Account {
id: i32,
name: String,
}
let account: Account = sqlx::query_as(
"SELECT * from (VALUES (1, 'Herp Derpinson')) accounts(id, name) where id = $1",
)
.bind(1_i32)
.fetch_one(&mut conn)
.await?;
assert_eq!(account.id, 1);
assert_eq!(account.name, "Herp Derpinson");
// A _single_ lifetime may be used but only when using the lowest-level API currently (Query::fetch)
#[derive(sqlx::FromRow)]
struct RefAccount<'a> {
id: i32,
name: &'a str,
}
let mut cursor = sqlx::query(
"SELECT * from (VALUES (1, 'Herp Derpinson')) accounts(id, name) where id = $1",
)
.bind(1_i32)
.fetch(&mut conn);
let account = RefAccount::from_row(&cursor.next().await?.unwrap())?;
assert_eq!(account.id, 1);
assert_eq!(account.name, "Herp Derpinson");
Ok(())
}
#[cfg(feature = "macros")]
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
async fn test_from_row_with_keyword() -> anyhow::Result<()> {
use sqlx::prelude::*;
#[derive(Debug, sqlx::FromRow)]
struct AccountKeyword {
r#type: i32,
r#static: String,
r#let: Option<String>,
r#struct: Option<String>,
name: Option<String>,
}
let mut conn = new::<Postgres>().await?;
let account: AccountKeyword = sqlx::query_as(
r#"SELECT * from (VALUES (1, 'foo', 'bar', null, null)) accounts(type, static, let, struct, name)"#
)
.fetch_one(&mut conn)
.await?;
println!("{:?}", account);
assert_eq!(1, account.r#type);
assert_eq!("foo", account.r#static);
assert_eq!(None, account.r#struct);
assert_eq!(Some("bar".to_owned()), account.r#let);
assert_eq!(None, account.name);
Ok(())
}