Intended outcome:
I would like to be able to query the store without having to use the same variables in previous queries. For example, on a list page I have a query that looks like this:
query Company($cursor: String) {
company {
id
locations(first: 10, after: $cursor) {
pageInfo {
# ...
}
edges {
node {
id
# ...
}
}
}
}
}
I have a mutation to add a location and I'm attempting to load all locations associated with the company but it's forcing me to add the first
and after
field arguments. I would like to grab all locations by using the following query:
const data = this.props.client.readQuery({
query: gql` {
company {
healthySpots {
edges {
node {
id
# ...
}
}
}
}
}`,
});
Actual outcome:
The following error is being thrown:
Can't find field locations on object ($ROOT_QUERY.company) {
"name": "App",
"locations({\"first\":10,\"after\":null})": {
"type": "id",
"id": "$ROOT_QUERY.company.locations({\"first\":10,\"after\":null})",
"generated": true
},
"__typename": "Company"
}.
If I include the first
and after
arguments with the same variables used on my list page then it works but this requires me to keep track of those variables from a different location in my app. It would be nice to just be able to skip variables if I preferred to not filter any fields.
How to reproduce the issue:
If you are attempting to read a query from the store that was fulfilled with the use of variables then an error will be thrown.
Also, I have to applaud your efforts that have allowed me to be so much more productive than I was before Apollo was open sourced! Thank you for what you're doing for the community!!
Hey @chrissm79. I think the right solution for your use case is a custom resolver, but you'll still have to keep track of the variables manually in order to know which queries to run against the store. We're going to make this a lot easier in the new API though.
@helfer Hi, I've the same issue. Are there any updates for the new API?
Its still not easy, i have to track every single variables. The documentation holds just the easy use cases, but i have pagination, filtering and ordering, and the actions i have, modify records individually. The update mechanism is still hard and complicated
I also stuck with these problem, many solutions can be implemented like giving more flexibility to to readQuery( query: "queryName" ) returning the store with an array of all the stored variables
varialbe: "chri"
-Data 1
-Data 2
-Data 3
-Data 4
variable: "chris"
-Data 1
-Data2
etc
or have a more flexible refetchQuery('variableName') fire an update in ALL variables not just the last one set
The problem is readQuery and fetchQuery are very tight to pass ALWAYS variables, but they are many cases like a search, dynamic filters etc, where you don't have a trace off all the possible variables, the issue is when you try to add or remove elements
This might be a big blocker for a lot of people, as the following seems a very common use case:
We're going to make this a lot easier in the new API though.
@helfer , i'm not sure how this becam easier in the new API? In case i'm missing something please post a link 😀.
Otherwise i would suggest re-opening this issue. This still seems especially cumbersome if you use
fetchMore
) (Queries are merged -> which to use for update?)Would love to see something like this built into apollo client, it's been a HUGE help. It wasn't originally published to NPM but it looks like they've done so recently.
Here a video w/ the creator: https://www.youtube.com/watch?v=8ZKpIB1pDw8&t=482s
same issue.
Here is my angular
+ apollo
code:
@Injectable()
export class RepoService {
constructor(private apollo: Apollo) {}
public getRepoByNameAndOwner(owner: string, name: string, first?: number): Observable<any> {
return this.apollo
.watchQuery<any>({
query: RepoQuery,
variables: {
owner,
name,
first
}
})
.valueChanges.map((res: any) => {
const { data, ...rest } = res;
return { repository: data.repository, ...rest };
});
}
public updateTopics(updateTopicsInput: IUpdateTopicsInput): Observable<any> {
return this.apollo.mutate<any>({
mutation: M.updateTopics,
variables: {
input: updateTopicsInput
},
update: (proxy: DataProxy, mutationResult: FetchResult<any>) => {
const data = proxy.readQuery({ query: RepoQuery, variables: { owner: '', name: '', first: '' } });
debugger;
}
});
}
}
It will throw an error like below:
Error: Can't find field repository({"name":"","owner":""}) on object (ROOT_QUERY) {
"user({\"login\":\"mrdulin\"})": {
"type": "id",
"generated": true,
"id": "$ROOT_QUERY.user({\"login\":\"mrdulin\"})",
"typename": "User"
},
"repository({\"name\":\"react-tap-event-plugin-issues\",\"owner\":\"mrdulin\"})": {
"type": "id",
"generated": false,
"id": "Repository:MDEwOlJlcG9zaXRvcnkxMTg4ODEyMjU=",
"typename": "Repository"
}
}.
Here is my solution, but I think this solution sucks. Like @chrissm79 said, I saved variables
in my service for later using in proxy.readQuery()
method.
I saved RepoQuery
variables in "parent scope" - the repoQueryVariables
, so it can be used in updateTopics
function scope. That makes updateTopics
method impure.
It's a serious issue.
@Injectable()
export class RepoService {
constructor(private apollo: Apollo) {}
// for saving "RepoQuery" variables
private repoQueryVariables: any;
public getRepoByNameAndOwner(owner: string, name: string, first?: number): Observable<any> {
// save "RepoQuery" variables
this.repoQueryVariables = {
owner,
name,
first
};
return this.apollo
.watchQuery<any>({
query: RepoQuery,
variables: this.repoQueryVariables
})
.valueChanges.map((res: any) => {
const { data, ...rest } = res;
return { repository: data.repository, ...rest };
});
}
public updateTopics(updateTopicsInput: IUpdateTopicsInput): Observable<any> {
return this.apollo.mutate<any>({
mutation: M.updateTopics,
variables: {
input: updateTopicsInput
},
update: (proxy: DataProxy, mutationResult: FetchResult<any>) => {
// use "this.repoQueryVariables"
const data = proxy.readQuery({ query: RepoQuery, variables: this.repoQueryVariables });
debugger;
}
});
}
}
note: above code is a demo! Do not use it in any production environment!!
Still no clean solution ?
This is really embarrassing, how we cannot access a query without variables. I don't think it will be much of a problem if we get queries with the same name. And we also can come up with different query names in GraphQL and get directly that query by the custom name, no by the whole GraphQL query with its variables.
It seems very frustrating to store queries with all their variables, just so we can update them later in some of the code. We need to create additional code even though apollo can crate an API that can be easily handled with custom name queries. With the custom names, we will not need to manage additional code for mutating queries.
Currently, in my real project, I have an add todo modal and want to modify the list that shows on the dashboard, to add the todo on top of the list, but I cannot access the query with readQuery
, because it also requires the variables that are passed to the query. Well, this is a bummer because the components are not related.
I've been searching for any non-hacking ways, but it seems a bad API implementation to me.
Correct me if I am wrong.
I would like to see this functionality as well, since our application has filtering, paging and sorting and we don't want to keep track of those variables throughout the entire application. I tried using the keyArgs
option when initializing the InMemoryCache, excluding the filtering/sorting/paging variables from that list. The problem then, was that since keyArgs
did not include those filtering/paging/sorting variables, the query was not re-running when the variables were updated. Would it be worth re-creating this ticket in @apollo/client
? I'm not sure if this repo is actively monitored anymore
Most helpful comment
Its still not easy, i have to track every single variables. The documentation holds just the easy use cases, but i have pagination, filtering and ordering, and the actions i have, modify records individually. The update mechanism is still hard and complicated