CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tanstack--query-core

The framework agnostic core that powers TanStack Query for data fetching and caching

Pending
Overview
Eval results
Files

cache-management.mddocs/

Cache Management

Low-level cache operations for direct query and mutation cache manipulation with events, filtering, batch operations, and advanced cache strategies.

Capabilities

QueryCache

Low-level cache for managing query instances and their lifecycle.

/**
 * Cache for managing Query instances
 * Provides direct access to query storage and lifecycle management
 */
class QueryCache {
  constructor(config?: QueryCacheConfig);
  
  /**
   * Build or retrieve a query from the cache
   * Creates new query if it doesn't exist, otherwise returns existing
   * @param client - QueryClient instance
   * @param options - Query options
   * @param state - Optional initial state
   * @returns Query instance
   */
  build<T>(client: QueryClient, options: QueryOptions<T>, state?: QueryState<T>): Query<T>;
  
  /**
   * Add a query to the cache
   * @param query - Query instance to add
   */
  add(query: Query): void;
  
  /**
   * Remove a query from the cache
   * @param query - Query instance to remove
   */
  remove(query: Query): void;
  
  /**
   * Clear all queries from the cache
   */
  clear(): void;
  
  /**
   * Get a query by its hash
   * @param queryHash - The query hash to look up
   * @returns Query instance or undefined if not found
   */
  get<T>(queryHash: string): Query<T> | undefined;
  
  /**
   * Get all queries in the cache
   * @returns Array of all Query instances
   */
  getAll(): Array<Query>;
  
  /**
   * Find the first query matching the filters
   * @param filters - Query filters to match against
   * @returns First matching Query instance or undefined
   */
  find<T>(filters: QueryFilters): Query<T> | undefined;
  
  /**
   * Find all queries matching the filters
   * @param filters - Query filters to match against
   * @returns Array of matching Query instances
   */
  findAll(filters?: QueryFilters): Array<Query>;
  
  /**
   * Subscribe to cache events
   * @param callback - Callback function for cache events
   * @returns Unsubscribe function
   */
  subscribe(callback: (event: QueryCacheNotifyEvent) => void): () => void;
  
  /**
   * Notify cache listeners of an event
   * @param event - Cache event to broadcast
   */
  notify(event: QueryCacheNotifyEvent): void;
  
  /**
   * Handle window focus event
   * Triggers refetch for queries configured to refetch on focus
   */
  onFocus(): void;
  
  /**
   * Handle online event
   * Triggers refetch for queries configured to refetch on reconnect
   */
  onOnline(): void;
}

interface QueryCacheConfig {
  /**
   * Called when any query encounters an error
   * @param error - The error that occurred
   * @param query - The query that failed
   */
  onError?: (error: Error, query: Query) => void;
  
  /**
   * Called when any query succeeds
   * @param data - The data returned by the query
   * @param query - The query that succeeded
   */
  onSuccess?: (data: unknown, query: Query) => void;
  
  /**
   * Called when any query settles (success or error)
   * @param data - The data returned (undefined if error)
   * @param error - The error that occurred (null if success)
   * @param query - The query that settled
   */
  onSettled?: (data: unknown | undefined, error: Error | null, query: Query) => void;
}

Usage Examples:

import { QueryCache, QueryClient } from "@tanstack/query-core";

// Create cache with event handlers
const queryCache = new QueryCache({
  onError: (error, query) => {
    console.log(`Query failed:`, query.queryKey, error);
    
    // Log errors to monitoring service
    errorReporting.captureException(error, {
      tags: { queryKey: JSON.stringify(query.queryKey) },
    });
  },
  onSuccess: (data, query) => {
    console.log(`Query succeeded:`, query.queryKey);
  },
  onSettled: (data, error, query) => {
    console.log(`Query settled:`, query.queryKey, { data, error });
  },
});

const queryClient = new QueryClient({ queryCache });

// Subscribe to cache events
const unsubscribe = queryCache.subscribe((event) => {
  switch (event.type) {
    case 'added':
      console.log('Query added:', event.query.queryKey);
      break;
    case 'removed':
      console.log('Query removed:', event.query.queryKey);
      break;
    case 'updated':
      console.log('Query updated:', event.query.queryKey, event.action);
      break;
    case 'observerAdded':
      console.log('Observer added to query:', event.query.queryKey);
      break;
    case 'observerRemoved':
      console.log('Observer removed from query:', event.query.queryKey);
      break;
  }
});

// Find queries by filters
const staleQueries = queryCache.findAll({ stale: true });
console.log(`Found ${staleQueries.length} stale queries`);

const userQueries = queryCache.findAll({ 
  queryKey: ['user'],
  exact: false, // Partial match
});

// Get specific query
const userQuery = queryCache.find({ queryKey: ['user', 123], exact: true });
if (userQuery) {
  console.log('User query state:', userQuery.state);
}

// Clear cache
queryCache.clear();

// Cleanup
unsubscribe();

MutationCache

Low-level cache for managing mutation instances and their execution.

/**
 * Cache for managing Mutation instances
 * Handles mutation storage, scoping, and execution coordination
 */
class MutationCache {
  constructor(config?: MutationCacheConfig);
  
  /**
   * Build or retrieve a mutation from the cache
   * @param client - QueryClient instance
   * @param options - Mutation options
   * @param state - Optional initial state
   * @returns Mutation instance
   */
  build<T>(client: QueryClient, options: MutationOptions<T>, state?: MutationState<T>): Mutation<T>;
  
  /**
   * Add a mutation to the cache
   * @param mutation - Mutation instance to add
   */
  add(mutation: Mutation): void;
  
  /**
   * Remove a mutation from the cache
   * @param mutation - Mutation instance to remove
   */
  remove(mutation: Mutation): void;
  
  /**
   * Clear all mutations from the cache
   */
  clear(): void;
  
  /**
   * Get all mutations in the cache
   * @returns Array of all Mutation instances
   */
  getAll(): Array<Mutation>;
  
  /**
   * Find the first mutation matching the filters
   * @param filters - Mutation filters to match against
   * @returns First matching Mutation instance or undefined
   */
  find<T>(filters: MutationFilters): Mutation<T> | undefined;
  
  /**
   * Find all mutations matching the filters
   * @param filters - Mutation filters to match against
   * @returns Array of matching Mutation instances
   */
  findAll(filters?: MutationFilters): Array<Mutation>;
  
  /**
   * Subscribe to cache events
   * @param callback - Callback function for cache events
   * @returns Unsubscribe function
   */
  subscribe(callback: (event: MutationCacheNotifyEvent) => void): () => void;
  
  /**
   * Notify cache listeners of an event
   * @param event - Cache event to broadcast
   */
  notify(event: MutationCacheNotifyEvent): void;
  
  /**
   * Check if a mutation can run (respects scoping)
   * @param mutation - Mutation to check
   * @returns true if mutation can run
   */
  canRun(mutation: Mutation): boolean;
  
  /**
   * Run the next mutation in the scope queue
   * @param mutation - Mutation that just completed
   * @returns Promise that resolves when next mutation runs
   */
  runNext(mutation: Mutation): Promise<unknown>;
  
  /**
   * Resume all paused mutations
   * @returns Promise that resolves when all mutations are resumed
   */
  resumePausedMutations(): Promise<unknown>;
}

interface MutationCacheConfig {
  /**
   * Called when any mutation encounters an error
   * @param error - The error that occurred
   * @param variables - Variables passed to the mutation
   * @param context - Context from onMutate
   * @param mutation - The mutation that failed
   */
  onError?: (error: unknown, variables: unknown, context: unknown, mutation: Mutation) => Promise<unknown> | unknown;
  
  /**
   * Called when any mutation succeeds
   * @param data - The data returned by the mutation
   * @param variables - Variables passed to the mutation
   * @param context - Context from onMutate
   * @param mutation - The mutation that succeeded
   */
  onSuccess?: (data: unknown, variables: unknown, context: unknown, mutation: Mutation) => Promise<unknown> | unknown;
  
  /**
   * Called when any mutation settles
   * @param data - The data returned (undefined if error)
   * @param error - The error that occurred (null if success)
   * @param variables - Variables passed to the mutation
   * @param context - Context from onMutate
   * @param mutation - The mutation that settled
   */
  onSettled?: (data: unknown | undefined, error: unknown | null, variables: unknown, context: unknown, mutation: Mutation) => Promise<unknown> | unknown;
}

Usage Examples:

import { MutationCache, QueryClient } from "@tanstack/query-core";

// Create cache with global mutation handlers
const mutationCache = new MutationCache({
  onError: (error, variables, context, mutation) => {
    console.error('Mutation failed:', mutation.options.mutationKey, error);
    
    // Global error handling
    if (error.status === 401) {
      // Redirect to login
      window.location.href = '/login';
    }
  },
  onSuccess: (data, variables, context, mutation) => {
    console.log('Mutation succeeded:', mutation.options.mutationKey);
    
    // Global success tracking
    analytics.track('mutation_success', {
      mutationKey: mutation.options.mutationKey,
    });
  },
});

const queryClient = new QueryClient({ mutationCache });

// Subscribe to mutation events
const unsubscribe = mutationCache.subscribe((event) => {
  switch (event.type) {
    case 'added':
      console.log('Mutation added:', event.mutation.mutationId);
      break;
    case 'removed':
      console.log('Mutation removed:', event.mutation.mutationId);
      break;
    case 'updated':
      console.log('Mutation updated:', event.mutation.mutationId, event.action);
      break;
  }
});

// Find pending mutations
const pendingMutations = mutationCache.findAll({ 
  status: 'pending' 
});
console.log(`${pendingMutations.length} mutations pending`);

// Check mutation queue status
const allMutations = mutationCache.getAll();
const queuedMutations = allMutations.filter(m => !mutationCache.canRun(m));
console.log(`${queuedMutations.length} mutations queued`);

// Resume paused mutations (e.g., after network reconnection)
await mutationCache.resumePausedMutations();

// Cleanup
unsubscribe();

Cache Events

Understanding cache events for advanced cache monitoring and debugging.

type QueryCacheNotifyEvent = 
  | QueryCacheNotifyEventAdded
  | QueryCacheNotifyEventRemoved
  | QueryCacheNotifyEventUpdated
  | QueryCacheNotifyEventObserverAdded
  | QueryCacheNotifyEventObserverRemoved
  | QueryCacheNotifyEventObserverOptionsUpdated
  | QueryCacheNotifyEventObserverResultsUpdated;

interface QueryCacheNotifyEventAdded {
  type: 'added';
  query: Query;
}

interface QueryCacheNotifyEventRemoved {
  type: 'removed';
  query: Query;
}

interface QueryCacheNotifyEventUpdated {
  type: 'updated';
  query: Query;
  action: Action;
}

interface QueryCacheNotifyEventObserverAdded {
  type: 'observerAdded';
  query: Query;
  observer: QueryObserver;
}

interface QueryCacheNotifyEventObserverRemoved {
  type: 'observerRemoved';
  query: Query;
  observer: QueryObserver;
}

type MutationCacheNotifyEvent = 
  | MutationCacheNotifyEventAdded
  | MutationCacheNotifyEventRemoved
  | MutationCacheNotifyEventUpdated;

interface MutationCacheNotifyEventAdded {
  type: 'added';
  mutation: Mutation;
}

interface MutationCacheNotifyEventRemoved {
  type: 'removed';
  mutation: Mutation;
}

interface MutationCacheNotifyEventUpdated {
  type: 'updated';
  mutation: Mutation;
  action: Action;
}

Usage Examples:

// Advanced cache monitoring
const queryCache = new QueryCache();

queryCache.subscribe((event) => {
  // Track query lifecycle
  if (event.type === 'added') {
    console.log(`New query created: ${JSON.stringify(event.query.queryKey)}`);
    
    // Track memory usage
    const totalQueries = queryCache.getAll().length;
    console.log(`Total queries in cache: ${totalQueries}`);
  }
  
  if (event.type === 'updated') {
    const { query, action } = event;
    
    // Monitor specific query state changes
    if (action.type === 'success') {
      console.log(`Query succeeded: ${JSON.stringify(query.queryKey)}`);
      console.log(`Data size: ${JSON.stringify(query.state.data).length} bytes`);
    }
    
    if (action.type === 'error') {
      console.error(`Query failed: ${JSON.stringify(query.queryKey)}`, action.error);
    }
  }
  
  if (event.type === 'observerAdded') {
    console.log(`Observer added to: ${JSON.stringify(event.query.queryKey)}`);
    console.log(`Total observers: ${event.query.observers.length}`);
  }
});

Cache Filters

Advanced filtering options for finding specific queries and mutations.

interface QueryFilters {
  /** Query key to match (exact or partial based on 'exact' flag) */
  queryKey?: QueryKey;
  
  /** Whether to match query key exactly */
  exact?: boolean;
  
  /** Filter by stale status */
  stale?: boolean;
  
  /** Filter by active status (has observers) */
  active?: boolean;
  
  /** Filter by inactive status (no observers) */
  inactive?: boolean;
  
  /** Filter by fetch status */
  fetchStatus?: FetchStatus;
  
  /** Filter by query status */
  status?: QueryStatus;
  
  /** Custom predicate function */
  predicate?: (query: Query) => boolean;
  
  /** Filter by query type */
  type?: QueryTypeFilter;
}

interface MutationFilters {
  /** Mutation key to match (exact or partial based on 'exact' flag) */
  mutationKey?: MutationKey;
  
  /** Whether to match mutation key exactly */
  exact?: boolean;
  
  /** Filter by mutation status */
  status?: MutationStatus;
  
  /** Custom predicate function */
  predicate?: (mutation: Mutation) => boolean;
}

type QueryTypeFilter = 'all' | 'active' | 'inactive';
type FetchStatus = 'fetching' | 'paused' | 'idle';
type QueryStatus = 'pending' | 'error' | 'success';
type MutationStatus = 'idle' | 'pending' | 'success' | 'error';

Usage Examples:

// Complex filtering examples
const queryCache = new QueryCache();

// Find all stale user queries
const staleUserQueries = queryCache.findAll({
  queryKey: ['user'],
  exact: false,
  stale: true,
});

// Find queries that are currently fetching
const fetchingQueries = queryCache.findAll({
  fetchStatus: 'fetching',
});

// Find inactive queries older than 1 hour
const oldInactiveQueries = queryCache.findAll({
  inactive: true,
  predicate: (query) => {
    const oneHourAgo = Date.now() - 60 * 60 * 1000;
    return query.state.dataUpdatedAt < oneHourAgo;
  },
});

// Custom cleanup based on filters
const cleanupOldQueries = () => {
  const queriesToRemove = queryCache.findAll({
    predicate: (query) => {
      // Remove queries older than 24 hours with no observers
      const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
      return query.observers.length === 0 && 
             query.state.dataUpdatedAt < oneDayAgo;
    },
  });
  
  queriesToRemove.forEach(query => {
    queryCache.remove(query);
  });
  
  console.log(`Cleaned up ${queriesToRemove.length} old queries`);
};

// Run cleanup periodically
setInterval(cleanupOldQueries, 60 * 60 * 1000); // Every hour

Core Types

interface QueryOptions<T> {
  queryKey: QueryKey;
  queryFn?: QueryFunction<T>;
  enabled?: boolean;
  networkMode?: NetworkMode;
  retry?: RetryValue<T>;
  retryDelay?: RetryDelayValue<T>;
  staleTime?: number;
  gcTime?: number;
  meta?: QueryMeta;
  initialData?: T;
  initialDataUpdatedAt?: number;
  structuralSharing?: boolean;
}

interface MutationOptions<T> {
  mutationKey?: MutationKey;
  mutationFn?: MutationFunction<T>;
  retry?: RetryValue<T>;
  retryDelay?: RetryDelayValue<T>;
  networkMode?: NetworkMode;
  meta?: MutationMeta;
  scope?: { id: string };
}

type QueryKey = ReadonlyArray<unknown>;
type MutationKey = ReadonlyArray<unknown>;
type NetworkMode = 'online' | 'always' | 'offlineFirst';

Install with Tessl CLI

npx tessl i tessl/npm-tanstack--query-core

docs

browser-integration.md

cache-management.md

client-management.md

hydration.md

index.md

infinite-queries.md

mutations.md

query-observers.md

query-operations.md

utilities.md

tile.json