GraphQL fragment matching system for handling fragments on unions, interfaces, and complex query structures with different levels of type information.
Basic fragment matcher using heuristic matching for fragments when detailed type information is unavailable.
/**
* Basic fragment matcher that uses heuristic approach
* Works well for simple cases but limited with unions/interfaces
* Provides warnings when encountering complex fragment scenarios
*/
class HeuristicFragmentMatcher implements FragmentMatcherInterface {
/**
* Creates a new heuristic fragment matcher
* No configuration required - ready to use immediately
*/
constructor();
/**
* Always ready - no initialization required
* @returns Promise resolving immediately
*/
ensureReady(): Promise<void>;
/**
* Can bypass initialization - no setup needed
* @returns Always true
*/
canBypassInit(): boolean;
/**
* Matches fragments using heuristic approach
* @param idValue - Object identifier to match against
* @param typeCondition - GraphQL type condition from fragment
* @param context - Read context containing store and config
* @returns true if matches, false if doesn't match, 'heuristic' if uncertain
*/
match(
idValue: IdValue,
typeCondition: string,
context: ReadStoreContext
): boolean | 'heuristic';
}Usage Example:
import { InMemoryCache, HeuristicFragmentMatcher } from "apollo-cache-inmemory";
const cache = new InMemoryCache({
fragmentMatcher: new HeuristicFragmentMatcher()
});
// Works well with simple fragments
const query = gql`
query GetUser {
user {
id
name
... on PremiumUser {
subscriptionLevel
}
}
}
`;Advanced fragment matcher using GraphQL introspection data for precise union and interface fragment matching.
/**
* Advanced fragment matcher using introspection data
* Provides precise matching for unions and interfaces
* Requires introspection query result for configuration
*/
class IntrospectionFragmentMatcher implements FragmentMatcherInterface {
/**
* Creates introspection-based fragment matcher
* @param options - Configuration including introspection data
*/
constructor(options?: {
introspectionQueryResultData?: IntrospectionResultData;
});
/**
* Matches fragments using introspection type information
* @param idValue - Object identifier to match against
* @param typeCondition - GraphQL type condition from fragment
* @param context - Read context containing store and config
* @returns true if fragment matches, false otherwise
*/
match(
idValue: IdValue,
typeCondition: string,
context: ReadStoreContext
): boolean;
}Usage Example:
import {
InMemoryCache,
IntrospectionFragmentMatcher,
IntrospectionResultData
} from "apollo-cache-inmemory";
// First, obtain introspection data from your GraphQL server
const introspectionQueryResultData: IntrospectionResultData = {
__schema: {
types: [
{
kind: "INTERFACE",
name: "Node",
possibleTypes: [
{ name: "User" },
{ name: "Post" }
]
},
{
kind: "UNION",
name: "SearchResult",
possibleTypes: [
{ name: "User" },
{ name: "Post" },
{ name: "Comment" }
]
}
]
}
};
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData
});
const cache = new InMemoryCache({
fragmentMatcher
});
// Now fragments on unions/interfaces work correctly
const query = gql`
query Search($term: String!) {
search(term: $term) {
... on User {
id
name
email
}
... on Post {
id
title
content
}
}
}
`;Core interface that all fragment matchers must implement.
interface FragmentMatcherInterface {
/**
* Determines if a fragment matches an object in the cache
* @param idValue - Identifier of the object to test
* @param typeCondition - GraphQL type condition from the fragment
* @param context - Context containing cache store and configuration
* @returns true if match, false if no match, 'heuristic' if uncertain
*/
match(
idValue: IdValue,
typeCondition: string,
context: ReadStoreContext
): boolean | 'heuristic';
}Pre-built GraphQL introspection query for obtaining type information needed by IntrospectionFragmentMatcher.
/**
* GraphQL introspection query document for fragment matching
* Query to run against your GraphQL server to get type information
* Export is the complete DocumentNode ready to execute
* Default export from 'apollo-cache-inmemory/lib/fragmentMatcherIntrospectionQuery'
*/
const introspectionQuery: DocumentNode;Usage Example:
import introspectionQuery from "apollo-cache-inmemory/lib/fragmentMatcherIntrospectionQuery";
import { ApolloClient } from "apollo-client";
// Execute introspection query against your server
async function getIntrospectionData(client: ApolloClient<any>) {
const result = await client.query({
query: introspectionQuery,
// Disable cache for introspection
fetchPolicy: 'network-only'
});
return result.data;
}
// Use the result with IntrospectionFragmentMatcher
getIntrospectionData(client).then(introspectionResultData => {
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData: introspectionResultData
});
const cache = new InMemoryCache({ fragmentMatcher });
});interface ReadStoreContext {
readonly store: NormalizedCache;
readonly cacheRedirects: CacheResolverMap;
readonly dataIdFromObject?: IdGetter;
}
interface IntrospectionResultData {
__schema: {
types: {
kind: string;
name: string;
possibleTypes: {
name: string;
}[];
}[];
};
}
type PossibleTypesMap = {
[key: string]: string[]
};
interface IdValue {
type: "id";
id: string;
generated: boolean;
}Use HeuristicFragmentMatcher when:
Use IntrospectionFragmentMatcher when:
// Method 1: Manual introspection query
import introspectionQuery from "apollo-cache-inmemory/lib/fragmentMatcherIntrospectionQuery";
const client = new ApolloClient({ ... });
const { data } = await client.query({
query: introspectionQuery
});
// Method 2: Using Apollo CLI
// Run: apollo client:codegen --target=typescript --includes="./src/**/*.{ts,tsx}" --excludes="./src/**/__tests__/**/*"
// Method 3: Build-time generation
// Add to your build process to fetch introspection data
// and generate static fragment matcher configuration