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

Optional nested beans support for join results #94

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

hpgliniecki
Copy link

@hpgliniecki hpgliniecki commented Jun 2, 2023

Description

The proposed feature deals with deserialisation of optional nested beans, which is required when dealing with a result of a LEFT JOIN and view beans.

The Problem

Let's suppose we've got two tables for Foo and Bar objects namely foos and bars, we'd like to fetch a view object FooBar which is a result of a:

select foo.foo_prop, bar.bar_prop_one, bar.bar_prop_two FROM foo LEFT JOIN bar on foo.bar_id = bar.id;

while the bean itself has the following structure:

class FooBar {
  Foo getFoo(); // some Foo property
  Optional<Bar> getBar();
}

Naturally, we might not find some Bars however the result of the query will be a json of the form:

{
  "foo": {
    "foo_prop": "someValue"
  },
  "bar": {
    "bar_prop_one": null,
    "bar_prop_two": null
  },
  (...) // other fields
}

which will result in a deserialisation error of the Optional<Bar> as for it to work correctly it would need to get either null or no bar at all.

Currently, we would need to use an intermediate structure to fetch the results, including an 'all Optional' version of Bar:

class BarRow {
  Optional<String> getBarPropOne();
  Optional<String> getBarPropTwo();
}

which for more verbose objects may be cumbersome.

Proposed Solution

This PR introduces the NestedOptionalDeserializer<> which checks whether all fields are null and if it is the case, provides an empty Optional<> as a result, so that intermediate structures are no longer necessary.

In other words, the deserializer will treat:

{
  "foo": {
    "foo_prop": "someValue"
  },
  "bar": {
    "bar_prop_one": null,
    "bar_prop_two": null
  }
}

as if the following has been given for deserialization:

{
  "foo": {
    "foo_prop": "someValue"
  },
  "bar": null,
}

iff all of the bar properties are null and the bar field is marked with the @NestedOptional annotation.

The annotation is introduced so that Rosetta can recognise that the above rule should be applied, providing a simple way to control this behavior.

WIP

Please note, this PR is only a bare minimum to illustrate the issue and a possible solution, so the tests and the naming are likely to change - also, additional effort will be put forward to check the performance of the changes if the proposal is accepted.

@hpgliniecki hpgliniecki requested a review from jhaber June 2, 2023 09:15
Copy link
Contributor

@jaredstehler jaredstehler left a comment

Choose a reason for hiding this comment

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

would be nice if you could add a test in the jdbi3 package showing this with an actual left join?

@stevie400
Copy link
Contributor

I agree, without a test case I think it's hard to see the utility here.

@hpgliniecki
Copy link
Author

I've provided two test cases:

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.

3 participants