Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Decode and Encode derives (#1031) #2940

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

benluelo
Copy link

Reopening #2329

@asteinba
Copy link

asteinba commented Jan 7, 2024

Hey @benluelo,

seems like some checks failed because there is a unused import which is treated as an error. Can you fix that? I would love to see this merged as this issue bugs me since a while.

Happy to help out as well :)

@abonander
Copy link
Collaborator

It's fixed in main, it just needs rebased.

@asteinba
Copy link

asteinba commented Jan 8, 2024

I opened up a PR to your branch with the rebase on main :)

@asteinba
Copy link

asteinba commented Jan 9, 2024

@abonander FYI: Rebase is merged, checks are green :).

@asteinba
Copy link

@abonander Can you merge this :)?

@asteinba
Copy link

asteinba commented Feb 5, 2024

Don't want to bother but I would really love to see this merged :) Anything that is missing that I can assist with?

@asteinba
Copy link

@abonander last try before I stop bothering you: Is there anything missing or anything I can help with to get this merged? I would not like to see the PR dying again as @benluelo already reopened that and the value that this PR adds is huge (at least for me, I ran into this "bug" multiple times).

@jelacious
Copy link

I am going to second that this is a fairly huge PR in terms of usability and would like to see this merged.

Furthermore, the lack of response for a month for such a big project is concerning.

@benluelo
Copy link
Author

benluelo commented Mar 3, 2024

@abonander any update?

@abonander
Copy link
Collaborator

Strictly speaking, this appears to be a potential breaking change as discussed by @jplatte in #1031 (comment) because it changes lifetime obligations for field types:

If I understand correctly, the previous bounds would potentially allow, e.g. a type that only implemented Decode<'static, Postgres> to be used as it would bubble up the obligation to the derived impl. But after the change, it would require all fields to implement for<'decode> Decode<'decode, Postgres>, either implicitly (by invoking Decode::decode()) or explicitly (on generics).

Would this realistically affect anybody in practice? It seems unlikely, but unless we're confident that this is not a breaking change because code relying on the previous behavior wouldn't have compiled anyways, then it has to wait for 0.8.0.

Copy link
Collaborator

@abonander abonander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also like to see a regression test that can be demonstrated to be fixed by this.

@jplatte
Copy link
Contributor

jplatte commented Mar 5, 2024

Actually no, I wasn't talking about lifetimes. I was talking about something like this:

#[derive(sqlx::Encode)]
struct Foo<T> {
    field: sqlx::types::Json<T>,
}

which currently works because it generates a sqlx::types::Json<T>: sqlx::Encode bound but will fail with this PR because it generates T: sqlx::Encode when actually T: serde::Serialize is required.

This is an actual regression in functionality, but IMO warranted because otherwise private field types leak into the public trait implementation. It's also how virtually all other derives work. See also serde(bound), which is serde's solution for this that does not implicitly leak private implementation details.

@abonander
Copy link
Collaborator

That is a much better point than I was trying to make. Adding a #[sqlx(bound)] sounds like a good idea.

@abonander
Copy link
Collaborator

@benluelo we are now merging breaking changes, so if you could rebase and fix the conflict that'd be great.

@benluelo
Copy link
Author

squashed and rebased, should be good to go (barring any issues I missed post-rebase)

// add db type for impl generics & where clause
for type_param in &mut generics.type_params_mut() {
type_param.bounds.extend::<[TypeParamBound; 2]>([
parse_quote!(for<'decode> ::sqlx::decode::Decode<'decode, ::sqlx::Postgres>),
Copy link
Contributor

@jplatte jplatte Mar 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this now a higher-order bound instead of Decode<'r, _> like before?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

honestly, i wrote this so long ago, i don't recall any of the reasoning behind my changes. happy to change this though

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it works, I think 'r without the for<> makes more sense. If not, I'd be curious why.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may have been to get around an "implementation is not general enough" error. People complain about those from time to time.

This change is what I was thinking about in this comment BTW #2940

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which "this comment"? GitHub doesn't highlight anything for me when clicking that link.

And I'm pretty sure the for<'decode> makes the impl less general and can't possibly fix any errors.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment I @-mention'd you in above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, so you agree with keeping the 'r if possible, right?

}

let (impl_generics, _, where_clause) = generics.split_for_impl();
generics.params.push(parse_quote!('r));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what the idea behind this is (I know it existed before already).

// add db type for impl generics & where clause
for type_param in &mut generics.type_params_mut() {
type_param.bounds.extend::<[TypeParamBound; 2]>([
parse_quote!(for<'encode> ::sqlx::encode::Encode<'encode, ::sqlx::Postgres>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

}

let (impl_generics, _, where_clause) = generics.split_for_impl();
generics.params.push(parse_quote!('q));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@joelawm
Copy link

joelawm commented May 3, 2024

Is there a update to this as this is a blocking issue for a lot of people that want to use composite types in postgres that have null values. If there is anything I can do to help let me know. @abonander

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants