Primary cache functionality for storing, retrieving, and manipulating normalized GraphQL data with automatic normalization and denormalization.
Main cache implementation providing normalized data storage and GraphQL query processing.
/**
* Main cache implementation for Apollo Client providing normalized data storage
* Extends ApolloCache to provide GraphQL-specific caching functionality
*/
class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
/**
* Creates a new InMemoryCache instance
* @param config - Optional configuration object
*/
constructor(config?: InMemoryCacheConfig);
/**
* Restores cache state from a serialized object
* @param data - Normalized cache data to restore
* @returns This cache instance for chaining
*/
restore(data: NormalizedCacheObject): this;
/**
* Extracts current cache state as a serializable object
* @param optimistic - Whether to include optimistic data (default: false)
* @returns Serialized cache state
*/
extract(optimistic?: boolean): NormalizedCacheObject;
/**
* Reads data from cache using a GraphQL query
* @param options - Query options including query document and variables
* @returns Query result or null if not found
*/
read<T>(options: Cache.ReadOptions): T | null;
/**
* Writes data to cache from a GraphQL query result
* @param write - Write options including query, result, and variables
*/
write(write: Cache.WriteOptions): void;
/**
* Compares query against current cache state
* @param query - Diff options including query and variables
* @returns Diff result indicating completeness and data changes
*/
diff<T>(query: Cache.DiffOptions): Cache.DiffResult<T>;
/**
* Watches cache for changes to a specific query
* @param watch - Watch options including query and callback
* @returns Function to stop watching
*/
watch(watch: Cache.WatchOptions): () => void;
/**
* Evicts data from cache (NOT IMPLEMENTED - throws InvariantError)
* This method is inherited from ApolloCache but not implemented in InMemoryCache
* Calling this method will throw an error: "eviction is not implemented on InMemory Cache"
* @param query - Eviction query options
* @throws InvariantError Always throws - eviction not supported
*/
evict(query: Cache.EvictOptions): never;
/**
* Resets cache to empty state
* @returns Promise resolving when reset is complete
*/
reset(): Promise<void>;
/**
* Removes specific optimistic update layer
* @param idToRemove - ID of optimistic update to remove
*/
removeOptimistic(idToRemove: string): void;
/**
* Performs transaction with optional optimistic layer
* @param transaction - Transaction function to execute
* @param optimisticId - Optional ID for optimistic transaction
*/
performTransaction(
transaction: Transaction<NormalizedCacheObject>,
optimisticId?: string
): void;
/**
* Records optimistic transaction with specific ID
* @param transaction - Transaction function to execute
* @param id - ID for the optimistic transaction
*/
recordOptimisticTransaction(
transaction: Transaction<NormalizedCacheObject>,
id: string
): void;
/**
* Transforms GraphQL document by adding __typename fields
* @param document - GraphQL document to transform
* @returns Transformed document with __typename fields
*/
transformDocument(document: DocumentNode): DocumentNode;
/**
* Transforms GraphQL document for link usage (inherited from ApolloCache)
* @param document - GraphQL document to transform
* @returns Transformed document for network layer
*/
transformForLink(document: DocumentNode): DocumentNode;
// DataProxy Methods (inherited from ApolloCache for direct cache access)
/**
* Reads a GraphQL query from cache
* @param options - Query options including query and variables
* @param optimistic - Whether to include optimistic data (default: false)
* @returns Query result or null if not found
*/
readQuery<QueryType, TVariables = any>(
options: DataProxy.Query<TVariables>,
optimistic?: boolean
): QueryType | null;
/**
* Reads a GraphQL fragment from cache
* @param options - Fragment options including fragment and id
* @param optimistic - Whether to include optimistic data (default: false)
* @returns Fragment result or null if not found
*/
readFragment<FragmentType, TVariables = any>(
options: DataProxy.Fragment<TVariables>,
optimistic?: boolean
): FragmentType | null;
/**
* Writes a complete GraphQL query result to cache
* @param options - Write options including query, data, and variables
*/
writeQuery<TData = any, TVariables = any>(
options: Cache.WriteQueryOptions<TData, TVariables>
): void;
/**
* Writes a GraphQL fragment to cache
* @param options - Write options including fragment, id, and data
*/
writeFragment<TData = any, TVariables = any>(
options: Cache.WriteFragmentOptions<TData, TVariables>
): void;
/**
* Writes raw data to cache with root query context
* @param options - Write options including data to write
*/
writeData<TData = any>(options: Cache.WriteDataOptions<TData>): void;
}Usage Examples:
import { InMemoryCache } from "apollo-cache-inmemory";
import { gql } from "graphql-tag";
const cache = new InMemoryCache();
// Write data to cache
cache.write({
query: gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`,
variables: { id: "1" },
result: {
user: {
id: "1",
name: "Alice",
email: "alice@example.com",
__typename: "User"
}
}
});
// Read data from cache
const result = cache.read({
query: gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`,
variables: { id: "1" }
});
// Watch for changes
const unwatch = cache.watch({
query: gql`query GetUser($id: ID!) { user(id: $id) { id name } }`,
variables: { id: "1" },
callback: (result) => {
console.log("Cache updated:", result);
}
});
// Stop watching
unwatch();
// DataProxy methods for direct cache access
// Write query data directly
cache.writeQuery({
query: gql`
query GetUser($id: ID!) {
user(id: $id) { id name email }
}
`,
variables: { id: "2" },
data: {
user: {
id: "2",
name: "Bob",
email: "bob@example.com",
__typename: "User"
}
}
});
// Read query data directly
const userData = cache.readQuery({
query: gql`
query GetUser($id: ID!) {
user(id: $id) { id name email }
}
`,
variables: { id: "2" }
});
// Write fragment data
cache.writeFragment({
id: "User:1",
fragment: gql`
fragment UserName on User {
name
}
`,
data: {
name: "Alice Updated",
__typename: "User"
}
});
// Read fragment data
const userName = cache.readFragment({
id: "User:1",
fragment: gql`
fragment UserName on User {
name
}
`
});Configuration interface for customizing InMemoryCache behavior.
interface InMemoryCacheConfig extends ApolloReducerConfig {
/**
* Enable result caching with dependency tracking (default: true)
* Improves performance for repeated reads but uses more memory
*/
resultCaching?: boolean;
/**
* Freeze result objects to prevent mutation (default: false)
* Helps catch accidental mutations but impacts performance
*/
freezeResults?: boolean;
}
interface ApolloReducerConfig {
/**
* Function to generate unique IDs for objects during normalization
* Default uses __typename + id or _id fields
*/
dataIdFromObject?: IdGetter;
/**
* Fragment matcher for handling GraphQL fragments on unions/interfaces
* Default uses HeuristicFragmentMatcher
*/
fragmentMatcher?: FragmentMatcherInterface;
/**
* Automatically add __typename to queries (default: true)
* Required for proper normalization and fragment matching
*/
addTypename?: boolean;
/**
* Map of cache redirects for resolving fields from other locations
* Used for denormalization and computed fields
*/
cacheRedirects?: CacheResolverMap;
// Backward compatibility properties (deprecated)
/**
* @deprecated Use cacheRedirects instead
* Maintained for backward compatibility
*/
customResolvers?: CacheResolverMap;
/**
* @deprecated Use cacheRedirects instead
* Maintained for backward compatibility
*/
cacheResolvers?: CacheResolverMap;
}Utility function for generating object IDs during normalization.
/**
* Default function for generating unique IDs from GraphQL objects
* Uses __typename combined with id or _id field
* @param result - Object to generate ID for
* @returns Unique ID string or null if cannot generate
*/
function defaultDataIdFromObject(result: any): string | null;Usage Example:
import { InMemoryCache, defaultDataIdFromObject } from "apollo-cache-inmemory";
const cache = new InMemoryCache({
dataIdFromObject: (object) => {
// Custom ID generation logic
if (object.__typename === "User") {
return `User:${object.email}`;
}
// Fall back to default behavior
return defaultDataIdFromObject(object);
}
});Methods for extracting and restoring cache state for persistence and hydration.
/**
* Extracts current cache state as serializable object
* @param optimistic - Include optimistic updates in extraction
* @returns Normalized cache object suitable for serialization
*/
extract(optimistic?: boolean): NormalizedCacheObject;
/**
* Restores cache from previously extracted state
* @param data - Normalized cache data to restore
* @returns Cache instance for method chaining
*/
restore(data: NormalizedCacheObject): this;Usage Example:
// Extract cache state for persistence
const cacheState = cache.extract();
localStorage.setItem("apollo-cache", JSON.stringify(cacheState));
// Restore cache state
const savedState = JSON.parse(localStorage.getItem("apollo-cache") || "{}");
cache.restore(savedState);interface NormalizedCacheObject {
[dataId: string]: StoreObject | undefined;
}
interface StoreObject {
__typename?: string;
[storeFieldKey: string]: StoreValue;
}
type IdGetter = (value: IdGetterObj) => string | null | undefined;
interface IdGetterObj extends Object {
__typename?: string;
id?: string;
}
interface FragmentMatcherInterface {
match(
idValue: IdValue,
typeCondition: string,
context: ReadStoreContext
): boolean | 'heuristic';
}
type CacheResolverMap = {
[typeName: string]: {
[fieldName: string]: CacheResolver;
};
};
type CacheResolver = (
rootValue: any,
args: { [argName: string]: any },
context: any
) => any;