···11+---
22+'@urql/exchange-graphcache': minor
33+---
44+55+Allow `cache.resolve` to return `undefined` when a value is not cached to make it easier to cause a cache miss in resolvers. **Reminder:** Returning `undefined` from a resolver means a field is uncached, while returning `null` means that a field’s value is `null` without causing a cache miss.
+27-14
docs/graphcache/local-resolvers.md
···6060 docs](../api/graphcache.md#info).
61616262The local resolvers may return any value that fits the query document's shape, however we must
6363-ensure that what we return matches the types of our schema. It for instance isn't possible to turn a
6363+ensure that what we return matches the types of our schema. It, for instance, isn't possible to turn a
6464record field into a link, i.e. replace a scalar with an entity. Instead, local resolvers are useful
6565to transform records, like dates in our previous example, or to imitate server-side logic to allow
6666Graphcache to retrieve more data from its cache without sending a query to our API.
···6969methods to read from our cache, only ["Cache Updates"](./cache-updates.md) get to write and change
7070the cache. If you call `cache.updateQuery`, `cache.writeFragment`, or `cache.link` in resolvers,
7171you‘ll get an error, since it‘s not possible to update the cache while reading from it.
7272+7373+When writing a resolver you’ll mostly use `cache.resolve`, which can be chained, to read field
7474+values from the cache. When a field points to another entity we may get a key, but resolvers are
7575+allowed to return keys or partial entities containing keys.
7676+7777+> **Note:** This essentially means that resolvers can return either scalar values for fields without
7878+> selection sets, and either partial entities or keys for fields with selection sets, i.e.
7979+> links / relations. When we return `null`, this will be interpreted a the literal GraphQL Null scalar,
8080+> while returning `undefined` will cause a cache miss.
72817382## Transforming Records
7483···222231223232However sometimes we'll need to resolve data from other fields in our resolvers.
224233225225-For records, if the other field is on the same `parent` entity, it may seem logical to access it on
226226-`parent[otherFieldName]` as well, however the `parent` object will only be sparsely populated with
227227-fields that the cache has already queried prior to reaching the resolver.
228228-229229-In the previous example, where we've created a resolver for `Todo.updatedAt` and accessed
230230-`parent.updatedAt` to transform its value the `parent.updatedAt` field is essentially a shortcut
231231-that allows us to get to the record quickly.
234234+> **Note:** For records, if the other field is on the same `parent` entity, it may seem logical to access it on
235235+> `parent[otherFieldName]` as well, however the `parent` object will only be sparsely populated with
236236+> fields that the cache has already queried prior to reaching the resolver.
237237+> In the previous example, where we've created a resolver for `Todo.updatedAt` and accessed
238238+> `parent.updatedAt` to transform its value the `parent.updatedAt` field is essentially a shortcut
239239+> that allows us to get to the record quickly.
232240233241Instead we can use [the `cache.resolve` method](../api/graphcache.md#resolve). This method
234242allows us to access Graphcache's cached data directly. It is used to resolve records or links on any
···261269262270When we call `cache.resolve(parent, "updatedAt")`, the cache will look up the `"updatedAt"` field on
263271the `parent` entity, i.e. on the current `Todo` entity.
264264-We've also previously learned that `parent` may not contain all fields that the entity may have and
265265-may hence be missing its keyable fields, like `id`, so why does this then work?
266266-It works because `cache.resolve(parent)` is a shortcut for `cache.resolve(info.parentKey)`.
272272+273273+> **Note:** We've also previously learned that `parent` may not contain all fields that the entity may have and
274274+> may hence be missing its keyable fields, like `id`, so why does this then work?
275275+> It works because `cache.resolve(parent)` is a shortcut for `cache.resolve(info.parentKey)`.
267276268277Like the `info.fieldName` property `info.parentKey` gives us information about the current state of
269278Graphcache's query operation. In this case, `info.parentKey` tells us what the parent's key is.
···308317other entities ("links") instead. It can even give you arrays of keys or records when the field's
309318value contains a list.
310319311311-It's a pretty flexible method that allows us to access arbitrary values from our cache, however, we
312312-have to be careful about what value will be resolved by it, since the cache can't know itself what
313313-type of value it may return.
320320+When a value is not present in the cache, `cache.resolve` will instead return `undefined` to signal
321321+that a value is uncached. Similarly, a resolver may return `undefined` to tell Graphcache that the
322322+field isn’t cached and that a call to the API is necessary.
323323+324324+`cache.resolve` is a pretty flexible method that allows us to access arbitrary values from our cache,
325325+however, we have to be careful about what value will be resolved by it, since the cache can't know
326326+itself what type of value it may return.
314327315328The last trick this method allows you to apply is to access arbitrary fields on the root `Query`
316329type. If we call `cache.resolve("Query", ...)` then we're also able to access arbitrary fields
+7-1
docs/graphcache/normalized-caching.md
···393393object is keyable, it will tell _Graphcache_ what the key of the returned entity is. In other words,
394394we've told it how to get to a `Todo` from the `Query.todo` field.
395395396396-This mechanism is immensely more powerful than this example. We have two other use-cases that
396396+This mechanism is immensely more powerful than this example. We have other use-cases that
397397resolvers may be used for:
398398399399- Resolvers can be applied to fields with records, which means that it can be used to change or
···402402- Resolvers can return deeply nested results, which will be layered on top of the in-memory
403403 relational cached data of _Graphcache_, which means that it can emulate infinite pagination and
404404 other complex behaviour.
405405+- Resolvers can change when a cache miss or hit occurs. Returning `null` means that a field’s value
406406+ is literally `null`, which will not cause a cache miss, while returning `undefined` will mean
407407+ a field’s value is uncached.
408408+- Resolvers can return either partial entities or keys, so we can chain `cache.resolve` calls to
409409+ read fields from the cache, even when a field is pointing at another entity, since we can return
410410+ keys to the other entity directly.
405411406412[Read more about resolvers on the following page about "Local Resolvers".](./local-resolvers.md)
407413
+2-2
exchanges/graphcache/src/operations/shared.ts
···223223 x == null ? null : (x as Data | NullArray<Data>);
224224225225export const ensureLink = (store: Store, ref: Link<Entity>): Link => {
226226- if (ref == null) {
227227- return ref;
226226+ if (!ref) {
227227+ return ref || null;
228228 } else if (Array.isArray(ref)) {
229229 const link = new Array(ref.length);
230230 for (let i = 0, l = link.length; i < l; i++)
···131131 * as retrieved for instance by {@link Cache.keyOfEntity} or a partial GraphQL object
132132 * (i.e. an object with a `__typename` and key field).
133133 */
134134-export type Entity = null | Data | string;
134134+export type Entity = undefined | null | Data | string;
135135136136/** A key of an entity, or `null`; or a list of keys.
137137 *
···284284 * If it’s passed a `string` or `null`, it will simply return what it’s been passed.
285285 * Objects that lack a `__typename` field will return `null`.
286286 */
287287- keyOfEntity(entity: Entity): string | null;
287287+ keyOfEntity(entity: Entity | undefined): string | null;
288288289289 /** Returns the cache key for a field.
290290 *
···327327 * );
328328 * ```
329329 */
330330- resolve(entity: Entity, fieldName: string, args?: FieldArgs): DataField;
330330+ resolve(
331331+ entity: Entity | undefined,
332332+ fieldName: string,
333333+ args?: FieldArgs
334334+ ): DataField | undefined;
331335332336 /** Returns a cached value on a given entity’s field by its field key.
333337 *
334338 * @deprecated
335339 * Use {@link cache.resolve} instead.
336340 */
337337- resolveFieldByKey(entity: Entity, fieldKey: string): DataField;
341341+ resolveFieldByKey(
342342+ entity: Entity | undefined,
343343+ fieldKey: string
344344+ ): DataField | undefined;
338345339346 /** Returns a list of cached fields for a given GraphQL object (“entity”).
340347 *
···372379 * However, if a field name (and optionally, its arguments) are passed,
373380 * only a single field is erased.
374381 */
375375- invalidate(entity: Entity, fieldName?: string, args?: FieldArgs): void;
382382+ invalidate(
383383+ entity: Entity | undefined,
384384+ fieldName?: string,
385385+ args?: FieldArgs
386386+ ): void;
376387377388 /** Updates a GraphQL query‘s cached data.
378389 *