Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions sqlx-macros-core/src/derives/attributes.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -73,6 +73,7 @@ pub struct SqlxChildAttributes {
pub try_from: Option<Type>,
pub skip: bool,
pub json: Option<JsonAttribute>,
pub ordinal: Option<usize>,
}

pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result<SqlxContainerAttributes> {
Expand Down Expand Up @@ -150,6 +151,7 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result<SqlxChildAttri
let mut flatten = false;
let mut skip: bool = false;
let mut json = None;
let mut ordinal = None;

for attr in input.iter().filter(|a| a.path().is_ident("sqlx")) {
attr.parse_nested_meta(|meta| {
Expand Down Expand Up @@ -177,6 +179,11 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result<SqlxChildAttri
} else {
json = Some(JsonAttribute::NonNullable);
}
} else if meta.path.is_ident("ordinal") {
meta.input.parse::<Token![=]>()?;
let val: LitInt = meta.input.parse()?;
let ord = val.base10_parse::<usize>()?;
try_set!(ordinal, ord, val);
}

Ok(())
Expand All @@ -197,6 +204,7 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result<SqlxChildAttri
try_from,
skip,
json,
ordinal,
})
}

Expand Down
9 changes: 8 additions & 1 deletion sqlx-macros-core/src/derives/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ fn expand_derive_from_row_struct(
}
};

let id_s = if let Some(ordinal) = attributes.ordinal {
predicates.push(parse_quote!(::std::primitive::usize: ::sqlx::ColumnIndex<R>));
quote!(#ordinal)
} else {
quote!(#id_s)
};

let expr: Expr = match (attributes.flatten, attributes.try_from, attributes.json) {
// <No attributes>
(false, None, None) => {
Expand Down Expand Up @@ -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<R::Database>));
predicates.push(parse_quote!(#try_from: ::sqlx::types::Type<R::Database>));

parse_quote!(
__row.try_get(#id_s)
Expand Down
32 changes: 32 additions & 0 deletions tests/postgres/derives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32>,
#[sqlx(ordinal = 2)]
active: bool,
}

let mut conn = new::<Postgres>().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<()> {
Expand Down