-
Notifications
You must be signed in to change notification settings - Fork 178
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
Is it possible to use graphql-tag to combine two predefined queries? #169
Comments
@maxdarque i'm not sure i fully understand the question here. the declaration you made for
now, that being said, are you asking whether or not
i could use a more concrete use-case to figure out why combining them manually or using fragments doesn't solve this issue for you. e.g., could you define your queries as fragments instead? fragment BookFragment on Root {
book { ... }
}
fragment CarFragment on Root {
car { ... }
}
query { ...BookFragment, CarFragment } the downside here is that when you have parameterized fragments, the parent needs to know about those parameters, but maybe this spec might be useful for you: graphql/graphql-spec#204 (there's experimental support for parameterized fragments in graphql-tag) let me know what you think! im going to close this for now just to get my workload under control. |
I also faced the same problem here, I think this is a very practical requirement, it makes sense sometimes we want to combine the query together, but as @jnwng mentioned above, there are a lot of potential problems to consider while doing this. So what's the best practice for programmatically combine different queries together? The point is we want to reuse the predefined queries as much as possible. |
I had a workaround here: const bookQuery = `
book(id: $bookId) {
id
author
}
`
const carQuery = `
car(id: $carId) {
id
name
}
`
const oneQuery = gql(String.raw`
query ($bookId: ID!, $carId: ID!) {
${bookQuery}
${carQuery}
}
`) I know it's pretty hacky, if you have graphql syntax highlight plugin, this kind of lose the hightlight for the first two queries, but it actually make you reuse the predefined queries somehow. |
Yes this is what I was referring to. Rather than defining queries inside each React component, I like to centralize them in my api folder. This way, when there's a change, it reduces my surface area. I also have a preference for fragments for similar reasons. Maybe the best approach would be use fragments in the fashion outlined below until there is mature support for parameterized fragments. const fieldsOnBook = gql`
fragment fieldsOnBook on Book {
id
author
}
`;
const fieldsOnCar = gql`
fragment fieldsOnCar on Car {
id
name
}
`;
const bookQuery = gql`
query ($bookId: ID!) {
book(id: $bookId) {
.... fieldsOnBook
}
}
${fieldsOnBook}
`
const carQuery = gql`
query ($carId: ID!) {
car(id: $carId) {
... fieldsOnCar
}
}
${fieldsOnCar}
`
const oneQuery = gql`
query ($bookId: ID! $carId: ID!) {
book(id: $bookId) {
.... fieldsOnBook
}
car(id: $carId) {
... fieldsOnCar
}
}
${fieldsOnBook}
${fieldsOnCar}
` |
If the goal for combining queries is to minimize the number of HTTP requests, then you might want to look into Apollo query batching: |
I'm doing in the same way. What's about build the queries conditionally? |
I have potential use case. Imagine a scenario with nested routes. The parent component needs to load data, but then doesn't display it's children until after it finishes. You wind up with cascading requests, and cascading spinners. It would be cool if the two requests could be merged (I supposed there could be a link similar to the batching link that would be the hook for this). Especially if both components (parent and child) are making the same query with the same arguments (think the parent shows some summary info about an entity while the children show more details. |
the requested feature is now possible thanks to parameterized fragments 🎉 https://graphql.org/learn/queries/#using-variables-inside-fragments assuming book and car query are fields of the root query type named "RootQueryType", the above graphql-tag example #169 (comment) could be implemented as follows:
|
The return value of gql is just an object, you can modify it.
And another query:
To combine them into one:
Then the userInfoQuery is what you want |
I created simple combine method that uses gql ready objects, extracts them and convert in one new combined gql
|
Hi! I created a lib for this: https://github.com/domasx2/graphql-combine-query import combineQuery from 'graphql-combine-query'
import gql from 'graphql-tag'
const fooQuery = gql`
query FooQuery($foo: String!) {
getFoo(foo: $foo)
}
`
const barQuery = gql`
query BarQuery($bar: String!) {
getBar(bar: $bar)
}
`
const { document, variables } = combineQuery('FooBarQuery')
.add(fooQuery, { foo: 'some value' })
.add(barQuery, { bar: 'another value' })
console.log(variables)
// { foo: 'some value', bar: 'another value' }
print(document)
/*
query FooBarQuery($foo: String!, $bar: String!) {
getFoo(foo: $foo)
getBar(bar: $bar)
}
*/ |
Although the approaches mentioned above may work, I think a more efficient way to do it, would be to combine the queries (and I'm talking only about queries, not mutations, because I don't see the value there) at the tree level. We have a similar situation as the one described by @blocka , multiple components loading different parts of data for the same object at more or less the same time, but we would like each component to manage its own data. So, instead of having the parent component load data for all its children and pass it on to them, which is the approach we're following now, each component will try to load each own slice of the data more or less at the same time as its siblings. So, imagine you have these 2 queries:
where
Which I believe is what the approaches above return, we would get:
Depending on the underlying implementation, the previous solution may result it two separate queries to the database for the same record, while the last one is only one. It would be far more complicated to implement, having to compare variables at multiple levels, but wouldn't it be better? I think given that the |
Does this work with mutations too? Would it be possible to get it working with mutations? |
It does work with mutations! |
absolute legend |
Regarding the For example const oneQuery = gql`
query ($bookId: ID! $carId: ID!) {
book(id: $bookId) {
id
author
}
car(id: $carId) {
id
name
}
trains { // since trains will remain the same even when variables change, refetching this field every time the variables changed is not ideal
id
name
}
} |
Is it possible to use
graphql-tag
to combine two predefined queries? The goal is to pass them into<Query/>
. I say this because I only want to define each query once and re-use them across React components. i.e.Would it be possible to combine both into something like?
The text was updated successfully, but these errors were encountered: