Closed liontariai closed 2 months ago
Apparently it is valid GQL to use variables defined in the query/mutation in the fragment snippet: https://graphql.org/learn/queries/#using-variables-inside-fragments
Therefore the generated GraphQL code is valid and also with 6080e1a now supports automatically resolving conflicts, in case the fragment is used multiple times and the variable is set to different values for each fragment. In this case multiple fragments are needed, so that the right variable is referenced.
import unions, { ArticleSelection } from "./unions2";
function titleOnly(this: any, language?: string) {
return ArticleSelection.bind(this)((s) => ({
titleFromFragment: s.title,
books: s.books({
language,
})((s) => ({
...s.$scalars(),
})),
}));
}
const { op1 } = await unions((op) => ({
op1: op.query((s) => ({
b: s.books((s) => ({
title: s.title,
})),
a_DE: s.articles((s) => ({
...s.$fragment(titleOnly)("de"),
})),
a_EN: s.articles((s) => ({
...s.$fragment(titleOnly)("en"),
})),
all: s.search(({ $on }) => ({
...$on.Book((s) => ({
...s.$scalars(),
})),
...$on.Article((s) => ({
...s.$scalars(),
})),
})),
})),
}));
generates:
fragment titleOnly_language on Article {
titleFromFragment: title
books: books(language: $language) {
title
author
}
}
fragment titleOnly_language_1 on Article {
titleFromFragment: title
books: books(language: $language_1) {
title
author
}
}
query op1($language: String, $language_1: String) {
b: books {
title
}
a_DE: articles {
...titleOnly_language
}
a_EN: articles {
...titleOnly_language_1
}
all: search {
... on Book {
title
author
}
}
}
variables: {
language: "de",
language_1: "en"
}
and results in:
[
{
"titleFromFragment": "GraphQL is awesome",
"books": [
{
"title": "The Awakening (translated to de)",
"author": "Kate Chopin"
},
{
"title": "City of Glass (translated to de)",
"author": "Paul Auster"
}
]
},
{
"titleFromFragment": "REST is dead",
"books": [
{
"title": "The Awakening (translated to de)",
"author": "Kate Chopin"
},
{
"title": "City of Glass (translated to de)",
"author": "Paul Auster"
}
]
}
]
[
{
"titleFromFragment": "GraphQL is awesome",
"books": [
{
"title": "The Awakening",
"author": "Kate Chopin"
},
{
"title": "City of Glass",
"author": "Paul Auster"
}
]
},
{
"titleFromFragment": "REST is dead",
"books": [
{
"title": "The Awakening",
"author": "Kate Chopin"
},
{
"title": "City of Glass",
"author": "Paul Auster"
}
]
}
]
[
{
title: "The Awakening",
author: "Kate Chopin",
}, {
title: "City of Glass",
author: "Paul Auster",
}, {
title: "GraphQL is awesome",
publisher: "Apollo",
}, {
title: "REST is dead",
publisher: "Medium",
}
]
Therefore "Parameterized Fragments" (https://github.com/graphql/graphql-spec/issues/204) is correctly implemented with this PR
Example usage:
output:
Implicit Inline Fragments
The exported "*Selection" functions can be used as implicit inline fragments from anywhere. It can be used and constructed anywhere outside the operation and then object-spread into the selection. However, there is not typesafety for this right now. As one can see, the
ArticlesSelection
fragment also works on the Books type, because it also defines atitle
field.Explicitly defined query fragments
When used extensively in the Query, it may be useful to use real GraphQL fragments. This can be done using the
$fragment
helper selection function and a separately defined fragment function.function titleOnly
is such a function. Please note, that it is defined asfunction
and not anarrow function
, because it needs to have it's own scope withthis
. Also, you need to pass thethis
viabind
to the*Selection
function, so that it get's registered as named fragment later on.Possible Usages
Apart from these requirements, you can do whatever you want in your custom fragment functions, opening possibilities to conditional and parameterized fragments (similar to what is being discussed here: https://github.com/graphql/graphql-spec/issues/204 ) In case of named parameterized fragments, I have not yet tested what the generated query will look like when there're arguments in the selection. It should collect and hoist them to variables in the query but still reference them in the fragment. This might not be valid gql, but you can still use Implicit Inline Fragments, so you have the convenience of fragments being defined once as code and have them generate the wanted gql code based on your input.