Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1---
2title: '@urql/exchange-graphcache'
3order: 4
4---
5
6# @urql/exchange-graphcache
7
8> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.
9> You can view TSDocs while using these packages in your editor, as long as it supports the
10> TypeScript Language Server.
11> We're planning to replace these API docs with a separate web app soon.
12
13The `@urql/exchange-graphcache` package contains an addon `cacheExchange` for `urql` that may be
14used to replace the default [`cacheExchange`](./core.md#cacheexchange), which switches `urql` from
15using ["Document Caching"](../basics/document-caching.md) to ["Normalized
16Caching"](../graphcache/normalized-caching.md).
17
18[Read more about how to use and configure _Graphcache_ in the "Graphcache"
19section](../graphcache/README.md)
20
21## cacheExchange
22
23The `cacheExchange` function, as exported by `@urql/exchange-graphcache`, accepts a single object of
24options and returns an [`Exchange`](./core.md#exchange).
25
26| Input | Description |
27| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
28| `keys` | A mapping of key generator functions for types that are used to override the default key generation that _Graphcache_ uses to normalize data for given types. |
29| `resolvers` | A nested mapping of resolvers, which are used to override the record or entity that _Graphcache_ resolves for a given field for a type. |
30| `directives` | A mapping of directives, which are functions accepting directive arguments and returning a resolver, which can be referenced by `@localDirective` or `@_localDirective` in queries. |
31| `updates` | A nested mapping of updater functions for mutation and subscription fields, which may be used to add side-effects that update other parts of the cache when the given subscription or mutation field is written to the cache. |
32| `optimistic` | A mapping of mutation fields to resolvers that may be used to provide _Graphcache_ with an optimistic result for a given mutation field that should be applied to the cached data temporarily. |
33| `schema` | A serialized GraphQL schema that is used by _Graphcache_ to resolve partial data, interfaces, and enums. The schema also used to provide helpful warnings for [schema awareness](../graphcache/schema-awareness.md). |
34| `storage` | A persisted storage interface that may be provided to preserve cache data for [offline support](../graphcache/offline.md). |
35| `globalIDs` | A boolean or list of typenames that have globally unique ids, this changes how graphcache internally keys the entities. This can be useful for complex interface relationships. |
36| `logger` | A function that will be invoked for warning/debug/... logs |
37
38The `@urql/exchange-graphcache` package also exports the `offlineExchange`; which is identical to
39the `cacheExchange` but activates [offline support](../graphcache/offline.md) when the `storage` option is passed.
40
41### `keys` option
42
43This is a mapping of typenames to `KeyGenerator` functions.
44
45```ts
46interface KeyingConfig {
47 [typename: string]: (data: Data) => null | string;
48}
49```
50
51It may be used to alter how _Graphcache_ generates the key it uses for normalization for individual
52types. The key generator function may also always return `null` when a type should always be
53embedded.
54
55[Read more about how to set up `keys` in the "Key Generation" section of the "Normalized Caching"
56page.](../graphcache/normalized-caching.md#key-generation)
57
58### `resolvers` option
59
60This configuration is a mapping of typenames to field names to `Resolver` functions.
61A resolver may be defined to override the entity or record that a given field on a type should
62resolve on the cache.
63
64```ts
65interface ResolverConfig {
66 [typeName: string]: {
67 [fieldName: string]: Resolver;
68 };
69}
70```
71
72A `Resolver` receives four arguments when it's called: `parent`, `args`, `cache`, and
73`info`.
74
75| Argument | Type | Description |
76| -------- | -------- | ----------------------------------------------------------------------------------------------------------- |
77| `parent` | `Data` | The parent entity that the given field is on. |
78| `args` | `object` | The arguments for the given field the updater is executed on. |
79| `cache` | `Cache` | The cache using which data can be read or written. [See `Cache`.](#cache) |
80| `info` | `Info` | Additional metadata and information about the current operation and the current field. [See `Info`.](#info) |
81
82We can use the arguments it receives to either return new data based on just the arguments and other
83cache information, but we may also read information about the parent and return new data for the
84current field.
85
86```js
87{
88 Todo: {
89 createdAt(parent, args, cache) {
90 // Read `createdAt` on the parent but return a Date instance
91 const date = cache.resolve(parent, 'createdAt');
92 return new Date(date);
93 }
94 }
95}
96```
97
98[Read more about how to set up `resolvers` on the "Computed Queries"
99page.](../graphcache/local-resolvers.md)
100
101### `updates` option
102
103The `updates` configuration is a mapping of `'Mutation' | 'Subscription'` to field names to
104`UpdateResolver` functions. An update resolver may be defined to add side-effects that run when a
105given mutation field or subscription field is written to the cache. These side-effects are helpful
106to update data in the cache that is implicitly changed on the GraphQL API, that _Graphcache_ can't
107know about automatically.
108
109For mutation fields that don't have an updater, Graphcache has a fallback: if a returned entity
110isn't currently found in the cache, it assumes a create-mutation and invalidates cached
111entities of that type. This behavior was introduced in Graphcache v7 and is skipped once an updater
112for the mutation field is added.
113
114```ts
115interface UpdatesConfig {
116 Mutation: {
117 [fieldName: string]: UpdateResolver;
118 };
119 Subscription: {
120 [fieldName: string]: UpdateResolver;
121 };
122}
123```
124
125An `UpdateResolver` receives four arguments when it's called: `result`, `args`, `cache`, and
126`info`.
127
128| Argument | Type | Description |
129| -------- | -------- | ----------------------------------------------------------------------------------------------------------- |
130| `result` | `any` | Always the entire `data` object from the mutation or subscription. |
131| `args` | `object` | The arguments for the given field the updater is executed on. |
132| `cache` | `Cache` | The cache using which data can be read or written. [See `Cache`.](#cache) |
133| `info` | `Info` | Additional metadata and information about the current operation and the current field. [See `Info`.](#info) |
134
135It's possible to derive more information about the current update using the `info` argument. For
136instance this metadata contains the current `fieldName` of the updater which may be used to make an
137updater function more reusable, along with `parentKey` and other key fields. It also contains
138`variables` and `fragments` which remain the same for the entire write operation, and additionally
139it may have the `error` field set to describe whether the current field is `null` because the API
140encountered a `GraphQLError`.
141
142[Read more about how to set up `updates` on the "Custom Updates"
143page.](../graphcache/cache-updates.md)
144
145### `optimistic` option
146
147The `optimistic` configuration is a mapping of Mutation field names to `OptimisticMutationResolver`
148functions, which return optimistic mutation results for given fields. These results are used by
149_Graphcache_ to optimistically update the cache data, which provides an immediate and temporary
150change to its data before a mutation completes.
151
152```ts
153interface OptimisticMutationConfig {
154 [mutationFieldName: string]: OptimisticMutationResolver;
155}
156```
157
158A `OptimisticMutationResolver` receives three arguments when it's called: `variables`, `cache`, and
159`info`.
160
161| Argument | Type | Description |
162| -------- | -------- | ----------------------------------------------------------------------------------------------------------- |
163| `args` | `object` | The arguments that the given mutation field received. |
164| `cache` | `Cache` | The cache using which data can be read or written. [See `Cache`.](#cache) |
165| `info` | `Info` | Additional metadata and information about the current operation and the current field. [See `Info`.](#info) |
166
167[Read more about how to set up `optimistic` on the "Custom Updates"
168page.](../graphcache/cache-updates.md)
169
170### `schema` option
171
172The `schema` option may be used to pass a `IntrospectionQuery` data to _Graphcache_, in other words
173it's used to provide schema information to it. This schema is then used to resolve and return
174partial results when querying, which are results that the cache can partially resolve as long as no
175required fields are missing.
176
177[Read more about how to use the `schema` option on the "Schema Awareness"
178page.](../graphcache/schema-awareness.md)
179
180### `storage` option
181
182The `storage` option is an interface of methods that are used by the `offlineExchange` to persist
183the cache's data to persisted storage on the user's device. it
184
185> **NOTE:** Offline Support is currently experimental! It hasn't been extensively tested yet and
186> may not always behave as expected. Please try it out with caution!
187
188| Method | Type | Description |
189| ----------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
190| `writeData` | `(delta: SerializedEntries) => Promise<void>` | This provided method must be able to accept an object of key-value entries that will be persisted to the storage. This method is called as a batch of updated entries becomes ready. |
191| `readData` | `() => Promise<SerializedEntries>` | This provided method must be able to return a single combined object of previous key-value entries that have been previously preserved using `writeData`. It's only called on startup. |
192| `writeMetadata` | `(json: SerializedRequest[]) => void` | This provided method must be able to persist metadata for the cache. For backwards compatibility it should be able to accept any JSON data. |
193| `readMetadata` | `() => Promise<null \| SerializedRequest[]>` | This provided method must be able to read the persisted metadata that has previously been written using `writeMetadata`. It's only called on startup. |
194| `onOnline` | `(cb: () => void) => void` | This method must be able to accept a callback that is called when the user's device comes back online. |
195| `onCacheHydrated` | `() => void` | This method will be called when the `cacheExchange` has finished hydrating the data coming from storage. |
196
197These options are split into three parts:
198
199- The `writeMetadata` and `readMetadata` methods are used to persist in-progress optimistic
200 mutations to a storage so that they may be retried if the app has been closed while some
201 optimistic mutations were still in progress.
202- The `writeData` and `readData` methods are used to persist any cache data. This is the normalized
203 data that _Graphcache_ usually keeps in memory. The `cacheExchange` will frequently call
204 `writeData` with a partial object of its cache data, which `readData` must then be able to return
205 in a single combined object on startup. We call the partial objects that `writeData` is called
206 with "deltas".
207- The `onOnline` method is only used to receive a trigger that determines whether the user's device
208 has come back online, which is used to retry optimistic mutations that have previously failed due
209 to being offline.
210
211The `storage` option may also be used with the `cacheExchange` instead of the `offlineExchange`, but
212will then only use `readData` and `writeData` to persist its cache data. This is not full offline
213support, but will rather be "persistence support".
214
215[Read more about how to use the `storage` option on the "Offline Support"
216page.](../graphcache/offline.md)
217
218## Cache
219
220An instance of the `Cache` interface is passed to every resolvers and updater function. It may be
221used to read cached data or write cached data, which may be used in combination with the
222[`cacheExchange` configuration](#cacheexchange) to alter the default behaviour of _Graphcache_.
223
224### keyOfEntity
225
226The `cache.keyOfEntity` method may be called with a partial `Data` object and will return the key
227for that object, or `null` if it's not keyable.
228
229An object may not be keyable if it's missing the `__typename` or `id` (which falls back to `_id`)
230fields. This method does take the [`keys` configuration](#keys-option) into account.
231
232```js
233cache.keyOfEntity({ __typename: 'Todo', id: 1 }); // 'Todo:1'
234cache.keyOfEntity({ __typename: 'Query' }); // 'Query'
235cache.keyOfEntity({ __typename: 'Unknown' }); // null
236```
237
238There's an alternative method, `cache.keyOfField` which generates a key for a given field. This is
239only rarely needed but similar to `cache.keyOfEntity`. This method accepts a field name and
240optionally a field's arguments.
241
242```js
243cache.keyOfField('todo'); // 'todo'
244cache.keyOfField('todo', { id: 1 }); // 'todo({"id":1})'
245```
246
247Internally, these are the keys that records and links are stored on per entity.
248
249### resolve
250
251This method retrieves a value or link for a given field, given a partially keyable `Data` object or
252entity, a field name, and optionally the field's arguments. Internally this method accesses the
253cache by using `cache.keyOfEntity` and `cache.keyOfField`.
254
255```js
256// This may resolve a link:
257cache.resolve({ __typename: 'Query' }, 'todo', { id: 1 }); // 'Todo:1'
258
259// This may also resolve records / scalar values:
260cache.resolve({ __typename: 'Todo', id: 1 }, 'id'); // 1
261
262// You can also chain multiple calls to `cache.resolve`!
263cache.resolve(cache.resolve({ __typename: 'Query' }, 'todo', { id: 1 }), 'id'); // 1
264```
265
266As you can see in the last example of this code snippet, the `Data` object can also be replaced by
267an entity key, which makes it possible to pass a key from `cache.keyOfEntity` or another call to
268`cache.resolve` instead of the partial entity.
269
270> **Note:** Because `cache.resolve` may return either a scalar value or another entity key, it may
271> be dangerous to use in some cases. It's a good idea to make sure first whether the field you're
272> reading will be a key or a value.
273
274The `cache.resolve` method may also be called with a field key as generated by `cache.keyOfField`.
275
276```js
277cache.resolve({ __typename: 'Query' }, cache.keyOfField('todo', { id: 1 })); // 'Todo:1'
278```
279
280This specialized case is likely only going to be useful in combination with
281[`cache.inspectFields`](#inspectfields).
282
283### inspectFields
284
285The `cache.inspectFields` method may be used to interrogate the cache about all available fields on
286a specific entity. It accepts a partial entity or an entity key, like [`cache.resolve`](#resolve)'s
287first argument.
288
289When calling the method this returns an array of `FieldInfo` objects, one per field (including
290differing arguments) that is known to the cache. The `FieldInfo` interface has three properties:
291`fieldKey`, `fieldName`, and `arguments`:
292
293| Argument | Type | Description |
294| ----------- | ---------------- | ------------------------------------------------------------------------------- |
295| `fieldName` | `string` | The field's name (without any arguments, just the name) |
296| `arguments` | `object \| null` | The field's arguments, or `null` if the field doesn't have any arguments |
297| `fieldKey` | `string` | The field's cache key, which is similar to what `cache.keyOfField` would return |
298
299This works on any given entity. When calling this method the cache works in reverse on its data
300structure, by parsing the entity's individual field keys.
301p
302
303```js
304cache.inspectFields({ __typename: 'Query' });
305
306/*
307 [
308 { fieldName: 'todo', arguments: { id: 1 }, fieldKey: 'id({"id":1})' },
309 { fieldName: 'todo', arguments: { id: 2 }, fieldKey: 'id({"id":2})' },
310 ...
311 ]
312*/
313```
314
315### readFragment
316
317`cache.readFragment` accepts a GraphQL `DocumentNode` as the first argument and a partial entity or
318an entity key as the second, like [`cache.resolve`](#resolve)'s first argument.
319
320The method will then attempt to read the entity according to the fragment entirely from the cached
321data. If any data is uncached and missing it'll return `null`.
322
323```js
324import { gql } from '@urql/core';
325
326cache.readFragment(
327 gql`
328 fragment _ on Todo {
329 id
330 text
331 }
332 `,
333 { id: 1 }
334); // Data or null
335```
336
337Note that the `__typename` may be left out on the partial entity if the fragment isn't on an
338interface or union type, since in that case the `__typename` is already present on the fragment
339itself.
340
341If any fields on the fragment require variables, you can pass them as the third argument like so:
342
343```js
344import { gql } from '@urql/core';
345
346cache.readFragment(
347 gql`
348 fragment _ on User {
349 id
350 permissions(byGroupId: $groupId)
351 }
352 `,
353 { id: 1 }, // this identifies the fragment (User) entity
354 { groupId: 5 } // any additional field variables
355);
356```
357
358If you need a specific fragment in a document containing multiple you can leverage
359the fourth argument like this:
360
361```js
362import { gql } from '@urql/core';
363
364cache.readFragment(
365 gql`
366 fragment todoFields on Todo {
367 id
368 }
369
370 fragment userFields on User {
371 id
372 }
373 `,
374 { id: 1 }, // this identifies the fragment (User) entity
375 undefined,
376 'userFields' // if not passed we take the first fragment, in this case todoFields
377);
378```
379
380[Read more about using `readFragment` on the ["Local Resolvers"
381page.](../graphcache/local-resolvers.md#reading-a-fragment)
382
383### readQuery
384
385The `cache.readQuery` method is similar to `cache.readFragment`, but instead of reading a fragment
386from cache, it reads an entire query. The only difference between how these two methods are used is
387`cache.readQuery`'s input, which is an object instead of two arguments.
388
389The method accepts a `{ query, variables }` object as the first argument, where `query` may either
390be a `DocumentNode` or a `string` and variables may optionally be an object.
391
392```js
393cache.readQuery({
394 query: `
395 query ($id: ID!) {
396 todo(id: $id) { id, text }
397 }
398 `,
399 variables: {
400 id: 1
401 }
402); // Data or null
403```
404
405[Read more about using `readQuery` on the ["Local Resolvers"
406page.](../graphcache/local-resolvers.md#reading-a-query)
407
408### link
409
410Corresponding to [`cache.resolve`](#resolve), the `cache.link` method allows
411links in the cache to be updated. While the `cache.resolve` method reads both
412records and links from the cache, the `cache.link` method will only ever write
413links as fragments (See [`cache.writeFragment`](#writefragment) below) are more
414suitable for updating scalar data in the cache.
415
416The arguments for `cache.link` are identical to [`cache.resolve`](#resolve) and
417the field's arguments are optional. However, the last argument must always be
418a link, meaning `null`, an entity key, a keyable entity, or a list of these.
419
420In other words, `cache.link` accepts an entity to write to as its first argument,
421with the same arguments as `cache.keyOfEntity`. It then accepts one or two arguments
422that are passed to `cache.keyOfField` to get the targeted field key. And lastly,
423you may pass a list or a single entity (or an entity key).
424
425```js
426// Link Query.todo field to a todo item
427cache.link({ __typename: 'Query' }, 'todo', { __typename: 'Todo', id: 1 });
428
429// You may also pass arguments instead:
430cache.link({ __typename: 'Query' }, 'todo', { id: 1 }, { __typename: 'Todo', id: 1 });
431
432// Or use entity keys instead of the entities themselves:
433cache.link('Query', 'todo', cache.keyOfEntity({ __typename: 'Todo', id: 1 }));
434```
435
436The method may [output a
437warning](../graphcache/errors.md#12-cant-generate-a-key-for-writefragment-or-link) when any of the
438entities were passed as objects but aren't keyable, which is useful when a scalar or a non-keyable
439object have been passed to `cache.link` accidentally.
440
441### writeFragment
442
443Corresponding to [`cache.readFragment`](#readfragments), the `cache.writeFragment` method allows
444data in the cache to be updated.
445
446The arguments for `cache.writeFragment` are identical to [`cache.readFragment`](#readfragment),
447however the second argument, `data`, should not only contain properties that are necessary to derive
448an entity key from the given data, but also the fields that will be written:
449
450```js
451import { gql } from '@urql/core';
452
453cache.writeFragment(
454 gql`
455 fragment _ on Todo {
456 text
457 }
458 `,
459 { id: 1, text: 'New Todo Text' }
460);
461```
462
463In the example we can see that the `writeFragment` method returns `undefined`. Furthermore we pass
464`id` in our `data` object so that an entity key can be written, but the fragment itself doesn't have
465to include these fields.
466
467If you need a specific fragment in a document containing multiple you can leverage
468the fourth argument like this:
469
470```js
471import { gql } from '@urql/core';
472
473cache.writeFragment(
474 gql`
475 fragment todoFields on Todo {
476 id
477 text
478 }
479
480 fragment userFields on User {
481 id
482 name
483 }
484 `,
485 { id: 1, name: 'New Name' }
486 undefined,
487 'userFields' // if not passed we take the first fragment, in this case todoFields
488);
489```
490
491[Read more about using `writeFragment` on the ["Custom Updates"
492page.](../graphcache/cache-updates.md#cachewritefragment)
493
494### updateQuery
495
496Similarly to [`cache.writeFragment`](#writefragment), there's an analogous method for
497[`cache.readQuery`](#readquery) that may be used to update query data.
498
499The `cache.updateQuery` method accepts the same `{ query, variables }` object input as its first
500argument, which is the query we'd like to write to the cache. As a second argument the method
501accepts an updater function. This function will be called with the query data that is already in the
502cache (which may be `null` if the data is uncached) and must return the new data that should be
503written to the cache.
504
505```js
506const TodoQuery = `
507 query ($id: ID!) {
508 todo(id: $id) { id, text }
509 }
510`;
511
512cache.updateQuery({ query: TodoQuery, variables: { id: 1 } }, data => {
513 if (!data) return null;
514 data.todo.text = 'New Todo Text';
515 return data;
516});
517```
518
519As we can see, our updater may return `null` to cancel updating any data, which we do in case the
520query data is uncached.
521
522We can also see that data can simply be mutated and doesn't have to be altered immutably. This is
523because all data from the cache is already a deep copy and hence we can do to it whatever we want.
524
525[Read more about using `updateQuery` on the "Custom Updates"
526page.](../graphcache/cache-updates.md#cacheupdatequery)
527
528### invalidate
529
530The `cache.invalidate` method can be used to delete (i.e. "evict") an entity from the cache
531entirely. This will cause it to disappear from all queries in _Graphcache_.
532
533Its arguments are identical to [`cache.resolve`](#resolve).
534
535Since deleting an entity will lead to some queries containing missing and uncached data, calling
536`invalidate` may lead to additional GraphQL requests being sent, unless you're using [_Graphcache_'s
537"Schema Awareness" feature](../graphcache/schema-awareness.md), which takes optional fields into
538account.
539
540This method accepts a partial entity or an entity key as its first argument, similar to
541[`cache.resolve`](#resolve)'s first argument.
542
543```js
544cache.invalidate({ __typename: 'Todo', id: 1 }); // Invalidates Todo:1
545```
546
547Additionally `cache.invalidate` may be used to delete specific fields only, which can be useful when
548for instance a list is supposed to be evicted from cache, where a full invalidation may be
549impossible. This is often the case when a field on the root `Query` needs to be deleted.
550
551This method therefore accepts two additional arguments, similar to [`cache.resolve`](#resolve).
552
553```js
554// Invalidates `Query.todos` with the `first: 10` argument:
555cache.invalidate('Query', 'todos', { first: 10 });
556```
557
558## Info
559
560This is a metadata object that is passed to every resolver and updater function. It contains basic
561information about the current GraphQL document and query, and also some information on the current
562field that a given resolver or updater is called on.
563
564| Argument | Type | Description |
565| ---------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
566| `parent` | `Data` | The field's parent entity's data, as it was written or read up until now, which means it may be incomplete. [Use `cache.resolve`](#resolve) to read from it. |
567| `parentTypeName` | `string` | The field's parent entity's typename |
568| `parentKey` | `string` | The field's parent entity's cache key (if any) |
569| `parentFieldKey` | `string` | The current key's cache key, which is the parent entity's key combined with the current field's key (This is mostly obsolete) |
570| `fieldName` | `string` | The current field's name |
571| `fragments` | `{ [name: string]: FragmentDefinitionNode }` | A dictionary of fragments from the current GraphQL document |
572| `variables` | `object` | The current GraphQL operation's variables (may be an empty object) |
573| `error` | `GraphQLError \| undefined` | The current GraphQLError for a given field. This will always be `undefined` for resolvers and optimistic updaters, but may be present for updaters when the API has returned an error for a given field. |
574| `partial` | `?boolean` | This may be set to `true` at any point in time (by your custom resolver or by _Graphcache_) to indicate that some data is uncached and missing |
575| `optimistic` | `?boolean` | This is only `true` when an optimistic mutation update is running |
576
577> **Note:** Using `info` is regarded as a last resort. Please only use information from it if
578> there's no other solution to get to the metadata you need. We don't regard the `Info` API as
579> stable and may change it with a simple minor version bump.
580
581## The `/extras` import
582
583The `extras` subpackage is published with _Graphcache_ and contains helpers and utilities that don't
584have to be included in every app or aren't needed by all users of _Graphcache_.
585All utilities from extras may be imported from `@urql/exchange-graphcache/extras`.
586
587Currently the `extras` subpackage only contains the [pagination resolvers that have been mentioned
588on the "Computed Queries" page.](../graphcache/local-resolvers.md#pagination)
589
590### simplePagination
591
592Accepts a single object of optional options and returns a resolver that can be inserted into the
593[`cacheExchange`'s](#cacheexchange) [`resolvers` configuration.](#resolvers-option)
594
595| Argument | Type | Description |
596| ---------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
597| `offsetArgument` | `?string` | The field arguments' property, as passed to the resolver, that contains the current offset, i.e. the number of items to be skipped. Defaults to `'skip'`. |
598| `limitArgument` | `?string` | The field arguments' property, as passed to the resolver, that contains the current page size limit, i.e. the number of items on each page. Defaults to `'limit'`. |
599| `mergeMode` | `'after' \| 'before'` | This option defines whether pages are merged before or after preceding ones when paginating. Defaults to `'after'`. |
600
601Once set up, the resulting resolver is able to automatically concatenate all pages of a given field
602automatically. Queries to this resolvers will from then on only return the infinite, combined list
603of all pages.
604
605[Read more about `simplePagination` on the "Computed Queries"
606page.](../graphcache/local-resolvers.md#simple-pagination)
607
608### relayPagination
609
610Accepts a single object of optional options and returns a resolver that can be inserted into the
611[`cacheExchange`'s](#cacheexchange) [`resolvers` configuration.](#resolvers-option)
612
613| Argument | Type | Description |
614| ----------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
615| `mergeMode` | `'outwards' \| 'inwards'` | With Relay pagination, pages can be queried forwards and backwards using `after` and `before` cursors. This option defines whether pages that have been queried backwards should be concatenated before (outwards) or after (inwards) all pages that have been queried forwards. |
616
617Once set up, the resulting resolver is able to automatically concatenate all pages of a given field
618automatically. Queries to this resolvers will from then on only return the infinite, combined list
619of all pages.
620
621[Read more about `relayPagnation` on the "Computed Queries"
622page.](../graphcache/local-resolvers.md#relay-pagination)
623
624## The `/default-storage` import
625
626The `default-storage` subpackage is published with _Graphcache_ and contains a default storage
627interface that may be used with the [`storage` option.](#storage-option)
628
629It contains the `makeDefaultStorage` export which is a factory function that accepts a few options
630and returns a full [storage interface](#storage-option). This storage by default persists to
631[IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).
632
633| Argument | Type | Description |
634| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
635| `idbName` | `string` | The name of the IndexedDB database that is used and created if needed. By default this is set to `"graphcache-v3"` |
636| `maxAge` | `number` | The maximum age of entries that the storage should use in whole days. By default the storage will discard entries that are older than seven days. |