diff --git a/sqlx-macros-core/src/derives/attributes.rs b/sqlx-macros-core/src/derives/attributes.rs index 6109863833..cdd47dbacf 100644 --- a/sqlx-macros-core/src/derives/attributes.rs +++ b/sqlx-macros-core/src/derives/attributes.rs @@ -1,8 +1,8 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote_spanned; use syn::{ - parenthesized, punctuated::Punctuated, token::Comma, Attribute, DeriveInput, Field, LitStr, - Meta, Token, Type, Variant, + parenthesized, punctuated::Punctuated, token::Comma, Attribute, DeriveInput, Field, LitInt, + LitStr, Meta, Token, Type, Variant, }; macro_rules! assert_attribute { @@ -73,6 +73,7 @@ pub struct SqlxChildAttributes { pub try_from: Option, pub skip: bool, pub json: Option, + pub ordinal: Option, } pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result { @@ -150,6 +151,7 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result syn::Result()?; + let val: LitInt = meta.input.parse()?; + let ord = val.base10_parse::()?; + try_set!(ordinal, ord, val); } Ok(()) @@ -197,6 +204,7 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result)); + quote!(#ordinal) + } else { + quote!(#id_s) + }; + let expr: Expr = match (attributes.flatten, attributes.try_from, attributes.json) { // (false, None, None) => { @@ -137,7 +144,7 @@ fn expand_derive_from_row_struct( (false, Some(try_from), None) => { predicates .push(parse_quote!(#try_from: ::sqlx::decode::Decode<#lifetime, R::Database>)); - predicates.push(parse_quote!(#try_from: ::sqlx::types::Type)); + predicates.push(parse_quote!(#try_from: ::sqlx::types::Type)); parse_quote!( __row.try_get(#id_s) diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index 96687e3113..e31fb471e5 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -719,6 +719,38 @@ async fn test_flatten() -> anyhow::Result<()> { Ok(()) } +#[cfg(feature = "macros")] +#[sqlx_macros::test] +pub async fn test_ordinal() -> anyhow::Result<()> { + #[derive(Debug, sqlx::FromRow)] + struct AccountOrdinal { + #[sqlx(ordinal = 1)] + id: i32, + #[sqlx(ordinal = 0)] + name: String, + #[sqlx(ordinal = 3)] + balance: Option, + #[sqlx(ordinal = 2)] + active: bool, + } + + let mut conn = new::().await?; + + let account: AccountOrdinal = sqlx::query_as( + r#"SELECT * from (VALUES ('foo', 1, true, 10000)) accounts("col_0", "col_1", "col_2", "col_3")"#, + ) + .fetch_one(&mut conn) + .await?; + println!("{account:?}"); + + assert_eq!(1, account.id); + assert_eq!("foo", account.name); + assert_eq!(Some(10000), account.balance); + assert_eq!(true, account.active); + + Ok(()) +} + #[cfg(feature = "macros")] #[sqlx_macros::test] async fn test_skip() -> anyhow::Result<()> {