diff --git a/sqlx-macros/src/derives/encode.rs b/sqlx-macros/src/derives/encode.rs index 68bd10ff..12ebb396 100644 --- a/sqlx-macros/src/derives/encode.rs +++ b/sqlx-macros/src/derives/encode.rs @@ -203,7 +203,7 @@ fn expand_derive_encode_struct( tts.extend(quote!( impl #impl_generics sqlx::encode::Encode for #ident #ty_generics #where_clause { - fn encode(&self, buf: &mut std::vec::Vec) { + fn encode(&self, buf: &mut sqlx::postgres::PgRawBuffer) { let mut encoder = sqlx::postgres::types::raw::PgRecordEncoder::new(buf); #(#writes)* diff --git a/tests/postgres-derives.rs b/tests/postgres-derives.rs index c8199d2a..3d630b69 100644 --- a/tests/postgres-derives.rs +++ b/tests/postgres-derives.rs @@ -1,4 +1,4 @@ -use sqlx::Postgres; +use sqlx::{postgres::PgQueryAs, Executor, Postgres}; use sqlx_test::{new, test_type}; use std::fmt::Debug; @@ -28,16 +28,15 @@ enum Strong { 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, -// price: Option -// } +#[derive(PartialEq, Debug, sqlx::Type)] +#[sqlx(rename = "inventory_item")] +struct InventoryItem { + name: String, + supplier_id: Option, + price: Option, +} test_type!(transparent( Postgres, @@ -62,29 +61,48 @@ test_type!(strong_enum( "'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_attr(feature = "runtime-async-std", async_std::test)] +#[cfg_attr(feature = "runtime-tokio", tokio::test)] +async fn test_record_type() -> anyhow::Result<()> { + let mut conn = new::().await?; + + conn.execute( + r#" +DO $$ BEGIN + +CREATE TYPE inventory_item AS ( + name text, + supplier_id int, + price bigint +); + +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + "#, + ) + .await?; + + let value = InventoryItem { + name: "fuzzy dice".to_owned(), + supplier_id: Some(42), + price: Some(199), + }; + + let rec: (bool, InventoryItem) = sqlx::query_as( + " + SELECT $1 = ROW('fuzzy dice', 42, 199)::inventory_item, $1 + ", + ) + .bind(&value) + .fetch_one(&mut conn) + .await?; + + assert!(rec.0); + assert_eq!(rec.1, value); + + Ok(()) +} #[cfg(feature = "macros")] #[cfg_attr(feature = "runtime-async-std", async_std::test)]