import type { ReadonlyJSONValue } from '../../shared/src/json.ts'; import { Zero } from '../../zero-client/src/client/zero.ts'; import type { Schema } from '../../zero-schema/src/builder/schema-builder.ts'; import { type HumanReadable, type Query } from '../../zql/src/query/query.ts'; import { type TTL } from '../../zql/src/query/ttl.ts'; export type QueryResultDetails = Readonly<{ type: 'complete'; } | { type: 'unknown'; } | QueryErrorDetails>; type QueryErrorDetails = { type: 'error'; refetch: (() => void) | undefined; error: { type: 'app'; queryName: string; details: ReadonlyJSONValue; } | { type: 'http'; queryName: string; status: number; details: ReadonlyJSONValue; }; }; export type QueryResult = readonly [ HumanReadable, QueryResultDetails ]; export type UseQueryOptions = { enabled?: boolean | undefined; /** * Time to live (TTL) in seconds. Controls how long query results are cached * after the query is removed. During this time, Zero continues to sync the query. * Default is 'never'. */ ttl?: TTL | undefined; }; export type UseSuspenseQueryOptions = UseQueryOptions & { /** * Whether to suspend until: * - 'partial': the query has partial results (partial array or defined * value for singular results) which may be of result type 'unknown', * or the query result type is 'complete' (in which case results may be * empty). This is useful for suspending until there are partial * optimistic local results, or the query has completed loading from the * server. * - 'complete': the query result type is 'complete'. * * Default is 'partial'. */ suspendUntil?: 'complete' | 'partial'; }; export declare function useQuery(query: Query, options?: UseQueryOptions | boolean): QueryResult; export declare function useSuspenseQuery(query: Query, options?: UseSuspenseQueryOptions | boolean): QueryResult; export declare function getAllViewsSizeForTesting(store: ViewStore): number; /** * A global store of all active views. * * React subscribes and unsubscribes to these views * via `useSyncExternalStore`. * * Managing views through `useEffect` or `useLayoutEffect` causes * inconsistencies because effects run after render. * * For example, if useQuery used use*Effect in the component below: * ```ts * function Foo({issueID}) { * const issue = useQuery(z.query.issue.where('id', issueID).one()); * if (issue?.id !== undefined && issue.id !== issueID) { * console.log('MISMATCH!', issue.id, issueID); * } * } * ``` * * `MISMATCH` will be printed whenever the `issueID` prop changes. * * This is because the component will render once with * the old state returned from `useQuery`. Then the effect inside * `useQuery` will run. The component will render again with the new * state. This inconsistent transition can cause unexpected results. * * Emulating `useEffect` via `useState` and `if` causes resource leaks. * That is: * * ```ts * function useQuery(q) { * const [oldHash, setOldHash] = useState(); * if (hash(q) !== oldHash) { * // make new view * } * * useEffect(() => { * return () => view.destroy(); * }, []); * } * ``` * * I'm not sure why but in strict mode the cleanup function * fails to be called for the first instance of the view and only * cleans up later instances. * * Swapping `useState` to `useRef` has similar problems. */ export declare class ViewStore { #private; constructor(); getView(zero: Zero, query: Query, enabled: boolean, ttl: TTL): { getSnapshot: () => QueryResult; subscribeReactInternals: (internals: () => void) => () => void; updateTTL: (ttl: TTL) => void; waitForComplete: () => Promise; waitForNonEmpty: () => Promise; complete: boolean; nonEmpty: boolean; }; } export {}; //# sourceMappingURL=use-query.d.ts.map