0

UPDATE: I solved the problem, but I'm not sure totally sure how. The code seems the same to me, but data is showing up now. Any new answers are still welcome!


So I have a cache updater for a mutation called createMeanings. (The mutation basically adds new Meaning entities — kind of like dictionary entries.) This updater added the newly created meanings to the cache (to query readMeanings). It worked fine until I changed the input object for readMeanings into a single object (vs. several arguments) (as GraphQL recommends).

To summarize:

  • the mutation works fine after the change (returns the expected result),
  • data is null in the updater,
  • field arguments in the updater (stringified) match field key in pagination local resolver, so I don't think they're the issue

This is from urql's createClient (feel free to ignore the as assertions):

updates: {
  Mutation: {
    createMeanings: (result, args, cache, info) => {
      // Update all readMeanings queries
      const newMeanings = (result as CreateMeaningsMutation)
        .createMeanings.meanings;
      if (newMeanings) {
        cache
          .inspectFields("Query")
          .filter((field) => field.fieldName === "readMeanings")
          .forEach((field) => {
            cache.updateQuery(
              {
                query: ReadMeaningsDocument,
                variables: field.arguments as QueryReadMeaningsArgs,
              },
              (data) => {
                (
                  data as ReadMeaningsQuery
                ).readMeanings.meanings.unshift(...newMeanings);
                return data;
              }
            );
          });
      }
    },

The input object for readMeanings is this:

@InputType()
class ReadMeaningsInput {
  @Field(() => Int)
  limit!: number;

  @Field(() => String, { nullable: true })
  cursor?: string;

  @Field(() => ReadMeaningsSorting)
  sorting?: ReadMeaningsSorting;
}

Before my update, these attributes were used as arguments for readMeanings. That was pretty much the only change — I haven't changed the input or output for createMeanings.

Importantly, I noticed that in the updater, data is null. It says null even when I write the query or variables explicitly.

I'm suspecting it has something to do with the pagination that I'm using. Here's the local resolver that (from Ben Awad's tutorial):

const cursorMeaningPagination = (): Resolver => {
  return (_parent, fieldArgs, cache, info) => {
    const { parentKey: entityKey, fieldName } = info; // entityKey is a query, fieldName is set to readMeanings

    const allFields = cache.inspectFields(entityKey); // This gives us all queries. Fetch all fields in cache under given query entity Key
    const fieldInfos = allFields.filter((info) => info.fieldName === fieldName); // Filter queries in cache, get ones we care about
    // (We can have multiple queries set for readMeanings, for example)
    const size = fieldInfos.length;
    // If no data, return undefined
    if (size === 0) {
      return undefined;
    }
    const fieldKey = `${fieldName}(${stringifyVariables(fieldArgs)})`;
    const isInCache = cache.resolve(
      cache.resolve(entityKey, fieldKey) as string,
      "meanings"
    ); // If given query is in cache
    let hasMore = true;
    const results: string[] = [];
    info.partial = !isInCache; // Do partial return if not in cache
    // For each particular cached query that we care about
    fieldInfos.forEach((fi) => {
      const key = cache.resolve(entityKey, fi.fieldKey) as Entity; // Get query's field key (includes specific args)
      console.log("readMeanings field key:", fi.fieldKey);
      const data = cache.resolve(key, "meanings") as string[]; // key like: 'posts({"limit":10})'
      const _hasMore = cache.resolve(key, "hasMore");
      if (!_hasMore) {
        hasMore = _hasMore as boolean; // If _hasMore is false
      }
      console.log("readMeanings local resolver results", results);
      results.push(...data);
    });
    return { __typename: "PaginatedMeanings", hasMore, meanings: results };
  };
};

I noticed that fi.fieldkey here is the same as stringified field.arguments in the updater, so I'm guessing there is no issues with variables (query keys). But I also noticed that results here is empty on the first load (when the cursor is null), but has all the records (with loaded new records) after clicking "Load more" — but that's how it was supposed to be, I guess — this local resolver still relies on an automatic cache update on query, right?

Extra info

The readMeanings query:

query ReadMeanings($options: ReadMeaningsInput!) {
  readMeanings(options: $options) {
    hasMore
    meanings {
      ...RegularMeaning
    }
  }
}

The createMeanings mutation:

mutation CreateMeanings($options: CreateEntryMeaningInput!) {
  createMeanings(options: $options) {
    ...RegularCreateMeaningsResponse
  }
}
fragment RegularCreateMeaningsResponse on CreateMeaningsResponse {
  errors {
    ...RegularError
  }
  meanings {
    ...RegularMeaning
  }
}

Any advice would be super helpful!

UPDATE: I recreated a simpler version, and the problem appears the moment I try to use one input object instead of just passing multiple arguments.

vls9
  • 113
  • 10

0 Answers0