Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add subscribeToMore function to useBackgroundQuery, useQueryRefHandlers, and useLoadableQuery #11923

Merged
merged 9 commits into from
Jul 5, 2024
12 changes: 7 additions & 5 deletions .api-reports/api-report-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2089,6 +2089,7 @@ UseBackgroundQueryResult<TData, TVariables>

// @public (undocumented)
export type UseBackgroundQueryResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> = {
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
};
Expand Down Expand Up @@ -2148,6 +2149,7 @@ queryRef: QueryRef<TData, TVariables> | null,
handlers: {
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
reset: ResetFunction;
}
];
Expand All @@ -2165,6 +2167,7 @@ export function useQueryRefHandlers<TData = unknown, TVariables extends Operatio
export interface UseQueryRefHandlersResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> {
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}

// Warning: (ae-forgotten-export) The symbol "ReactiveVar" needs to be exported by the entry point index.d.ts
Expand Down Expand Up @@ -2240,8 +2243,6 @@ export interface UseSuspenseQueryResult<TData = unknown, TVariables extends Oper
networkStatus: NetworkStatus;
// (undocumented)
refetch: RefetchFunction<TData, TVariables>;
// Warning: (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
//
// (undocumented)
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}
Expand Down Expand Up @@ -2305,9 +2306,10 @@ interface WatchQueryOptions<TVariables extends OperationVariables = OperationVar
// src/core/types.ts:203:5 - (ae-forgotten-export) The symbol "Resolver" needs to be exported by the entry point index.d.ts
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "IgnoreModifier" needs to be exported by the entry point index.d.ts
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "UpdateQueryFn" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:29:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:30:3 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useLoadableQuery.ts:107:1 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:38:3 - (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:54:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:78:4 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useLoadableQuery.ts:120:9 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
12 changes: 7 additions & 5 deletions .api-reports/api-report-react_hooks.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,7 @@ UseBackgroundQueryResult<TData, TVariables>

// @public (undocumented)
export type UseBackgroundQueryResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> = {
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
};
Expand Down Expand Up @@ -1976,6 +1977,7 @@ queryRef: QueryRef<TData, TVariables> | null,
handlers: {
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
reset: ResetFunction;
}
];
Expand All @@ -1996,6 +1998,7 @@ export function useQueryRefHandlers<TData = unknown, TVariables extends Operatio
export interface UseQueryRefHandlersResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> {
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}

// Warning: (ae-forgotten-export) The symbol "ReactiveVar" needs to be exported by the entry point index.d.ts
Expand Down Expand Up @@ -2075,8 +2078,6 @@ export interface UseSuspenseQueryResult<TData = unknown, TVariables extends Oper
networkStatus: NetworkStatus;
// (undocumented)
refetch: RefetchFunction<TData, TVariables>;
// Warning: (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
//
// (undocumented)
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}
Expand Down Expand Up @@ -2129,9 +2130,10 @@ interface WatchQueryOptions<TVariables extends OperationVariables = OperationVar
// src/core/types.ts:203:5 - (ae-forgotten-export) The symbol "Resolver" needs to be exported by the entry point index.d.ts
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "IgnoreModifier" needs to be exported by the entry point index.d.ts
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "UpdateQueryFn" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:29:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:30:3 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useLoadableQuery.ts:107:1 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:38:3 - (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:54:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:78:4 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useLoadableQuery.ts:120:9 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
9 changes: 5 additions & 4 deletions .api-reports/api-report-react_internal.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1923,6 +1923,7 @@ UseBackgroundQueryResult<TData, TVariables>

// @public (undocumented)
type UseBackgroundQueryResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> = {
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
};
Expand Down Expand Up @@ -1967,6 +1968,7 @@ function useQueryRefHandlers<TData = unknown, TVariables extends OperationVariab
interface UseQueryRefHandlersResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> {
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}

// Warning: (ae-forgotten-export) The symbol "UseReadQueryResult" needs to be exported by the entry point index.d.ts
Expand Down Expand Up @@ -2039,8 +2041,6 @@ interface UseSuspenseQueryResult<TData = unknown, TVariables extends OperationVa
networkStatus: NetworkStatus;
// (undocumented)
refetch: RefetchFunction<TData, TVariables>;
// Warning: (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
//
// (undocumented)
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}
Expand Down Expand Up @@ -2134,8 +2134,9 @@ export function wrapQueryRef<TData, TVariables extends OperationVariables>(inter
// src/core/types.ts:203:5 - (ae-forgotten-export) The symbol "Resolver" needs to be exported by the entry point index.d.ts
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "IgnoreModifier" needs to be exported by the entry point index.d.ts
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "UpdateQueryFn" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:29:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:30:3 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:38:3 - (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:54:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:78:4 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
12 changes: 7 additions & 5 deletions .api-reports/api-report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2752,6 +2752,7 @@ UseBackgroundQueryResult<TData, TVariables>

// @public (undocumented)
export type UseBackgroundQueryResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> = {
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
};
Expand Down Expand Up @@ -2811,6 +2812,7 @@ queryRef: QueryRef<TData, TVariables> | null,
handlers: {
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
reset: ResetFunction;
}
];
Expand All @@ -2828,6 +2830,7 @@ export function useQueryRefHandlers<TData = unknown, TVariables extends Operatio
export interface UseQueryRefHandlersResult<TData = unknown, TVariables extends OperationVariables = OperationVariables> {
fetchMore: FetchMoreFunction<TData, TVariables>;
refetch: RefetchFunction<TData, TVariables>;
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}

// @public
Expand Down Expand Up @@ -2901,8 +2904,6 @@ export interface UseSuspenseQueryResult<TData = unknown, TVariables extends Oper
networkStatus: NetworkStatus;
// (undocumented)
refetch: RefetchFunction<TData, TVariables>;
// Warning: (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
//
// (undocumented)
subscribeToMore: SubscribeToMoreFunction<TData, TVariables>;
}
Expand Down Expand Up @@ -2994,9 +2995,10 @@ interface WriteContext extends ReadMergeModifyContext {
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "IgnoreModifier" needs to be exported by the entry point index.d.ts
// src/core/watchQueryOptions.ts:269:2 - (ae-forgotten-export) The symbol "UpdateQueryFn" needs to be exported by the entry point index.d.ts
// src/link/http/selectHttpOptionsAndBody.ts:128:32 - (ae-forgotten-export) The symbol "HttpQueryOptions" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:29:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:30:3 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useLoadableQuery.ts:107:1 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:38:3 - (ae-forgotten-export) The symbol "SubscribeToMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:54:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useBackgroundQuery.ts:78:4 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts
// src/react/hooks/useLoadableQuery.ts:120:9 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
5 changes: 5 additions & 0 deletions .changeset/angry-ravens-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": minor
---

Add support for `subscribeToMore` function to `useQueryRefHandlers`.
5 changes: 5 additions & 0 deletions .changeset/chilly-dots-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": minor
---

Add support for `subscribeToMore` function to `useLoadableQuery`.
5 changes: 5 additions & 0 deletions .changeset/slimy-balloons-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": minor
---

Add support for `subscribeToMore` function to `useBackgroundQuery`.
4 changes: 2 additions & 2 deletions .size-limits.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dist/apollo-client.min.cjs": 39825,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32851
"dist/apollo-client.min.cjs": 39873,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32865
}
2 changes: 2 additions & 0 deletions src/core/ObservableQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ export class ObservableQuery<
this.waitForOwnResult = skipCacheDataFor(options.fetchPolicy);
this.isTornDown = false;

this.subscribeToMore = this.subscribeToMore.bind(this);

const {
watchQuery: { fetchPolicy: defaultFetchPolicy = "cache-first" } = {},
} = queryManager.defaultOptions;
Expand Down
137 changes: 136 additions & 1 deletion src/react/hooks/__tests__/useBackgroundQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
TypedDocumentNode,
ApolloLink,
Observable,
split,
} from "../../../core";
import {
MockedResponse,
Expand All @@ -29,6 +30,7 @@ import {
concatPagination,
offsetLimitPagination,
DeepPartial,
getMainDefinition,
} from "../../../utilities";
import { useBackgroundQuery } from "../useBackgroundQuery";
import { UseReadQueryResult, useReadQuery } from "../useReadQuery";
Expand All @@ -37,7 +39,10 @@ import { QueryRef, QueryReference } from "../../internal";
import { InMemoryCache } from "../../../cache";
import { SuspenseQueryHookFetchPolicy } from "../../types/types";
import equal from "@wry/equality";
import { RefetchWritePolicy } from "../../../core/watchQueryOptions";
import {
RefetchWritePolicy,
SubscribeToMoreOptions,
} from "../../../core/watchQueryOptions";
import { skipToken } from "../constants";
import {
PaginatedCaseData,
Expand All @@ -54,6 +59,7 @@ import {
spyOnConsole,
useTrackRenders,
} from "../../../testing/internal";
import { SubscribeToMoreFunction } from "../useSuspenseQuery";

afterEach(() => {
jest.useRealTimers();
Expand Down Expand Up @@ -6052,6 +6058,135 @@ describe("fetchMore", () => {

await expect(Profiler).not.toRerender();
});

it("can subscribe to subscriptions and react to cache updates via `subscribeToMore`", async () => {
interface SubscriptionData {
greetingUpdated: string;
}

type UpdateQueryFn = NonNullable<
SubscribeToMoreOptions<
SimpleCaseData,
Record<string, never>,
SubscriptionData
>["updateQuery"]
>;

const subscription: TypedDocumentNode<
SubscriptionData,
Record<string, never>
> = gql`
subscription {
greetingUpdated
}
`;

const { mocks, query } = setupSimpleCase();

const wsLink = new MockSubscriptionLink();
const mockLink = new MockLink(mocks);

const link = split(
({ query }) => {
const definition = getMainDefinition(query);

return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink,
mockLink
);

const client = new ApolloClient({ link, cache: new InMemoryCache() });

const Profiler = createProfiler({
initialSnapshot: {
subscribeToMore: null as SubscribeToMoreFunction<
SimpleCaseData,
Record<string, never>
> | null,
result: null as UseReadQueryResult<SimpleCaseData> | null,
},
});

const { SuspenseFallback, ReadQueryHook } =
createDefaultTrackedComponents(Profiler);

function App() {
useTrackRenders();
const [queryRef, { subscribeToMore }] = useBackgroundQuery(query);

Profiler.mergeSnapshot({ subscribeToMore });

return (
<Suspense fallback={<SuspenseFallback />}>
<ReadQueryHook queryRef={queryRef} />
</Suspense>
);
}

renderWithClient(<App />, { client, wrapper: Profiler });

{
const { renderedComponents } = await Profiler.takeRender();

expect(renderedComponents).toStrictEqual([App, SuspenseFallback]);
}

{
const { renderedComponents, snapshot } = await Profiler.takeRender();

expect(renderedComponents).toStrictEqual([ReadQueryHook]);
expect(snapshot.result).toEqual({
data: { greeting: "Hello" },
error: undefined,
networkStatus: NetworkStatus.ready,
});
}

const updateQuery = jest.fn<
ReturnType<UpdateQueryFn>,
Parameters<UpdateQueryFn>
>((_, { subscriptionData: { data } }) => {
return { greeting: data.greetingUpdated };
});

const { snapshot } = Profiler.getCurrentRender();

snapshot.subscribeToMore!({ document: subscription, updateQuery });

wsLink.simulateResult({
result: {
data: {
greetingUpdated: "Subscription hello",
},
},
});

{
const { snapshot, renderedComponents } = await Profiler.takeRender();

expect(renderedComponents).toStrictEqual([ReadQueryHook]);
expect(snapshot.result).toEqual({
data: { greeting: "Subscription hello" },
error: undefined,
networkStatus: NetworkStatus.ready,
});
}

expect(updateQuery).toHaveBeenCalledTimes(1);
expect(updateQuery).toHaveBeenCalledWith(
{ greeting: "Hello" },
{
subscriptionData: {
data: { greetingUpdated: "Subscription hello" },
},
variables: {},
}
);
});
});

describe.skip("type tests", () => {
Expand Down
Loading
Loading