diff --git a/.changeset/puny-walls-eat.md b/.changeset/puny-walls-eat.md new file mode 100644 index 0000000000..39691503b3 --- /dev/null +++ b/.changeset/puny-walls-eat.md @@ -0,0 +1,5 @@ +--- +'@tanstack/query-core': patch +--- + +Fix streamedQuery to avoid returning undefined when the stream yields no values diff --git a/docs/reference/streamedQuery.md b/docs/reference/streamedQuery.md index 8c70475ba3..fe5ed9f518 100644 --- a/docs/reference/streamedQuery.md +++ b/docs/reference/streamedQuery.md @@ -40,6 +40,6 @@ const query = queryOptions({ - If `TData` is not an array, you must provide a custom `reducer`. - `initialValue?: TData = TQueryFnData` - Optional - - Defines the initial data to be used while the first chunk is being fetched. + - Defines the initial data to be used while the first chunk is being fetched, and it is also returned when the stream yields no values. - It is mandatory when custom `reducer` is provided. - Defaults to an empty array. diff --git a/packages/query-core/src/__tests__/streamedQuery.test.tsx b/packages/query-core/src/__tests__/streamedQuery.test.tsx index 31a937f2a8..084ea7d9db 100644 --- a/packages/query-core/src/__tests__/streamedQuery.test.tsx +++ b/packages/query-core/src/__tests__/streamedQuery.test.tsx @@ -128,6 +128,35 @@ describe('streamedQuery', () => { unsubscribe() }) + test('should handle empty streams', async () => { + const key = queryKey() + + const observer = new QueryObserver(queryClient, { + queryKey: key, + queryFn: streamedQuery({ + streamFn: async function* () {}, + }), + }) + + const unsubscribe = observer.subscribe(vi.fn()) + + expect(observer.getCurrentResult()).toMatchObject({ + status: 'pending', + fetchStatus: 'fetching', + data: undefined, + }) + + await vi.advanceTimersByTimeAsync(50) + + expect(observer.getCurrentResult()).toMatchObject({ + status: 'success', + fetchStatus: 'idle', + data: [], + }) + + unsubscribe() + }) + test('should replace on refetch', async () => { const key = queryKey() const observer = new QueryObserver(queryClient, { diff --git a/packages/query-core/src/streamedQuery.ts b/packages/query-core/src/streamedQuery.ts index f4a60ee091..2eb944d699 100644 --- a/packages/query-core/src/streamedQuery.ts +++ b/packages/query-core/src/streamedQuery.ts @@ -41,7 +41,7 @@ type StreamedQueryParams = * Set to `'replace'` to write all data to the cache once the stream ends. * @param reducer - A function to reduce the streamed chunks into the final data. * Defaults to a function that appends chunks to the end of the array. - * @param initialValue - Initial value to be used while the first chunk is being fetched. + * @param initialValue - Initial value to be used while the first chunk is being fetched, and returned if the stream yields no values. */ export function streamedQuery< TQueryFnData = unknown, @@ -94,6 +94,6 @@ export function streamedQuery< context.client.setQueryData(context.queryKey, result) } - return context.client.getQueryData(context.queryKey)! + return context.client.getQueryData(context.queryKey) ?? initialValue } }