Skip to content
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

Update cache with mutations #13

Closed
awaik opened this issue Mar 30, 2020 · 8 comments
Closed

Update cache with mutations #13

awaik opened this issue Mar 30, 2020 · 8 comments

Comments

@awaik
Copy link
Contributor

awaik commented Mar 30, 2020

Hello guys, one more question - after we make a mutation, what is the best way to update the cache?

Right now in your documentation is example

final updateCacheHandlers = <dynamic, Function>{
  "MyHandlerKey": MyUpdateCacheHandler,
};

final options = ClientOptions(updateCacheHandlers: updateCacheHandlers);

final client = Client(
  link: link,
  options: options,
);

But for me, it is not clear, how to implement it. Maybe there are obvious approaches, but I just started to use graphql and will be appreciated for example.

Documentation. When I finished things in my app I ready to create one more example for your package for demonstrating mutations, links updates, and cache updates. I quests, that it will be topical questions from your users.

@smkhalsa
Copy link
Member

smkhalsa commented Mar 30, 2020

Yes, the documentation definitely needs to be improved. Any PRs to improve it would be greatly appreciated.

You'll need to implement an UpdateCacheHandler, which provides a CacheProxy object that gives you readQuery, writeQuery, readFragment, and writeFragment methods.

For example:

final UpdateCacheHandler<$MyMutation> myMutationHandler = (
  CacheProxy proxy,
  QueryResponse<$MyMutation> response,
) {
  final query = MyQueryToUpdate();
  final result = proxy.readQuery(query);

  /// update the result
  proxy.writeQuery(query, result);
};

class MyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FlatButton(
      child: Text("Click me"),
      onPressed: () {
        final mutation = MyMutation(
          updateCacheHandlerKey: "myMutationHandler",
          optimisticResponse: {
            /// JSON for optimistic response
          },
        );
      },
    );
  }
}

Then in your config:

import 'path/to/file/with/handler';

final updateCacheHandlers = <dynamic, Function>{
  "myMutationHandler": myMutationHandler,
};

final options = ClientOptions(updateCacheHandlers: updateCacheHandlers);

final client = Client(
  link: link,
  options: options,
);

@awaik
Copy link
Contributor Author

awaik commented Apr 1, 2020

Hello,

thank you! Your package is awesome, really enjoy it :)

I'll make an example with mutations, links updates, cache updates within 2 weeks.

How do you prefer to do it? Inside your package as standalone app or ..?

@awaik
Copy link
Contributor Author

awaik commented Apr 1, 2020

When tried to implement your example has such behavior:

CASE 1

final client = Client(
  link: link,
  options: options,
);

Works ok, final result = proxy.readQuery(query); got the data from last query.

CASE 2

  Client client = Client(
    link: link,
    options: options,
    cache: cache,
  );

final result = proxy.readQuery(query); got OLD data from the cache, not from the query. On the server data updates ok, locally in the app, we have old data from the cache

ezgif-2-534356a7b15e

@smkhalsa
Copy link
Member

smkhalsa commented Apr 1, 2020

I'll make an example with mutations, links updates, cache updates within 2 weeks.

How do you prefer to do it? Inside your package as standalone app or ..?

Great! Feel free to open a PR to the existing example or add a second example if you prefer.

@smkhalsa
Copy link
Member

smkhalsa commented Apr 1, 2020

final result = proxy.readQuery(query); got OLD data from the cache, not from the query. On the server data updates ok, locally in the app, we have old data from the cache

proxy.readQuery is supposed to return data from the Cache. If you want to data returned by the mutation, you can access that through QueryResponse.data.

@awaik can you post your full UpdateCacheHandler and describe where the behavior deviates from the expected behavior?

@awaik
Copy link
Contributor Author

awaik commented Apr 2, 2020

Hello,

after your last answer, I made the handler that gets info from the cache and from the results of Response.

class FerryCacheHandlers {
  static final UpdateCacheHandler<$ProfileBmiMutation>
      profileBmiMutationHandler = (
    CacheProxy proxy,
    QueryResponse<$ProfileBmiMutation> response,
  ) {
    final query = ProfileBmiQuery();
    final resultCache = proxy.readQuery(query);
    final resultNet = response.data.data;

    print(resultCache);
    print(resultNet);
    proxy.writeQuery(query, resultNet);
  };

And I have the mutation

final mutation = ProfileBmiMutation(
  buildVars: (b) => b..input = aa,
  updateCacheHandlerKey:
      IdCacheHandlers.profileBmiMutation,
//                              optimisticResponse: aa.input,
).copyWith(
  context: Context.fromList(
    [
      HttpLinkHeaders(
        headers: idToken,
      ),
    ],
  ),
);
client
    .responseStream(mutation)
    .firstWhere((response) => !response.optimistic)
    .then((response) {});
Navigator.pop(context);
},

It works like a charm!

BUT :)

With this code, we get time lag. We should wait for resultNet and only after we get it, the info in the cache is updated.

For me, an ideal algorithm should immediately update the cache and, after getting resultNet update it once again.

The demo of the time lag is on the attached gif.

ezgif-3-eac80b76e062

@smkhalsa
Copy link
Member

smkhalsa commented Apr 2, 2020

For me, an ideal algorithm should immediately update the cache and, after getting resultNet update it once again.

Ferry already does this. You need to pass an optimisticResponse to your mutation. Then Ferry will run your UpdateCacheHandler once with the optimistic data then again with the network data. Make sure your optimisticResponse object matches the shape of the network response JSON.

@awaik
Copy link
Contributor Author

awaik commented Apr 2, 2020

Thank you!
I close the issue and will come back with PR with the new example for mutations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants