UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

102 lines (94 loc) • 3.4 kB
import type { Collection } from './collection/index.js' import type { CollectionStatus, HealthNode } from './types.js' // Collection guards and status flags. Core modules import them from here, and // the adapter layer (`live-query-adapter.ts`) re-exports them. /** * Structural check for a live-query/`Collection` instance. * * Uses duck typing rather than `instanceof CollectionImpl` on purpose: adapters * and core can resolve to different copies of `@tanstack/db` (dual-package / * multi-realm), where `instanceof` gives false negatives. The three methods * below uniquely identify a Collection. */ export function isCollection( value: unknown, ): value is Collection<any, any, any> { return ( typeof value === `object` && value !== null && typeof (value as any).subscribeChanges === `function` && typeof (value as any).startSyncImmediate === `function` && typeof (value as any).id === `string` ) } /** * The Collection an adapter hands users as `collection`. A pooled live query * stands in for its live-query Collection and builds it only when touched. */ export function getPublicCollection< T extends Collection<any, any, any> | null | undefined, >(collection: T): T { return ( (collection as { publicCollection?: T } | null | undefined) ?.publicCollection ?? collection ) } /** Whether a collection yields a single result (`findOne`) rather than an array. */ export function isSingleResultCollection( collection: Collection<any, any, any>, ): boolean { return ( (collection.config as { singleResult?: boolean } | undefined) ?.singleResult === true ) } /** `error` and `crashed` end a sync run before it can serve its result. */ export function isFailedStatus(status: CollectionStatus): boolean { return status === `error` || status === `crashed` } /** * The derived flags and health every adapter exposes for a query, besides * `status`, which each adapter reports as its own field. */ export interface LiveQueryStatusFlags { isLoading: boolean isReady: boolean isIdle: boolean /** The first load failed: there is nothing to show. `status` is `error`. */ isLoadingError: boolean /** Local storage or an invariant broke. `status` is `crashed`. */ isCrashed: boolean isCleanedUp: boolean /** * The data is shown, and something keeps it from staying current: a sync * problem or failed request somewhere in `health`. Set only while `status` is * `ready`; a disabled query is never in a sync error. */ isSyncError: boolean /** * The health tree for the query and every Collection it depends on, or * `undefined` for a disabled query. */ health: HealthNode | undefined } /** * Derive the status flags from a collection status and its health tree. This is * the one place the `isSyncError` rule is written. Adapters represent a disabled * query separately (with `isReady: true`); this covers the real * `CollectionStatus` values. */ export function getLiveQueryStatusFlags( status: CollectionStatus, health?: HealthNode, ): LiveQueryStatusFlags { return { isLoading: status === `loading`, isReady: status === `ready`, isIdle: status === `idle`, isLoadingError: status === `error`, isCrashed: status === `crashed`, isCleanedUp: status === `cleaned-up`, isSyncError: status === `ready` && health?.hasErrors === true, health, } }