@tanstack/angular-query-experimental
Version:
Signals for managing, caching and syncing asynchronous and remote data in Angular
1 lines • 6.9 kB
Source Map (JSON)
{"version":3,"file":"create-base-query.mjs","sources":["../src/create-base-query.ts"],"sourcesContent":["import {\n NgZone,\n VERSION,\n computed,\n effect,\n inject,\n signal,\n untracked,\n} from '@angular/core'\nimport {\n QueryClient,\n notifyManager,\n shouldThrowError,\n} from '@tanstack/query-core'\nimport { signalProxy } from './signal-proxy'\nimport { injectIsRestoring } from './inject-is-restoring'\nimport { PENDING_TASKS } from './pending-tasks-compat'\nimport type { PendingTaskRef } from './pending-tasks-compat'\nimport type {\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { CreateBaseQueryOptions } from './types'\n\n/**\n * Base implementation for `injectQuery` and `injectInfiniteQuery`.\n * @param optionsFn\n * @param Observer\n */\nexport function createBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n optionsFn: () => CreateBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n) {\n const ngZone = inject(NgZone)\n const pendingTasks = inject(PENDING_TASKS)\n const queryClient = inject(QueryClient)\n const isRestoring = injectIsRestoring()\n\n /**\n * Signal that has the default options from query client applied\n * computed() is used so signals can be inserted into the options\n * making it reactive. Wrapping options in a function ensures embedded expressions\n * are preserved and can keep being applied after signal changes\n */\n const defaultedOptionsSignal = computed(() => {\n const defaultedOptions = queryClient.defaultQueryOptions(optionsFn())\n defaultedOptions._optimisticResults = isRestoring()\n ? 'isRestoring'\n : 'optimistic'\n return defaultedOptions\n })\n\n const observerSignal = (() => {\n let instance: QueryObserver<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n > | null = null\n\n return computed(() => {\n return (instance ||= new Observer(queryClient, defaultedOptionsSignal()))\n })\n })()\n\n const optimisticResultSignal = computed(() =>\n observerSignal().getOptimisticResult(defaultedOptionsSignal()),\n )\n\n const resultFromSubscriberSignal = signal<QueryObserverResult<\n TData,\n TError\n > | null>(null)\n\n effect(\n (onCleanup) => {\n const observer = observerSignal()\n const defaultedOptions = defaultedOptionsSignal()\n\n untracked(() => {\n observer.setOptions(defaultedOptions)\n })\n onCleanup(() => {\n ngZone.run(() => resultFromSubscriberSignal.set(null))\n })\n },\n {\n // Set allowSignalWrites to support Angular < v19\n // Set to undefined to avoid warning on newer versions\n allowSignalWrites: VERSION.major < '19' || undefined,\n },\n )\n\n effect((onCleanup) => {\n // observer.trackResult is not used as this optimization is not needed for Angular\n const observer = observerSignal()\n let pendingTaskRef: PendingTaskRef | null = null\n\n const unsubscribe = isRestoring()\n ? () => undefined\n : untracked(() =>\n ngZone.runOutsideAngular(() => {\n return observer.subscribe(\n notifyManager.batchCalls((state) => {\n ngZone.run(() => {\n if (state.fetchStatus === 'fetching' && !pendingTaskRef) {\n pendingTaskRef = pendingTasks.add()\n }\n\n if (state.fetchStatus === 'idle' && pendingTaskRef) {\n pendingTaskRef()\n pendingTaskRef = null\n }\n\n if (\n state.isError &&\n !state.isFetching &&\n shouldThrowError(observer.options.throwOnError, [\n state.error,\n observer.getCurrentQuery(),\n ])\n ) {\n ngZone.onError.emit(state.error)\n throw state.error\n }\n resultFromSubscriberSignal.set(state)\n })\n }),\n )\n }),\n )\n\n onCleanup(() => {\n if (pendingTaskRef) {\n pendingTaskRef()\n pendingTaskRef = null\n }\n unsubscribe()\n })\n })\n\n return signalProxy(\n computed(() => {\n const subscriberResult = resultFromSubscriberSignal()\n const optimisticResult = optimisticResultSignal()\n const result = subscriberResult ?? optimisticResult\n\n // Wrap methods to ensure observer has latest options before execution\n const observer = observerSignal()\n\n const originalRefetch = result.refetch\n return {\n ...result,\n refetch: ((...args: Parameters<typeof originalRefetch>) => {\n observer.setOptions(defaultedOptionsSignal())\n return originalRefetch(...args)\n }) as typeof originalRefetch,\n }\n }),\n )\n}\n"],"names":[],"mappings":";;;;;AA8BO,SAAS,gBAOd,WAOA,UACA;AACA,QAAM,SAAS,OAAO,MAAM;AAC5B,QAAM,eAAe,OAAO,aAAa;AACzC,QAAM,cAAc,OAAO,WAAW;AACtC,QAAM,cAAc,kBAAA;AAQpB,QAAM,yBAAyB,SAAS,MAAM;AAC5C,UAAM,mBAAmB,YAAY,oBAAoB,UAAA,CAAW;AACpE,qBAAiB,qBAAqB,YAAA,IAClC,gBACA;AACJ,WAAO;AAAA,EACT,CAAC;AAED,QAAM,kBAAkB,MAAM;AAC5B,QAAI,WAMO;AAEX,WAAO,SAAS,MAAM;AACpB,aAAQ,wBAAa,IAAI,SAAS,aAAa,wBAAwB;AAAA,IACzE,CAAC;AAAA,EACH,GAAA;AAEA,QAAM,yBAAyB;AAAA,IAAS,MACtC,eAAA,EAAiB,oBAAoB,wBAAwB;AAAA,EAAA;AAG/D,QAAM,6BAA6B,OAGzB,IAAI;AAEd;AAAA,IACE,CAAC,cAAc;AACb,YAAM,WAAW,eAAA;AACjB,YAAM,mBAAmB,uBAAA;AAEzB,gBAAU,MAAM;AACd,iBAAS,WAAW,gBAAgB;AAAA,MACtC,CAAC;AACD,gBAAU,MAAM;AACd,eAAO,IAAI,MAAM,2BAA2B,IAAI,IAAI,CAAC;AAAA,MACvD,CAAC;AAAA,IACH;AAAA,IACA;AAAA;AAAA;AAAA,MAGE,mBAAmB,QAAQ,QAAQ,QAAQ;AAAA,IAAA;AAAA,EAC7C;AAGF,SAAO,CAAC,cAAc;AAEpB,UAAM,WAAW,eAAA;AACjB,QAAI,iBAAwC;AAE5C,UAAM,cAAc,gBAChB,MAAM,SACN;AAAA,MAAU,MACR,OAAO,kBAAkB,MAAM;AAC7B,eAAO,SAAS;AAAA,UACd,cAAc,WAAW,CAAC,UAAU;AAClC,mBAAO,IAAI,MAAM;AACf,kBAAI,MAAM,gBAAgB,cAAc,CAAC,gBAAgB;AACvD,iCAAiB,aAAa,IAAA;AAAA,cAChC;AAEA,kBAAI,MAAM,gBAAgB,UAAU,gBAAgB;AAClD,+BAAA;AACA,iCAAiB;AAAA,cACnB;AAEA,kBACE,MAAM,WACN,CAAC,MAAM,cACP,iBAAiB,SAAS,QAAQ,cAAc;AAAA,gBAC9C,MAAM;AAAA,gBACN,SAAS,gBAAA;AAAA,cAAgB,CAC1B,GACD;AACA,uBAAO,QAAQ,KAAK,MAAM,KAAK;AAC/B,sBAAM,MAAM;AAAA,cACd;AACA,yCAA2B,IAAI,KAAK;AAAA,YACtC,CAAC;AAAA,UACH,CAAC;AAAA,QAAA;AAAA,MAEL,CAAC;AAAA,IAAA;AAGP,cAAU,MAAM;AACd,UAAI,gBAAgB;AAClB,uBAAA;AACA,yBAAiB;AAAA,MACnB;AACA,kBAAA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,SAAO;AAAA,IACL,SAAS,MAAM;AACb,YAAM,mBAAmB,2BAAA;AACzB,YAAM,mBAAmB,uBAAA;AACzB,YAAM,SAAS,oBAAoB;AAGnC,YAAM,WAAW,eAAA;AAEjB,YAAM,kBAAkB,OAAO;AAC/B,aAAO;AAAA,QACL,GAAG;AAAA,QACH,UAAU,IAAI,SAA6C;AACzD,mBAAS,WAAW,wBAAwB;AAC5C,iBAAO,gBAAgB,GAAG,IAAI;AAAA,QAChC;AAAA,MAAA;AAAA,IAEJ,CAAC;AAAA,EAAA;AAEL;"}