graphql-live-query icon indicating copy to clipboard operation
graphql-live-query copied to clipboard

Multi-argument custom query invalidation doesn't seem to work

Open strblr opened this issue 3 years ago • 6 comments
trafficstars

In a project, I have lists of entities called "hypotheses" that need to be refreshed via live queries. These lists are fetched using the following query:

type Query {
  hypotheses(
    project: ID!
    law: Int
    filters: ListFiltersInput!
  ): HypothesisPage!
}

Hypotheses are tied to specific "laws" (identified by integers). The second argument law can be null which returns all hypotheses regardless of their laws. I'm trying to invalidate based on a custom index that looks like this:

{
  field: "Query.hypotheses",
  args: ["project", "law"]
}

Here is the document I use on the frontend:

export const HypothesesQuery = gql`
  ${HypothesisPageFragment}

  query Hypotheses($project: ID!, $law: Int, $filters: ListFiltersInput!)
    @live {
    hypotheses(project: $project, law: $law, filters: $filters) {
      ...HypothesisPage
    }
  }
`;

Now when creating an hypothesis with a createHypothesis mutation (resolver is successfully called), the following invalidation doesn't work:

invalidate([
  `Query.hypotheses(project:"${project._id.toHexString()}",law:null)`,
  `Query.hypotheses(project:"${project._id.toHexString()}",law:${
    hypothesis.law
  })`
]);

(project._id.toHexString() has the correct value) Any idea of what's going on? Thank you.

strblr avatar Apr 22 '22 15:04 strblr

Ok by logging the generated indices, I can see what's going on. Here are some:

  'Query.hypotheses(project:"61008f309a516c36b4505363",law:"2")',
  'Query.hypotheses(project:"61008f309a516c36b4505363",law:"null")',
  'Query.hypotheses(project:"61008f309a516c36b4505363",law:"3")'

Non-string values seem to be cast to strings before generating the keys.

Edit: Issue seems to come from here:

https://github.com/n1ru4l/graphql-live-query/blob/17f57100f583d170c51e71c012cd83b20b0d4023/packages/in-memory-live-query-store/src/InMemoryLiveQueryStore.ts#L91-L109

This doesn't seem right.

strblr avatar Apr 22 '22 16:04 strblr

What behavior would you consider instead? If the type would implement a .toString() function you can customize how the thing is stringified 🤔

n1ru4l avatar May 12 '22 12:05 n1ru4l

@n1ru4l Well since the base scalars are JSON-ish, you could use JSON.stringify for numbers, strings, null and booleans, and .toString() for other values. This would make the indices closer to actual GraphQL syntax. What do you think?

strblr avatar May 12 '22 16:05 strblr

Why couldn't your id type implement a toString method?

class ID extends YourId {
  toString() {
    return this.toHexString()
  }
}

Relying on JSON.stringify is not safe and would require using something as https://www.npmjs.com/package/json-stable-stringify

I do not recommend using complex types for indices. I think it is safe to say that indices should only be set on values that can easily be serialized to a string.

n1ru4l avatar May 16 '22 15:05 n1ru4l

You would still have the hard-coded double quotes, which can bring weird indices collision. For example imagine a nullable query argument of type String: null and "null" would serialize to the same index.

strblr avatar May 16 '22 16:05 strblr

I see your point, in that case, JSON.stringify (aka https://www.npmjs.com/package/json-stable-stringify) might be the best solution. 🤔

I think adding json-stable-stringify as a dependency should be fine.

@strblr Would you like to create a PR with some tests and an implementation?

n1ru4l avatar May 16 '22 16:05 n1ru4l