@tanstack/db
Version:
A reactive client store for building super fast apps on sync
1 lines • 20.3 kB
Source Map (JSON)
{"version":3,"file":"live-query-options.cjs","sources":["../../src/live-query-options.ts"],"sourcesContent":["import { BaseQueryBuilder } from './query/builder/index.js'\nimport { collectSourceRefs, requireCollectionSource } from './query/ir.js'\nimport { isCollection, isFailedStatus } from './live-query-primitives.js'\nimport {\n DEFAULT_GC_TIME_MS,\n UNSUBSCRIBED_GC_FLOOR_MS,\n} from './collection/lifecycle.js'\nimport { createLiveQueryCollection } from './query/live-query-collection.js'\nimport { LIVE_QUERY_INTERNAL } from './query/live/internal.js'\nimport { getBuilderFromConfig } from './query/live/collection-registry.js'\nimport {\n getStableQueryBuilderHash,\n getStableValueHash,\n} from './query/ir-stable-identity.js'\nimport { getStringCollationIdentity } from './query/runtime-reference-identity.js'\nimport { codedMessage, devBuild } from './error-message.js'\nimport { InvalidPoolOptionError } from './errors.js'\nimport type { Collection, CollectionImpl } from './collection/index.js'\nimport type { CollectionOptionsIdentity } from './collection-options.js'\nimport type { CollectionOptions, DbClient } from './client.js'\nimport type { PooledLiveQueries } from './query/pooled-live-query.js'\nimport type {\n Context,\n InitialQueryBuilder,\n LiveQueryCollectionConfig,\n LiveQueryHookConfig,\n QueryBuilder,\n} from './query/index.js'\n\n/**\n * A hook config's pool: `pooledLiveQueries` or nothing. Any other value, such\n * as the removed boolean form, contradicts the hook contract, so every reader\n * rejects it the same way, whatever the config's other options. An adapter\n * that reads the pool from its own options, as Angular does, checks it here.\n */\nexport function configPool(config: object): PooledLiveQueries | undefined {\n const { pool } = config as { pool?: unknown }\n if (\n pool !== undefined &&\n typeof (pool as Partial<PooledLiveQueries> | null)\n ?.createPooledLiveQuery !== `function`\n )\n throw new InvalidPoolOptionError()\n return pool as PooledLiveQueries | undefined\n}\n\nexport type LiveQueryKey = ReadonlyArray<unknown>\n\nexport type LiveQueryOptions = LiveQueryCollectionConfig<any> & {\n queryKey?: LiveQueryKey\n}\n\nexport type DeferredLiveQueryCollections = Set<\n CollectionImpl<any, string | number, any, any, any>\n>\n\n/**\n * Release the sync starts a rejected query input deferred, then rethrow its\n * rejection. A framework hook calls this around its own render work, so a\n * query the hook rejects leaves no source deferred and a later reader can\n * start it. A render that throws after the hook returns, such as in a sibling\n * hook, is not a rejection of this input: like any render that never commits,\n * it releases its deferral through `releaseDeferredOnReclaim` when garbage\n * collection reclaims its live query. As for a\n * `DbClient` preload, the rejection wins over a source whose resumed start\n * fails; that source records its own failure.\n */\nexport function rejectLiveQueryInput(\n collections: DeferredLiveQueryCollections | undefined,\n rejection: unknown,\n): never {\n try {\n if (collections) resumeDeferredLiveQueryCollections(collections)\n } catch {\n // Report the rejection, not a later start failure.\n }\n throw rejection\n}\n\n/**\n * Release a render's deferred sync starts when the live query it built is\n * reclaimed. A render that commits releases them first, when it subscribes.\n * A render that never commits, because a sibling threw or it suspended, leaves\n * its live query unsubscribed until garbage collection cleans it up; that\n * cleanup releases the starts, so a direct reader's demand, made before or\n * after, then starts the sources. A live query that garbage collection never\n * reclaims, because its config disables GC or does not start its sync,\n * releases after the unsubscribed GC floor instead. Releases only the starts\n * deferred so far, not ones a later render of the same hook defers. Pass only\n * a live query the render built, and call the returned function when the\n * render commits, so a committed hook keeps no listener, timer, or copied\n * sources.\n */\nexport function releaseDeferredOnReclaim(\n liveQuery: Pick<Collection<any, any, any>, `once` | `config` | `status`>,\n deferredCollections: DeferredLiveQueryCollections,\n): (() => void) | undefined {\n if (deferredCollections.size === 0) return undefined\n const pending: DeferredLiveQueryCollections = new Set(deferredCollections)\n const release = () => {\n try {\n resumeDeferredLiveQueryCollections(pending)\n } catch {\n // A source whose resumed start fails records its own failure.\n }\n }\n // The lifecycle's own rule: GC reclaims only a started collection with a\n // finite, positive gcTime.\n const gcTime = liveQuery.config.gcTime ?? DEFAULT_GC_TIME_MS\n if (gcTime > 0 && Number.isFinite(gcTime) && liveQuery.status !== `idle`) {\n return liveQuery.once(`status:cleaned-up`, release)\n }\n const timer = setTimeout(release, UNSUBSCRIBED_GC_FLOOR_MS)\n return () => clearTimeout(timer)\n}\n\n/** Release every deferred source, then report the first startup failure. */\nexport function resumeDeferredLiveQueryCollections(\n collections: DeferredLiveQueryCollections,\n reportSourceErrors = false,\n): void {\n const pending = Array.from(collections)\n collections.clear()\n let firstFailure: { error: unknown } | undefined\n for (const collection of pending) {\n try {\n collection._resumeSyncStart()\n // An explicit preload owns source failure reporting even when graph\n // demand already released the gate. Ordinary hooks read the status.\n if (reportSourceErrors && isFailedStatus(collection.status)) {\n throw collection._lifecycle.getSyncError()\n }\n } catch (error) {\n firstFailure ??= { error }\n }\n }\n if (firstFailure) throw firstFailure.error\n}\n\ntype PreparedLiveQueryConfigInput = Omit<\n LiveQueryHookConfig<Context>,\n `query`\n> & {\n query:\n | QueryBuilder<Context>\n | ((q: InitialQueryBuilder) => QueryBuilder<Context> | undefined | null)\n queryKey?: LiveQueryKey\n client?: DbClient\n}\n\nfunction createInitialQueryBuilder(): InitialQueryBuilder {\n // Query construction does not materialize descriptor Collections.\n return new BaseQueryBuilder() as InitialQueryBuilder\n}\n\nfunction createCollectionResolver(\n dbClient: DbClient | undefined,\n deferredCollections?: DeferredLiveQueryCollections,\n) {\n if (!dbClient) return undefined\n return (\n options: CollectionOptionsIdentity<any, string | number, any, any, any>,\n ): CollectionImpl<any, string | number, any, any, any> => {\n if (!deferredCollections) {\n return dbClient.collection(\n options as CollectionOptions<any, string | number, any, any>,\n ) as CollectionImpl<any, string | number, any, any, any>\n }\n const collection = dbClient._materializeCollectionForRender(\n options as CollectionOptions<any, string | number, any, any>,\n ) as CollectionImpl<any, string | number, any, any, any>\n if (collection._deferSyncStart()) deferredCollections.add(collection)\n return collection\n }\n}\n\nexport function prepareLiveQueryValue(\n value: unknown,\n dbClient: DbClient | undefined,\n deferredCollections?: DeferredLiveQueryCollections,\n): unknown {\n if (typeof value === `function`) {\n return prepareLiveQueryValue(\n value(createInitialQueryBuilder()),\n dbClient,\n deferredCollections,\n )\n }\n\n if (value instanceof BaseQueryBuilder) {\n return value._bindCollectionSources(\n createCollectionResolver(dbClient, deferredCollections),\n )\n }\n\n if (\n value &&\n typeof value === `object` &&\n !isCollection(value) &&\n !(value instanceof BaseQueryBuilder) &&\n `query` in value\n ) {\n const pool = configPool(value)\n const {\n query,\n queryKey: _queryKey,\n client: _client,\n pool: _pool,\n ...config\n } = value as PreparedLiveQueryConfigInput\n\n const preparedQuery = prepareLiveQueryValue(\n query,\n dbClient,\n deferredCollections,\n )\n\n if (preparedQuery === undefined || preparedQuery === null) {\n return preparedQuery\n }\n\n return {\n ...config,\n // A DbClient query never pools, so its identity must not depend on\n // pool: a server preload and a client hook must hash alike.\n ...(pool && !dbClient ? { pool } : {}),\n query: preparedQuery,\n }\n }\n\n return value\n}\n\n/** Concrete source objects in query-position order for a prepared value. */\nexport function getPreparedLiveQuerySources(\n value: unknown,\n onUnboundDescriptor?: (alias: string) => never,\n): Array<Collection> {\n if (isCollection(value)) return [value]\n const query =\n value instanceof BaseQueryBuilder\n ? value\n : value && typeof value === `object` && `query` in value\n ? value.query\n : value\n if (query instanceof BaseQueryBuilder) {\n return collectSourceRefs(query._getQuery()).map((source) =>\n source.type === `descriptorRef`\n ? onUnboundDescriptor\n ? onUnboundDescriptor(source.alias)\n : requireCollectionSource(source)\n : source.collection,\n )\n }\n return isCollection(query) ? [query] : []\n}\n\n/** Local row behavior, kept separate from the portable query identity. */\nexport type LiveQueryRowOptions = readonly [getKey: unknown, schema: unknown]\n\nexport function getLiveQueryRowOptions(value: unknown): LiveQueryRowOptions {\n if (isCollection(value)) {\n const { config } = value\n const internal = config.utils?.[LIVE_QUERY_INTERNAL] as\n { hasCustomGetKey?: boolean } | undefined\n return [\n internal?.hasCustomGetKey ? config.getKey : undefined,\n config.schema,\n ]\n }\n const config = value as\n { getKey?: unknown; schema?: unknown } | null | undefined\n return [config?.getKey, config?.schema]\n}\n\nexport function getPreparedLiveQueryIdentity(\n value: unknown,\n pool?: PooledLiveQueries,\n): unknown {\n if (isCollection(value)) return [`collection`, value.id]\n if (value instanceof BaseQueryBuilder) {\n // A pooled query's fields and literals identify its rows without\n // canonicalizing its whole IR on every render.\n const pooled = pool?.getPooledQueryIdentity(value)\n return pooled === undefined\n ? [`query`, getStableQueryBuilderHash(value)]\n : [`pooled`, pooled]\n }\n if (value && typeof value === `object` && `query` in value) {\n const config = value as LiveQueryCollectionConfig<any>\n return [\n // getKey and schema bind for this query identity. Inline options must\n // not turn a normal framework render into a new Collection.\n `config`,\n getPreparedLiveQueryIdentity(config.query, configPool(config)),\n [`singleResult`, config.singleResult === true],\n [\n `defaultStringCollation`,\n getStringCollationIdentity(config.defaultStringCollation),\n ],\n ]\n }\n if (value === undefined || value === null) return [`disabled`]\n return [`value`, value]\n}\n\nexport function getLiveQueryHash(\n preparedValue: unknown,\n queryKey?: LiveQueryKey,\n): string {\n if (queryKey?.length) {\n const query =\n preparedValue instanceof BaseQueryBuilder\n ? preparedValue\n : preparedValue &&\n typeof preparedValue === `object` &&\n `query` in preparedValue\n ? preparedValue.query\n : undefined\n const ir = isCollection(preparedValue)\n ? getBuilderFromConfig(preparedValue.config)?.getWindow()\n : query instanceof BaseQueryBuilder\n ? query._getQuery()\n : undefined\n const window =\n ir && (ir.limit !== undefined || (ir.offset ?? 0) !== 0)\n ? [{ limit: ir.limit, offset: ir.offset ?? 0 }]\n : []\n return getStableValueHash([`queryKey`, queryKey, ...window], `queryKey`)\n }\n const identity = isCollection(preparedValue)\n ? [`collection`, preparedValue.id]\n : [`derived`, getPreparedLiveQueryIdentity(preparedValue)]\n\n return getStableValueHash(identity, `queryKey`)\n}\n\n// A config that names only its query and lifetime describes the same live\n// query as its builder. Any other option shapes its Collection, so compiles.\nfunction poolConfig(\n config: LiveQueryCollectionConfig<any>,\n gcTime: number | undefined,\n pool: PooledLiveQueries,\n): Collection<any, any, any> | undefined {\n if (\n !(config.query instanceof BaseQueryBuilder) ||\n !Object.keys(config).every((key) => key === `query` || key === `gcTime`)\n ) {\n return undefined\n }\n return pool.createPooledLiveQuery(config.query, {\n gcTime: config.gcTime ?? gcTime,\n })\n}\n\n/**\n * Resolve an adapter's query value to what its observer watches: `null` for a\n * disabled query, an existing Collection with sync started, or a live query.\n * A query builder whose shape a shared partition can serve gets a pooled view\n * instead of its own live-query Collection.\n */\nexport function resolveLiveQueryValue(\n value: unknown,\n {\n gcTime,\n pool,\n startSync = true,\n }: {\n gcTime?: number\n // `false` keeps a hook that cannot pool, such as a Suspense or DbClient\n // query, from pooling even when its config passes `pooledLiveQueries`.\n // A pool here has passed `configPool`.\n pool?: PooledLiveQueries | false\n startSync?: boolean\n } = {},\n): Collection<any, any, any> | null {\n if (value === undefined || value === null) return null\n if (isCollection(value)) {\n value.startSyncImmediate()\n return value\n }\n if (value instanceof BaseQueryBuilder) {\n return (\n (pool ? pool.createPooledLiveQuery(value, { gcTime }) : undefined) ??\n createLiveQueryCollection({ query: value, startSync, gcTime })\n )\n }\n if (typeof value === `object`) {\n const requested = configPool(value)\n const { pool: _pool, ...given } = value as LiveQueryHookConfig<any>\n const pooling = pool === false ? undefined : (requested ?? pool)\n // A pooled view needs the built query. Build a query function once and\n // compile the same builder if the partition cannot serve it.\n const built =\n pooling && typeof given.query === `function`\n ? given.query(createInitialQueryBuilder())\n : undefined\n const config =\n built instanceof BaseQueryBuilder ? { ...given, query: built } : given\n return (\n (pooling ? poolConfig(config, gcTime, pooling) : undefined) ??\n createLiveQueryCollection({\n ...config,\n startSync: config.startSync ?? startSync,\n gcTime: config.gcTime ?? gcTime,\n })\n )\n }\n throw new Error(\n devBuild() && process.env.NODE_ENV !== `production`\n ? `A live query must be a QueryBuilder, LiveQueryCollectionConfig, Collection, undefined, or null. Got: ${typeof value}`\n : codedMessage(102, { type: typeof value }),\n )\n}\n"],"names":["InvalidPoolOptionError","DEFAULT_GC_TIME_MS","UNSUBSCRIBED_GC_FLOOR_MS","isFailedStatus","BaseQueryBuilder","isCollection","collectSourceRefs","requireCollectionSource","config","internal","LIVE_QUERY_INTERNAL","getStableQueryBuilderHash","getStringCollationIdentity","ir","getBuilderFromConfig","getStableValueHash","createLiveQueryCollection","devBuild","codedMessage"],"mappings":"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"}