UNPKG

@tanstack/solid-db

Version:

Solid integration for @tanstack/db

223 lines (222 loc) 7.69 kB
import { ReactiveMap } from '@solid-primitives/map'; import { Accessor } from 'solid-js'; import { Collection, CollectionStatus, Context, GetResult, InferResultType, InitialQueryBuilder, LiveQueryCollectionConfig, NonSingleResult, QueryBuilder, SingleResult } from '@tanstack/db'; /** * Create a live query using a query function * @param queryFn - Query function that defines what data to fetch * @returns Accessor that returns data with Suspense support, with state and status information as properties * @example * // Basic query with object syntax * const todosQuery = useLiveQuery((q) => * q.from({ todos: todosCollection }) * .where(({ todos }) => eq(todos.completed, false)) * .select(({ todos }) => ({ id: todos.id, text: todos.text })) * ) * * @example * // With dependencies that trigger re-execution * const todosQuery = useLiveQuery( * (q) => q.from({ todos: todosCollection }) * .where(({ todos }) => gt(todos.priority, minPriority())), * ) * * @example * // Join pattern * const personIssues = 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 * const todosQuery = useLiveQuery((q) => * q.from({ todos: todoCollection }) * ) * * return ( * <Switch> * <Match when={todosQuery.isLoading}> * <div>Loading...</div> * </Match> * <Match when={todosQuery.isError}> * <div>Error: {todosQuery.status}</div> * </Match> * <Match when={todosQuery.isReady}> * <For each={todosQuery()}> * {(todo) => <li key={todo.id}>{todo.text}</li>} * </For> * </Match> * </Switch> * ) * * @example * // Use Suspense boundaries * const todosQuery = useLiveQuery((q) => * q.from({ todos: todoCollection }) * ) * * return ( * <Suspense fallback={<div>Loading...</div>}> * <For each={todosQuery()}> * {(todo) => <li key={todo.id}>{todo.text}</li>} * </For> * </Suspense> * ) */ export declare function useLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>): Accessor<InferResultType<TContext>> & { /** * @deprecated use function result instead * query.data -> query() */ data: InferResultType<TContext>; state: ReactiveMap<string | number, GetResult<TContext>>; collection: Collection<GetResult<TContext>, string | number, {}>; status: CollectionStatus; isLoading: boolean; isReady: boolean; isIdle: boolean; isError: boolean; isCleanedUp: boolean; }; export declare function useLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext> | undefined | null): Accessor<InferResultType<TContext>> & { /** * @deprecated use function result instead * query.data -> query() */ data: InferResultType<TContext>; state: ReactiveMap<string | number, GetResult<TContext>>; collection: Collection<GetResult<TContext>, string | number, {}> | null; status: CollectionStatus | `disabled`; isLoading: boolean; isReady: boolean; isIdle: boolean; isError: boolean; isCleanedUp: boolean; }; /** * Create a live query using configuration object * @param config - Configuration object with query and options * @returns Accessor that returns data with Suspense support, with state and status information as properties * @example * // Basic config object usage * const todosQuery = useLiveQuery(() => ({ * query: (q) => q.from({ todos: todosCollection }), * gcTime: 60000 * })) * * @example * // With query builder and options * const queryBuilder = new Query() * .from({ persons: collection }) * .where(({ persons }) => gt(persons.age, 30)) * .select(({ persons }) => ({ id: persons.id, name: persons.name })) * * const personsQuery = useLiveQuery(() => ({ query: queryBuilder })) * * @example * // Handle all states uniformly * const itemsQuery = useLiveQuery(() => ({ * query: (q) => q.from({ items: itemCollection }) * })) * * return ( * <Switch fallback={<div>{itemsQuery().length} items loaded</div>}> * <Match when={itemsQuery.isLoading}> * <div>Loading...</div> * </Match> * <Match when={itemsQuery.isError}> * <div>Something went wrong</div> * </Match> * <Match when={!itemsQuery.isReady}> * <div>Preparing...</div> * </Match> * </Switch> * ) */ export declare function useLiveQuery<TContext extends Context>(config: Accessor<LiveQueryCollectionConfig<TContext>>): Accessor<InferResultType<TContext>> & { /** * @deprecated use function result instead * query.data -> query() */ data: InferResultType<TContext>; state: ReactiveMap<string | number, GetResult<TContext>>; collection: Collection<GetResult<TContext>, string | number, {}>; status: CollectionStatus; isLoading: boolean; isReady: boolean; isIdle: boolean; isError: boolean; isCleanedUp: boolean; }; /** * Subscribe to an existing live query collection * @param liveQueryCollection - Pre-created live query collection to subscribe to * @returns Accessor that returns data with Suspense support, with state and status information as properties * @example * // Using pre-created live query collection * const myLiveQuery = createLiveQueryCollection((q) => * q.from({ todos: todosCollection }).where(({ todos }) => eq(todos.active, true)) * ) * const todosQuery = useLiveQuery(() => myLiveQuery) * * @example * // Access collection methods directly * const existingQuery = useLiveQuery(() => existingCollection) * * // Use collection for mutations * const handleToggle = (id) => { * existingQuery.collection.update(id, draft => { draft.completed = !draft.completed }) * } * * @example * // Handle states consistently * const sharedQuery = useLiveQuery(() => sharedCollection) * * return ( * <Switch fallback={<div><For each={sharedQuery()}>{(item) => <Item key={item.id} {...item} />}</For></div>}> * <Match when={sharedQuery.isLoading}> * <div>Loading...</div> * </Match> * <Match when={sharedQuery.isError}> * <div>Error loading data</div> * </Match> * </Switch> * ) */ export declare function useLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Accessor<Collection<TResult, TKey, TUtils> & NonSingleResult>): Accessor<Array<TResult>> & { /** * @deprecated use function result instead * query.data -> query() */ data: Array<TResult>; state: ReactiveMap<TKey, TResult>; collection: Collection<TResult, TKey, TUtils>; status: CollectionStatus; isLoading: boolean; isReady: boolean; isIdle: boolean; isError: boolean; isCleanedUp: boolean; }; export declare function useLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Accessor<Collection<TResult, TKey, TUtils> & SingleResult>): Accessor<TResult | undefined> & { /** * @deprecated use function result instead * query.data -> query() */ data: TResult | undefined; state: ReactiveMap<TKey, TResult>; collection: Collection<TResult, TKey, TUtils> & SingleResult; status: CollectionStatus; isLoading: boolean; isReady: boolean; isIdle: boolean; isError: boolean; isCleanedUp: boolean; };