urql icon indicating copy to clipboard operation
urql copied to clipboard

RFC: Add transform functions in Graphcache's optimistic updater returned data

Open villesau opened this issue 2 years ago • 2 comments

Summary

Would be cool if there would be an easy way to pick the previous value of an object and modify that optimistically. Now my code looks something like that:

        likeArticle: (variables, cache) => {
          const likeCount = cache.resolve(
            { __typename: 'Article', id: variables.articleId },
            'likeCount'
          );
          return {
            __typename: 'Article',
            id: variables.articleId,
            liked: true,
            likeCount: likeCount + 1
          };
        },

Proposed Solution

Something like this:

        likeArticle: (variables) => ({
            __typename: 'Article',
            id: variables.articleId,
            liked: true,
            likeCount: previousValue => previousValue + 1 
          }),

This would make optimistic updates less verbose, probably less error prone and easier to read.

villesau avatar Feb 13 '22 14:02 villesau

I'm currently not super inclined to say that this is worth the added internal complexity 😅 It may lead to some confusion across all of our APIs (what doesn't and what does support transform functions?) and the associated burden associated with supporting it everywhere where it makes sense.

Currently, the reason why I favour a simple API here is that it doesn't have to be visually more complex than this, if we assume that often it can come down to cache.resolve(article, 'likeCount') + 1 for instance.

However, what I find a lot more interesting here for optimistic resolvers specifically is that if we do allow it it could solve a longstanding issue I see here with arguments.

For instance, say a mutation needs to modify nested data, e.g. likeArticle(id: $id) { id liked, likeCount(since: "yesterday") } (or even nested selection sets) Then if any field with arguments needs to be modified it becomes a little tricky to keep track of this. In theory, function values in the returned objects could allow us to elegantly bypass this as the function itself would receive the arguments and provide the correct value potentially, but the added bonus here is that it reduces the mental workload on users.

So, tl;dr I see a lot more value here in the "optimistic nested fields with arguments" case. The question is: how often does that come up and can't be simply implemented with an updater 🤔


On another topic, the above is basically just a reaction, however, I think the RFC isn't quite compelling yet, and hence it does allow me to read a lot into it 😅 In other words, I'm not sure I'd act on an RFC just yet if the argument for it that an existing way is just not to everyone's taste. Now, I'm sure once we narrow down an exact proposed solution, summary, and requirements (which are really important to determine whether an implementation is possible, before it's attempted) we can see the merit clearly. But for now, I think we simply have too many questions that still need to be explored :v:

kitten avatar Feb 16 '22 02:02 kitten

@kitten came up with a bit similar need here: https://github.com/FormidableLabs/urql/discussions/2346 It's a question since I'm not sure if there is some idiomatic way to achieve what I'm trying to do or not. I think this and the question are both about the ease of reusing the existing state and I believe that in both cases some callback based approach would result in more robust and less error prone software.

villesau avatar Mar 13 '22 13:03 villesau

We forgot to mark this, but it's been resolved and implemented by: https://github.com/urql-graphql/urql/pull/2616

kitten avatar Dec 01 '22 13:12 kitten