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.