-
Notifications
You must be signed in to change notification settings - Fork 125
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
feat: allow distinguishing between null and absent values in gql_code_builder #381
Conversation
@knaeckeKami Thanks for working on this issue with literal null; what it's called in the GrapQL spec if I'm not mistaken (graphql/graphql-spec#83). How does one go about using these changes together with Ferry? |
Hi! ferry_generator internally uses gql_code_builder, so if you add dependency_overrides to use gql_code_builder from this commit, ferry_generator should pick it up. It's possible that there are small changes required in ferry_generator, similar to the ones in gql_build (I don't remember the current state of this PR exactly) note that I consider this as an experiment, which is untested and possibly incomplete |
@knaeckeKami Thanks! Unfortunately that seems to not work so I think you're right. Changes in I think it would make sense to have a branch for the ferry-specific changes required by this MR. |
pushed changes to feat/null-experiment, it builds with the test schema ferry-test-graphql2 |
@knaeckeKami Thanks so much! I must thank you and others for taking over as maintainers on this project! It really is very much appreciated! I'll try this out and report back! |
@knaeckeKami Sorry to bother you again! I can't seem to find the |
I think you need to add dependency_overrides like this: dependency_overrides:
gql_exec:
git:
url: https://github.com/gql-dart/gql.git
ref: feat/triStateNull
path: links/gql_exec
gql_code_builder:
git:
url: https://github.com/gql-dart/gql.git
ref: feat/triStateNull
path: codegen/gql_code_builder
ferry_generator:
url: https://github.com/gql-dart/ferry.git
ref: feat/null-experiment
path: packages/ferry_generator |
I have been looking at these warnings for quite some time and I simply cannot find the problem;
Nothing is generated. Which makes sense since it can't find the builders. I haven't changed anything else than the changes in the
Here's my
|
you need to depend on ferry_generator in your dev_dependencies to make the builder visible. you can check out the https://github.com/gql-dart/ferry/blob/feat/null-experiment/packages/ferry_test_graphql2/pubspec.yaml for an example |
This feature works as intended. I know we have missing/failed tests. One thing that strikes me is that |
Can you clarify? Fields should only be wrapped in Value when they are nullable. E.g. an input # The input object sent when someone is creating a new review
input ReviewInput {
# 0-5 stars
stars: Int!
# Comment about the movie, optional
commentary: String
# Favorite color, optional
favorite_color: ColorInput
# Date viewed
seenOn: [Date]
}
generates abstract class GReviewInput
implements Built<GReviewInput, GReviewInputBuilder> {
GReviewInput._();
factory GReviewInput([Function(GReviewInputBuilder b) updates]) =
_$GReviewInput;
int get stars; // non- nullable, so not wrapped
//rest of the fields are nullable, so they are wrapped
_i1.Value<String>? get commentary;
_i1.Value<GColorInput>? get favorite_color;
_i1.Value<BuiltList<DateTime?>>? get seenOn;
Map<String, dynamic> toJson() => (_i2.serializers.serializeWith(
GReviewInput.serializer,
this,
) as Map<String, dynamic>);
static GReviewInput? fromJson(Map<String, dynamic> json) =>
_i2.serializers.deserializeWith(
GReviewInput.serializer,
json,
);
@BuiltValueSerializer(custom: true, serializeNulls: true)
static Serializer<GReviewInput> get serializer => GReviewInputSerializer();
} I agree that this API is not pretty, but I did not come up with a better way yet. |
Scratch that! You're right! Agree that the API could be better. I'm wondering if it's better to create a custom serializer instead of using this draft API for now but it's very unfortunate as we will have to have many custom serializers. Another consequence of this
Because of the wrapper you now have to write something like if I'm not mistaken;
Another way of thinking about this is the suggestion you made yourself. Having the possiblity to set in the build configuration that you want to always serialize In my case that would actually work as we almost always specifically set all fields (from a previous query with the fields) when we do a mutations etc.. Again I'm sorry to take your time but I think this is an important feature that needs to work with Ferry. I am contemplating if I could contribute myself; but I'm not well-versed on the inner workings of Ferry currently. |
Yes, this can potentially be fixed by making Value itself an instance of Built, so the nested syntax works again.
I'm hesitant to add this, because this would basically break any "update" mutations. consider this schema: input editUserInput {
email: String
firstName: String
lastName: String
}
type Mutation {
updateUser(input: editUserInput): User
mutation UpdateUser($input: editUserInput){
updateUser(input: $input){
id
9
} when we set final req = GUpdateUserReq((b) => b..vars.email = "[email protected]"); it would set the firstname and lastname of the user to null. this would likely by highly unexpected by users.
Yes, I agree, and I would like to get to finish this feature, but it still needs some work (most importantly, to make this configurable so it's an opt-in feature in order to not break existing users, but also potentially making the API nicer if possible). I will probably not have time to get this done in the next few weeks. |
Yes that is certainly true! I think it still has its merits as an opt-in configuration with an appropiate disclaimer of sorts. Today I had a look around the Thanks for the discussion and help! |
@knaeckeKami I have pushed changes to ferry_generator and gql_code_builder that support the new Here are the pull requests; As I said this So where do we go from here? Do you agree on having this opt-in feature? What are your thoughts? |
6f3e0e5
to
46a5407
Compare
dfeec06
to
9458373
Compare
9458373
to
0981246
Compare
… to end test with tri state null
0981246
to
e4d2024
Compare
I finally got around to finishing this feature and adding tests. @twklessor sorry for the late response. I think that a And, to be honest, I don't want to maintain an additional mode of code generation which increases to complexity of adding new features and adds more surface for bugs. |
Hi @knaeckeKami, could you please provide some examples of how to use the tristate option? Our backend needs to distinguish between null and absent, and I'm having difficulty achieving that. I have the latest version of the ferry package and have added |
this is an attempt to solve issues like gql-dart/ferry#473 gql-dart/ferry#474 and gql-dart/ferry#219 . also related: google/built_value.dart#1123
It requires wrapping all nullable inputs and variables in a "Value" class so we make it explicit wether a field is explicitly set to null or just absent.
Then we generate a custom serializer for each input/var class that distinguish between a
Value
field that is null (will be absent in the json), is set toValue(null)
(the key will be present in the json but the value will benull
) or a present, non-null value likeValue('Hello World')
which will be serialized as String.Most of the new logic here atm: https://github.com/gql-dart/gql/pull/381/files#diff-b581f94cad07799afdef5d265482e91644e305579526f4276d9d5388faf4c40d