Error writing result to store for query. Cannot read property 'query' of undefined - graphql

I'm getting an error when writing a query to store after a mutation. The mutation works and i'm able to read the query post mutation. When i write the same query to the store cache i get the following Error:
index.js:2178 Error: Error writing result to store for query:
query ($applicationId: Int) {
vApplicationApprovalChainList(ApplicationId: $applicationId) {
id
approvalOrder
approverId
name
applicationId
__typename
}
}
Cannot read property 'vApplicationApprovalChainList' of undefined
at writeToStore.js:101
at Array.forEach (<anonymous>)
at writeSelectionSetToStore (writeToStore.js:97)
at writeResultToStore (writeToStore.js:75)
at InMemoryCache../node_modules/apollo-cache-inmemory/lib/inMemoryCache.js.InMemoryCache.write (inMemoryCache.js:99)
Here is my code.. the mutation and store.readQuery works but the store.writeQuery gives above error. Thank you in advance for any feedback.
APPROVERSLIST_QUERY = gql`
query ($applicationId:Int){
vApplicationApprovalChainList(ApplicationId:$applicationId){
id
approvalOrder
approverId
name
applicationId
}
}
`;
handleClick() {
const { row, mutate} = this.props;
mutate({
variables: {
id: row.id
},
update: (store, { data: { deleteApprover } }) => {
const newdata = store.readQuery({
query: APPROVERSLIST_QUERY,
variables: { applicationId: row.applicationId }
});
console.log(newdata);
newdata.vApplicationApprovalChainList = newdata.vApplicationApprovalChainList.filter(approver => approver.id !== deleteApprover.id);
store.writeQuery({
query: APPROVERSLIST_QUERY, newdata });
}
});
}

You're not passing in the new data to writeQuery. The object passed to writeQuery must have a property named data containing the new data. Additionally, since your query contains variables, you will need to include that information as well.
store.writeQuery({
query: APPROVERSLIST_QUERY,
data: newdata,
variables: {
applicationId: row.applicationId,
},
});
Please see the official docs for more examples and a more thorough explanation of the two methods.

Related

Graphql sending empty string

I am using graphql to get some data.
let { loading, error, data } = useQuery(GET_JOBS_SEARCH, {
variables: {
category: category,
type: jobType
}
});
Now when I update the category the API gets called with variables like
variables: {category: "leadership", type: ""}
Now I don't want the type:'' in my call.

How do I query my API for a single entity by its "slug" with GraphQL?

I am creating a Next.js blog that uses an API created with KeystoneJS. I am extremely confused by how I can get an individual post on a dynamic route from the post's slug.
The Query
This is how I thought the query should be:
query Post($slug: String) {
Post(where: { slug: $slug }) {
id
}
}
And this was queried like so in a file called post.service.js:
export async function getBySlug(slug) {
return apolloClient
.query({
query: gql`
query Post($slug: String) {
Post(where: { slug: $slug }) {
id
}
}
`,
})
.then((result) => {
return result.data.Post;
});
}
Unsurprisingly, that causes an ApolloError because how would the query know what slug to query the API for when accessing posts/[slug].js?
It's also worth noting that KeystoneJS say on their guides that:
The single entity query accepts a where parameter which must provide an id.
How would I pass the post's ID to the query depending on what slug was accessed at [slug].js and does this mean I can't query by the slug at all?
On [slug].js I am using getStaticPaths() and getStaticProps() like this:
export async function getStaticPaths() {
const posts = await getAll();
const paths = posts.map((post) => ({
params: { slug: post.slug },
}));
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
const term = await getBySlug(params.slug);
return { props: { post } };
}
How can I do this?
If you're using a where clause rather than matching on id, you have to query allPosts rather than Post.
A tested example, matching a user by their email address:
query($email: String!) {
allUsers(where : {email: $email}){
id
}
}
Variables:
{
"email": "user#email.com"
}
So I think you want:
query($slug: String!) {
allPosts(where: {slug: $slug}) {
id
}
}

Apollo-client: Add item to array in cache

Suppose I have the following GraphQL types:
type User {
id: String!
posts: [Post!]!
}
type Post {
id: String!
text: String,
}
And here is a mutation that returns the updated post:
mutation addNewPost(
$userId: String!
$text: String!
) {
addNewPost(userId: $userId, text: $text) {
id
text
}
}
After running this mutation my cache contains a new entry of a post. How do I add it to the user's posts array? I have tried cache.writeQuery and cache.modify but I cannot figure it out.
We do push the item into array inside the update function, which is one of the options of useMutation.
I'm writing the whole mutation so that you can get the idea 💡, let have a look at example:
By Update function:
const [createPost, { data, loading, error }] = useMutation(CREATE_POST, {
update(cache, response) {
// Here we write the update
// Step 1: Read/Fetch the data 👈
const data = client.readQuery({
query: FETCH_POSTS_QUERY,
});
// Step 2: Update the cache by immutable way 👈
client.writeQuery({
query: FETCH_POSTS_QUERY,
data: {
getPosts: [response.data.createPost, ...data.getPosts],
},
});
},
variables: formValues,
});
By refetchQueries:
That's really shortcut 🔥 way to update the cache, by using DocumentNode object parsed with the gql function
const [createPost, { data, loading, error }] = useMutation(CREATE_POST, {
refetchQueries: [ 👈
FETCH_POSTS_QUERY
'fetchPosts`' // OR Query name
],
variables: formValues,
});
You're going to want to directly write to the Apollo cache in order to update the other entities that your mutation has modified.
Have a look at the docs https://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updates here for specifics (you're going to want to use cache.modify and cache.writeFragment)

Query variables not being passed down from vue component in apollo

I have a simple query which takes in an ID parameter, but it is not working. It says "TypeError: Cannot read property 'taskId' of undefined" . So I think it does not recognize the 'this' keyword for some reason.
Please take a look:
Apollo query from frontend component:
getCommentsByTask: {
query: GET_COMMENTS_BY_TASK,
variables: {
taskId: this.taskId
},
result({ data }) {
this.getComments = data;
console.log("data", data);
}
}
Defined the query in frontend:
query GET_COMMENTS_BY_TASK($taskId: ID!) {
getCommentsByTask(taskId: $taskId) {
id
parentId
ownerId
text
}
}
Resolver in server:
async getCommentsByTask (_, {taskId}, context) {
const userId = getUserId(context)
const user = await User.findById(userId)
if (!user) return
const comments = await Comment.findById(taskId)
return comments
}
Schema:
type Query {
getCommentsByTask(taskId: ID!): [Comment]
}
Assuming that's a smart query, variables should be a (regular, non-arrow) function if you need access to this.

Apollo response from mutation is undefined

I use Apollo-client 2.3.5 to to add some data and then update the local cache. The mutation works but the return from the mutation is undefined in the Apollo client, but the response in the network request is correct.
So I have two querys, one for fetching all bookings and one for adding a booking.
const addBookingGQL = gql`
mutation createBooking($ref: String, $title: String, $description: String, $status: String!){
createBooking(ref: $ref, title: $title, description: $description, status: $status){
id
ref
title
description
status
}
}
`;
const GET_BOOKINGS = gql`
query {
bookings {
id
ref
title
status
description
}
}
`;
I then have a Apollo mutation wrapper where I use the update prop. addBooking should be populated with the result of the mutation, but unfortunately it is undefined.
<Mutation
mutation={addBookingGQL}
update={(cache, { data: { addBooking } }) => {
const { bookings } = cache.readQuery({ query: GET_BOOKINGS });
console.log("cache read query bookings: ", cache);
cache.writeQuery({
query: GET_BOOKINGS,
data: { bookings: bookings.concat([addBooking]) }
});
}}
>
{(addBooking, { loading, error }) => (
<div>
<Button
onClick={() => {
addBooking({
variables: {
ref: this.state.ref,
title: this.state.title,
description: this.state.description,
status: "BOOK_BOX",
}
});
this.handleClose();
}}
color="primary">
Create
</Button>
{loading && <p>Loading...</p>}
{error && <p>Error :( Please try again</p>}
</div>
)}
</Mutation>
This results in following error in the console:
errorHandling.js:7 Error: Error writing result to store for query:
{
bookings {
id
ref
title
status
description
__typename
}
}
Cannot read property '__typename' of undefined
at Object.defaultDataIdFromObject [as dataIdFromObject] (inMemoryCache.js:33)
at writeToStore.js:347
at Array.map (<anonymous>)
at processArrayValue (writeToStore.js:337)
at writeFieldToStore (writeToStore.js:244)
at writeToStore.js:120
at Array.forEach (<anonymous>)
at writeSelectionSetToStore (writeToStore.js:113)
at writeResultToStore (writeToStore.js:91)
at InMemoryCache.webpackJsonp../node_modules/apollo-cache-inmemory/lib/inMemoryCache.js.InMemoryCache.write (inMemoryCache.js:96)
I tried running the mutation in the Graphiql dev tool receiving the expected response:
{
"data": {
"createBooking": {
"id": "bd954579-144b-41b4-9c76-5e3c176fe66a",
"ref": "test",
"title": "test",
"description": "test",
"status": "test"
}
}
}
Last I looked at the actual response from the graphql server:
{
"data":{
"createBooking":{
"id":"6f5ed8df-1c4c-4039-ae59-6a8c0f86a0f6",
"ref":"test",
"title":"test",
"description":"test",
"status":"BOOK_BOX",
"__typename":"BookingType"
}
}
}
If i use the Apollo dev tool for chrome i can see that the new data is actually appended to the cache, which confuses me.
Have you checked out this apollo issue comment?
The suggestion is to create an apollo-link that parses the operation variables and omits keys containing __typename:
function createOmitTypenameLink() {
return new ApolloLink((operation, forward) => {
if (operation.variables) {
operation.variables = JSON.parse(JSON.stringify(operation.variables), omitTypename)
}
return forward(operation)
})
}
function omitTypename(key, value) {
return key === '__typename' ? undefined : value
}

Resources