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 UnexpectedNullError when deserializing (NULL,NotNull) into Option #2275

Closed

Conversation

Ten0
Copy link
Member

@Ten0 Ten0 commented Jan 22, 2020

Resolves #2274

I'm not sure if this was originally a bug or not, but in any case as described on the issue, often the NotNull field (say, zzz::some_nullable_thing.is_not_null()) doesn't have any meaning if we couldn't left_join on the zzz table and select the NULL field (say, zzz::id).

This is why I'm very happy to not have access to the second field if the first field is NULL.

However I can't think of a scenario where I'd prefer a runtime error: cases where I could unintentionally "forget" a field should be covered by the typing after the query: "Why can't I get the value of this field? Oh it's because it was packed in this Option...)

This is why I beleive that this behaviour that ends up giving Ok(None) instead of Err(DeserializationError(UnexpectedNullError)) is better.

Accorging to the tests this implementation seems to work properly, though I'm not sure why recovering from the error skips the proper amount of fields... Can anyone confirm that (and why) this indeed behaves as expected ? :)
EDIT: This indeed did not skip the proper amount of fields, and is now fixed.

Also open to any comments :)

@Ten0 Ten0 force-pushed the 2274_deserialize-null-and-not-null-in-option branch from 210974c to ea89edb Compare January 22, 2020 16:23
@weiznich weiznich requested a review from a team January 23, 2020 09:53
@weiznich weiznich force-pushed the 2274_deserialize-null-and-not-null-in-option branch from ea89edb to d5b6e2f Compare January 24, 2020 10:20
@weiznich
Copy link
Member

Could you add a testcase that would trigger the bad behaviour to the test suite? Otherwise this looks fine 👍

@Ten0 Ten0 force-pushed the 2274_deserialize-null-and-not-null-in-option branch 2 times, most recently from d519fc7 to 1a08162 Compare February 17, 2020 17:29
@Ten0 Ten0 force-pushed the 2274_deserialize-null-and-not-null-in-option branch from 1a08162 to f00c46e Compare February 17, 2020 17:36
@Ten0
Copy link
Member Author

Ten0 commented Feb 21, 2020

Hello,

I've added the test case (it indeed did not work where I expected it to not work) and fixed it :)

Comments (or merge ^^) welcome. :)

///
/// May be used to skip the right number of fields when recovering for an `UnexpectedNullError` when
/// deserializing an `Option`
fn column_index(&self) -> usize;
Copy link
Member

Choose a reason for hiding this comment

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

As this is a public API I would prefer not to add this method here, because it only has an internal meaning. That said I'm not sure what would be the right approach here.

Copy link
Member Author

Choose a reason for hiding this comment

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

If Row has to be public for others to be able to connect new backends I feel like this is close to being the only alternative. Another way I see would be to make sure that when the error is thrown all the fields have been consumed, but that is useless for every other error case and that possibly means a lot of places where we would have to take care of this and possibly make a mistake (enums, structs with Queryable derive,...) .

Given the other functions that this trait requires, this one doesn't seem too absurd to me, especially since the field is already required by most impls.

Copy link
Member Author

Choose a reason for hiding this comment

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

Since it is consistent with advance, the meaning is not only internal.

Copy link
Member

@weiznich weiznich Apr 1, 2020

Choose a reason for hiding this comment

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

I've not forgot this issue, it should definitively be fixed with the diesel 2.0 release, so I've added it the the corresponding mile stone. That said, unfortunately I was pretty occupied with other things in the last time, so I had not really the bandwidth to think much about that. It will be done, but takes probably some time.

@Ten0
Copy link
Member Author

Ten0 commented Mar 2, 2020

Hello,

I keep hitting this as a runtime error regularly, and code that makes requests work is far from being as clear as the one this PR enables.

I understand this changes the API a bit so it requires a thorough examination.
Is there anything I can do to help this advance or should we just wait until more reviewers happen to pass by ?

@weiznich
Copy link
Member

weiznich commented Mar 2, 2020

I have currently rather limited bandwidth, so I was not able to think about a better API yet, so this needs to wait till I find some time or any of the other reviewers comments. In general we should try to unify the change to the Row trait with that one done in #2181

@weiznich weiznich added this to the 2.0 milestone Apr 1, 2020
@Ten0
Copy link
Member Author

Ten0 commented Jun 2, 2020

Hello,

Just an up, as I keep hitting this error/having to write and maintain intermediate structures when fetching from the database due to this, and would really benefit from this moving forward.

@weiznich
Copy link
Member

weiznich commented Jun 2, 2020

There has nothing changed from my side. I do currently not have the bandwidth to work on so much things in parallel due to my real life engagements, a fix for this is scheduled to be included in a 2.0 release (I see it as blocker for 2.0) and I want to see some experimentation about how to unify that with the changes required in #2182 (Especially about how it interacts with FIELDS_NEEDED for dynamic clauses where this is not a static member and how that could be integrated into each other)

EDIT: To add something that is actually actionable for others here: I someone has the time to figure out how to make this interact in a nice way with the changes in #2182 I can try to find some time to review such a change. For a backport to the 1.4.x branch I would require a non-breaking way to implement this change. Adding a non-default method to Row is a breaking change.

@Ten0
Copy link
Member Author

Ten0 commented Jul 11, 2020

This is eventually being solved in #2182 and there's probably a problem in the implementation of this PR that triggers when nullable booleans come into play (due to #104).
=> closing

@Ten0 Ten0 closed this Jul 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

UnexpectedNullError when deserializing (Null,Boolean,Boolean) into Option<(a,b,c)>
2 participants