@tanstack/svelte-db
Version:
Svelte integration for @tanstack/db
137 lines (136 loc) • 5.47 kB
JavaScript
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,
};
}