-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Selectable derive breaks embedded optional fields #3173
Comments
This is a tricky one. It seems like the behaviour described in that issue should work out of the box, but it doesn't. I've spend some time to investigate various solutions to make this work, but I came to the conclusion that the current behaviour is the correct one. The underlying issue here is that such an query promotes the inner `Nullable<_>` of the field onto the outer `Queryable` wrapper. Without `Selectable` that would require a select clause like `.select((table::column.assume_not_null(),).nullable())`. This is technically a safe pattern, but requires the usage of the "advanced" `assume_not_null()` method to forcibly convert types to their not null representation. Possible solutions tried to make the enable constructs shown in that issue: * I've tried to make the `impl Selectable for Option<T>` return the following `SelectExpression`: `dsl::Nullable<dsl::AssumeNotNull<T::SelectExpression>>` where `AssumeNotNull` converts each tuple element to the corresponding not nullable expression, while `Nullable` wraps the tuple itself into a nullable type wrapper. * I've tried to apply a similar approach like that one above, but only for derived impls by manipulating the generated code for a optional field with `#[diesel(embed)]` Both solutions require changes to our sql type system, as for example allowing to load a non nullable value into a `Option<T>` to enable their usage in a more general scope as the presented example case. (See the added test cases for this). That by itself would be fine in my opinion, as this is always a safe operation. Unfortunately the `AssumeNotNull` transformation would be applied recursively for all sub-tuples, which in turn would cause trouble with nested joins (again see the examples). We would be able to workaround this issue by allowing the `FromSql<ST, DB> for Option<T>` impl for non-nullable types to catch null values, which in turn really feels like a bad hack. (You would like to get an error there instead, but nested nullable information are gone.) All in all this lead me to the conclusion that the current behaviour is correct. This PR adds a few additional tests (an adjusted version of the test from the bug report + more tests around nested joins) and does move around some code bits that I noticed while working on this. I think the official answer for the bug report would be: Either wrap the inner type also in an `Option` or provide a manual `Selectable` impl that does the "right" thing there.
Thanks for this bug report. I spend some time to investigate this. See #3181 for more details. Closed as not a bug. |
This is a tricky one. It seems like the behaviour described in that issue should work out of the box, but it doesn't. I've spend some time to investigate various solutions to make this work, but I came to the conclusion that the current behaviour is the correct one. The underlying issue here is that such an query promotes the inner `Nullable<_>` of the field onto the outer `Queryable` wrapper. Without `Selectable` that would require a select clause like `.select((table::column.assume_not_null(),).nullable())`. This is technically a safe pattern, but requires the usage of the "advanced" `assume_not_null()` method to forcibly convert types to their not null representation. Possible solutions tried to make the enable constructs shown in that issue: * I've tried to make the `impl Selectable for Option<T>` return the following `SelectExpression`: `dsl::Nullable<dsl::AssumeNotNull<T::SelectExpression>>` where `AssumeNotNull` converts each tuple element to the corresponding not nullable expression, while `Nullable` wraps the tuple itself into a nullable type wrapper. * I've tried to apply a similar approach like that one above, but only for derived impls by manipulating the generated code for a optional field with `#[diesel(embed)]` Both solutions require changes to our sql type system, as for example allowing to load a non nullable value into a `Option<T>` to enable their usage in a more general scope as the presented example case. (See the added test cases for this). That by itself would be fine in my opinion, as this is always a safe operation. Unfortunately the `AssumeNotNull` transformation would be applied recursively for all sub-tuples, which in turn would cause trouble with nested joins (again see the examples). We would be able to workaround this issue by allowing the `FromSql<ST, DB> for Option<T>` impl for non-nullable types to catch null values, which in turn really feels like a bad hack. (You would like to get an error there instead, but nested nullable information are gone.) All in all this lead me to the conclusion that the current behaviour is correct. This PR adds a few additional tests (an adjusted version of the test from the bug report + more tests around nested joins) and does move around some code bits that I noticed while working on this. I think the official answer for the bug report would be: Either wrap the inner type also in an `Option` or provide a manual `Selectable` impl that does the "right" thing there.
Setup
Versions
Feature Flags
Problem Description
For a struct with an embedded optional struct the
Selectable
derive doesn't work correctly and, therefore, the compilation fails.There is an unit test that tests exactly this scenario but the underlying diesel schema definition mistakenly is lacking the
Nullable
wrapper for the optional field.What are you trying to accomplish?
Compile the code without errors.
What is the expected output?
Successful compilation.
What is the actual output?
For more information about this error, try
rustc --explain E0277
.error: could not compile
diesel_derives
due to previous errorAre you seeing any additional errors?
No.
Steps to reproduce
Add the following schema definition
and patch this test to use
my_structs_nullable
instead.Checklist
closed if this is not the case)
The text was updated successfully, but these errors were encountered: