UNPKG

@tanstack/svelte-db

Version:

Svelte integration for @tanstack/db

137 lines (136 loc) 5.47 kB
import { assertLiveQueryWindowManyResult, compareLiveQueryWindowDependencies, createLiveQueryCollection, createLiveQueryWindowController, fetchNextLiveQueryWindowPage, getLiveQueryWindowCollectionWarning, normalizeLiveQueryWindowPageSize, resolveLiveQueryWindowInput, shouldPreserveLiveQueryWindowPageCount, } from '@tanstack/db'; import { tick, untrack } from 'svelte'; const DEFAULT_GC_TIME_MS = 1; export function useLiveInfiniteQuery(queryFnOrCollection, config, deps = []) { let validatedCollection = null; let previousController = null; let previousInput = null; let previousDependencies = null; let previousPageSize = null; let previousInitialPageParam = null; const pageSize = $derived(normalizeLiveQueryWindowPageSize(config.pageSize)); const initialPageParam = $derived(config.initialPageParam ?? 0); const controller = $derived.by(() => { const dependencies = deps.map((dependency) => dependency()); const input = resolveLiveQueryWindowInput(queryFnOrCollection); const dependencyComparison = compareLiveQueryWindowDependencies(previousDependencies, dependencies); const dependenciesChanged = dependencyComparison.changed; const dependenciesStructurallyEqual = dependencyComparison.structurallyEqual; const pageShapeChanged = previousPageSize !== pageSize || previousInitialPageParam !== initialPageParam; const sameCollection = input.kind === `collection` && previousInput?.kind === `collection` && previousInput.collection === input.collection; const canPreservePageCount = shouldPreserveLiveQueryWindowPageCount({ hasPreviousController: previousController !== null, previousInputKind: previousInput?.kind, inputKind: input.kind, sameCollection, dependenciesChanged, dependenciesStructurallyEqual, pageShapeChanged, }); const previousPageCount = previousController ? Math.max(1, previousController.getSnapshot().pages.length) : 1; const initialPageCount = canPreservePageCount ? previousPageCount : 1; previousInput = input; previousDependencies = [...dependencies]; previousPageSize = pageSize; previousInitialPageParam = initialPageParam; if (input.kind === `collection`) { const collection = input.collection; const warning = getLiveQueryWindowCollectionWarning(collection, pageSize + 1); if (validatedCollection !== collection) { validatedCollection = collection; if (warning) console.warn(warning); } const currentController = createLiveQueryWindowController(collection, { pageSize, initialPageParam, initialPageCount, }); previousController = currentController; return currentController; } const collection = createLiveQueryCollection({ query: input.query.limit(pageSize + 1).offset(0), startSync: false, gcTime: DEFAULT_GC_TIME_MS, }); assertLiveQueryWindowManyResult(collection); const currentController = createLiveQueryWindowController(collection, { pageSize, initialPageParam, initialPageCount, }); previousController = currentController; return currentController; }); let snapshot = $state.raw(untrack(() => controller.getSnapshot())); $effect(() => { const currentController = controller; snapshot = currentController.getSnapshot(); const unsubscribe = currentController.subscribe(() => { snapshot = currentController.getSnapshot(); }); snapshot = currentController.getSnapshot(); return () => { unsubscribe(); currentController.dispose(); }; }); const fetchNextPage = async () => { // A dependency can invalidate the derived controller before Svelte runs the // effect that subscribes it. Queue the imperative call until that handoff // has completed so it cannot target an inactive controller. await tick(); await fetchNextLiveQueryWindowPage(controller); }; return { get state() { return snapshot.state; }, get data() { return snapshot.data; }, get collection() { return snapshot.collection; }, get status() { return snapshot.status; }, get isLoading() { return snapshot.isLoading; }, get isReady() { return snapshot.isReady; }, get isIdle() { return snapshot.isIdle; }, get isError() { return snapshot.isError; }, get isCleanedUp() { return snapshot.isCleanedUp; }, get pages() { return snapshot.pages; }, get pageParams() { return snapshot.pageParams; }, get hasNextPage() { return snapshot.hasNextPage; }, get isFetchingNextPage() { return snapshot.isFetchingNextPage; }, get error() { return snapshot.error; }, fetchNextPage, }; }