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) - Allow partial schema to be passed for altered root names (#1379)

* (graphcache) - Allow partial schema to be passed for altered root names

* Fix up PartialIntrospectionSchema type

authored by

Phil Pluckthun and committed by
GitHub
d0e067ad a861de8d

+74 -41
+5
.changeset/blue-bees-join.md
··· 1 + --- 2 + '@urql/exchange-graphcache': minor 3 + --- 4 + 5 + Allow `schema` option to be passed with a partial introspection result that only contains `queryType`, `mutationType`, and `subscriptionType` with their respective names. This allows you to pass `{ __schema: { queryType: { name: 'Query' } } }` and the likes to Graphcache's `cacheExchange` to alter the default root names without enabling full schema awareness.
+29 -12
exchanges/graphcache/src/ast/schema.ts
··· 1 1 import { 2 2 IntrospectionQuery, 3 + IntrospectionSchema, 3 4 IntrospectionInputValue, 4 5 IntrospectionTypeRef, 5 6 IntrospectionType, ··· 28 29 query: string | null; 29 30 mutation: string | null; 30 31 subscription: string | null; 31 - types: Record<string, SchemaObject | SchemaUnion>; 32 + types?: Record<string, SchemaObject | SchemaUnion>; 32 33 isSubType(abstract: string, possible: string): boolean; 33 34 } 34 35 36 + export interface PartialIntrospectionSchema { 37 + queryType: { name: string; kind?: any }; 38 + mutationType?: { name: string; kind?: any }; 39 + subscriptionType?: { name: string; kind?: any }; 40 + types?: IntrospectionSchema['types']; 41 + } 42 + 43 + export type IntrospectionData = 44 + | IntrospectionQuery 45 + | { __schema: PartialIntrospectionSchema }; 46 + 35 47 export const buildClientSchema = ({ 36 48 __schema, 37 - }: IntrospectionQuery): SchemaIntrospector => { 49 + }: IntrospectionData): SchemaIntrospector => { 38 50 const typemap: Record<string, SchemaObject | SchemaUnion> = {}; 39 51 40 52 const buildNameMap = <T extends { name: string }>( ··· 72 84 } 73 85 }; 74 86 75 - for (let i = 0; i < __schema.types.length; i++) { 76 - const type = __schema.types[i]; 77 - if (type && type.name) { 78 - const out = buildType(type); 79 - if (out) typemap[type.name] = out; 80 - } 81 - } 82 - 83 - return { 87 + const schema: SchemaIntrospector = { 84 88 query: __schema.queryType ? __schema.queryType.name : null, 85 89 mutation: __schema.mutationType ? __schema.mutationType.name : null, 86 90 subscription: __schema.subscriptionType 87 91 ? __schema.subscriptionType.name 88 92 : null, 89 - types: typemap, 93 + types: undefined, 90 94 isSubType(abstract: string, possible: string) { 91 95 const abstractType = typemap[abstract]; 92 96 const possibleType = typemap[possible]; ··· 104 108 } 105 109 }, 106 110 }; 111 + 112 + if (__schema.types) { 113 + schema.types = typemap; 114 + for (let i = 0; i < __schema.types.length; i++) { 115 + const type = __schema.types[i]; 116 + if (type && type.name) { 117 + const out = buildType(type); 118 + if (out) typemap[type.name] = out; 119 + } 120 + } 121 + } 122 + 123 + return schema; 107 124 };
+17 -17
exchanges/graphcache/src/ast/schemaPredicates.ts
··· 53 53 const typeCondition = getTypeCondition(node); 54 54 if (!typeCondition || typename === typeCondition) return true; 55 55 if ( 56 - schema.types[typeCondition] && 57 - schema.types[typeCondition].kind === 'OBJECT' 56 + schema.types![typeCondition] && 57 + schema.types![typeCondition].kind === 'OBJECT' 58 58 ) 59 59 return typeCondition === typename; 60 60 expectAbstractType(schema, typeCondition!); ··· 68 68 fieldName: string 69 69 ) => { 70 70 expectObjectType(schema, typename); 71 - const object = schema.types[typename] as SchemaObject; 71 + const object = schema.types![typename] as SchemaObject; 72 72 const field = object.fields[fieldName]; 73 73 if (!field) { 74 74 warn( ··· 88 88 89 89 function expectObjectType(schema: SchemaIntrospector, typename: string) { 90 90 invariant( 91 - schema.types[typename] && schema.types[typename].kind === 'OBJECT', 91 + schema.types![typename] && schema.types![typename].kind === 'OBJECT', 92 92 'Invalid Object type: The type `' + 93 93 typename + 94 94 '` is not an object in the defined schema, ' + ··· 99 99 100 100 function expectAbstractType(schema: SchemaIntrospector, typename: string) { 101 101 invariant( 102 - schema.types[typename] && 103 - (schema.types[typename].kind === 'INTERFACE' || 104 - schema.types[typename].kind === 'UNION'), 102 + schema.types![typename] && 103 + (schema.types![typename].kind === 'INTERFACE' || 104 + schema.types![typename].kind === 'UNION'), 105 105 'Invalid Abstract type: The type `' + 106 106 typename + 107 107 '` is not an Interface or Union type in the defined schema, ' + ··· 116 116 ): void { 117 117 if (process.env.NODE_ENV !== 'production') { 118 118 for (const key in keys) { 119 - if (!schema.types[key]) { 119 + if (!schema.types![key]) { 120 120 warn( 121 121 'Invalid Object type: The type `' + 122 122 key + ··· 137 137 } 138 138 139 139 if (schema.mutation) { 140 - const mutationFields = (schema.types[schema.mutation] as SchemaObject) 140 + const mutationFields = (schema.types![schema.mutation] as SchemaObject) 141 141 .fields; 142 142 const givenMutations = updates[schema.mutation] || {}; 143 143 for (const fieldName in givenMutations) { ··· 153 153 } 154 154 155 155 if (schema.subscription) { 156 - const subscriptionFields = (schema.types[ 156 + const subscriptionFields = (schema.types![ 157 157 schema.subscription 158 158 ] as SchemaObject).fields; 159 159 const givenSubscription = updates[schema.subscription] || {}; ··· 200 200 for (const key in resolvers) { 201 201 if (key === 'Query') { 202 202 if (schema.query) { 203 - const validQueries = (schema.types[schema.query] as SchemaObject) 203 + const validQueries = (schema.types![schema.query] as SchemaObject) 204 204 .fields; 205 205 for (const resolverQuery in resolvers.Query) { 206 206 if (!validQueries[resolverQuery]) { ··· 211 211 warnAboutResolver('Query'); 212 212 } 213 213 } else { 214 - if (!schema.types[key]) { 214 + if (!schema.types![key]) { 215 215 warnAboutResolver(key); 216 216 } else if ( 217 - schema.types[key].kind === 'INTERFACE' || 218 - schema.types[key].kind === 'UNION' 217 + schema.types![key].kind === 'INTERFACE' || 218 + schema.types![key].kind === 'UNION' 219 219 ) { 220 220 warnAboutAbstractResolver( 221 221 key, 222 - schema.types[key].kind as 'INTERFACE' | 'UNION' 222 + schema.types![key].kind as 'INTERFACE' | 'UNION' 223 223 ); 224 224 } else { 225 - const validTypeProperties = (schema.types[key] as SchemaObject).fields; 225 + const validTypeProperties = (schema.types![key] as SchemaObject).fields; 226 226 for (const resolverProperty in resolvers[key]) { 227 227 if (!validTypeProperties[resolverProperty]) { 228 228 warnAboutResolver(key + '.' + resolverProperty); ··· 242 242 } 243 243 244 244 if (schema.mutation) { 245 - const validMutations = (schema.types[schema.mutation] as SchemaObject) 245 + const validMutations = (schema.types![schema.mutation] as SchemaObject) 246 246 .fields; 247 247 for (const mutation in optimisticMutations) { 248 248 if (!validMutations[mutation]) {
+2 -4
exchanges/graphcache/src/cacheExchange.ts
··· 1 - import { IntrospectionQuery } from 'graphql'; 2 - 3 1 import { 4 2 Exchange, 5 3 formatDocument, ··· 30 28 import { query, write, writeOptimistic } from './operations'; 31 29 import { makeDict, isDictEmpty } from './helpers/dict'; 32 30 import { addCacheOutcome, toRequestPolicy } from './helpers/operation'; 33 - import { filterVariables, getMainOperation } from './ast'; 31 + import { IntrospectionData, filterVariables, getMainOperation } from './ast'; 34 32 import { Store, noopDataState, hydrateData, reserveLayer } from './store'; 35 33 36 34 import { ··· 57 55 resolvers?: ResolverConfig; 58 56 optimistic?: OptimisticMutationConfig; 59 57 keys?: KeyingConfig; 60 - schema?: IntrospectionQuery; 58 + schema?: IntrospectionData; 61 59 storage?: StorageAdapter; 62 60 } 63 61
+2 -1
exchanges/graphcache/src/offlineExchange.ts
··· 20 20 getName, 21 21 } from './ast'; 22 22 23 - import { makeDict } from './helpers/dict'; 24 23 import { 25 24 SerializedRequest, 26 25 OptimisticMutationConfig, 27 26 Variables, 28 27 } from './types'; 28 + 29 + import { makeDict } from './helpers/dict'; 29 30 import { cacheExchange, CacheExchangeOpts } from './cacheExchange'; 30 31 import { toRequestPolicy } from './helpers/operation'; 31 32
+13 -3
exchanges/graphcache/src/store/store.test.ts
··· 881 881 const fakeUpdater = jest.fn(); 882 882 883 883 const store = new Store({ 884 - schema: minifyIntrospectionQuery( 885 - require('../test-utils/altered_root_schema.json') 886 - ), 884 + schema: { 885 + __schema: { 886 + queryType: { 887 + name: 'query_root', 888 + }, 889 + mutationType: { 890 + name: 'mutation_root', 891 + }, 892 + subscriptionType: { 893 + name: 'subscription_root', 894 + }, 895 + }, 896 + }, 887 897 updates: { 888 898 Mutation: { 889 899 toggleTodo: fakeUpdater,
+6 -4
exchanges/graphcache/src/store/store.ts
··· 1 - import { DocumentNode, IntrospectionQuery } from 'graphql'; 2 - 1 + import { DocumentNode } from 'graphql'; 3 2 import { TypedDocumentNode, formatDocument, createRequest } from '@urql/core'; 4 3 5 4 import { ··· 25 24 import * as InMemoryData from './data'; 26 25 27 26 import { 27 + IntrospectionData, 28 28 SchemaIntrospector, 29 29 buildClientSchema, 30 30 expectValidKeyingConfig, ··· 40 40 resolvers?: ResolverConfig; 41 41 optimistic?: OptimisticMutationConfig; 42 42 keys?: KeyingConfig; 43 - schema?: IntrospectionQuery; 43 + schema?: IntrospectionData; 44 44 } 45 45 46 46 export class Store implements Cache { ··· 66 66 let mutationName = 'Mutation'; 67 67 let subscriptionName = 'Subscription'; 68 68 if (opts.schema) { 69 - const schema = (this.schema = buildClientSchema(opts.schema)); 69 + const schema = buildClientSchema(opts.schema); 70 70 queryName = schema.query || queryName; 71 71 mutationName = schema.mutation || mutationName; 72 72 subscriptionName = schema.subscription || subscriptionName; 73 + // Only add schema introspector if it has types info 74 + if (schema.types) this.schema = schema; 73 75 } 74 76 75 77 this.updates = {