UNPKG

@tanstack/solid-db

Version:

Solid integration for @tanstack/db

192 lines (191 loc) 5.03 kB
import { createMemo, createSignal, createResource, batch, createEffect, onCleanup } from "solid-js"; import { ReactiveMap } from "@solid-primitives/map"; import { BaseQueryBuilder, createLiveQueryCollection, isCollection, createLiveQueryObserver, isSingleResultCollection } from "@tanstack/db"; import { createStore, reconcile } from "solid-js/store"; function useLiveQuery(configOrQueryOrCollection) { const collection = createMemo( () => { if (configOrQueryOrCollection.length === 1) { const queryBuilder = new BaseQueryBuilder(); const result = configOrQueryOrCollection(queryBuilder); if (result === void 0 || result === null) { return null; } return createLiveQueryCollection({ query: configOrQueryOrCollection, startSync: true }); } const innerCollection = configOrQueryOrCollection(); if (innerCollection === void 0 || innerCollection === null) { return null; } if (isCollection(innerCollection)) { innerCollection.startSyncImmediate(); return innerCollection; } return createLiveQueryCollection({ ...innerCollection, startSync: true }); }, void 0, { name: `TanstackDBCollectionMemo` } ); const state = new ReactiveMap(); const [data, setData] = createStore([], { name: `TanstackDBData` }); const [status, setStatus] = createSignal( collection() ? collection().status : `disabled`, { name: `TanstackDBStatus` } ); const syncDataFromCollection = (currentCollection) => { setData( (prev) => reconcile(Array.from(currentCollection.values()))(prev).filter(Boolean) ); }; let resourceGeneration = 0; const [getDataResource] = createResource( () => ({ currentCollection: collection() }), async ({ currentCollection }) => { const generation = ++resourceGeneration; if (!currentCollection) { return []; } setStatus(currentCollection.status); try { await currentCollection.toArrayWhenReady(); } catch (error) { if (generation === resourceGeneration) setStatus(`error`); throw error; } if (generation !== resourceGeneration) { return data; } batch(() => { state.clear(); for (const [key, value] of currentCollection.entries()) { state.set(key, value); } syncDataFromCollection(currentCollection); setStatus(currentCollection.status); }); return data; }, { name: `TanstackDBData`, deferStream: false, initialValue: data } ); createEffect(() => { const currentCollection = collection(); if (!currentCollection) { setStatus(`disabled`); state.clear(); setData([]); return; } const observer = createLiveQueryObserver(currentCollection); state.clear(); const unsubscribe = observer.subscribe( (changes) => { batch(() => { if (changes) { for (const change of changes) { switch (change.type) { case `insert`: case `update`: state.set(change.key, change.value); break; case `delete`: state.delete(change.key); break; } } } else { state.clear(); for (const [key, value] of observer.getSnapshot().state ?? []) { state.set(key, value); } } syncDataFromCollection(currentCollection); setStatus(observer.getSnapshot().status); }); } ); batch(() => { syncDataFromCollection(currentCollection); setStatus(observer.getSnapshot().status); }); onCleanup(() => { unsubscribe(); observer.dispose(); }); }); function getData() { const currentCollection = collection(); if (currentCollection) { if (isSingleResultCollection(currentCollection)) { getDataResource(); return data[0]; } } return getDataResource(); } Object.defineProperties(getData, { data: { get() { return getData(); } }, status: { get() { return status(); } }, collection: { get() { return collection(); } }, state: { get() { return state; } }, isLoading: { get() { return status() === `loading`; } }, isReady: { get() { return status() === `ready` || status() === `disabled`; } }, isIdle: { get() { return status() === `idle`; } }, isError: { get() { return status() === `error`; } }, isCleanedUp: { get() { return status() === `cleaned-up`; } } }); return getData; } export { useLiveQuery }; //# sourceMappingURL=useLiveQuery.js.map