Core Concepts
QueryClient architecture, key generation, and type system.
QueryClient Class
The QueryClient is an abstract base class for organizing queries and mutations within a specific resource domain. Each resource (projects, users, orgs) gets its own client.
import { QueryClient, type TanstackQueryClient } from "@teardown/queries";
class ProjectsClient extends QueryClient<"projects"> {
constructor(tanstackClient: TanstackQueryClient) {
super(tanstackClient, "projects", {
staleTime: 5 * 60 * 1000,
gcTime: 30 * 60 * 1000,
});
}
}Constructor Parameters
| Parameter | Type | Description |
|---|---|---|
client | TanstackQueryClient | TanStack Query's QueryClient instance |
resource | string | Resource name (e.g., "projects", "users") |
defaultOptions | DefaultOptions | Optional default staleTime and gcTime |
Query Key Architecture
Queries are organized in a hierarchical structure:
- Resource - Top-level domain (e.g., "projects", "teams")
- Sub-resource - Query type within domain (e.g., "list", "byId")
- Arguments - Additional parameters for uniqueness
Query Key Format
["@teardown", resource, "query", subResource, ...args]
// Examples:
["@teardown", "projects", "query", "list", { page: 1 }]
["@teardown", "projects", "query", "byId", "proj-123"]
["@teardown", "users", "query", "profile", "user-456"]Mutation Key Format
["@teardown", resource, "mutation", mutationKey, ...args]
// Examples:
["@teardown", "projects", "mutation", "create"]
["@teardown", "projects", "mutation", "update", "proj-123"]Type System
QueryKey Type
type QueryKey<Resource, SubResource, Args> = [
"@teardown",
Resource,
"query",
SubResource,
...Args
];MutationKey Type
type MutationKey<Resource, SubResource, Args> = [
"@teardown",
Resource,
"mutation",
SubResource,
...Args
];DefaultOptions
interface DefaultOptions {
staleTime?: number; // How long data stays fresh (ms)
gcTime?: number; // How long unused data is kept (ms)
}Key Generation Methods
The QueryClient provides methods for generating consistent keys:
class ProjectsClient extends QueryClient<"projects"> {
someMethod() {
// Generate query key
const queryKey = this.queryKeyGen("list", userId);
// Result: ["@teardown", "projects", "query", "list", userId]
// Generate mutation key
const mutationKey = this.mutationKeyGen("create");
// Result: ["@teardown", "projects", "mutation", "create"]
}
}Query Result Interface
The query() method returns an enhanced result with utility methods:
interface CreateQueryResult<Resource, SubResource, Args, TData, TError> {
// Standard TanStack Query options
queryKey: QueryKey;
queryFn: QueryFunction<TData>;
// Convenience methods
fetch(): Promise<TData>; // One-time fetch
prefetch(): Promise<void>; // Populate cache without subscribing
get(): TData | undefined; // Read current cache value
set(param): void; // Update cache value
refresh(): Promise<void>; // Invalidate and refetch
}Cache Invalidation
The refresh() method invalidates queries at different levels:
// Invalidate specific query with args
await projectsClient.refresh("list", userId);
// Invalidate all queries for a sub-resource
await projectsClient.refresh("list");
// Invalidate entire resource domain
await projectsClient.refresh();Multiple QueryClients
Organize multiple resources with a container class:
class QueryClients {
projects: ProjectsClient;
users: UsersClient;
orgs: OrgsClient;
constructor(tanstackClient: TanstackQueryClient) {
this.projects = new ProjectsClient(tanstackClient);
this.users = new UsersClient(tanstackClient);
this.orgs = new OrgsClient(tanstackClient);
}
shutdown() {
this.projects.shutdown();
this.users.shutdown();
this.orgs.shutdown();
}
}