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
WIP: Code Generators #15
Conversation
This is now published as |
Usage example can be found in this branch. See |
For fragments, may I suggest that we generate them as a concrete class and then have any queries that use the fragment simply implement that class? That way the fragment class can be used independent of any particular query. For example, I have a music player app, and I want my player to interact with |
@klavs I just created a fragment builder that creates a single Let me know what you think. Next steps would be to: |
I just realized that my implementation above only works for the top level data class. However, consider a situation like this: fragment pokemonWeights on Pokemon {
weight {
id
minimum
}
}
query FindPokemon($name: String!) {
pokemon(name: $name) {
...pokemonWeights
weight {
minimum
maximum
}
height {
minimum
maximum
}
}
} In this case, not only should I'll dig into this a bit deeper. |
To me, practice of reusing fragments promotes and invites overfetching. But I might think about it that way because I use a certain flavour of apollo-inspired practices. It could be that there are other valid ways to think about it. @smkhalsa, could you adjust the |
@klavs, I've just added a flutter example to show how fragments could be used. Since fragments are all about code reuse, I felt an example using flutter would be more instructive. As you can see, both the Using a fragment, we can define all of the fields that
I hope this is clear. Please let me know your thoughts. |
@smkhalsa looks good and I would like to encourage you to continue exploring this. Besides some smaller things, I'm wondering would do nested and multiple levels deep fragments behave. |
I think the phase one could be to generate fragment classes separately and use them by passing data via the constructor instead of data classes implementing fragment classes. The reason for it is that from the standpoint of data classes, we have to consider anonymous fragments as well. Also anonymous classes are usually used with unions and interfaces, which are still not considered by the data classes. I'm still not sure how they impact the API. I'm hoping they could guide us in understanding what the API should be. |
@klavs great timing :) I just pushed an update that now adds fragment getters to data classes and also adds recursive fragment support. |
For inline fragments, since we don't know at build time whether the class is of the given type, I just add all inlined fields to the data class. (I still need to test this) I thought about creating a subclass for each concrete type used in the inline fragment, but I didn't really see the value in doing so (and it would add complexity). |
@klavs If you have time, I'd love to for you to test out any fragment corner cases. |
In order to take full advantage of the request builder and not have to manually instantiate the data class with the returned data, I'd like to recommend we add a parse function to the request class, similar to artemis. I've taken a first pass at this here. (see example) This is necessary for me to be able to incorporate the builders into the client I'm working on. There may be a better way to accomplish this. Please let me know your thoughts. |
@smkhalsa you can easily create a builder which gives you that kind of API. Currently: final result = await link
.request(
FindPokemon()..name = find,
)
.first;
final data = $FindPokemon(result.data);
final pokemon = data.pokemon; Proposed API: final result = await FindPokemon(
(b) => b..name = find,
).execute(link).first;
final pokemon = result.data.pokemon; Now I'm starting to think that instead of or in addition to a |
I've published these builders as 0.0.X version packages as part some of them are already useful. @smkhalsa please create PRs with your work on fragments and built request to discuss them separately. |
Extends the set of code builders available.
ast_builder
Generates an AST representation of a GraphQL Document
data_builder
Generates a typed view on top of
data
JSON. The generated classes are not supposed to be used directly as that would introduce tight coupling between your GraphQL documents and your application code.op_builder
Wraps AST and operation name into an
Operation
.req_builder
Extend
Request
class to use specificOperation
and provide ability to build variables. Builder pattern let's you handle nullable variables correctly (GraphQL spec pretty much requires bothundefined
andnull
values).enum_builder
Generates an enum-like class per GraphQL enum type. Defines known enum values to be used in your code, and allows unknown enum values to be used without causing runtime error when handling response data.
scalar_builder
Generates a container for a scalar value to be used when viewing the response data and building request variables.
input_builder
Generates an input builder to be used to build request variables.
schema_builder
Combines
enum_builder
,input_builder
andscalar_builder
.Usage example