Skip to content

Support ArgumentValue wrapper for input parameters #1450

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

Merged
merged 18 commits into from
Feb 24, 2024

Conversation

rwo-trackunit
Copy link
Contributor

@rwo-trackunit rwo-trackunit commented Jan 16, 2024


Description

When updating an object we want to support patch-like procedure:

  • If value is not send, do not change the value
  • If value is null set the value to null
  • If value is set, set that value

In #966 it was debated if we could use Optional to solve this, ultimately concluding that it would not be appropriate.

Java 8's Optional was mainly intended for return values from methods, and not for properties of Java classes, as described in Optional in Java SE 8

This PR tries to solve it by using the existing ArgumentValue wrapper for input parameters, when that input is not mandatory and is not a list.

Example:

input PersonLocationInput {
    location: CoordinatesInput!
    age: Float
    name: String = null
    description: String = "a very good desc"
}

becomes

public class PersonLocationInput {
    private CoordinatesInput location;
    private ArgumentValue<Double> age = ArgumentValue.omitted();
    private ArgumentValue<String> name = ArgumentValue.ofNullable(null);
    private ArgumentValue<String> description = ArgumentValue.ofNullable("a very good desc");
    
    ...

This works because ArgumentValue (just like Optional) is supported by spring-graphql GraphQlArgumentBinder
It is all locked behind the configuration useWrapperForNullableInputTypes.

TODO:

As I have no experience with Kotlin or Scala, this currently only works for Java.


Changes were made to:

  • Codegen library - Java
  • Codegen library - Kotlin
  • Codegen library - Scala

@jxnu-liguobin
Copy link
Collaborator

The optional specification of Java SE8 is not applicable to scala and kotlin. In the functional programming, the data class has accurately described the data type. Therefore, I think only Java needs it.

@rwo-trackunit
Copy link
Contributor Author

rwo-trackunit commented Jan 16, 2024

I could also use some suggestions on naming: undefined smells a bit like Javascript.

@jxnu-liguobin
Copy link
Collaborator

I could also use some suggestions on naming: undefined smells a bit like Javascript.

Maybe we don't need it, only isDefined is needed.

@rwo-trackunit
Copy link
Contributor Author

rwo-trackunit commented Jan 16, 2024

I could also use some suggestions on naming: undefined smells a bit like Javascript.

Maybe we don't need it, only isDefined is needed.

Yea, I should only have one of Defined/Undefined. Maybe we should adopt the Optional.isPresent() naming. And .get and .orElse Although I'm keen to show this is not just a homemade Optional.
Why is naming always the hardest part of coding?

@jxnu-liguobin
Copy link
Collaborator

I could also use some suggestions on naming: undefined smells a bit like Javascript.

Maybe we don't need it, only isDefined is needed.

Yea, I should only have one of Defined/Undefined. Maybe we should adopt the Optional.isPresent() naming. And .get and .orElse Although I'm keen to show this is not just a homemade Optional. Why is naming always the hardest part of coding?

People from different languages and backgrounds have different norms. 😄

@jxnu-liguobin
Copy link
Collaborator

It looks good, just describe the option in the markdown document and wait for @kobylynskyi review.

@rwo-trackunit
Copy link
Contributor Author

rwo-trackunit commented Jan 17, 2024

After some feedback, this has been rewritten to use ArgumentValue, rather than generating its own class that solves the same problem.

Which also solves the naming problem, by adopting someone elses.

@lilianchiassai
Copy link

Thanks for the PR. If projects are not based on spring-graphql, it might be valuable to let the wrapper type up to the user, like this:
<useWrapperForNullableInputTypes>org.springframework.graphql.data.ArgumentValue</useWrapperForNullableInputTypes>
<useWrapperForNullableInputTypes>java.util.Optional</useWrapperForNullableInputTypes>
<useWrapperForNullableInputTypes>custom.example.Undefined</useWrapperForNullableInputTypes>

@rwo-trackunit
Copy link
Contributor Author

Thanks for the PR. If projects are not based on spring-graphql, it might be valuable to let the wrapper type up to the user, like this: <useWrapperForNullableInputTypes>org.springframework.graphql.data.ArgumentValue</useWrapperForNullableInputTypes> <useWrapperForNullableInputTypes>java.util.Optional</useWrapperForNullableInputTypes> <useWrapperForNullableInputTypes>custom.example.Undefined</useWrapperForNullableInputTypes>

I thought about that, and even have had it compatible with Optional at an earlier point in the PoC.
But to support default values, each wrapper type requires 3 string replacement strings to support fx. ArgumentValue.omitted() vs Optional.empty(). Adding that in config quickly becomes very messy.

Alternative solution would be an interface, but ArgumentValue doesn't extend one.

Last good idea is a factory, that is default provided supporting ArgumentValue, but could be replaced with a custom factory.
That could work in general, but could never work with spring-graphql, since GraphQlArgumentBinder only supports Optional and ArgumentValue wrappers.

Other alternative solution would be a custom object provided by this project, but that doesn't support spring-graphql for the same reason.

If there is further request for some solution to support more wrappers (be it the factory or some other good idea), I'm happy to code it up. But I feel this PR is big enough.

Copy link
Owner

@kobylynskyi kobylynskyi left a comment

Choose a reason for hiding this comment

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

@rwo-trackunit good job! Your changes look good. I will merge this soon, wait for some other PRs to be merged and release it ASAP.
Thanks!

@kobylynskyi kobylynskyi changed the title Support undefined input parameter Support ArgumentValue wrapper for input parameters Feb 1, 2024
@kobylynskyi kobylynskyi added this to the 5.10.0 milestone Feb 1, 2024
@rwo-trackunit
Copy link
Contributor Author

Once merged, don't hesitate to tag me in any found bugs, or suggested changes to this corner of the project.

@rwo-trackunit
Copy link
Contributor Author

Consider squashing this PR. The commits in here includes several PoCs, so it may give a confusing git history.

@kobylynskyi kobylynskyi merged commit 3ac1021 into kobylynskyi:main Feb 24, 2024
@kobylynskyi kobylynskyi added the enhancement New feature or request label Feb 24, 2024
@kobylynskyi
Copy link
Owner

This was released in 5.10.0. Thanks!

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

Successfully merging this pull request may close these issues.

4 participants