aerogear / offix

GraphQL Offline Client and Server
https://offix.dev
Apache License 2.0
758 stars 45 forks source link

Error when using offlineMutate cache not updated #451

Closed dioxapp closed 4 years ago

dioxapp commented 4 years ago

Hello and thanks for the great library you made!!!

I am getting this error Offix_error

When i try to add a new record in my entity, ame issue for the delete statement :

const mutationOptions = {
        mutation: gql/`
          mutation ADD_ADDRESS($obj: [address_insert_input!]!) {
            insert_address(objects: $obj) {
              affected_rows
              returning {
                id
                name
                street
                city
                zipCode
                country
              }
              affected_rows
            }
          }/`
        ,
        variables: {
          obj: _obj
        },
        query: gql`
               address(order_by: {id: asc}) {
                id
                name
                street,
                city,
                zipCode,
                country
              }
            `,
        returnType: 'address',
        operationType: CacheOperation.ADD,
        idField: 'id'
      }

      const options = createMutationOptions(mutationOptions)
      this.offixClient
        .offlineMutate(options)
        .then((ret) => {
          console.log('ADD OK ')
          return resolve(true)
        })
        .catch((err) => {
          return reject(new Error('ADD ERROR ' + err))
        })

But the database is well updated, its seems be a cache refresh issue... Any help is appreciated !!!

Thanks

wtrocki commented 4 years ago

Hi

There are actually two issues I see:

As per docs update query field is updateQuery: https://offix.dev/docs/offix-cache#mutation-cache-helpers

Error printed to user is kinda bad so we going to change that.

An additional issue is that automatic cache updates are designed to work with arguments in the root. When using single object in mutation additional mapping needs to be added like here:

https://github.com/aerogear/datasync-starter/blob/master/client/src/config/clientConfig.ts#L98-L105

We need to document this.

@darahayes @kingsleyzissou Do we have ability to define mapping per operation as well?

dioxapp commented 4 years ago

Hi wtrocki

Thanks for your reply Changes done but i'am getting the same error message, below my offix config:

  const config: OffixBoostOptions = {
    cache: new InMemoryCache(),
    httpUrl: process.env.GRAPHQL_URL ? process.env.GRAPHQL_URL : '',
    wsUrl: process.env.GRAPHQL_WS_URL ? process.env.GRAPHQL_WS_URL : '',
    connectToDevTools: true,
    fileUpload: true,
    inputMapper: {
      deserialize: (variables: any) => {
        return variables && variables.input ? variables.input : variables
      },
      serialize: (variables: any) => {
        return { input: variables }
      }
    },
    authContextProvider: this.header, // Subscription
    websocketClientOptions: {
      connectionParams: {
        reconnect: true,
        timeout: 3000
      }
    },
    resolvers
  }

Thanks!!!

wtrocki commented 4 years ago

Your query using obj as argument instead of variables:

variables.input => variables.obj

offix is basing on concept that all arguments are put directly into mutation. We can change that when client is created.

eltonec commented 4 years ago

i use angular & offix-angular and i get same error!

wkLogout(id, logout): Promise { const qm = gql mutation update_logons($input: logons_set_input) { update_logons( where: {id: {_eq: ${id}}}, _set: $input ) { id outtime outpt outdist } }; const mutationOptions = { mutation: qm, variables: { input: logout }, updateQuery: { query: this.logonQm }, returnType: 'logons', operationType: CacheOperation.UPDATE, idField: 'id' }; return this.apollo.getClient().offlineMutate(mutationOptions); }

wtrocki commented 4 years ago

Ok. I will try to replicate this problem locally in the sample app and get back to you

eltonec commented 4 years ago

thanks a lot!

I have another problem because my server uses hasura, and the mutation response fields is included in the returning (such as the following program snippet), this causing offix to fail to analyze。

wkLogon(login): Promise { const qm = gql mutation insert_logons($input:[logons_insert_input!]!) { insert_logons( objects: $input ) { returning { id userid companyid wkdate logtime logpt tordist } } }; const mutationOptions = { mutation: qm, variables: { input: [login] }, updateQuery: { query: this.logonQm }, returnType: 'logons', operationType: CacheOperation.ADD, idField: 'id' }; return this.apollo.getClient().offlineMutate(mutationOptions); }

dioxapp commented 4 years ago

Thanks a lot wtrocki for your reply ! As eltonec i am also using Hasura too !

kingsleyzissou commented 4 years ago

I have managed to replicate the particular error messsage that @dioxapp is getting.

you are getting the error because you are escaping the gql backticks:

It should be:

const mutationOptions = {
        mutation: gql`
          mutation ADD_ADDRESS($obj: [address_insert_input!]!) {
            insert_address(objects: $obj) {
              affected_rows
              returning {
                id
                name
                street
                city
                zipCode
                country
              }
              affected_rows
            }
          }`
        ,
    ...
}

Instead of this:

const mutationOptions = {
        mutation: gql/`
          mutation ADD_ADDRESS($obj: [address_insert_input!]!) {
            insert_address(objects: $obj) {
              affected_rows
              returning {
                id
                name
                street
                city
                zipCode
                country
              }
              affected_rows
            }
          }/`
        ,
    ...
}
kingsleyzissou commented 4 years ago

@eltonec I can see the returning object there after a mutation has been played. I am busy looking at the moment.

The issue I see is that the returnType is not an address, but is an array. My understanding is that the input mapper in it's current state would not provide the correct update function for you. @wtrocki, maybe you could confirm?

You could provide your own update function: https://hasura.io/learn/graphql/react/mutations-variables/3-create-mutation/

It would look something like:

const mutationOptions = {
      mutation: qm,
      variables: {
        input: [login]
      },
      update: updateCache,
      returnType: 'logons',
      operationType: CacheOperation.ADD,
      idField: 'id'
};

And the updateCache function would look something like:

const updateCache = (cache, {data}) => {
  // If this is for the public feed, do nothing
  // Fetch the todos from the cache
  const logons = cache.readQuery({
    query: <YOUR_FIND_QUERY>
  });
  // Add the new todo to the cache
  if (data.insert_logons.returning) {
    const newLogon = data.insert_logons.returning[0];
    cache.writeQuery({
      query: <YOUR_FIND_QUERY>,
      data: {logons: [newLogon, ...existingLogons.logons]}
    });
  }
};

You might have to play around with that, but that's more or less the idea.

dioxapp commented 4 years ago

Hi,

Thank you @kingsleyzissou the solution you proposed works!!!. But when i goes offline my update method is not called during mutations. It is called only when i get back online, this make my optimistic responses fail. Did i miss something ?

Thanks !

kingsleyzissou commented 4 years ago

Hey @dioxapp I’m glad that worked for you.

I think it’s probably a similar issue to what eltonec was having in that it’s the way that hassura returns the data. You could write a custom update similar to the one I proposed for eltonec and that should work for the optimistic response

dioxapp commented 4 years ago

Hi kingsleyzissou,

It's what i did, i've create my own updatedCache method. But i am facing one issue, when i turn my app offline my updatedCache was not called (so my data array is not updated)

By debuging i can see that it is called back when i get back online.

Thanks

kingsleyzissou commented 4 years ago

But when i goes offline my update method is not called during mutations.

@dioxapp apologies, I missed that. If the update function is only firing when you come back online, that seems to be a bug with the cache updates.

We are busy looking to see how we can improve how we handle the cache with offline mutations at the moment and it is part of the roadmap for v1.0.0.

I will try debug this on my end too

kingsleyzissou commented 4 years ago

Hi @dioxapp,

we're busy doing some exciting changes to Offix and are actively looking at some solutions that would move us away from the cache and the cache updates and improve the overall developer experience.

I haven't been able to reproduce this issue on my end. I'm closing this issue since it is unrelated to the initial one. If you are still having trouble with this, maybe you could create a new issue with some of the code you are using.