From 743f41b4ba2ec588e59556f9f913580ac0ecfd0e Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 19 Mar 2025 11:39:24 -0700 Subject: [PATCH 1/4] Fix react typings --- packages/react/src/data-connect/index.ts | 3 +-- packages/react/src/data-connect/query-client.ts | 11 +++++------ .../react/src/data-connect/useDataConnectQuery.ts | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/react/src/data-connect/index.ts b/packages/react/src/data-connect/index.ts index 44cd316a..c3d3ce83 100644 --- a/packages/react/src/data-connect/index.ts +++ b/packages/react/src/data-connect/index.ts @@ -1,4 +1,3 @@ -import { ReservedQueryKeys } from "./types"; export { DataConnectQueryClient, @@ -12,4 +11,4 @@ export { useDataConnectMutation, type useDataConnectMutationOptions, } from "./useDataConnectMutation"; -export type { FlattenedQueryResult, FlattenedMutationResult } from "./types"; +export type { QueryResultRequiredRef, UseDataConnectMutationResult, UseDataConnectQueryResult } from "./types"; diff --git a/packages/react/src/data-connect/query-client.ts b/packages/react/src/data-connect/query-client.ts index b5d2561c..433d44a4 100644 --- a/packages/react/src/data-connect/query-client.ts +++ b/packages/react/src/data-connect/query-client.ts @@ -9,13 +9,12 @@ import { type QueryResult, executeQuery, } from "firebase/data-connect"; -import type { FlattenedQueryResult } from "./types"; export type DataConnectQueryOptions = Omit< FetchQueryOptions< - FlattenedQueryResult, + Data, FirebaseError, - FlattenedQueryResult, + Data, QueryKey >, "queryFn" | "queryKey" @@ -30,7 +29,7 @@ export class DataConnectQueryClient extends QueryClient { options?: DataConnectQueryOptions, ) { let queryRef: QueryRef; - let initialData: FlattenedQueryResult | undefined; + let initialData: Data | undefined; if ("ref" in refOrResult) { queryRef = refOrResult.ref; @@ -45,9 +44,9 @@ export class DataConnectQueryClient extends QueryClient { } return this.prefetchQuery< - FlattenedQueryResult, + Data, FirebaseError, - FlattenedQueryResult, + Data, QueryKey >({ ...options, diff --git a/packages/react/src/data-connect/useDataConnectQuery.ts b/packages/react/src/data-connect/useDataConnectQuery.ts index 65d95de3..27c169cf 100644 --- a/packages/react/src/data-connect/useDataConnectQuery.ts +++ b/packages/react/src/data-connect/useDataConnectQuery.ts @@ -10,7 +10,7 @@ import { import type { PartialBy } from "../../utils"; import { QueryResultRequiredRef, - UseDataConnectQuery, + UseDataConnectQueryResult, } from "./types"; import { useState } from "react"; @@ -26,7 +26,7 @@ export function useDataConnectQuery( FirebaseError >, _callerSdkType: CallerSdkType = CallerSdkTypeEnum.TanstackReactCore -): UseDataConnectQuery { +): UseDataConnectQueryResult { const [dataConnectResult, setDataConnectResult] = useState>('ref' in refOrResult ? refOrResult : { ref: refOrResult }); let initialData: Data | undefined; const { ref } = dataConnectResult; From e9c95f737883a9de6a5f42ec21fc4e469cd66ab4 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 19 Mar 2025 15:53:13 -0700 Subject: [PATCH 2/4] Fixed issue with initialData --- .../data-connect/useDataConnectQuery.test.tsx | 18 ++++++++++++++++++ .../src/data-connect/useDataConnectQuery.ts | 7 +++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/react/src/data-connect/useDataConnectQuery.test.tsx b/packages/react/src/data-connect/useDataConnectQuery.test.tsx index 5d2c49f3..517033a1 100644 --- a/packages/react/src/data-connect/useDataConnectQuery.test.tsx +++ b/packages/react/src/data-connect/useDataConnectQuery.test.tsx @@ -214,6 +214,24 @@ describe("useDataConnectQuery", () => { expect(result.current.dataConnectResult).toHaveProperty("source"); expect(result.current.dataConnectResult).toHaveProperty("fetchTime"); }); + test("avails the data immediately when initialData is passed", async () => { + const queryResult = await executeQuery(listMoviesRef()); + + const { result } = renderHook(() => useDataConnectQuery(listMoviesRef(), { initialData: queryResult.data }), { + wrapper, + }); + + // Should not enter a loading state + expect(result.current.isLoading).toBe(false); + expect(result.current.isPending).toBe(false); + + expect(result.current.isSuccess).toBe(true); + + expect(result.current.data).toBeDefined(); + expect(result.current.dataConnectResult).toHaveProperty("ref"); + expect(result.current.dataConnectResult).toHaveProperty("source"); + expect(result.current.dataConnectResult).toHaveProperty("fetchTime"); + }); test("a query with no variables has null as the second query key argument", async () => { const queryClient = new DataConnectQueryClient(); diff --git a/packages/react/src/data-connect/useDataConnectQuery.ts b/packages/react/src/data-connect/useDataConnectQuery.ts index 27c169cf..a5e0a805 100644 --- a/packages/react/src/data-connect/useDataConnectQuery.ts +++ b/packages/react/src/data-connect/useDataConnectQuery.ts @@ -1,4 +1,4 @@ -import { type UseQueryOptions, useQuery } from "@tanstack/react-query"; +import { InitialDataFunction, type UseQueryOptions, useQuery } from "@tanstack/react-query"; import type { FirebaseError } from "firebase/app"; import { type QueryRef, @@ -28,13 +28,16 @@ export function useDataConnectQuery( _callerSdkType: CallerSdkType = CallerSdkTypeEnum.TanstackReactCore ): UseDataConnectQueryResult { const [dataConnectResult, setDataConnectResult] = useState>('ref' in refOrResult ? refOrResult : { ref: refOrResult }); - let initialData: Data | undefined; + // TODO(mtewani): in the future we should allow for users to pass in `QueryResult` objects into `initialData`. + let initialData: Data | InitialDataFunction | undefined; const { ref } = dataConnectResult; if ("ref" in refOrResult) { initialData = { ...refOrResult.data, }; + } else { + initialData = options?.initialData; } // @ts-expect-error function is hidden under `DataConnect`. From 4a3f0e1cfbe7b190361af0ab8727bfb5a3f529de Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 19 Mar 2025 16:05:56 -0700 Subject: [PATCH 3/4] Fixed race condition in test --- .../js/default-connector/esm/index.esm.js | 16 ++++++++-------- .../data-connect/useDataConnectQuery.test.tsx | 12 +++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/dataconnect-sdk/js/default-connector/esm/index.esm.js b/dataconnect-sdk/js/default-connector/esm/index.esm.js index 6b2bec26..01524f0c 100644 --- a/dataconnect-sdk/js/default-connector/esm/index.esm.js +++ b/dataconnect-sdk/js/default-connector/esm/index.esm.js @@ -7,7 +7,7 @@ export const connectorConfig = { }; export function createMovieRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars } = validateArgs(connectorConfig, dcOrVars, vars, true); + const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); dcInstance._useGeneratedSdk(); return mutationRef(dcInstance, 'CreateMovie', inputVars); } @@ -17,7 +17,7 @@ export function createMovie(dcOrVars, vars) { } export function upsertMovieRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars } = validateArgs(connectorConfig, dcOrVars, vars, true); + const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); dcInstance._useGeneratedSdk(); return mutationRef(dcInstance, 'UpsertMovie', inputVars); } @@ -27,7 +27,7 @@ export function upsertMovie(dcOrVars, vars) { } export function deleteMovieRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars } = validateArgs(connectorConfig, dcOrVars, vars, true); + const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); dcInstance._useGeneratedSdk(); return mutationRef(dcInstance, 'DeleteMovie', inputVars); } @@ -37,7 +37,7 @@ export function deleteMovie(dcOrVars, vars) { } export function addMetaRef(dc) { - const { dc: dcInstance } = validateArgs(connectorConfig, dc, undefined); + const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined); dcInstance._useGeneratedSdk(); return mutationRef(dcInstance, 'AddMeta'); } @@ -47,7 +47,7 @@ export function addMeta(dc) { } export function deleteMetaRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars } = validateArgs(connectorConfig, dcOrVars, vars, true); + const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); dcInstance._useGeneratedSdk(); return mutationRef(dcInstance, 'DeleteMeta', inputVars); } @@ -57,7 +57,7 @@ export function deleteMeta(dcOrVars, vars) { } export function listMoviesRef(dc) { - const { dc: dcInstance } = validateArgs(connectorConfig, dc, undefined); + const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined); dcInstance._useGeneratedSdk(); return queryRef(dcInstance, 'ListMovies'); } @@ -67,7 +67,7 @@ export function listMovies(dc) { } export function getMovieByIdRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars } = validateArgs(connectorConfig, dcOrVars, vars, true); + const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); dcInstance._useGeneratedSdk(); return queryRef(dcInstance, 'GetMovieById', inputVars); } @@ -77,7 +77,7 @@ export function getMovieById(dcOrVars, vars) { } export function getMetaRef(dc) { - const { dc: dcInstance } = validateArgs(connectorConfig, dc, undefined); + const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined); dcInstance._useGeneratedSdk(); return queryRef(dcInstance, 'GetMeta'); } diff --git a/packages/react/src/data-connect/useDataConnectQuery.test.tsx b/packages/react/src/data-connect/useDataConnectQuery.test.tsx index 517033a1..d18b74b1 100644 --- a/packages/react/src/data-connect/useDataConnectQuery.test.tsx +++ b/packages/react/src/data-connect/useDataConnectQuery.test.tsx @@ -110,16 +110,15 @@ describe("useDataConnectQuery", () => { }); test("returns the correct data properties", async () => { - const { result } = renderHook(() => useDataConnectQuery(listMoviesRef()), { - wrapper, - }); - await createMovie({ title: "tanstack query firebase", genre: "library", imageUrl: "https://invertase.io/", }); - + const { result } = renderHook(() => useDataConnectQuery(listMoviesRef()), { + wrapper, + }); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); result.current.data?.movies.forEach((i) => { @@ -228,9 +227,8 @@ describe("useDataConnectQuery", () => { expect(result.current.isSuccess).toBe(true); expect(result.current.data).toBeDefined(); + expect(result.current.data).to.deep.eq(queryResult.data); expect(result.current.dataConnectResult).toHaveProperty("ref"); - expect(result.current.dataConnectResult).toHaveProperty("source"); - expect(result.current.dataConnectResult).toHaveProperty("fetchTime"); }); test("a query with no variables has null as the second query key argument", async () => { From 0c14495806a4aa0136ed803ab338ee3f57be09b5 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 20 Mar 2025 15:29:11 -0700 Subject: [PATCH 4/4] Removed extra newline --- packages/react/src/data-connect/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/src/data-connect/index.ts b/packages/react/src/data-connect/index.ts index c3d3ce83..19584f66 100644 --- a/packages/react/src/data-connect/index.ts +++ b/packages/react/src/data-connect/index.ts @@ -1,4 +1,3 @@ - export { DataConnectQueryClient, type DataConnectQueryOptions,