Make BoolExpressionMethods not always return a Nullable<bool>#2597
Make BoolExpressionMethods not always return a Nullable<bool>#2597weiznich merged 12 commits intodiesel-rs:masterfrom
Conversation
- Fix corresponding usages in diesel - Fix test Note: tests do not pass atm due to a massive arrival of `Cannot infer type` errors.
to allow compiler to always infer ST when using `.and` or `.or`
pksunkara
left a comment
There was a problem hiding this comment.
I might be misunderstanding something, but don't we need to revert the following?
- File 7ff5e63#diff-cb055b4bb9e7efa6083a07a27019f0d52abeedb051162b636867fe309730d854
- Line 7ff5e63#diff-354105a6b67774b9eeb51dd06d81db7a1b30232369b26c872385803da0f7698eR449
Otherwise looks good.
|
I am still having trouble using this PR. If there's a column |
In SQL, if one of the values of an operator such as Consequently, the behavior you're looking for should be achieved by using an SQL operator that has this behavior internally to your database, e.g. Note: it looks like as declared in Diesel, this one does not know it can never return null regardless of whether the input values are NULL: diesel/diesel/src/expression/operators.rs Lines 229 to 237 in 06494e8 That would be a separate issue to solve. |
But we are not doing I understand |
Thats not correct. |
I meant |
(somewhat unrelated fix)
weiznich
left a comment
There was a problem hiding this comment.
Looks good but we should talk about that minor nit regarding to the not function.
diesel/src/expression/not.rs
Outdated
| pub fn not<T>(expr: T) -> not<T> | ||
| where | ||
| T: AsExpression<Nullable<Bool>>, | ||
| T: AsExpression<Bool>, |
There was a problem hiding this comment.
I'm not sure if that should only accept non nullable values. I think accepting both Bool and Nullable<Bool> here is more meaningful. On the other hand that could potentially lead to situations where rustc cannot infer the correct type for ST from AsExpression here.
There was a problem hiding this comment.
Hmm that looks like kind of the same problem as and/or no? Where if we enforce that it takes an AsExpression<Nullable<Bool>> we'll never be able to make it return a non-nullable bool?
Additionally, not all expressions of SqlType Bool implement AsExpression<Nullable<Bool>> anymore, because otherwise this creates type inference issues with and/or: #2597 (comment)
Hence the following does not compile anymore if we do this: not(name.eq("Sean") (from tests)
Finally, I believe the behavior of not on Nullable<Bool> is a bit of a trap in that NULL values result in NULL, so they do not change "truthiness" with regards to e.g. a filter, which may lead to nasty bugs in case this kind of confusion is made and the compiler does not prevent it.
So overall I believe we should keep this behavior where we only accept non-nullable values here.
There was a problem hiding this comment.
I think accepting both Bool and Nullable
I had encountered a situation where I want to store the same. Is there a way we can specify that?
There was a problem hiding this comment.
We must accept both variants (Bool and Nullable<Bool>) here otherwise it's not possible to write queries like not(foo.and(bar)) or even not(foo.eq(bar)) anymore in cases one of the arguments is Nullable<Bool>
Edit: @pksunkara Seems like you've added your comment while I typed mine. Yes we need this method to automatically accept both variants, otherwise we would restrict quite a lot of possible queries using not.
There was a problem hiding this comment.
I had encountered a situation where I want to store the same
Not sure what you mean by "the same".
We must accept both variants (
BoolandNullable<Bool>) here otherwise it's not possible to write queries likenot(foo.and(bar))or evennot(foo.eq(bar))anymore in cases one of the arguments isNullable<Bool>
So I thought it maybe wasn't a good idea to have not support this implicitly, as this may easily lead to nasty bugs:
I believe the behavior of
notonNullable<Bool>is a bit of a trap in thatNULLvalues result inNULL, so they do not change "truthiness" with regards to e.g. afilter, which may lead to nasty bugs in case this kind of confusion is made and the compiler does not prevent it.
Example:
table.filter(not(foo.eq(bar)))Where foo = true and bar = NULL, the lines won't show, because not won't change the "truthiness" of the expression, which is a bit counter-intuitive.
Also, our codebase is rather large and we have zero such patterns.
Given that, do you still believe it's important for not to support this? (and we couldn't be happy with a separate nullable_not?)
There was a problem hiding this comment.
I still believe that not should support that as this is just the behavior of the underlying SQL operator. I feel that we had this discussion already about a few operators (for example eq in another context). Every time the final answer was: We follow the semantic of the underlying SQL operator as we do not try to hide complexity at this level of abstraction. Hiding this complexity can be done in a crate build on top of diesel, providing it owns set of operators that is not based on SQL in my opinion.
expression - make `not` work with both `Bool` and `Nullable<Bool>`
9319d74 to
4847044
Compare
Fixes #2589
With new ideas from #2589 and specifically #2589 (comment), it turns out we can solve the issue encountered when writing 7ff5e63 of "not all methods had an equivalent type in
diesel::dsl" in a simpler way, without making "BoolExpressionMethods::and(andor) unconditonally nullable" nor being a breaking change in most places.As a consequence, this mostly reverts the part of 7ff5e63 that was focusing on this change, while introducing typing suggested in #2589 (comment), reducing a bit the overall amount of code.