-
Notifications
You must be signed in to change notification settings - Fork 54
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
adds decoder support to fragment definition #80
adds decoder support to fragment definition #80
Conversation
let with_decoder = | ||
switch (fg_directives |> find_directive("bsDecoder")) { | ||
| None => Ok(None) | ||
| Some({item: {d_arguments, _}, span}) => | ||
switch (find_argument("fn", d_arguments)) { | ||
| None => | ||
Error( | ||
make_error( | ||
error_marker, | ||
config.map_loc, | ||
span, | ||
"bsDecoder must be given 'fn' argument", | ||
), | ||
) | ||
| Some((_, {item: Iv_string(fn_name), span})) => | ||
Ok( | ||
Some( | ||
structure => | ||
Res_custom_decoder( | ||
config.map_loc(span), | ||
fn_name, | ||
structure, | ||
), | ||
), | ||
) | ||
| Some((_, {span, _})) => | ||
Error( | ||
make_error( | ||
error_marker, | ||
config.map_loc, | ||
span, | ||
"The 'fn' argument must be a string", | ||
), | ||
) | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should in principle be no problems abstracting this out and using it for fields, fragments and operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with leaving it as is. A lot will change with #67 and we'll have to do major code cleanup after that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
switch (with_decoder) { | ||
| Error(err) => Mod_fragment(fg_name.item, [], true, fg, err) | ||
| Ok(decoder) => | ||
Mod_fragment( | ||
fg_name.item, | ||
[], | ||
error_marker.has_error, | ||
fg, | ||
switch (decoder) { | ||
| Some(decoder) => decoder(structure) | ||
| None => structure | ||
}, | ||
) | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a couple of different ways of doing this, but to me this seemed the most legible to newcomers to the library.
Do I understand correctly this adds a decoder on the fragment spread? Why would you want to do that? You can add decoders on fields in fragments right? (or did that not work correctly and are you fixing that?). It would be great btw if you can look into doing this PR on top of the records PR (#67). Because a lot of the code has changed, so it would bet tricky to merge this in later. |
I named the PR poorly. It's for adding a decoder to a fragment definition.
You can add decoders on fields. Decoders on spreads (with or without
is equivalent to
That should probably also be fixed, but this PR a'int for that.
(I'm here answering the question assuming it's about decoders on fragment definitions.) A couple of reasons. Firstly, I just think it should be possible to add
gives an error message: (You're working on introducing records (which is great BTW!), so this exact point won't be relevant for long. My thoughts on Anyway... I can add
and I have to worry about whether A concrete use case from the app I'm currently working on (the one I also talked about in #20) is that we have a price concept. A price can be either a definite price or a price range. We're defining a module as follows:
In every query or other fragment that wants to use Price, we have to expose the inner workings of the price module so that the decoder can be added there. Having the fragment know how to decode itself is really powerful. It's also convenient: If there's one query that uses the fragment with an optional field and another that uses it with a list these would have the correct types already. As it is now, each of those queries have to get the
You might be right. I am worried however, by how long it'll take take to finish #67. This feature would be really useful to have in a minor version (for me at least). Unlike #67 it's non-breaking. I'd rather have this merged and released, maybe just as a release candidate, instead waiting for the records rewrite to be finished (even if it just takes another couple of weeks). I'd be happy to re-implement this once #67 has been finished and merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let with_decoder = | ||
switch (fg_directives |> find_directive("bsDecoder")) { | ||
| None => Ok(None) | ||
| Some({item: {d_arguments, _}, span}) => | ||
switch (find_argument("fn", d_arguments)) { | ||
| None => | ||
Error( | ||
make_error( | ||
error_marker, | ||
config.map_loc, | ||
span, | ||
"bsDecoder must be given 'fn' argument", | ||
), | ||
) | ||
| Some((_, {item: Iv_string(fn_name), span})) => | ||
Ok( | ||
Some( | ||
structure => | ||
Res_custom_decoder( | ||
config.map_loc(span), | ||
fn_name, | ||
structure, | ||
), | ||
), | ||
) | ||
| Some((_, {span, _})) => | ||
Error( | ||
make_error( | ||
error_marker, | ||
config.map_loc, | ||
span, | ||
"The 'fn' argument must be a string", | ||
), | ||
) | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with leaving it as is. A lot will change with #67 and we'll have to do major code cleanup after that.
@jfrolich It's much better to have automated steps for converting GraphQL raw data into business logic types. In my example, I'm using ID module which hides internal |
Interesting... You example helped 😁 I think this would be pretty nice but wouldn’t it be better to collocate this with the fragment instead of where the fragment is being spread? |
I think having it on the fragment is much better because you're just using the fragment and interact with it via public API of the |
Basically adding the decoder to the fragment definition. This means that it always has the same fields, and where the fragment is used, it is decoded automatically. |
Lol sorry I am on my phone and looking at the other example. I see that it is on the fragment definition. That sound great. Forget my previous comments :) |
LGTM 🎉 |
This adds support for
@bsDecoder
on fragments + tests. Previously you could add@bsDecoder(fn: "some_decoder")
, but it would be removed from the printed query and have no effect.@baransu We talked about this over in #20.
This PR fixes that.
AFAICT there shouldn't be a problem with adding decoder support to queries as well, but I'm new here so might not know what I'm talking about.