Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

(graphcache) - Add generics for codegen to store and cacheExchange (#1562)

* add generics for graphCache store/exchange

* disable all packages apart from graphcache

* temp disable closure

* revert used command

* remove extends UpdatesConfig

* add the extends back

* add generics to the Resolver types

* lint and add changeset

* revert changes to csb-ci and rollup-config

* fix types

* try with one generic

* Fix undefinedundefinedundefined

* fix types

* Update offlineExchange.ts

* allow for array data

* Update types.ts

* fix some types

* undo type-change

* update types

* Update exchanges/graphcache/src/types.ts

Co-authored-by: Phil Pluckthun <phil@kitten.sh>

* Update .changeset/silent-turtles-check.md

Co-authored-by: Phil Pluckthun <phil@kitten.sh>

* lint store.ts

Co-authored-by: Andy Richardson <andy.john.richardson@gmail.com>
Co-authored-by: Phil Pluckthun <phil@kitten.sh>

authored by

Jovi De Croock
Phil Pluckthun
Andy Richardson
and committed by
GitHub
367d1985 aa5685b3

+46 -56
+5
.changeset/silent-turtles-check.md
··· 1 + --- 2 + '@urql/exchange-graphcache': minor 3 + --- 4 + 5 + Add on a generic to `cacheExchange` and `offlineExchange` for future, experimental type-generation support.
+6 -25
exchanges/graphcache/src/cacheExchange.ts
··· 28 28 import { query, write, writeOptimistic } from './operations'; 29 29 import { makeDict, isDictEmpty } from './helpers/dict'; 30 30 import { addCacheOutcome, toRequestPolicy } from './helpers/operation'; 31 - import { IntrospectionData, filterVariables, getMainOperation } from './ast'; 31 + import { filterVariables, getMainOperation } from './ast'; 32 32 import { Store, noopDataState, hydrateData, reserveLayer } from './store'; 33 - 34 - import { 35 - UpdatesConfig, 36 - ResolverConfig, 37 - OptimisticMutationConfig, 38 - KeyingConfig, 39 - StorageAdapter, 40 - Dependencies, 41 - } from './types'; 33 + import { Dependencies, CacheExchangeOpts } from './types'; 42 34 43 35 type OperationResultWithMeta = OperationResult & { 44 36 outcome: CacheOutcome; ··· 50 42 type OptimisticDependencies = Map<number, Dependencies>; 51 43 type DependentOperations = Record<string, number[]>; 52 44 53 - export interface CacheExchangeOpts { 54 - updates?: Partial<UpdatesConfig>; 55 - resolvers?: ResolverConfig; 56 - optimistic?: OptimisticMutationConfig; 57 - keys?: KeyingConfig; 58 - schema?: IntrospectionData; 59 - storage?: StorageAdapter; 60 - } 61 - 62 - export const cacheExchange = (opts?: CacheExchangeOpts): Exchange => ({ 63 - forward, 64 - client, 65 - dispatchDebug, 66 - }) => { 67 - const store = new Store(opts); 45 + export const cacheExchange = <C extends Partial<CacheExchangeOpts>>( 46 + opts?: C 47 + ): Exchange => ({ forward, client, dispatchDebug }) => { 48 + const store = new Store<C>(opts); 68 49 69 50 let hydration: void | Promise<void>; 70 51 if (opts && opts.storage) {
+7 -4
exchanges/graphcache/src/offlineExchange.ts
··· 24 24 SerializedRequest, 25 25 OptimisticMutationConfig, 26 26 Variables, 27 + CacheExchangeOpts, 27 28 } from './types'; 28 29 29 30 import { makeDict } from './helpers/dict'; 30 - import { cacheExchange, CacheExchangeOpts } from './cacheExchange'; 31 + import { cacheExchange } from './cacheExchange'; 31 32 import { toRequestPolicy } from './helpers/operation'; 32 33 33 34 /** Determines whether a given query contains an optimistic mutation field */ 34 - const isOptimisticMutation = ( 35 - config: OptimisticMutationConfig, 35 + const isOptimisticMutation = <T extends OptimisticMutationConfig>( 36 + config: T, 36 37 operation: Operation 37 38 ) => { 38 39 const vars: Variables = operation.variables || makeDict(); ··· 65 66 error.networkError.message 66 67 )); 67 68 68 - export const offlineExchange = (opts: CacheExchangeOpts): Exchange => input => { 69 + export const offlineExchange = <C extends Partial<CacheExchangeOpts>>( 70 + opts: C 71 + ): Exchange => input => { 69 72 const { storage } = opts; 70 73 71 74 if (
+6 -13
exchanges/graphcache/src/store/store.ts
··· 11 11 Link, 12 12 Data, 13 13 QueryInput, 14 - UpdatesConfig, 15 14 UpdateResolver, 16 15 OptimisticMutationConfig, 17 16 KeyingConfig, 18 17 Entity, 18 + CacheExchangeOpts, 19 19 } from '../types'; 20 20 21 21 import { invariant } from '../helpers/help'; ··· 27 27 import * as InMemoryData from './data'; 28 28 29 29 import { 30 - IntrospectionData, 31 30 SchemaIntrospector, 32 31 buildClientSchema, 33 32 expectValidKeyingConfig, ··· 38 37 39 38 type RootField = 'query' | 'mutation' | 'subscription'; 40 39 41 - export interface StoreOpts { 42 - updates?: Partial<UpdatesConfig>; 43 - resolvers?: ResolverConfig; 44 - optimistic?: OptimisticMutationConfig; 45 - keys?: KeyingConfig; 46 - schema?: IntrospectionData; 47 - } 48 - 49 - export class Store implements Cache { 40 + export class Store< 41 + C extends Partial<CacheExchangeOpts> = Partial<CacheExchangeOpts> 42 + > implements Cache { 50 43 data: InMemoryData.InMemoryData; 51 44 52 45 resolvers: ResolverConfig; ··· 58 51 rootFields: { query: string; mutation: string; subscription: string }; 59 52 rootNames: { [name: string]: RootField }; 60 53 61 - constructor(opts?: StoreOpts) { 62 - if (!opts) opts = {}; 54 + constructor(opts?: C) { 55 + if (!opts) opts = {} as C; 63 56 64 57 this.resolvers = opts.resolvers || {}; 65 58 this.optimisticMutations = opts.optimistic || {};
+22 -14
exchanges/graphcache/src/types.ts
··· 1 1 import { TypedDocumentNode } from '@urql/core'; 2 2 import { GraphQLError, DocumentNode, FragmentDefinitionNode } from 'graphql'; 3 + import { IntrospectionData } from './ast'; 3 4 4 5 // Helper types 5 6 export type NullArray<T> = Array<null | T | NullArray<T>>; ··· 135 136 | null 136 137 | undefined; 137 138 139 + export type CacheExchangeOpts = { 140 + updates?: Partial<UpdatesConfig>; 141 + resolvers?: ResolverConfig; 142 + optimistic?: OptimisticMutationConfig; 143 + keys?: KeyingConfig; 144 + schema?: IntrospectionData; 145 + storage?: StorageAdapter; 146 + }; 147 + 138 148 // Cache resolvers are user-defined to overwrite an entity field result 139 - export type Resolver = ( 140 - parent: Data, 141 - args: Variables, 142 - cache: Cache, 143 - info: ResolveInfo 144 - ) => ResolverResult; 149 + export type Resolver< 150 + ParentData = DataFields, 151 + Args = Variables, 152 + Result = ResolverResult 153 + > = (parent: ParentData, args: Args, cache: Cache, info: ResolveInfo) => Result; 145 154 146 155 export interface ResolverConfig { 147 156 [typeName: string]: { ··· 149 158 }; 150 159 } 151 160 152 - export type UpdateResolver = ( 153 - result: Data, 154 - args: Variables, 161 + export type UpdateResolver<ParentData = DataFields, Args = Variables> = ( 162 + parent: ParentData, 163 + args: Args, 155 164 cache: Cache, 156 165 info: ResolveInfo 157 166 ) => void; ··· 167 176 }; 168 177 } 169 178 170 - export type OptimisticMutationResolver = ( 171 - vars: Variables, 172 - cache: Cache, 173 - info: ResolveInfo 174 - ) => Link<Data>; 179 + export type OptimisticMutationResolver< 180 + Args = Variables, 181 + Result = Link<Data> 182 + > = (vars: Args, cache: Cache, info: ResolveInfo) => Result; 175 183 176 184 export interface OptimisticMutationConfig { 177 185 [mutationFieldName: string]: OptimisticMutationResolver;