@tanstack/vue-db
Version:
Vue integration for @tanstack/db
173 lines (172 loc) • 7.66 kB
text/typescript
import { Collection, CollectionStatus, Context, GetResult, InferResultType, InitialQueryBuilder, LiveQueryCollectionConfig, NonSingleResult, QueryBuilder, SingleResult } from '@tanstack/db';
import { ComputedRef, MaybeRefOrGetter } from 'vue';
/**
* Return type for useLiveQuery hook
* @property state - Reactive Map of query results (key → item)
* @property data - Reactive array of query results in order, or single result for findOne queries
* @property collection - The underlying query collection instance
* @property status - Current query status
* @property isLoading - True while initial query data is loading
* @property isReady - True when query has received first data and is ready
* @property isIdle - True when query hasn't started yet
* @property isError - True when query encountered an error
* @property isCleanedUp - True when query has been cleaned up
*/
export interface UseLiveQueryReturn<TContext extends Context> {
state: ComputedRef<Map<string | number, GetResult<TContext>>>;
data: ComputedRef<InferResultType<TContext>>;
collection: ComputedRef<Collection<GetResult<TContext>, string | number, {}>>;
status: ComputedRef<CollectionStatus>;
isLoading: ComputedRef<boolean>;
isReady: ComputedRef<boolean>;
isIdle: ComputedRef<boolean>;
isError: ComputedRef<boolean>;
isCleanedUp: ComputedRef<boolean>;
}
export interface UseLiveQueryReturnWithCollection<T extends object, TKey extends string | number, TUtils extends Record<string, any>> {
state: ComputedRef<Map<TKey, T>>;
data: ComputedRef<Array<T>>;
collection: ComputedRef<Collection<T, TKey, TUtils>>;
status: ComputedRef<CollectionStatus>;
isLoading: ComputedRef<boolean>;
isReady: ComputedRef<boolean>;
isIdle: ComputedRef<boolean>;
isError: ComputedRef<boolean>;
isCleanedUp: ComputedRef<boolean>;
}
export interface UseLiveQueryReturnWithSingleResultCollection<T extends object, TKey extends string | number, TUtils extends Record<string, any>> {
state: ComputedRef<Map<TKey, T>>;
data: ComputedRef<T | undefined>;
collection: ComputedRef<Collection<T, TKey, TUtils> & SingleResult>;
status: ComputedRef<CollectionStatus>;
isLoading: ComputedRef<boolean>;
isReady: ComputedRef<boolean>;
isIdle: ComputedRef<boolean>;
isError: ComputedRef<boolean>;
isCleanedUp: ComputedRef<boolean>;
}
/**
* Create a live query using a query function
* @param queryFn - Query function that defines what data to fetch
* @param deps - Array of reactive dependencies that trigger query re-execution when changed
* @returns Reactive object with query data, state, and status information
* @example
* // Basic query with object syntax
* const { data, isLoading } = useLiveQuery((q) =>
* q.from({ todos: todosCollection })
* .where(({ todos }) => eq(todos.completed, false))
* .select(({ todos }) => ({ id: todos.id, text: todos.text }))
* )
*
* @example
* // With reactive dependencies
* const minPriority = ref(5)
* const { data, state } = useLiveQuery(
* (q) => q.from({ todos: todosCollection })
* .where(({ todos }) => gt(todos.priority, minPriority.value)),
* [minPriority] // Re-run when minPriority changes
* )
*
* @example
* // Join pattern
* const { data } = useLiveQuery((q) =>
* q.from({ issues: issueCollection })
* .join({ persons: personCollection }, ({ issues, persons }) =>
* eq(issues.userId, persons.id)
* )
* .select(({ issues, persons }) => ({
* id: issues.id,
* title: issues.title,
* userName: persons.name
* }))
* )
*
* @example
* // Handle loading and error states in template
* const { data, isLoading, isError, status } = useLiveQuery((q) =>
* q.from({ todos: todoCollection })
* )
*
* // In template:
* // <div v-if="isLoading">Loading...</div>
* // <div v-else-if="isError">Error: {{ status }}</div>
* // <ul v-else>
* // <li v-for="todo in data" :key="todo.id">{{ todo.text }}</li>
* // </ul>
*/
export declare function useLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>, deps?: Array<MaybeRefOrGetter<unknown>>): UseLiveQueryReturn<TContext>;
export declare function useLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext> | undefined | null, deps?: Array<MaybeRefOrGetter<unknown>>): UseLiveQueryReturn<TContext>;
/**
* Create a live query using configuration object
* @param config - Configuration object with query and options
* @param deps - Array of reactive dependencies that trigger query re-execution when changed
* @returns Reactive object with query data, state, and status information
* @example
* // Basic config object usage
* const { data, status } = useLiveQuery({
* query: (q) => q.from({ todos: todosCollection }),
* gcTime: 60000
* })
*
* @example
* // With reactive dependencies
* const filter = ref('active')
* const { data, isReady } = useLiveQuery({
* query: (q) => q.from({ todos: todosCollection })
* .where(({ todos }) => eq(todos.status, filter.value))
* }, [filter])
*
* @example
* // Handle all states uniformly
* const { data, isLoading, isReady, isError } = useLiveQuery({
* query: (q) => q.from({ items: itemCollection })
* })
*
* // In template:
* // <div v-if="isLoading">Loading...</div>
* // <div v-else-if="isError">Something went wrong</div>
* // <div v-else-if="!isReady">Preparing...</div>
* // <div v-else>{{ data.length }} items loaded</div>
*/
export declare function useLiveQuery<TContext extends Context>(config: LiveQueryCollectionConfig<TContext>, deps?: Array<MaybeRefOrGetter<unknown>>): UseLiveQueryReturn<TContext>;
/**
* Subscribe to an existing query collection (can be reactive)
* @param liveQueryCollection - Pre-created query collection to subscribe to (can be a ref)
* @returns Reactive object with query data, state, and status information
* @example
* // Using pre-created query collection
* const myLiveQuery = createLiveQueryCollection((q) =>
* q.from({ todos: todosCollection }).where(({ todos }) => eq(todos.active, true))
* )
* const { data, collection } = useLiveQuery(myLiveQuery)
*
* @example
* // Reactive query collection reference
* const selectedQuery = ref(todosQuery)
* const { data, collection } = useLiveQuery(selectedQuery)
*
* // Switch queries reactively
* selectedQuery.value = archiveQuery
*
* @example
* // Access query collection methods directly
* const { data, collection, isReady } = useLiveQuery(existingQuery)
*
* // Use underlying collection for mutations
* const handleToggle = (id) => {
* collection.value.update(id, draft => { draft.completed = !draft.completed })
* }
*
* @example
* // Handle states consistently
* const { data, isLoading, isError } = useLiveQuery(sharedQuery)
*
* // In template:
* // <div v-if="isLoading">Loading...</div>
* // <div v-else-if="isError">Error loading data</div>
* // <div v-else>
* // <Item v-for="item in data" :key="item.id" v-bind="item" />
* // </div>
*/
export declare function useLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: MaybeRefOrGetter<Collection<TResult, TKey, TUtils> & NonSingleResult>): UseLiveQueryReturnWithCollection<TResult, TKey, TUtils>;
export declare function useLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: MaybeRefOrGetter<Collection<TResult, TKey, TUtils> & SingleResult>): UseLiveQueryReturnWithSingleResultCollection<TResult, TKey, TUtils>;