From d9d6bef804f9a8409a4ae9c990d78ae5ee128fe0 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Thu, 24 Oct 2024 13:50:41 -0400 Subject: [PATCH 01/15] Finish query client tests and APIs Signed-off-by: Paul Sachs --- .../src/create-infinite-query-options.ts | 4 +- .../src/create-query-options.ts | 4 +- .../src/query-client.test.ts | 381 ++++++++++++ .../connect-query-core/src/query-client.ts | 560 ++++++++++++++++++ packages/connect-query-core/src/utils.ts | 2 +- 5 files changed, 946 insertions(+), 5 deletions(-) create mode 100644 packages/connect-query-core/src/query-client.test.ts create mode 100644 packages/connect-query-core/src/query-client.ts diff --git a/packages/connect-query-core/src/create-infinite-query-options.ts b/packages/connect-query-core/src/create-infinite-query-options.ts index f4aa2d5f..352dcfa1 100644 --- a/packages/connect-query-core/src/create-infinite-query-options.ts +++ b/packages/connect-query-core/src/create-infinite-query-options.ts @@ -64,7 +64,7 @@ function createUnaryInfiniteQueryFn< pageParamKey, }: { pageParamKey: ParamKey; - }, + } ): QueryFunction< MessageShape, ConnectQueryKey, @@ -180,7 +180,7 @@ export function createInfiniteQueryOptions< transport, getNextPageParam, pageParamKey, - }: ConnectInfiniteQueryOptions & { transport: Transport }, + }: ConnectInfiniteQueryOptions & { transport: Transport } ): { getNextPageParam: ConnectInfiniteQueryOptions< I, diff --git a/packages/connect-query-core/src/create-query-options.ts b/packages/connect-query-core/src/create-query-options.ts index 3d7069b8..c18132be 100644 --- a/packages/connect-query-core/src/create-query-options.ts +++ b/packages/connect-query-core/src/create-query-options.ts @@ -31,7 +31,7 @@ import { createStructuralSharing } from "./structural-sharing.js"; function createUnaryQueryFn( transport: Transport, schema: DescMethodUnary, - input: MessageInitShape | undefined, + input: MessageInitShape | undefined ): QueryFunction, ConnectQueryKey> { return async (context) => { return callUnaryMethod(transport, schema, input, { @@ -101,7 +101,7 @@ export function createQueryOptions< transport, }: { transport: Transport; - }, + } ): { queryKey: ConnectQueryKey; queryFn: QueryFunction, ConnectQueryKey> | SkipToken; diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts new file mode 100644 index 00000000..1e93d1ba --- /dev/null +++ b/packages/connect-query-core/src/query-client.test.ts @@ -0,0 +1,381 @@ +import type { MessageShape } from "@bufbuild/protobuf"; +import type { Query } from "@tanstack/query-core"; +import { describe, expect, it, vi } from "vitest"; + +import { createConnectQueryKey } from "./connect-query-key.js"; +import type { SayResponseSchema } from "./gen/eliza_pb.js"; +import { ElizaService } from "./gen/eliza_pb.js"; +import { ListService } from "./gen/list_pb.js"; +import { QueryClient } from "./query-client.js"; +import { mockEliza, mockPaginatedTransport } from "./test/test-utils.js"; + +// TODO: maybe create a helper to take a service and method and generate this. +const sayMethodDescriptor = ElizaService.method.say; + +const mockedElizaTransport = mockEliza(); + +const paginatedTransport = mockPaginatedTransport(); + +const queryDetails = { + schema: sayMethodDescriptor, + input: { + sentence: "Pablo", + }, + transport: mockedElizaTransport, +}; + +describe("prefetch APIs", () => { + it("populates a single query cache", async () => { + const queryClient = new QueryClient(); + const currentCacheItems = queryClient.getQueryCache().findAll(); + expect(currentCacheItems).toHaveLength(0); + + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + const item = queryClient.getConnectQueryData({ + ...queryDetails, + cardinality: "finite", + }); + expect(item?.sentence).toBe("Hello Pablo"); + + const queryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + expect(queryState?.status).toBe("success"); + expect(queryState?.fetchStatus).toBe("idle"); + expect(queryState?.dataUpdateCount).toBe(1); + }); + + it("populates an infinite query cache", async () => { + const queryClient = new QueryClient(); + const currentCacheItems = queryClient.getQueryCache().findAll(); + expect(currentCacheItems).toHaveLength(0); + + await queryClient.prefetchConnectInfiniteQuery( + ListService.method.list, + { + preview: true, + page: 0n, + }, + { + transport: paginatedTransport, + pageParamKey: "page", + getNextPageParam: (data) => data.page, + } + ); + + const details = { + schema: ListService.method.list, + transport: paginatedTransport, + input: { + preview: true, + }, + cardinality: "infinite" as const, + }; + + const item = queryClient.getConnectQueryData(details); + + const nextItems = queryClient.getQueryCache().findAll(); + expect(nextItems).toHaveLength(1); + expect(item?.pages[0].items).toHaveLength(3); + + const queryState = queryClient.getConnectQueryState(details); + expect(queryState?.status).toBe("success"); + expect(queryState?.fetchStatus).toBe("idle"); + expect(queryState?.dataUpdateCount).toBe(1); + }); +}); + +describe("invalidateConnectQueries", () => { + it("invalidates a specific query", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + await queryClient.invalidateConnectQueries(queryDetails); + const queryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + expect(queryState?.isInvalidated).toBe(true); + }); + + it("invalidate all methods for a given service", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + + await queryClient.invalidateConnectQueries({ + schema: ElizaService, + transport: mockedElizaTransport, + }); + const queryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + expect(queryState?.isInvalidated).toBe(true); + }); +}); + +describe("refetchConnectQueries", () => { + it("refetch a specific query", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + await queryClient.refetchConnectQueries(queryDetails); + const queryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + expect(queryState?.dataUpdateCount).toBe(2); + }); + + it("refetch all methods for a given service", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + + await queryClient.refetchConnectQueries({ + schema: ElizaService, + transport: mockedElizaTransport, + }); + const queryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + expect(queryState?.dataUpdateCount).toBe(2); + }); +}); + +describe("setConnectQueryData", () => { + it("updates locally fetched data", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + + const queryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + expect(queryState?.dataUpdateCount).toBe(1); + expect(queryState?.data?.sentence).toBe("Hello Pablo"); + + queryClient.setConnectQueryData( + { + ...queryDetails, + cardinality: "finite", + }, + { + sentence: "Hello Stu", + } + ); + + const newQueryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + + expect(newQueryState?.dataUpdateCount).toBe(2); + expect(newQueryState?.data?.sentence).toBe("Hello Stu"); + }); + + it("updates locally fetched data with a callback", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + + const queryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + expect(queryState?.dataUpdateCount).toBe(1); + expect(queryState?.data?.sentence).toBe("Hello Pablo"); + + queryClient.setConnectQueryData( + { + ...queryDetails, + cardinality: "finite", + }, + (prev) => { + if (prev === undefined) { + return undefined; + } + expect(prev.sentence).toBe("Hello Pablo"); + return { + ...prev, + sentence: "Hello Stu", + }; + } + ); + + const newQueryState = queryClient.getConnectQueryState({ + ...queryDetails, + cardinality: "finite", + }); + + expect(newQueryState?.dataUpdateCount).toBe(2); + expect(newQueryState?.data?.sentence).toBe("Hello Stu"); + }); +}); + +describe("setConnectQueriesData", () => { + it("update locally fetched data across multiple queries", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + queryDetails.input, + { transport: queryDetails.transport } + ); + await queryClient.prefetchConnectQuery( + queryDetails.schema, + { + sentence: "Stu", + }, + { transport: queryDetails.transport } + ); + + const cachedItems = queryClient.getQueryCache().findAll({ + queryKey: createConnectQueryKey({ + ...queryDetails, + input: {}, + cardinality: "finite", + }), + }); + expect(cachedItems).toHaveLength(2); + + queryClient.setConnectQueriesData( + { + schema: sayMethodDescriptor, + }, + (prev) => { + if (prev === undefined) { + return undefined; + } + return { + ...prev, + sentence: prev.sentence + "!", + }; + } + ); + + const newCachedItems = queryClient.getQueryCache().findAll() as Query< + MessageShape + >[]; + expect(newCachedItems).toHaveLength(2); + expect(newCachedItems[0].state.data?.sentence).toBe("Hello Pablo!"); + expect(newCachedItems[1].state.data?.sentence).toBe("Hello Stu!"); + }); +}); + +describe("fetchConnectInfiniteQuery", () => { + it("fetches infinite data", async () => { + const queryClient = new QueryClient(); + const result = await queryClient.fetchConnectInfiniteQuery( + ListService.method.list, + { + preview: true, + page: 0n, + }, + { + transport: paginatedTransport, + getNextPageParam: (data) => { + return data.page + 1n; + }, + pageParamKey: "page", + } + ); + + expect(result).toBeDefined(); + expect(result.pages).toHaveLength(1); + expect(result.pages[0].$typeName).toBe("ListResponse"); + expect(result.pages[0].items).toHaveLength(3); + }); +}); + +describe("getConnectQueryState", () => { + it("can get state for infinite queries", async () => { + const queryClient = new QueryClient(); + await queryClient.fetchConnectInfiniteQuery( + ListService.method.list, + { + preview: true, + page: 0n, + }, + { + transport: paginatedTransport, + getNextPageParam: (data) => { + return data.page + 1n; + }, + pageParamKey: "page", + } + ); + + const state = queryClient.getConnectQueryState({ + schema: ListService.method.list, + transport: paginatedTransport, + input: { + preview: true, + }, + cardinality: "infinite", + }); + + expect(state?.status).toBe("success"); + expect(state?.fetchStatus).toBe("idle"); + expect(state?.dataUpdateCount).toBe(1); + }); +}); + +describe("ensure APIs", () => { + it("ensure data exists for infinite queries", async () => { + const queryClient = new QueryClient(); + const data = await queryClient.ensureConnectInfiniteQueryData( + ListService.method.list, + { + preview: true, + page: 0n, + }, + { + transport: paginatedTransport, + getNextPageParam: (data) => { + return data.page + 1n; + }, + pageParamKey: "page", + staleTime: 1000, + } + ); + + const state = queryClient.getConnectQueryState({ + schema: ListService.method.list, + transport: paginatedTransport, + input: { + preview: true, + }, + cardinality: "infinite", + }); + expect(state?.status).toBe("success"); + expect(state?.fetchStatus).toBe("idle"); + expect(state?.dataUpdateCount).toBe(1); + expect(data.pages[0]).toBe(state?.data?.pages[0]); + }); +}); diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts new file mode 100644 index 00000000..e03dcf7f --- /dev/null +++ b/packages/connect-query-core/src/query-client.ts @@ -0,0 +1,560 @@ +import type { + DescMessage, + DescMethod, + DescMethodUnary, + DescService, + MessageInitShape, + MessageShape, +} from "@bufbuild/protobuf"; +import type { ConnectError, Transport } from "@connectrpc/connect"; +import type { + FetchInfiniteQueryOptions as TanstackFetchInfiniteQueryOptions, + FetchQueryOptions as TanstackFetchQueryOptions, + InvalidateOptions, + InvalidateQueryFilters, + QueryFilters, + RefetchOptions, + RefetchQueryFilters, + ResetOptions, + SetDataOptions, + InfiniteData, + QueryState, +} from "@tanstack/query-core"; +import { QueryClient as TSQueryClient } from "@tanstack/query-core"; + +import type { ConnectQueryKey } from "./connect-query-key.js"; +import { createConnectQueryKey } from "./connect-query-key.js"; +import type { ConnectInfiniteQueryOptions } from "./create-infinite-query-options.js"; +import { createInfiniteQueryOptions } from "./create-infinite-query-options.js"; +import { createQueryOptions } from "./create-query-options.js"; +import type { ConnectUpdater } from "./utils.js"; +import { createProtobufSafeUpdater } from "./utils.js"; + +type FetchQueryOptions< + O extends DescMessage, + SelectOutData = MessageShape, +> = Omit< + TanstackFetchQueryOptions< + MessageShape, + ConnectError, + SelectOutData, + ConnectQueryKey + >, + "queryFn" | "queryKey" +> & { + /** The transport to be used for the fetching. */ + transport?: Transport; +}; + +type FetchInfiniteQueryOptions< + I extends DescMessage, + O extends DescMessage, + ParamKey extends keyof MessageInitShape, +> = Omit< + TanstackFetchInfiniteQueryOptions< + MessageShape, + ConnectError, + MessageShape, + ConnectQueryKey, + MessageInitShape[ParamKey] + >, + "getNextPageParam" | "initialPageParam" | "queryFn" | "queryKey" +> & + ConnectInfiniteQueryOptions & { + transport: Transport; + }; + +type KeyParams = + Desc extends DescMethodUnary + ? { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality?: "finite" | "infinite" | undefined; + pageParamKey?: keyof MessageInitShape; + } + : { + schema: Desc; + transport: Transport; + cardinality?: "finite" | "infinite" | undefined; + }; + +/** + * A custom query client that adds some useful methods to access typesafe query data and other shortcuts. + */ +export class QueryClient extends TSQueryClient { + /** + * Invalidate and refetch all queries that match the given schema. This + * can include all queries for a service (and sub methods), or all queries for a method. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientinvalidatequeries} + */ + public async invalidateConnectQueries< + Desc extends DescMethod | DescService, + Params extends KeyParams, + >( + params: Desc | Params, + filterOptions?: Omit, + options?: InvalidateOptions + ) { + if ("schema" in params) { + return this.invalidateQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }, + options + ); + } + return this.invalidateQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + schema: params as DescMethod, + cardinality: undefined, + }), + }, + options + ); + } + + /** + * Refetches all queries that match the given schema. This can include all queries for a service (and sub methods), + * or all queries for a method. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientrefetchqueries} + */ + public async refetchConnectQueries< + Desc extends DescMethod | DescService, + Params extends KeyParams, + >( + params: Params, + filterOptions?: Omit, + options?: RefetchOptions + ) { + return this.refetchQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }, + options + ); + } + + /** + * Set the data for a single query. The query must match exactly the input provided, as well + * as the transport and cardinality (whether it was a finite or infinite query). + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetquerydata} + */ + public setConnectQueryData( + keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "finite" | "infinite"; + }, + updater: ConnectUpdater, + + options?: SetDataOptions | undefined + ) { + return this.setQueryData( + createConnectQueryKey({ + ...keyDescriptor, + // Since we are matching on the exact input, we match what connect-query does in createQueryOptions + input: keyDescriptor.input ?? {}, + }), + createProtobufSafeUpdater(keyDescriptor.schema, updater), + options + ); + } + + /** + * Get the data for a single query. The query must match exactly the input provided, as well + * as the transport and cardinality (whether it was a finite or infinite query). + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetquerydata} + */ + public getConnectQueryData(keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "finite"; + }): MessageShape; + public getConnectQueryData(keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "infinite"; + }): InfiniteData>; + public getConnectQueryData(keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "finite" | "infinite"; + }): + | MessageShape + | InfiniteData> + | undefined { + const key = createConnectQueryKey({ + ...keyDescriptor, + // Since we are matching on the exact input, we match what connect-query does in createQueryOptions + input: keyDescriptor.input ?? {}, + }); + return this.getQueryData(key); + } + + /** + * Sets the data for any matching queries for a given method. The input is optional, and anything left + * as undefined will greedily match queries. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetqueriesdata} + */ + public setConnectQueriesData( + keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport?: Transport; + cardinality?: "finite" | "infinite" | undefined; + }, + updater: ConnectUpdater, + options?: + | (SetDataOptions & { + exact?: boolean; + }) + | undefined + ) { + return this.setQueriesData( + { + queryKey: createConnectQueryKey({ + ...keyDescriptor, + cardinality: keyDescriptor.cardinality, + }), + exact: options?.exact ?? false, + }, + createProtobufSafeUpdater(keyDescriptor.schema, updater), + options + ); + } + + /** + * Fetch a single query and return the result. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientfetchquery} + */ + public async fetchConnectQuery< + I extends DescMessage, + O extends DescMessage, + SelectOutData = MessageShape, + >( + schema: DescMethodUnary, + input: MessageInitShape | undefined, + { + transport, + ...queryOptions + }: { + transport: Transport; + } & FetchQueryOptions + ) { + return this.fetchQuery({ + ...createQueryOptions(schema, input, { transport }), + ...queryOptions, + }); + } + + /** + * Fetch a single infinite query and return the result. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientfetchinfinitequery} + */ + public async fetchConnectInfiniteQuery< + I extends DescMessage, + O extends DescMessage, + ParamKey extends keyof MessageInitShape, + >( + schema: DescMethodUnary, + input: MessageInitShape & Required, ParamKey>>, + { + transport, + getNextPageParam, + pageParamKey, + ...queryOptions + }: FetchInfiniteQueryOptions + ) { + return this.fetchInfiniteQuery({ + ...createInfiniteQueryOptions(schema, input, { + transport, + pageParamKey, + getNextPageParam, + }), + ...queryOptions, + }); + } + + /** + * Prefetch a single query and discard the result. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientprefetchquery} + */ + public async prefetchConnectQuery< + I extends DescMessage, + O extends DescMessage, + SelectOutData = MessageShape, + >( + schema: DescMethodUnary, + input: MessageInitShape | undefined, + { + transport, + ...queryOptions + }: { + transport: Transport; + } & FetchQueryOptions + ) { + return this.prefetchQuery({ + ...createQueryOptions(schema, input, { transport }), + ...queryOptions, + }); + } + + /** + * Prefetch a single infinite query and discard the result. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientprefetchinfinitequery} + */ + public async prefetchConnectInfiniteQuery< + I extends DescMessage, + O extends DescMessage, + ParamKey extends keyof MessageInitShape, + >( + schema: DescMethodUnary, + input: MessageInitShape & Required, ParamKey>>, + { + transport, + getNextPageParam, + pageParamKey, + ...queryOptions + }: FetchInfiniteQueryOptions + ) { + return this.prefetchInfiniteQuery({ + ...createInfiniteQueryOptions(schema, input, { + transport, + pageParamKey, + getNextPageParam, + }), + ...queryOptions, + }); + } + + /** + * Get the query state for a single query. The query must match exactly the input provided, as well + * as the transport and cardinality (whether it was a finite or infinite query). + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetquerystate} + */ + public getConnectQueryState(keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "finite"; + }): QueryState, ConnectError>; + public getConnectQueryState(keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "infinite"; + }): QueryState>, ConnectError>; + public getConnectQueryState(keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "finite" | "infinite"; + }) { + return this.getQueryState(createConnectQueryKey(keyDescriptor)); + } + + /** + * Ensure the query data for a single query. The query must match exactly the input provided, as well + * as the transport and cardinality (whether it was a finite or infinite query). + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientensurequerydata} + */ + public async ensureConnectQueryData< + I extends DescMessage, + O extends DescMessage, + SelectOutData = MessageShape, + >( + schema: DescMethodUnary, + input: MessageInitShape | undefined, + { + transport, + ...queryOptions + }: { + transport: Transport; + } & FetchQueryOptions + ) { + return this.ensureQueryData({ + ...createQueryOptions(schema, input, { transport }), + ...queryOptions, + }); + } + + /** + * Ensure the query data for a single infinite query. The query must match exactly the input provided, as well + * as the transport and cardinality (whether it was a finite or infinite query). + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientensureinfinitequerydata} + */ + public async ensureConnectInfiniteQueryData< + I extends DescMessage, + O extends DescMessage, + ParamKey extends keyof MessageInitShape, + >( + schema: DescMethodUnary, + input: MessageInitShape & Required, ParamKey>>, + { + transport, + getNextPageParam, + pageParamKey, + ...queryOptions + }: FetchInfiniteQueryOptions + ) { + return this.ensureInfiniteQueryData({ + ...createInfiniteQueryOptions(schema, input, { + transport, + pageParamKey, + getNextPageParam, + }), + ...queryOptions, + }); + } + + /** + * Get all data entries that match the given schema. This + * can include all queries for a service (and sub methods), or all queries for a method. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetqueriesdata} + */ + public getConnectQueriesData< + Desc extends DescMethod | DescService, + Params extends KeyParams, + >(params: Desc | Params, filterOptions?: Omit) { + if ("schema" in params) { + return this.getQueriesData({ + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }); + } + return this.getQueriesData({ + ...filterOptions, + queryKey: createConnectQueryKey({ + schema: params as DescMethod, + cardinality: undefined, + }), + }); + } + + /** + * Cancels any outgoing queries that match the given schema. This + * can include all queries for a service (and sub methods), or all queries for a method. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientcancelqueries} + */ + public async cancelConnectQueries< + Desc extends DescMethod | DescService, + Params extends KeyParams, + >(params: Desc | Params, filterOptions?: Omit) { + if ("schema" in params) { + return this.cancelQueries({ + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }); + } + return this.cancelQueries({ + ...filterOptions, + queryKey: createConnectQueryKey({ + schema: params as DescMethod, + cardinality: undefined, + }), + }); + } + + /** + * Removes any queries from the cache that match the given schema. This + * can include all queries for a service (and sub methods), or all queries for a method. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientremovequeries} + */ + public removeConnectQueries< + Desc extends DescMethod | DescService, + Params extends KeyParams, + >(params: Desc | Params, filterOptions?: Omit) { + if ("schema" in params) { + this.removeQueries({ + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }); + return; + } + this.removeQueries({ + ...filterOptions, + queryKey: createConnectQueryKey({ + schema: params as DescMethod, + cardinality: undefined, + }), + }); + return; + } + + /** + * Resets any queries that match the given schema. This + * can include all queries for a service (and sub methods), or all queries for a method. + * + * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientresetqueries} + */ + public async resetConnectQueries< + Desc extends DescMethod | DescService, + Params extends KeyParams, + >( + params: Desc | Params, + filterOptions?: Omit, + options?: ResetOptions + ) { + if ("schema" in params) { + return this.resetQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }, + options + ); + } + return this.resetQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + schema: params as DescMethod, + cardinality: undefined, + }), + }, + options + ); + } +} diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index b51b6a89..a16ce3d8 100644 --- a/packages/connect-query-core/src/utils.ts +++ b/packages/connect-query-core/src/utils.ts @@ -64,7 +64,7 @@ export type ConnectUpdater = export const createProtobufSafeUpdater = ( schema: Pick, "output">, - updater: ConnectUpdater, + updater: ConnectUpdater ) => (prev?: MessageShape): MessageShape | undefined => { if (typeof updater !== "function") { From c096c4eaf70587641984ead9b6fe4b975bd97a3e Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Thu, 24 Oct 2024 13:59:51 -0400 Subject: [PATCH 02/15] Fix lint Signed-off-by: Paul Sachs --- packages/connect-query-core/src/query-client.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index 1e93d1ba..4451bb0c 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -1,6 +1,6 @@ import type { MessageShape } from "@bufbuild/protobuf"; import type { Query } from "@tanstack/query-core"; -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; import { createConnectQueryKey } from "./connect-query-key.js"; import type { SayResponseSchema } from "./gen/eliza_pb.js"; From 4ed77d5f22101d52b476a14b5827ec17094fab38 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Thu, 24 Oct 2024 15:12:42 -0400 Subject: [PATCH 03/15] Format Signed-off-by: Paul Sachs --- .../src/create-infinite-query-options.ts | 4 +- .../src/create-query-options.ts | 4 +- .../src/query-client.test.ts | 104 ++++++++++-------- .../connect-query-core/src/query-client.ts | 54 +++++---- packages/connect-query-core/src/utils.ts | 2 +- packages/test-utils/src/index.tsx | 6 +- 6 files changed, 101 insertions(+), 73 deletions(-) diff --git a/packages/connect-query-core/src/create-infinite-query-options.ts b/packages/connect-query-core/src/create-infinite-query-options.ts index 352dcfa1..f4aa2d5f 100644 --- a/packages/connect-query-core/src/create-infinite-query-options.ts +++ b/packages/connect-query-core/src/create-infinite-query-options.ts @@ -64,7 +64,7 @@ function createUnaryInfiniteQueryFn< pageParamKey, }: { pageParamKey: ParamKey; - } + }, ): QueryFunction< MessageShape, ConnectQueryKey, @@ -180,7 +180,7 @@ export function createInfiniteQueryOptions< transport, getNextPageParam, pageParamKey, - }: ConnectInfiniteQueryOptions & { transport: Transport } + }: ConnectInfiniteQueryOptions & { transport: Transport }, ): { getNextPageParam: ConnectInfiniteQueryOptions< I, diff --git a/packages/connect-query-core/src/create-query-options.ts b/packages/connect-query-core/src/create-query-options.ts index c18132be..3d7069b8 100644 --- a/packages/connect-query-core/src/create-query-options.ts +++ b/packages/connect-query-core/src/create-query-options.ts @@ -31,7 +31,7 @@ import { createStructuralSharing } from "./structural-sharing.js"; function createUnaryQueryFn( transport: Transport, schema: DescMethodUnary, - input: MessageInitShape | undefined + input: MessageInitShape | undefined, ): QueryFunction, ConnectQueryKey> { return async (context) => { return callUnaryMethod(transport, schema, input, { @@ -101,7 +101,7 @@ export function createQueryOptions< transport, }: { transport: Transport; - } + }, ): { queryKey: ConnectQueryKey; queryFn: QueryFunction, ConnectQueryKey> | SkipToken; diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index 4451bb0c..3b3dea73 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -1,3 +1,17 @@ +// Copyright 2021-2023 The Connect Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import type { MessageShape } from "@bufbuild/protobuf"; import type { Query } from "@tanstack/query-core"; import { describe, expect, it } from "vitest"; @@ -33,21 +47,21 @@ describe("prefetch APIs", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const item = queryClient.getConnectQueryData({ ...queryDetails, cardinality: "finite", }); - expect(item?.sentence).toBe("Hello Pablo"); + expect(item.sentence).toBe("Hello Pablo"); const queryState = queryClient.getConnectQueryState({ ...queryDetails, cardinality: "finite", }); - expect(queryState?.status).toBe("success"); - expect(queryState?.fetchStatus).toBe("idle"); - expect(queryState?.dataUpdateCount).toBe(1); + expect(queryState.status).toBe("success"); + expect(queryState.fetchStatus).toBe("idle"); + expect(queryState.dataUpdateCount).toBe(1); }); it("populates an infinite query cache", async () => { @@ -65,7 +79,7 @@ describe("prefetch APIs", () => { transport: paginatedTransport, pageParamKey: "page", getNextPageParam: (data) => data.page, - } + }, ); const details = { @@ -81,12 +95,12 @@ describe("prefetch APIs", () => { const nextItems = queryClient.getQueryCache().findAll(); expect(nextItems).toHaveLength(1); - expect(item?.pages[0].items).toHaveLength(3); + expect(item.pages[0].items).toHaveLength(3); const queryState = queryClient.getConnectQueryState(details); - expect(queryState?.status).toBe("success"); - expect(queryState?.fetchStatus).toBe("idle"); - expect(queryState?.dataUpdateCount).toBe(1); + expect(queryState.status).toBe("success"); + expect(queryState.fetchStatus).toBe("idle"); + expect(queryState.dataUpdateCount).toBe(1); }); }); @@ -96,14 +110,14 @@ describe("invalidateConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.invalidateConnectQueries(queryDetails); const queryState = queryClient.getConnectQueryState({ ...queryDetails, cardinality: "finite", }); - expect(queryState?.isInvalidated).toBe(true); + expect(queryState.isInvalidated).toBe(true); }); it("invalidate all methods for a given service", async () => { @@ -111,7 +125,7 @@ describe("invalidateConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.invalidateConnectQueries({ @@ -122,7 +136,7 @@ describe("invalidateConnectQueries", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState?.isInvalidated).toBe(true); + expect(queryState.isInvalidated).toBe(true); }); }); @@ -132,14 +146,14 @@ describe("refetchConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.refetchConnectQueries(queryDetails); const queryState = queryClient.getConnectQueryState({ ...queryDetails, cardinality: "finite", }); - expect(queryState?.dataUpdateCount).toBe(2); + expect(queryState.dataUpdateCount).toBe(2); }); it("refetch all methods for a given service", async () => { @@ -147,7 +161,7 @@ describe("refetchConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.refetchConnectQueries({ @@ -158,7 +172,7 @@ describe("refetchConnectQueries", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState?.dataUpdateCount).toBe(2); + expect(queryState.dataUpdateCount).toBe(2); }); }); @@ -168,15 +182,15 @@ describe("setConnectQueryData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const queryState = queryClient.getConnectQueryState({ ...queryDetails, cardinality: "finite", }); - expect(queryState?.dataUpdateCount).toBe(1); - expect(queryState?.data?.sentence).toBe("Hello Pablo"); + expect(queryState.dataUpdateCount).toBe(1); + expect(queryState.data?.sentence).toBe("Hello Pablo"); queryClient.setConnectQueryData( { @@ -185,7 +199,7 @@ describe("setConnectQueryData", () => { }, { sentence: "Hello Stu", - } + }, ); const newQueryState = queryClient.getConnectQueryState({ @@ -193,8 +207,8 @@ describe("setConnectQueryData", () => { cardinality: "finite", }); - expect(newQueryState?.dataUpdateCount).toBe(2); - expect(newQueryState?.data?.sentence).toBe("Hello Stu"); + expect(newQueryState.dataUpdateCount).toBe(2); + expect(newQueryState.data?.sentence).toBe("Hello Stu"); }); it("updates locally fetched data with a callback", async () => { @@ -202,15 +216,15 @@ describe("setConnectQueryData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const queryState = queryClient.getConnectQueryState({ ...queryDetails, cardinality: "finite", }); - expect(queryState?.dataUpdateCount).toBe(1); - expect(queryState?.data?.sentence).toBe("Hello Pablo"); + expect(queryState.dataUpdateCount).toBe(1); + expect(queryState.data?.sentence).toBe("Hello Pablo"); queryClient.setConnectQueryData( { @@ -226,7 +240,7 @@ describe("setConnectQueryData", () => { ...prev, sentence: "Hello Stu", }; - } + }, ); const newQueryState = queryClient.getConnectQueryState({ @@ -234,8 +248,8 @@ describe("setConnectQueryData", () => { cardinality: "finite", }); - expect(newQueryState?.dataUpdateCount).toBe(2); - expect(newQueryState?.data?.sentence).toBe("Hello Stu"); + expect(newQueryState.dataUpdateCount).toBe(2); + expect(newQueryState.data?.sentence).toBe("Hello Stu"); }); }); @@ -245,14 +259,14 @@ describe("setConnectQueriesData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.prefetchConnectQuery( queryDetails.schema, { sentence: "Stu", }, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const cachedItems = queryClient.getQueryCache().findAll({ @@ -276,7 +290,7 @@ describe("setConnectQueriesData", () => { ...prev, sentence: prev.sentence + "!", }; - } + }, ); const newCachedItems = queryClient.getQueryCache().findAll() as Query< @@ -303,7 +317,7 @@ describe("fetchConnectInfiniteQuery", () => { return data.page + 1n; }, pageParamKey: "page", - } + }, ); expect(result).toBeDefined(); @@ -328,7 +342,7 @@ describe("getConnectQueryState", () => { return data.page + 1n; }, pageParamKey: "page", - } + }, ); const state = queryClient.getConnectQueryState({ @@ -340,9 +354,9 @@ describe("getConnectQueryState", () => { cardinality: "infinite", }); - expect(state?.status).toBe("success"); - expect(state?.fetchStatus).toBe("idle"); - expect(state?.dataUpdateCount).toBe(1); + expect(state.status).toBe("success"); + expect(state.fetchStatus).toBe("idle"); + expect(state.dataUpdateCount).toBe(1); }); }); @@ -357,12 +371,12 @@ describe("ensure APIs", () => { }, { transport: paginatedTransport, - getNextPageParam: (data) => { - return data.page + 1n; + getNextPageParam: (localData) => { + return localData.page + 1n; }, pageParamKey: "page", staleTime: 1000, - } + }, ); const state = queryClient.getConnectQueryState({ @@ -373,9 +387,9 @@ describe("ensure APIs", () => { }, cardinality: "infinite", }); - expect(state?.status).toBe("success"); - expect(state?.fetchStatus).toBe("idle"); - expect(state?.dataUpdateCount).toBe(1); - expect(data.pages[0]).toBe(state?.data?.pages[0]); + expect(state.status).toBe("success"); + expect(state.fetchStatus).toBe("idle"); + expect(state.dataUpdateCount).toBe(1); + expect(data.pages[0]).toBe(state.data?.pages[0]); }); }); diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index e03dcf7f..1e3637f2 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -1,3 +1,17 @@ +// Copyright 2021-2023 The Connect Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import type { DescMessage, DescMethod, @@ -10,15 +24,15 @@ import type { ConnectError, Transport } from "@connectrpc/connect"; import type { FetchInfiniteQueryOptions as TanstackFetchInfiniteQueryOptions, FetchQueryOptions as TanstackFetchQueryOptions, + InfiniteData, InvalidateOptions, InvalidateQueryFilters, QueryFilters, + QueryState, RefetchOptions, RefetchQueryFilters, ResetOptions, SetDataOptions, - InfiniteData, - QueryState, } from "@tanstack/query-core"; import { QueryClient as TSQueryClient } from "@tanstack/query-core"; @@ -95,7 +109,7 @@ export class QueryClient extends TSQueryClient { >( params: Desc | Params, filterOptions?: Omit, - options?: InvalidateOptions + options?: InvalidateOptions, ) { if ("schema" in params) { return this.invalidateQueries( @@ -106,7 +120,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } return this.invalidateQueries( @@ -117,7 +131,7 @@ export class QueryClient extends TSQueryClient { cardinality: undefined, }), }, - options + options, ); } @@ -133,7 +147,7 @@ export class QueryClient extends TSQueryClient { >( params: Params, filterOptions?: Omit, - options?: RefetchOptions + options?: RefetchOptions, ) { return this.refetchQueries( { @@ -143,7 +157,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } @@ -162,7 +176,7 @@ export class QueryClient extends TSQueryClient { }, updater: ConnectUpdater, - options?: SetDataOptions | undefined + options?: SetDataOptions | undefined, ) { return this.setQueryData( createConnectQueryKey({ @@ -171,7 +185,7 @@ export class QueryClient extends TSQueryClient { input: keyDescriptor.input ?? {}, }), createProtobufSafeUpdater(keyDescriptor.schema, updater), - options + options, ); } @@ -228,7 +242,7 @@ export class QueryClient extends TSQueryClient { | (SetDataOptions & { exact?: boolean; }) - | undefined + | undefined, ) { return this.setQueriesData( { @@ -239,7 +253,7 @@ export class QueryClient extends TSQueryClient { exact: options?.exact ?? false, }, createProtobufSafeUpdater(keyDescriptor.schema, updater), - options + options, ); } @@ -260,7 +274,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.fetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -285,7 +299,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.fetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -314,7 +328,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.prefetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -339,7 +353,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.prefetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -396,7 +410,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.ensureQueryData({ ...createQueryOptions(schema, input, { transport }), @@ -422,7 +436,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.ensureInfiniteQueryData({ ...createInfiniteQueryOptions(schema, input, { @@ -532,7 +546,7 @@ export class QueryClient extends TSQueryClient { >( params: Desc | Params, filterOptions?: Omit, - options?: ResetOptions + options?: ResetOptions, ) { if ("schema" in params) { return this.resetQueries( @@ -543,7 +557,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } return this.resetQueries( @@ -554,7 +568,7 @@ export class QueryClient extends TSQueryClient { cardinality: undefined, }), }, - options + options, ); } } diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index a16ce3d8..b51b6a89 100644 --- a/packages/connect-query-core/src/utils.ts +++ b/packages/connect-query-core/src/utils.ts @@ -64,7 +64,7 @@ export type ConnectUpdater = export const createProtobufSafeUpdater = ( schema: Pick, "output">, - updater: ConnectUpdater + updater: ConnectUpdater, ) => (prev?: MessageShape): MessageShape | undefined => { if (typeof updater !== "function") { diff --git a/packages/test-utils/src/index.tsx b/packages/test-utils/src/index.tsx index 10fca078..a577f9ef 100644 --- a/packages/test-utils/src/index.tsx +++ b/packages/test-utils/src/index.tsx @@ -41,7 +41,7 @@ export const sleep = async (timeout: number) => */ export const mockEliza = ( override?: MessageInitShape, - addDelay = false + addDelay = false, ) => createRouterTransport(({ service }) => { service(ElizaService, { @@ -51,7 +51,7 @@ export const mockEliza = ( } return create( SayResponseSchema, - override ?? { sentence: `Hello ${input.sentence}` } + override ?? { sentence: `Hello ${input.sentence}` }, ); }, }); @@ -92,7 +92,7 @@ export const mockStatefulBigIntTransport = (addDelay = false) => */ export const mockPaginatedTransport = ( override?: MessageInitShape, - addDelay = false + addDelay = false, ) => createRouterTransport(({ service }) => { service(ListService, { From 4a77a5e3a479ca9081710e3ff5bb3c55159d1177 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Thu, 24 Oct 2024 15:20:48 -0400 Subject: [PATCH 04/15] Add gitignore for local vscode Signed-off-by: Paul Sachs --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1514fce5..4291a7b6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules /packages/*/dist /packages/*/coverage *.tsbuildinfo -.turbo \ No newline at end of file +.turbo +.vscode \ No newline at end of file From 38ca830ea9639f1a9ca95b9f80fc9c8ce8aa3f8a Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Fri, 15 Nov 2024 16:13:11 -0500 Subject: [PATCH 05/15] Fix test imports Signed-off-by: Paul Sachs --- packages/connect-query-core/src/query-client.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index 3b3dea73..73903eb4 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -14,14 +14,14 @@ import type { MessageShape } from "@bufbuild/protobuf"; import type { Query } from "@tanstack/query-core"; +import { mockEliza, mockPaginatedTransport } from "test-utils"; +import type { SayResponseSchema } from "test-utils/gen/eliza_pb.js"; +import { ElizaService } from "test-utils/gen/eliza_pb.js"; +import { ListService } from "test-utils/gen/list_pb.js"; import { describe, expect, it } from "vitest"; import { createConnectQueryKey } from "./connect-query-key.js"; -import type { SayResponseSchema } from "./gen/eliza_pb.js"; -import { ElizaService } from "./gen/eliza_pb.js"; -import { ListService } from "./gen/list_pb.js"; import { QueryClient } from "./query-client.js"; -import { mockEliza, mockPaginatedTransport } from "./test/test-utils.js"; // TODO: maybe create a helper to take a service and method and generate this. const sayMethodDescriptor = ElizaService.method.say; From 8245612043e0eeee4f8ed084ed12cae3d3b0e871 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Sat, 8 Feb 2025 22:06:29 -0500 Subject: [PATCH 06/15] Add support for inifinite data in updater methods Signed-off-by: Paul Sachs --- .../src/query-client.test.ts | 91 +++++++++++++++---- .../connect-query-core/src/query-client.ts | 77 +++++++++++----- packages/connect-query-core/src/utils.test.ts | 75 ++++++++++++++- packages/connect-query-core/src/utils.ts | 35 +++++++ 4 files changed, 236 insertions(+), 42 deletions(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index 73903eb4..7358b874 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -47,7 +47,7 @@ describe("prefetch APIs", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); const item = queryClient.getConnectQueryData({ ...queryDetails, @@ -79,7 +79,7 @@ describe("prefetch APIs", () => { transport: paginatedTransport, pageParamKey: "page", getNextPageParam: (data) => data.page, - }, + } ); const details = { @@ -110,7 +110,7 @@ describe("invalidateConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); await queryClient.invalidateConnectQueries(queryDetails); const queryState = queryClient.getConnectQueryState({ @@ -125,7 +125,7 @@ describe("invalidateConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); await queryClient.invalidateConnectQueries({ @@ -146,7 +146,7 @@ describe("refetchConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); await queryClient.refetchConnectQueries(queryDetails); const queryState = queryClient.getConnectQueryState({ @@ -161,7 +161,7 @@ describe("refetchConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); await queryClient.refetchConnectQueries({ @@ -182,7 +182,7 @@ describe("setConnectQueryData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); const queryState = queryClient.getConnectQueryState({ @@ -199,7 +199,7 @@ describe("setConnectQueryData", () => { }, { sentence: "Hello Stu", - }, + } ); const newQueryState = queryClient.getConnectQueryState({ @@ -216,7 +216,7 @@ describe("setConnectQueryData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); const queryState = queryClient.getConnectQueryState({ @@ -240,7 +240,7 @@ describe("setConnectQueryData", () => { ...prev, sentence: "Hello Stu", }; - }, + } ); const newQueryState = queryClient.getConnectQueryState({ @@ -251,6 +251,65 @@ describe("setConnectQueryData", () => { expect(newQueryState.dataUpdateCount).toBe(2); expect(newQueryState.data?.sentence).toBe("Hello Stu"); }); + + it("can update infinite paginated data", async () => { + const queryClient = new QueryClient(); + await queryClient.prefetchConnectInfiniteQuery( + ListService.method.list, + { + page: 0n, + }, + { + transport: paginatedTransport, + getNextPageParam: (l) => l.page + 1n, + pageParamKey: "page", + } + ); + + const queryState = queryClient.getConnectQueryState({ + schema: ListService.method.list, + transport: paginatedTransport, + cardinality: "infinite", + input: { + page: 0n, + }, + }); + expect(queryState.dataUpdateCount).toBe(1); + expect(queryState.data?.pages).toHaveLength(1); + + queryClient.setConnectQueryData( + { + schema: ListService.method.list, + transport: paginatedTransport, + cardinality: "infinite", + }, + { + pageParams: [0n, 1n], + pages: [ + { + page: 0n, + items: ["a", "b", "c"] + }, + { + page: 1n, + items: ["x", "y", "z"] + } + ] + } + ); + + const newQueryState = queryClient.getConnectQueryState({ + schema: ListService.method.list, + transport: paginatedTransport, + cardinality: "infinite", + input: { + page: 0n + } + }); + + expect(newQueryState.dataUpdateCount).toBe(2); + expect(newQueryState.data?.pages).toHaveLength(2); + }); }); describe("setConnectQueriesData", () => { @@ -259,14 +318,14 @@ describe("setConnectQueriesData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); await queryClient.prefetchConnectQuery( queryDetails.schema, { sentence: "Stu", }, - { transport: queryDetails.transport }, + { transport: queryDetails.transport } ); const cachedItems = queryClient.getQueryCache().findAll({ @@ -290,7 +349,7 @@ describe("setConnectQueriesData", () => { ...prev, sentence: prev.sentence + "!", }; - }, + } ); const newCachedItems = queryClient.getQueryCache().findAll() as Query< @@ -317,7 +376,7 @@ describe("fetchConnectInfiniteQuery", () => { return data.page + 1n; }, pageParamKey: "page", - }, + } ); expect(result).toBeDefined(); @@ -342,7 +401,7 @@ describe("getConnectQueryState", () => { return data.page + 1n; }, pageParamKey: "page", - }, + } ); const state = queryClient.getConnectQueryState({ @@ -376,7 +435,7 @@ describe("ensure APIs", () => { }, pageParamKey: "page", staleTime: 1000, - }, + } ); const state = queryClient.getConnectQueryState({ diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index 1e3637f2..8331f308 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -41,8 +41,11 @@ import { createConnectQueryKey } from "./connect-query-key.js"; import type { ConnectInfiniteQueryOptions } from "./create-infinite-query-options.js"; import { createInfiniteQueryOptions } from "./create-infinite-query-options.js"; import { createQueryOptions } from "./create-query-options.js"; -import type { ConnectUpdater } from "./utils.js"; -import { createProtobufSafeUpdater } from "./utils.js"; +import type { ConnectInfiniteUpdater, ConnectUpdater } from "./utils.js"; +import { + createProtobufSafeInfiniteUpdater, + createProtobufSafeUpdater, +} from "./utils.js"; type FetchQueryOptions< O extends DescMessage, @@ -109,7 +112,7 @@ export class QueryClient extends TSQueryClient { >( params: Desc | Params, filterOptions?: Omit, - options?: InvalidateOptions, + options?: InvalidateOptions ) { if ("schema" in params) { return this.invalidateQueries( @@ -120,7 +123,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options, + options ); } return this.invalidateQueries( @@ -131,7 +134,7 @@ export class QueryClient extends TSQueryClient { cardinality: undefined, }), }, - options, + options ); } @@ -147,7 +150,7 @@ export class QueryClient extends TSQueryClient { >( params: Params, filterOptions?: Omit, - options?: RefetchOptions, + options?: RefetchOptions ) { return this.refetchQueries( { @@ -157,7 +160,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options, + options ); } @@ -172,11 +175,33 @@ export class QueryClient extends TSQueryClient { schema: Desc; input?: MessageInitShape | undefined; transport: Transport; - cardinality: "finite" | "infinite"; + cardinality: "infinite"; + }, + updater: ConnectInfiniteUpdater, + options?: SetDataOptions | undefined + ): Desc["output"]; + public setConnectQueryData( + keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "finite"; }, updater: ConnectUpdater, + options?: SetDataOptions | undefined + ): Desc["output"]; + public setConnectQueryData( + keyDescriptor: { + schema: Desc; + input?: MessageInitShape | undefined; + transport: Transport; + cardinality: "finite" | "infinite"; + }, + updater: + | ConnectUpdater + | ConnectInfiniteUpdater, - options?: SetDataOptions | undefined, + options?: SetDataOptions | undefined ) { return this.setQueryData( createConnectQueryKey({ @@ -184,8 +209,16 @@ export class QueryClient extends TSQueryClient { // Since we are matching on the exact input, we match what connect-query does in createQueryOptions input: keyDescriptor.input ?? {}, }), - createProtobufSafeUpdater(keyDescriptor.schema, updater), - options, + keyDescriptor.cardinality === "finite" + ? createProtobufSafeUpdater( + keyDescriptor.schema, + updater as ConnectUpdater + ) + : createProtobufSafeInfiniteUpdater( + keyDescriptor.schema, + updater as ConnectInfiniteUpdater + ), + options ); } @@ -242,7 +275,7 @@ export class QueryClient extends TSQueryClient { | (SetDataOptions & { exact?: boolean; }) - | undefined, + | undefined ) { return this.setQueriesData( { @@ -253,7 +286,7 @@ export class QueryClient extends TSQueryClient { exact: options?.exact ?? false, }, createProtobufSafeUpdater(keyDescriptor.schema, updater), - options, + options ); } @@ -274,7 +307,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, + } & FetchQueryOptions ) { return this.fetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -299,7 +332,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, + }: FetchInfiniteQueryOptions ) { return this.fetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -328,7 +361,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, + } & FetchQueryOptions ) { return this.prefetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -353,7 +386,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, + }: FetchInfiniteQueryOptions ) { return this.prefetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -410,7 +443,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, + } & FetchQueryOptions ) { return this.ensureQueryData({ ...createQueryOptions(schema, input, { transport }), @@ -436,7 +469,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, + }: FetchInfiniteQueryOptions ) { return this.ensureInfiniteQueryData({ ...createInfiniteQueryOptions(schema, input, { @@ -546,7 +579,7 @@ export class QueryClient extends TSQueryClient { >( params: Desc | Params, filterOptions?: Omit, - options?: ResetOptions, + options?: ResetOptions ) { if ("schema" in params) { return this.resetQueries( @@ -557,7 +590,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options, + options ); } return this.resetQueries( @@ -568,7 +601,7 @@ export class QueryClient extends TSQueryClient { cardinality: undefined, }), }, - options, + options ); } } diff --git a/packages/connect-query-core/src/utils.test.ts b/packages/connect-query-core/src/utils.test.ts index db621562..717f12fa 100644 --- a/packages/connect-query-core/src/utils.test.ts +++ b/packages/connect-query-core/src/utils.test.ts @@ -18,6 +18,7 @@ import { describe, expect, it } from "vitest"; import { assert, + createProtobufSafeInfiniteUpdater, createProtobufSafeUpdater, isAbortController, } from "./utils.js"; @@ -57,7 +58,7 @@ describe("isAbortController", () => { expect(isAbortController({ signal: { aborted: undefined } })).toBeFalsy(); expect(isAbortController({ signal: { aborted: true } })).toBeFalsy(); expect( - isAbortController({ signal: { aborted: true }, abort: undefined }), + isAbortController({ signal: { aborted: true }, abort: undefined }) ).toBeFalsy(); }); @@ -68,7 +69,7 @@ describe("isAbortController", () => { aborted: false, }, abort: () => {}, - }), + }) ).toBeTruthy(); expect(isAbortController(new AbortController())).toBeTruthy(); @@ -158,7 +159,7 @@ describe("createProtobufSafeUpdater", () => { it("for unset field", () => { const prev = create(Proto2MessageSchema); expect(isFieldSet(prev, Proto2MessageSchema.field.stringField)).toBe( - false, + false ); const next = safeUpdater(prev); const hasStringField = @@ -172,7 +173,7 @@ describe("createProtobufSafeUpdater", () => { stringField: "abc", }); expect(isFieldSet(prev, Proto2MessageSchema.field.stringField)).toBe( - true, + true ); const next = safeUpdater(prev); const hasStringField = @@ -184,3 +185,69 @@ describe("createProtobufSafeUpdater", () => { }); }); }); + +describe("createProtobufSafeInfiniteUpdater", () => { + describe("with update message", () => { + const schema = { output: Proto2MessageSchema }; + const update = { + pageParams: [], + pages: [ + { + int32Field: 999, + }, + ], + }; + const safeUpdater = createProtobufSafeInfiniteUpdater(schema, update); + it("returns update message for previous value undefined", () => { + const next = safeUpdater(undefined); + expect(next?.pages[0].$typeName).toBe("test.Proto2Message"); + }); + }); + + describe("with update message init", () => { + const schema = { output: Proto2MessageSchema }; + const update = { + pageParams: [], + pages: [ + { + int32Field: 999, + }, + ], + }; + const safeUpdater = createProtobufSafeInfiniteUpdater(schema, update); + it("returns update message for previous value undefined", () => { + const next = safeUpdater(undefined); + expect(next?.pages[0].int32Field).toBe(999); + }); + it("returns update message for previous value", () => { + const prev = { + pageParams: [], + pages: [ + create(Proto2MessageSchema, { + int32Field: 123, + }), + ], + }; + const next = safeUpdater(prev); + expect(next?.pages[0].$typeName).toBe(Proto2MessageSchema.typeName); + expect(next?.pages[0].int32Field).toBe(999); + }); + }); + + describe("with updater function", () => { + const schema = { output: Proto2MessageSchema }; + const safeUpdater = createProtobufSafeInfiniteUpdater(schema, (prev) => { + if (prev === undefined) { + return undefined; + } + return { + ...prev, + int32Field: 999, + }; + }); + it("accepts undefined", () => { + const next = safeUpdater(undefined); + expect(next).toBeUndefined(); + }); + }); +}); diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index b51b6a89..0e07c2fa 100644 --- a/packages/connect-query-core/src/utils.ts +++ b/packages/connect-query-core/src/utils.ts @@ -19,6 +19,7 @@ import type { MessageShape, } from "@bufbuild/protobuf"; import { create, isMessage } from "@bufbuild/protobuf"; +import type { InfiniteData } from "@tanstack/query-core"; /** * Throws an error with the provided message when the condition is `false` @@ -58,6 +59,14 @@ export type ConnectUpdater = | undefined | ((prev?: MessageShape) => MessageShape | undefined); +/** + * @see `Updater` from `@tanstack/react-query` + */ +export type ConnectInfiniteUpdater = + | InfiniteData> + | undefined + | ((prev?: InfiniteData>) => InfiniteData> | undefined); + /** * This helper makes sure that the type for the original response message is returned. */ @@ -78,3 +87,29 @@ export const createProtobufSafeUpdater = } return updater(prev); }; + + +export const createProtobufSafeInfiniteUpdater = +( + schema: Pick, "output">, + updater: ConnectInfiniteUpdater, +) => +(prev?: InfiniteData>): InfiniteData> | undefined => { + if (typeof updater !== "function") { + if (updater === undefined) { + return undefined; + } + return { + pageParams: updater.pageParams, + pages: updater.pages.map(i => create(schema.output, i)) + } + } + const result = updater(prev); + if (result === undefined) { + return undefined; + } + return { + pageParams: result.pageParams, + pages: result.pages.map(i => create(schema.output, i)) + } +}; From b7cd0e51c87a8de797c8ac5903eec6ee4cde14a4 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Fri, 14 Feb 2025 11:37:04 -0500 Subject: [PATCH 07/15] Update tests and types Signed-off-by: Paul Sachs --- .../src/query-client.test.ts | 52 +-- .../connect-query-core/src/query-client.ts | 352 ++++++++++-------- packages/connect-query-core/src/utils.test.ts | 8 +- packages/connect-query-core/src/utils.ts | 47 +-- 4 files changed, 246 insertions(+), 213 deletions(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index 7358b874..ede133a6 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { MessageShape } from "@bufbuild/protobuf"; +import { type MessageShape } from "@bufbuild/protobuf"; import type { Query } from "@tanstack/query-core"; import { mockEliza, mockPaginatedTransport } from "test-utils"; import type { SayResponseSchema } from "test-utils/gen/eliza_pb.js"; @@ -23,7 +23,6 @@ import { describe, expect, it } from "vitest"; import { createConnectQueryKey } from "./connect-query-key.js"; import { QueryClient } from "./query-client.js"; -// TODO: maybe create a helper to take a service and method and generate this. const sayMethodDescriptor = ElizaService.method.say; const mockedElizaTransport = mockEliza(); @@ -47,7 +46,7 @@ describe("prefetch APIs", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const item = queryClient.getConnectQueryData({ ...queryDetails, @@ -79,7 +78,7 @@ describe("prefetch APIs", () => { transport: paginatedTransport, pageParamKey: "page", getNextPageParam: (data) => data.page, - } + }, ); const details = { @@ -110,7 +109,7 @@ describe("invalidateConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.invalidateConnectQueries(queryDetails); const queryState = queryClient.getConnectQueryState({ @@ -125,7 +124,7 @@ describe("invalidateConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.invalidateConnectQueries({ @@ -146,7 +145,7 @@ describe("refetchConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.refetchConnectQueries(queryDetails); const queryState = queryClient.getConnectQueryState({ @@ -161,7 +160,7 @@ describe("refetchConnectQueries", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.refetchConnectQueries({ @@ -182,7 +181,7 @@ describe("setConnectQueryData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const queryState = queryClient.getConnectQueryState({ @@ -199,7 +198,7 @@ describe("setConnectQueryData", () => { }, { sentence: "Hello Stu", - } + }, ); const newQueryState = queryClient.getConnectQueryState({ @@ -216,7 +215,7 @@ describe("setConnectQueryData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const queryState = queryClient.getConnectQueryState({ @@ -240,7 +239,7 @@ describe("setConnectQueryData", () => { ...prev, sentence: "Hello Stu", }; - } + }, ); const newQueryState = queryClient.getConnectQueryState({ @@ -263,7 +262,7 @@ describe("setConnectQueryData", () => { transport: paginatedTransport, getNextPageParam: (l) => l.page + 1n, pageParamKey: "page", - } + }, ); const queryState = queryClient.getConnectQueryState({ @@ -288,14 +287,14 @@ describe("setConnectQueryData", () => { pages: [ { page: 0n, - items: ["a", "b", "c"] + items: ["a", "b", "c"], }, { page: 1n, - items: ["x", "y", "z"] - } - ] - } + items: ["x", "y", "z"], + }, + ], + }, ); const newQueryState = queryClient.getConnectQueryState({ @@ -303,8 +302,8 @@ describe("setConnectQueryData", () => { transport: paginatedTransport, cardinality: "infinite", input: { - page: 0n - } + page: 0n, + }, }); expect(newQueryState.dataUpdateCount).toBe(2); @@ -318,14 +317,14 @@ describe("setConnectQueriesData", () => { await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); await queryClient.prefetchConnectQuery( queryDetails.schema, { sentence: "Stu", }, - { transport: queryDetails.transport } + { transport: queryDetails.transport }, ); const cachedItems = queryClient.getQueryCache().findAll({ @@ -340,6 +339,7 @@ describe("setConnectQueriesData", () => { queryClient.setConnectQueriesData( { schema: sayMethodDescriptor, + cardinality: "finite" }, (prev) => { if (prev === undefined) { @@ -349,7 +349,7 @@ describe("setConnectQueriesData", () => { ...prev, sentence: prev.sentence + "!", }; - } + }, ); const newCachedItems = queryClient.getQueryCache().findAll() as Query< @@ -376,7 +376,7 @@ describe("fetchConnectInfiniteQuery", () => { return data.page + 1n; }, pageParamKey: "page", - } + }, ); expect(result).toBeDefined(); @@ -401,7 +401,7 @@ describe("getConnectQueryState", () => { return data.page + 1n; }, pageParamKey: "page", - } + }, ); const state = queryClient.getConnectQueryState({ @@ -435,7 +435,7 @@ describe("ensure APIs", () => { }, pageParamKey: "page", staleTime: 1000, - } + }, ); const state = queryClient.getConnectQueryState({ diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index 8331f308..1d1deef4 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { - DescMessage, - DescMethod, - DescMethodUnary, - DescService, - MessageInitShape, - MessageShape, +import { + type DescMessage, + type DescMethod, + type DescMethodUnary, + type DescService, + type MessageInitShape, + type MessageShape, } from "@bufbuild/protobuf"; import type { ConnectError, Transport } from "@connectrpc/connect"; import type { @@ -81,20 +81,46 @@ type FetchInfiniteQueryOptions< transport: Transport; }; -type KeyParams = - Desc extends DescMethodUnary - ? { - schema: Desc; - input?: MessageInitShape | undefined; - transport: Transport; - cardinality?: "finite" | "infinite" | undefined; - pageParamKey?: keyof MessageInitShape; - } - : { - schema: Desc; - transport: Transport; - cardinality?: "finite" | "infinite" | undefined; - }; +type KeyParamsForMethod = { + /** + * Set `serviceName` and `methodName` in the key. + */ + schema: Desc; + /** + * Set `input` in the key: + * - If a SkipToken is provided, `input` is "skipped". + * - If an init shape is provided, `input` is set to a message key. + * - If omitted or undefined, `input` is not set in the key. + */ + input?: MessageInitShape | undefined; + /** + * Set `transport` in the key. + */ + transport?: Transport; + /** + * Set `cardinality` in the key - undefined is used for filters to match both finite and infinite queries. + */ + cardinality?: "finite" | "infinite"; + /** + * If omit the field with this name from the key for infinite queries. + */ + pageParamKey?: keyof MessageInitShape; +}; + +type KeyParamsForService = { + /** + * Set `serviceName` in the key, and omit `methodName`. + */ + schema: Desc; + /** + * Set `transport` in the key. + */ + transport?: Transport; + /** + * Set `cardinality` in the key - undefined is used for filters to match both finite and infinite queries. + */ + cardinality?: "finite" | "infinite"; +}; /** * A custom query client that adds some useful methods to access typesafe query data and other shortcuts. @@ -107,31 +133,22 @@ export class QueryClient extends TSQueryClient { * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientinvalidatequeries} */ public async invalidateConnectQueries< - Desc extends DescMethod | DescService, - Params extends KeyParams, + I extends DescMessage, + O extends DescMessage, + Desc extends DescService, >( - params: Desc | Params, + params: + | KeyParamsForMethod> + | KeyParamsForService, filterOptions?: Omit, options?: InvalidateOptions ) { - if ("schema" in params) { - return this.invalidateQueries( - { - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }, - options - ); - } return this.invalidateQueries( { ...filterOptions, queryKey: createConnectQueryKey({ - schema: params as DescMethod, - cardinality: undefined, + ...params, + cardinality: params.cardinality, }), }, options @@ -139,16 +156,19 @@ export class QueryClient extends TSQueryClient { } /** - * Refetches all queries that match the given schema. This can include all queries for a service (and sub methods), + * Refetch all queries that match the given schema. This can include all queries for a service (and sub methods), * or all queries for a method. * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientrefetchqueries} */ public async refetchConnectQueries< - Desc extends DescMethod | DescService, - Params extends KeyParams, + I extends DescMessage, + O extends DescMessage, + Desc extends DescService, >( - params: Params, + params: + | KeyParamsForMethod> + | KeyParamsForService, filterOptions?: Omit, options?: RefetchOptions ) { @@ -170,53 +190,51 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetquerydata} */ - public setConnectQueryData( + public setConnectQueryData( keyDescriptor: { - schema: Desc; - input?: MessageInitShape | undefined; + schema: DescMethodUnary; + input?: MessageInitShape; transport: Transport; cardinality: "infinite"; }, - updater: ConnectInfiniteUpdater, - options?: SetDataOptions | undefined - ): Desc["output"]; - public setConnectQueryData( + updater: ConnectInfiniteUpdater, + options?: SetDataOptions + ): O; + public setConnectQueryData( keyDescriptor: { - schema: Desc; - input?: MessageInitShape | undefined; + schema: DescMethodUnary; + input?: MessageInitShape; transport: Transport; cardinality: "finite"; }, - updater: ConnectUpdater, - options?: SetDataOptions | undefined - ): Desc["output"]; - public setConnectQueryData( + updater: ConnectUpdater, + options?: SetDataOptions + ): O; + public setConnectQueryData( keyDescriptor: { - schema: Desc; - input?: MessageInitShape | undefined; + schema: DescMethodUnary; + input?: MessageInitShape; transport: Transport; cardinality: "finite" | "infinite"; }, - updater: - | ConnectUpdater - | ConnectInfiniteUpdater, + updater: ConnectUpdater | ConnectInfiniteUpdater, - options?: SetDataOptions | undefined + options?: SetDataOptions ) { return this.setQueryData( createConnectQueryKey({ ...keyDescriptor, // Since we are matching on the exact input, we match what connect-query does in createQueryOptions - input: keyDescriptor.input ?? {}, + input: keyDescriptor.input ?? ({} as MessageInitShape), }), keyDescriptor.cardinality === "finite" - ? createProtobufSafeUpdater( + ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater + updater as ConnectUpdater ) - : createProtobufSafeInfiniteUpdater( + : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater + updater as ConnectInfiniteUpdater ), options ); @@ -228,33 +246,34 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetquerydata} */ - public getConnectQueryData(keyDescriptor: { - schema: Desc; - input?: MessageInitShape | undefined; + public getConnectQueryData< + I extends DescMessage, + O extends DescMessage, + >(keyDescriptor: { + schema: DescMethodUnary; + input?: MessageInitShape; transport: Transport; cardinality: "finite"; - }): MessageShape; - public getConnectQueryData(keyDescriptor: { - schema: Desc; - input?: MessageInitShape | undefined; + }): MessageShape; + public getConnectQueryData< + I extends DescMessage, + O extends DescMessage, + >(keyDescriptor: { + schema: DescMethodUnary; + input?: MessageInitShape; transport: Transport; cardinality: "infinite"; - }): InfiniteData>; - public getConnectQueryData(keyDescriptor: { - schema: Desc; - input?: MessageInitShape | undefined; + }): InfiniteData>; + public getConnectQueryData< + I extends DescMessage, + O extends DescMessage, + >(keyDescriptor: { + schema: DescMethodUnary; + input?: MessageInitShape; transport: Transport; cardinality: "finite" | "infinite"; - }): - | MessageShape - | InfiniteData> - | undefined { - const key = createConnectQueryKey({ - ...keyDescriptor, - // Since we are matching on the exact input, we match what connect-query does in createQueryOptions - input: keyDescriptor.input ?? {}, - }); - return this.getQueryData(key); + }): MessageShape | InfiniteData> | undefined { + return this.getQueryData(createConnectQueryKey(keyDescriptor)); } /** @@ -263,19 +282,41 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetqueriesdata} */ - public setConnectQueriesData( + public setConnectQueriesData( + keyDescriptor: { + schema: DescMethodUnary; + input?: MessageInitShape; + transport?: Transport; + cardinality: "finite"; + }, + updater: ConnectUpdater, + options?: SetDataOptions & { + exact?: boolean; + } + ): [readonly unknown[], unknown][]; + public setConnectQueriesData( + keyDescriptor: { + schema: DescMethodUnary; + input?: MessageInitShape; + transport?: Transport; + cardinality: "infinite"; + }, + updater: ConnectInfiniteUpdater, + options?: SetDataOptions & { + exact?: boolean; + } + ): [readonly unknown[], unknown][]; + public setConnectQueriesData( keyDescriptor: { - schema: Desc; - input?: MessageInitShape | undefined; + schema: DescMethodUnary; + input?: MessageInitShape; transport?: Transport; - cardinality?: "finite" | "infinite" | undefined; + cardinality: "finite" | "infinite"; }, - updater: ConnectUpdater, - options?: - | (SetDataOptions & { - exact?: boolean; - }) - | undefined + updater: ConnectUpdater | ConnectInfiniteUpdater, + options?: SetDataOptions & { + exact?: boolean; + } ) { return this.setQueriesData( { @@ -285,7 +326,15 @@ export class QueryClient extends TSQueryClient { }), exact: options?.exact ?? false, }, - createProtobufSafeUpdater(keyDescriptor.schema, updater), + keyDescriptor.cardinality === "finite" + ? createProtobufSafeUpdater( + keyDescriptor.schema, + updater as ConnectUpdater + ) + : createProtobufSafeInfiniteUpdater( + keyDescriptor.schema, + updater as ConnectInfiniteUpdater + ), options ); } @@ -406,19 +455,19 @@ export class QueryClient extends TSQueryClient { */ public getConnectQueryState(keyDescriptor: { schema: Desc; - input?: MessageInitShape | undefined; + input?: MessageInitShape; transport: Transport; cardinality: "finite"; }): QueryState, ConnectError>; public getConnectQueryState(keyDescriptor: { schema: Desc; - input?: MessageInitShape | undefined; + input?: MessageInitShape; transport: Transport; cardinality: "infinite"; }): QueryState>, ConnectError>; public getConnectQueryState(keyDescriptor: { schema: Desc; - input?: MessageInitShape | undefined; + input?: MessageInitShape; transport: Transport; cardinality: "finite" | "infinite"; }) { @@ -488,23 +537,20 @@ export class QueryClient extends TSQueryClient { * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetqueriesdata} */ public getConnectQueriesData< - Desc extends DescMethod | DescService, - Params extends KeyParams, - >(params: Desc | Params, filterOptions?: Omit) { - if ("schema" in params) { - return this.getQueriesData({ - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }); - } + I extends DescMessage, + O extends DescMessage, + Desc extends DescService, + >( + params: + | KeyParamsForMethod> + | KeyParamsForService, + filterOptions?: Omit + ) { return this.getQueriesData({ ...filterOptions, queryKey: createConnectQueryKey({ - schema: params as DescMethod, - cardinality: undefined, + ...params, + cardinality: params.cardinality, }), }); } @@ -516,23 +562,20 @@ export class QueryClient extends TSQueryClient { * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientcancelqueries} */ public async cancelConnectQueries< - Desc extends DescMethod | DescService, - Params extends KeyParams, - >(params: Desc | Params, filterOptions?: Omit) { - if ("schema" in params) { - return this.cancelQueries({ - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }); - } + I extends DescMessage, + O extends DescMessage, + Desc extends DescService, + >( + params: + | KeyParamsForMethod> + | KeyParamsForService, + filterOptions?: Omit + ) { return this.cancelQueries({ ...filterOptions, queryKey: createConnectQueryKey({ - schema: params as DescMethod, - cardinality: undefined, + ...params, + cardinality: params.cardinality, }), }); } @@ -544,24 +587,20 @@ export class QueryClient extends TSQueryClient { * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientremovequeries} */ public removeConnectQueries< - Desc extends DescMethod | DescService, - Params extends KeyParams, - >(params: Desc | Params, filterOptions?: Omit) { - if ("schema" in params) { - this.removeQueries({ - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }); - return; - } + I extends DescMessage, + O extends DescMessage, + Desc extends DescService, + >( + params: + | KeyParamsForMethod> + | KeyParamsForService, + filterOptions?: Omit + ) { this.removeQueries({ ...filterOptions, queryKey: createConnectQueryKey({ - schema: params as DescMethod, - cardinality: undefined, + ...params, + cardinality: params.cardinality, }), }); return; @@ -574,31 +613,22 @@ export class QueryClient extends TSQueryClient { * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientresetqueries} */ public async resetConnectQueries< - Desc extends DescMethod | DescService, - Params extends KeyParams, + I extends DescMessage, + O extends DescMessage, + Desc extends DescService, >( - params: Desc | Params, + params: + | KeyParamsForMethod> + | KeyParamsForService, filterOptions?: Omit, options?: ResetOptions ) { - if ("schema" in params) { - return this.resetQueries( - { - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }, - options - ); - } return this.resetQueries( { ...filterOptions, queryKey: createConnectQueryKey({ - schema: params as DescMethod, - cardinality: undefined, + ...params, + cardinality: params.cardinality, }), }, options diff --git a/packages/connect-query-core/src/utils.test.ts b/packages/connect-query-core/src/utils.test.ts index 717f12fa..9f4910ef 100644 --- a/packages/connect-query-core/src/utils.test.ts +++ b/packages/connect-query-core/src/utils.test.ts @@ -58,7 +58,7 @@ describe("isAbortController", () => { expect(isAbortController({ signal: { aborted: undefined } })).toBeFalsy(); expect(isAbortController({ signal: { aborted: true } })).toBeFalsy(); expect( - isAbortController({ signal: { aborted: true }, abort: undefined }) + isAbortController({ signal: { aborted: true }, abort: undefined }), ).toBeFalsy(); }); @@ -69,7 +69,7 @@ describe("isAbortController", () => { aborted: false, }, abort: () => {}, - }) + }), ).toBeTruthy(); expect(isAbortController(new AbortController())).toBeTruthy(); @@ -159,7 +159,7 @@ describe("createProtobufSafeUpdater", () => { it("for unset field", () => { const prev = create(Proto2MessageSchema); expect(isFieldSet(prev, Proto2MessageSchema.field.stringField)).toBe( - false + false, ); const next = safeUpdater(prev); const hasStringField = @@ -173,7 +173,7 @@ describe("createProtobufSafeUpdater", () => { stringField: "abc", }); expect(isFieldSet(prev, Proto2MessageSchema.field.stringField)).toBe( - true + true, ); const next = safeUpdater(prev); const hasStringField = diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index 0e07c2fa..a73aaeb4 100644 --- a/packages/connect-query-core/src/utils.ts +++ b/packages/connect-query-core/src/utils.ts @@ -65,7 +65,9 @@ export type ConnectUpdater = export type ConnectInfiniteUpdater = | InfiniteData> | undefined - | ((prev?: InfiniteData>) => InfiniteData> | undefined); + | (( + prev?: InfiniteData>, + ) => InfiniteData> | undefined); /** * This helper makes sure that the type for the original response message is returned. @@ -88,28 +90,29 @@ export const createProtobufSafeUpdater = return updater(prev); }; - export const createProtobufSafeInfiniteUpdater = -( - schema: Pick, "output">, - updater: ConnectInfiniteUpdater, -) => -(prev?: InfiniteData>): InfiniteData> | undefined => { - if (typeof updater !== "function") { - if (updater === undefined) { + ( + schema: Pick, "output">, + updater: ConnectInfiniteUpdater, + ) => + ( + prev?: InfiniteData>, + ): InfiniteData> | undefined => { + if (typeof updater !== "function") { + if (updater === undefined) { + return undefined; + } + return { + pageParams: updater.pageParams, + pages: updater.pages.map((i) => create(schema.output, i)), + }; + } + const result = updater(prev); + if (result === undefined) { return undefined; } return { - pageParams: updater.pageParams, - pages: updater.pages.map(i => create(schema.output, i)) - } - } - const result = updater(prev); - if (result === undefined) { - return undefined; - } - return { - pageParams: result.pageParams, - pages: result.pages.map(i => create(schema.output, i)) - } -}; + pageParams: result.pageParams, + pages: result.pages.map((i) => create(schema.output, i)), + }; + }; From 62fad41592421ad7ef76e1d0aee41c99c141b623 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Fri, 14 Feb 2025 11:50:22 -0500 Subject: [PATCH 08/15] format Signed-off-by: Paul Sachs --- .../src/query-client.test.ts | 2 +- .../connect-query-core/src/query-client.ts | 54 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index ede133a6..8be1a83a 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -339,7 +339,7 @@ describe("setConnectQueriesData", () => { queryClient.setConnectQueriesData( { schema: sayMethodDescriptor, - cardinality: "finite" + cardinality: "finite", }, (prev) => { if (prev === undefined) { diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index 1d1deef4..1e4f691d 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -141,7 +141,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: InvalidateOptions + options?: InvalidateOptions, ) { return this.invalidateQueries( { @@ -151,7 +151,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } @@ -170,7 +170,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: RefetchOptions + options?: RefetchOptions, ) { return this.refetchQueries( { @@ -180,7 +180,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } @@ -198,7 +198,7 @@ export class QueryClient extends TSQueryClient { cardinality: "infinite"; }, updater: ConnectInfiniteUpdater, - options?: SetDataOptions + options?: SetDataOptions, ): O; public setConnectQueryData( keyDescriptor: { @@ -208,7 +208,7 @@ export class QueryClient extends TSQueryClient { cardinality: "finite"; }, updater: ConnectUpdater, - options?: SetDataOptions + options?: SetDataOptions, ): O; public setConnectQueryData( keyDescriptor: { @@ -219,7 +219,7 @@ export class QueryClient extends TSQueryClient { }, updater: ConnectUpdater | ConnectInfiniteUpdater, - options?: SetDataOptions + options?: SetDataOptions, ) { return this.setQueryData( createConnectQueryKey({ @@ -230,13 +230,13 @@ export class QueryClient extends TSQueryClient { keyDescriptor.cardinality === "finite" ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater + updater as ConnectUpdater, ) : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater + updater as ConnectInfiniteUpdater, ), - options + options, ); } @@ -292,7 +292,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ): [readonly unknown[], unknown][]; public setConnectQueriesData( keyDescriptor: { @@ -304,7 +304,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ): [readonly unknown[], unknown][]; public setConnectQueriesData( keyDescriptor: { @@ -316,7 +316,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectUpdater | ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ) { return this.setQueriesData( { @@ -329,13 +329,13 @@ export class QueryClient extends TSQueryClient { keyDescriptor.cardinality === "finite" ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater + updater as ConnectUpdater, ) : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater + updater as ConnectInfiniteUpdater, ), - options + options, ); } @@ -356,7 +356,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.fetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -381,7 +381,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.fetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -410,7 +410,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.prefetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -435,7 +435,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.prefetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -492,7 +492,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.ensureQueryData({ ...createQueryOptions(schema, input, { transport }), @@ -518,7 +518,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.ensureInfiniteQueryData({ ...createInfiniteQueryOptions(schema, input, { @@ -544,7 +544,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ) { return this.getQueriesData({ ...filterOptions, @@ -569,7 +569,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ) { return this.cancelQueries({ ...filterOptions, @@ -594,7 +594,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ) { this.removeQueries({ ...filterOptions, @@ -621,7 +621,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: ResetOptions + options?: ResetOptions, ) { return this.resetQueries( { @@ -631,7 +631,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } } From 0cadbff57280b20b77547f8204b15693ae3d3641 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Tue, 18 Feb 2025 11:14:51 -0500 Subject: [PATCH 09/15] Migrated to a version of connect safe updater that allows returning init shape Signed-off-by: Paul Sachs --- .../src/query-client.test.ts | 3 +- .../connect-query-core/src/query-client.ts | 125 +++++++++++++----- packages/connect-query-core/src/utils.ts | 38 +----- 3 files changed, 96 insertions(+), 70 deletions(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index 8be1a83a..6c124967 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -236,7 +236,6 @@ describe("setConnectQueryData", () => { } expect(prev.sentence).toBe("Hello Pablo"); return { - ...prev, sentence: "Hello Stu", }; }, @@ -249,6 +248,8 @@ describe("setConnectQueryData", () => { expect(newQueryState.dataUpdateCount).toBe(2); expect(newQueryState.data?.sentence).toBe("Hello Stu"); + expect(newQueryState.data?.$typeName).toBe("connectrpc.eliza.v1.SayResponse"); + }); it("can update infinite paginated data", async () => { diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index 1e4f691d..9ec8a48a 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -13,6 +13,8 @@ // limitations under the License. import { + create, + isMessage, type DescMessage, type DescMethod, type DescMethodUnary, @@ -41,11 +43,6 @@ import { createConnectQueryKey } from "./connect-query-key.js"; import type { ConnectInfiniteQueryOptions } from "./create-infinite-query-options.js"; import { createInfiniteQueryOptions } from "./create-infinite-query-options.js"; import { createQueryOptions } from "./create-query-options.js"; -import type { ConnectInfiniteUpdater, ConnectUpdater } from "./utils.js"; -import { - createProtobufSafeInfiniteUpdater, - createProtobufSafeUpdater, -} from "./utils.js"; type FetchQueryOptions< O extends DescMessage, @@ -141,7 +138,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: InvalidateOptions, + options?: InvalidateOptions ) { return this.invalidateQueries( { @@ -151,7 +148,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options, + options ); } @@ -170,7 +167,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: RefetchOptions, + options?: RefetchOptions ) { return this.refetchQueries( { @@ -180,7 +177,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options, + options ); } @@ -198,7 +195,7 @@ export class QueryClient extends TSQueryClient { cardinality: "infinite"; }, updater: ConnectInfiniteUpdater, - options?: SetDataOptions, + options?: SetDataOptions ): O; public setConnectQueryData( keyDescriptor: { @@ -208,7 +205,7 @@ export class QueryClient extends TSQueryClient { cardinality: "finite"; }, updater: ConnectUpdater, - options?: SetDataOptions, + options?: SetDataOptions ): O; public setConnectQueryData( keyDescriptor: { @@ -219,7 +216,7 @@ export class QueryClient extends TSQueryClient { }, updater: ConnectUpdater | ConnectInfiniteUpdater, - options?: SetDataOptions, + options?: SetDataOptions ) { return this.setQueryData( createConnectQueryKey({ @@ -230,13 +227,13 @@ export class QueryClient extends TSQueryClient { keyDescriptor.cardinality === "finite" ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater, + updater as ConnectUpdater ) : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater, + updater as ConnectInfiniteUpdater ), - options, + options ); } @@ -292,7 +289,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectUpdater, options?: SetDataOptions & { exact?: boolean; - }, + } ): [readonly unknown[], unknown][]; public setConnectQueriesData( keyDescriptor: { @@ -304,7 +301,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - }, + } ): [readonly unknown[], unknown][]; public setConnectQueriesData( keyDescriptor: { @@ -316,7 +313,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectUpdater | ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - }, + } ) { return this.setQueriesData( { @@ -329,13 +326,13 @@ export class QueryClient extends TSQueryClient { keyDescriptor.cardinality === "finite" ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater, + updater as ConnectUpdater ) : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater, + updater as ConnectInfiniteUpdater ), - options, + options ); } @@ -356,7 +353,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, + } & FetchQueryOptions ) { return this.fetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -381,7 +378,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, + }: FetchInfiniteQueryOptions ) { return this.fetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -410,7 +407,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, + } & FetchQueryOptions ) { return this.prefetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -435,7 +432,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, + }: FetchInfiniteQueryOptions ) { return this.prefetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -492,7 +489,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, + } & FetchQueryOptions ) { return this.ensureQueryData({ ...createQueryOptions(schema, input, { transport }), @@ -518,7 +515,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, + }: FetchInfiniteQueryOptions ) { return this.ensureInfiniteQueryData({ ...createInfiniteQueryOptions(schema, input, { @@ -544,7 +541,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit, + filterOptions?: Omit ) { return this.getQueriesData({ ...filterOptions, @@ -569,7 +566,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit, + filterOptions?: Omit ) { return this.cancelQueries({ ...filterOptions, @@ -594,7 +591,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit, + filterOptions?: Omit ) { this.removeQueries({ ...filterOptions, @@ -621,7 +618,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: ResetOptions, + options?: ResetOptions ) { return this.resetQueries( { @@ -631,7 +628,71 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options, + options ); } } + +type ConnectInfiniteUpdater = + | InfiniteData> + | undefined + | (( + prev?: InfiniteData> + ) => InfiniteData> | undefined); + +const createProtobufSafeInfiniteUpdater = + ( + schema: Pick, "output">, + updater: ConnectInfiniteUpdater + ) => + ( + prev?: InfiniteData> + ): InfiniteData> | undefined => { + if (typeof updater !== "function") { + if (updater === undefined) { + return undefined; + } + return { + pageParams: updater.pageParams, + pages: updater.pages.map((i) => create(schema.output, i)), + }; + } + const result = updater(prev); + if (result === undefined) { + return undefined; + } + return { + pageParams: result.pageParams, + pages: result.pages.map((i) => create(schema.output, i)), + }; + }; + + type ConnectUpdater = + | MessageInitShape + | undefined + | ((prev?: MessageShape) => MessageInitShape | undefined); + +/** + * This method makes sure that the object returned + * is of the message type. If an init shape is returned, + * we'll run it through create again. + */ +const createProtobufSafeUpdater = + ( + schema: Pick, "output">, + updater: ConnectUpdater, + ) => + (prev?: MessageShape): MessageShape | undefined => { + if (typeof updater !== "function") { + if (updater === undefined) { + return undefined; + } + if (isMessage(updater, schema.output)) { + return updater; + } + return create(schema.output, updater); + } + return create(schema.output, updater(prev)); + }; + + diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index a73aaeb4..803c3114 100644 --- a/packages/connect-query-core/src/utils.ts +++ b/packages/connect-query-core/src/utils.ts @@ -19,7 +19,6 @@ import type { MessageShape, } from "@bufbuild/protobuf"; import { create, isMessage } from "@bufbuild/protobuf"; -import type { InfiniteData } from "@tanstack/query-core"; /** * Throws an error with the provided message when the condition is `false` @@ -59,16 +58,6 @@ export type ConnectUpdater = | undefined | ((prev?: MessageShape) => MessageShape | undefined); -/** - * @see `Updater` from `@tanstack/react-query` - */ -export type ConnectInfiniteUpdater = - | InfiniteData> - | undefined - | (( - prev?: InfiniteData>, - ) => InfiniteData> | undefined); - /** * This helper makes sure that the type for the original response message is returned. */ @@ -90,29 +79,4 @@ export const createProtobufSafeUpdater = return updater(prev); }; -export const createProtobufSafeInfiniteUpdater = - ( - schema: Pick, "output">, - updater: ConnectInfiniteUpdater, - ) => - ( - prev?: InfiniteData>, - ): InfiniteData> | undefined => { - if (typeof updater !== "function") { - if (updater === undefined) { - return undefined; - } - return { - pageParams: updater.pageParams, - pages: updater.pages.map((i) => create(schema.output, i)), - }; - } - const result = updater(prev); - if (result === undefined) { - return undefined; - } - return { - pageParams: result.pageParams, - pages: result.pages.map((i) => create(schema.output, i)), - }; - }; + From 1dfd9cd0d294c2dbb1c5473f90d9eaa30b7b25d3 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Tue, 18 Feb 2025 11:16:44 -0500 Subject: [PATCH 10/15] Cleanup tests and lint Signed-off-by: Paul Sachs --- .../src/query-client.test.ts | 5 +- .../connect-query-core/src/query-client.ts | 66 +++++++++--------- packages/connect-query-core/src/utils.test.ts | 67 ------------------- packages/connect-query-core/src/utils.ts | 2 - 4 files changed, 35 insertions(+), 105 deletions(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index 6c124967..c9cc26a9 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -248,8 +248,9 @@ describe("setConnectQueryData", () => { expect(newQueryState.dataUpdateCount).toBe(2); expect(newQueryState.data?.sentence).toBe("Hello Stu"); - expect(newQueryState.data?.$typeName).toBe("connectrpc.eliza.v1.SayResponse"); - + expect(newQueryState.data?.$typeName).toBe( + "connectrpc.eliza.v1.SayResponse", + ); }); it("can update infinite paginated data", async () => { diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index 9ec8a48a..1911b078 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -138,7 +138,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: InvalidateOptions + options?: InvalidateOptions, ) { return this.invalidateQueries( { @@ -148,7 +148,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } @@ -167,7 +167,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: RefetchOptions + options?: RefetchOptions, ) { return this.refetchQueries( { @@ -177,7 +177,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } @@ -195,7 +195,7 @@ export class QueryClient extends TSQueryClient { cardinality: "infinite"; }, updater: ConnectInfiniteUpdater, - options?: SetDataOptions + options?: SetDataOptions, ): O; public setConnectQueryData( keyDescriptor: { @@ -205,7 +205,7 @@ export class QueryClient extends TSQueryClient { cardinality: "finite"; }, updater: ConnectUpdater, - options?: SetDataOptions + options?: SetDataOptions, ): O; public setConnectQueryData( keyDescriptor: { @@ -216,7 +216,7 @@ export class QueryClient extends TSQueryClient { }, updater: ConnectUpdater | ConnectInfiniteUpdater, - options?: SetDataOptions + options?: SetDataOptions, ) { return this.setQueryData( createConnectQueryKey({ @@ -227,13 +227,13 @@ export class QueryClient extends TSQueryClient { keyDescriptor.cardinality === "finite" ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater + updater as ConnectUpdater, ) : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater + updater as ConnectInfiniteUpdater, ), - options + options, ); } @@ -289,7 +289,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ): [readonly unknown[], unknown][]; public setConnectQueriesData( keyDescriptor: { @@ -301,7 +301,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ): [readonly unknown[], unknown][]; public setConnectQueriesData( keyDescriptor: { @@ -313,7 +313,7 @@ export class QueryClient extends TSQueryClient { updater: ConnectUpdater | ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ) { return this.setQueriesData( { @@ -326,13 +326,13 @@ export class QueryClient extends TSQueryClient { keyDescriptor.cardinality === "finite" ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater + updater as ConnectUpdater, ) : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater + updater as ConnectInfiniteUpdater, ), - options + options, ); } @@ -353,7 +353,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.fetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -378,7 +378,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.fetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -407,7 +407,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.prefetchQuery({ ...createQueryOptions(schema, input, { transport }), @@ -432,7 +432,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.prefetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -489,7 +489,7 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ) { return this.ensureQueryData({ ...createQueryOptions(schema, input, { transport }), @@ -515,7 +515,7 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ) { return this.ensureInfiniteQueryData({ ...createInfiniteQueryOptions(schema, input, { @@ -541,7 +541,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ) { return this.getQueriesData({ ...filterOptions, @@ -566,7 +566,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ) { return this.cancelQueries({ ...filterOptions, @@ -591,7 +591,7 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ) { this.removeQueries({ ...filterOptions, @@ -618,7 +618,7 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: ResetOptions + options?: ResetOptions, ) { return this.resetQueries( { @@ -628,7 +628,7 @@ export class QueryClient extends TSQueryClient { cardinality: params.cardinality, }), }, - options + options, ); } } @@ -637,16 +637,16 @@ type ConnectInfiniteUpdater = | InfiniteData> | undefined | (( - prev?: InfiniteData> + prev?: InfiniteData>, ) => InfiniteData> | undefined); const createProtobufSafeInfiniteUpdater = ( schema: Pick, "output">, - updater: ConnectInfiniteUpdater + updater: ConnectInfiniteUpdater, ) => ( - prev?: InfiniteData> + prev?: InfiniteData>, ): InfiniteData> | undefined => { if (typeof updater !== "function") { if (updater === undefined) { @@ -667,13 +667,13 @@ const createProtobufSafeInfiniteUpdater = }; }; - type ConnectUpdater = +type ConnectUpdater = | MessageInitShape | undefined | ((prev?: MessageShape) => MessageInitShape | undefined); /** - * This method makes sure that the object returned + * This method makes sure that the object returned * is of the message type. If an init shape is returned, * we'll run it through create again. */ @@ -694,5 +694,3 @@ const createProtobufSafeUpdater = } return create(schema.output, updater(prev)); }; - - diff --git a/packages/connect-query-core/src/utils.test.ts b/packages/connect-query-core/src/utils.test.ts index 9f4910ef..db621562 100644 --- a/packages/connect-query-core/src/utils.test.ts +++ b/packages/connect-query-core/src/utils.test.ts @@ -18,7 +18,6 @@ import { describe, expect, it } from "vitest"; import { assert, - createProtobufSafeInfiniteUpdater, createProtobufSafeUpdater, isAbortController, } from "./utils.js"; @@ -185,69 +184,3 @@ describe("createProtobufSafeUpdater", () => { }); }); }); - -describe("createProtobufSafeInfiniteUpdater", () => { - describe("with update message", () => { - const schema = { output: Proto2MessageSchema }; - const update = { - pageParams: [], - pages: [ - { - int32Field: 999, - }, - ], - }; - const safeUpdater = createProtobufSafeInfiniteUpdater(schema, update); - it("returns update message for previous value undefined", () => { - const next = safeUpdater(undefined); - expect(next?.pages[0].$typeName).toBe("test.Proto2Message"); - }); - }); - - describe("with update message init", () => { - const schema = { output: Proto2MessageSchema }; - const update = { - pageParams: [], - pages: [ - { - int32Field: 999, - }, - ], - }; - const safeUpdater = createProtobufSafeInfiniteUpdater(schema, update); - it("returns update message for previous value undefined", () => { - const next = safeUpdater(undefined); - expect(next?.pages[0].int32Field).toBe(999); - }); - it("returns update message for previous value", () => { - const prev = { - pageParams: [], - pages: [ - create(Proto2MessageSchema, { - int32Field: 123, - }), - ], - }; - const next = safeUpdater(prev); - expect(next?.pages[0].$typeName).toBe(Proto2MessageSchema.typeName); - expect(next?.pages[0].int32Field).toBe(999); - }); - }); - - describe("with updater function", () => { - const schema = { output: Proto2MessageSchema }; - const safeUpdater = createProtobufSafeInfiniteUpdater(schema, (prev) => { - if (prev === undefined) { - return undefined; - } - return { - ...prev, - int32Field: 999, - }; - }); - it("accepts undefined", () => { - const next = safeUpdater(undefined); - expect(next).toBeUndefined(); - }); - }); -}); diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index 803c3114..b51b6a89 100644 --- a/packages/connect-query-core/src/utils.ts +++ b/packages/connect-query-core/src/utils.ts @@ -78,5 +78,3 @@ export const createProtobufSafeUpdater = } return updater(prev); }; - - From cbe94923c6af9f4adb9f475bbb787d70970139b3 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Fri, 11 Apr 2025 10:57:35 -0400 Subject: [PATCH 11/15] Extract interface Signed-off-by: Paul Sachs --- .../connect-query-core/src/query-client.ts | 525 ++++++++++-------- 1 file changed, 302 insertions(+), 223 deletions(-) diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index 1911b078..6bb57b08 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -122,14 +122,14 @@ type KeyParamsForService = { /** * A custom query client that adds some useful methods to access typesafe query data and other shortcuts. */ -export class QueryClient extends TSQueryClient { +export interface ConnectQueryClient { /** * Invalidate and refetch all queries that match the given schema. This * can include all queries for a service (and sub methods), or all queries for a method. * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientinvalidatequeries} */ - public async invalidateConnectQueries< + invalidateConnectQueries< I extends DescMessage, O extends DescMessage, Desc extends DescService, @@ -138,19 +138,8 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: InvalidateOptions, - ) { - return this.invalidateQueries( - { - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }, - options, - ); - } + options?: InvalidateOptions + ): Promise; /** * Refetch all queries that match the given schema. This can include all queries for a service (and sub methods), @@ -158,7 +147,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientrefetchqueries} */ - public async refetchConnectQueries< + refetchConnectQueries< I extends DescMessage, O extends DescMessage, Desc extends DescService, @@ -167,19 +156,8 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: RefetchOptions, - ) { - return this.refetchQueries( - { - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }, - options, - ); - } + options?: RefetchOptions + ): Promise; /** * Set the data for a single query. The query must match exactly the input provided, as well @@ -187,7 +165,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetquerydata} */ - public setConnectQueryData( + setConnectQueryData( keyDescriptor: { schema: DescMethodUnary; input?: MessageInitShape; @@ -195,9 +173,9 @@ export class QueryClient extends TSQueryClient { cardinality: "infinite"; }, updater: ConnectInfiniteUpdater, - options?: SetDataOptions, + options?: SetDataOptions ): O; - public setConnectQueryData( + setConnectQueryData( keyDescriptor: { schema: DescMethodUnary; input?: MessageInitShape; @@ -205,9 +183,9 @@ export class QueryClient extends TSQueryClient { cardinality: "finite"; }, updater: ConnectUpdater, - options?: SetDataOptions, + options?: SetDataOptions ): O; - public setConnectQueryData( + setConnectQueryData( keyDescriptor: { schema: DescMethodUnary; input?: MessageInitShape; @@ -216,26 +194,8 @@ export class QueryClient extends TSQueryClient { }, updater: ConnectUpdater | ConnectInfiniteUpdater, - options?: SetDataOptions, - ) { - return this.setQueryData( - createConnectQueryKey({ - ...keyDescriptor, - // Since we are matching on the exact input, we match what connect-query does in createQueryOptions - input: keyDescriptor.input ?? ({} as MessageInitShape), - }), - keyDescriptor.cardinality === "finite" - ? createProtobufSafeUpdater( - keyDescriptor.schema, - updater as ConnectUpdater, - ) - : createProtobufSafeInfiniteUpdater( - keyDescriptor.schema, - updater as ConnectInfiniteUpdater, - ), - options, - ); - } + options?: SetDataOptions + ): O; /** * Get the data for a single query. The query must match exactly the input provided, as well @@ -243,7 +203,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetquerydata} */ - public getConnectQueryData< + getConnectQueryData< I extends DescMessage, O extends DescMessage, >(keyDescriptor: { @@ -251,8 +211,8 @@ export class QueryClient extends TSQueryClient { input?: MessageInitShape; transport: Transport; cardinality: "finite"; - }): MessageShape; - public getConnectQueryData< + }): MessageShape | undefined; + getConnectQueryData< I extends DescMessage, O extends DescMessage, >(keyDescriptor: { @@ -260,18 +220,7 @@ export class QueryClient extends TSQueryClient { input?: MessageInitShape; transport: Transport; cardinality: "infinite"; - }): InfiniteData>; - public getConnectQueryData< - I extends DescMessage, - O extends DescMessage, - >(keyDescriptor: { - schema: DescMethodUnary; - input?: MessageInitShape; - transport: Transport; - cardinality: "finite" | "infinite"; - }): MessageShape | InfiniteData> | undefined { - return this.getQueryData(createConnectQueryKey(keyDescriptor)); - } + }): InfiniteData> | undefined; /** * Sets the data for any matching queries for a given method. The input is optional, and anything left @@ -279,7 +228,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetqueriesdata} */ - public setConnectQueriesData( + setConnectQueriesData( keyDescriptor: { schema: DescMethodUnary; input?: MessageInitShape; @@ -289,9 +238,9 @@ export class QueryClient extends TSQueryClient { updater: ConnectUpdater, options?: SetDataOptions & { exact?: boolean; - }, + } ): [readonly unknown[], unknown][]; - public setConnectQueriesData( + setConnectQueriesData( keyDescriptor: { schema: DescMethodUnary; input?: MessageInitShape; @@ -301,47 +250,15 @@ export class QueryClient extends TSQueryClient { updater: ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - }, + } ): [readonly unknown[], unknown][]; - public setConnectQueriesData( - keyDescriptor: { - schema: DescMethodUnary; - input?: MessageInitShape; - transport?: Transport; - cardinality: "finite" | "infinite"; - }, - updater: ConnectUpdater | ConnectInfiniteUpdater, - options?: SetDataOptions & { - exact?: boolean; - }, - ) { - return this.setQueriesData( - { - queryKey: createConnectQueryKey({ - ...keyDescriptor, - cardinality: keyDescriptor.cardinality, - }), - exact: options?.exact ?? false, - }, - keyDescriptor.cardinality === "finite" - ? createProtobufSafeUpdater( - keyDescriptor.schema, - updater as ConnectUpdater, - ) - : createProtobufSafeInfiniteUpdater( - keyDescriptor.schema, - updater as ConnectInfiniteUpdater, - ), - options, - ); - } /** * Fetch a single query and return the result. * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientfetchquery} */ - public async fetchConnectQuery< + fetchConnectQuery< I extends DescMessage, O extends DescMessage, SelectOutData = MessageShape, @@ -353,20 +270,15 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, - ) { - return this.fetchQuery({ - ...createQueryOptions(schema, input, { transport }), - ...queryOptions, - }); - } + } & FetchQueryOptions + ): Promise; /** * Fetch a single infinite query and return the result. * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientfetchinfinitequery} */ - public async fetchConnectInfiniteQuery< + fetchConnectInfiniteQuery< I extends DescMessage, O extends DescMessage, ParamKey extends keyof MessageInitShape, @@ -378,24 +290,15 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, - ) { - return this.fetchInfiniteQuery({ - ...createInfiniteQueryOptions(schema, input, { - transport, - pageParamKey, - getNextPageParam, - }), - ...queryOptions, - }); - } + }: FetchInfiniteQueryOptions + ): Promise>>; /** * Prefetch a single query and discard the result. * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientprefetchquery} */ - public async prefetchConnectQuery< + prefetchConnectQuery< I extends DescMessage, O extends DescMessage, SelectOutData = MessageShape, @@ -407,20 +310,15 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, - ) { - return this.prefetchQuery({ - ...createQueryOptions(schema, input, { transport }), - ...queryOptions, - }); - } + } & FetchQueryOptions + ): Promise; /** * Prefetch a single infinite query and discard the result. * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientprefetchinfinitequery} */ - public async prefetchConnectInfiniteQuery< + prefetchConnectInfiniteQuery< I extends DescMessage, O extends DescMessage, ParamKey extends keyof MessageInitShape, @@ -432,17 +330,8 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, - ) { - return this.prefetchInfiniteQuery({ - ...createInfiniteQueryOptions(schema, input, { - transport, - pageParamKey, - getNextPageParam, - }), - ...queryOptions, - }); - } + }: FetchInfiniteQueryOptions + ): Promise; /** * Get the query state for a single query. The query must match exactly the input provided, as well @@ -450,26 +339,18 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetquerystate} */ - public getConnectQueryState(keyDescriptor: { + getConnectQueryState(keyDescriptor: { schema: Desc; input?: MessageInitShape; transport: Transport; cardinality: "finite"; - }): QueryState, ConnectError>; - public getConnectQueryState(keyDescriptor: { + }): QueryState, ConnectError> | undefined; + getConnectQueryState(keyDescriptor: { schema: Desc; input?: MessageInitShape; transport: Transport; cardinality: "infinite"; - }): QueryState>, ConnectError>; - public getConnectQueryState(keyDescriptor: { - schema: Desc; - input?: MessageInitShape; - transport: Transport; - cardinality: "finite" | "infinite"; - }) { - return this.getQueryState(createConnectQueryKey(keyDescriptor)); - } + }): QueryState>, ConnectError> | undefined; /** * Ensure the query data for a single query. The query must match exactly the input provided, as well @@ -477,7 +358,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientensurequerydata} */ - public async ensureConnectQueryData< + ensureConnectQueryData< I extends DescMessage, O extends DescMessage, SelectOutData = MessageShape, @@ -489,13 +370,8 @@ export class QueryClient extends TSQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions, - ) { - return this.ensureQueryData({ - ...createQueryOptions(schema, input, { transport }), - ...queryOptions, - }); - } + } & FetchQueryOptions + ): Promise; /** * Ensure the query data for a single infinite query. The query must match exactly the input provided, as well @@ -503,7 +379,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientensureinfinitequerydata} */ - public async ensureConnectInfiniteQueryData< + ensureConnectInfiniteQueryData< I extends DescMessage, O extends DescMessage, ParamKey extends keyof MessageInitShape, @@ -515,17 +391,8 @@ export class QueryClient extends TSQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions, - ) { - return this.ensureInfiniteQueryData({ - ...createInfiniteQueryOptions(schema, input, { - transport, - pageParamKey, - getNextPageParam, - }), - ...queryOptions, - }); - } + }: FetchInfiniteQueryOptions + ): Promise>>; /** * Get all data entries that match the given schema. This @@ -533,7 +400,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientgetqueriesdata} */ - public getConnectQueriesData< + getConnectQueriesData< I extends DescMessage, O extends DescMessage, Desc extends DescService, @@ -541,16 +408,8 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit, - ) { - return this.getQueriesData({ - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }); - } + filterOptions?: Omit + ): unknown; /** * Cancels any outgoing queries that match the given schema. This @@ -558,7 +417,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientcancelqueries} */ - public async cancelConnectQueries< + cancelConnectQueries< I extends DescMessage, O extends DescMessage, Desc extends DescService, @@ -566,16 +425,8 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit, - ) { - return this.cancelQueries({ - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }); - } + filterOptions?: Omit + ): Promise; /** * Removes any queries from the cache that match the given schema. This @@ -583,7 +434,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientremovequeries} */ - public removeConnectQueries< + removeConnectQueries< I extends DescMessage, O extends DescMessage, Desc extends DescService, @@ -591,17 +442,8 @@ export class QueryClient extends TSQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit, - ) { - this.removeQueries({ - ...filterOptions, - queryKey: createConnectQueryKey({ - ...params, - cardinality: params.cardinality, - }), - }); - return; - } + filterOptions?: Omit + ): void; /** * Resets any queries that match the given schema. This @@ -609,7 +451,7 @@ export class QueryClient extends TSQueryClient { * * @see {@link https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientresetqueries} */ - public async resetConnectQueries< + resetConnectQueries< I extends DescMessage, O extends DescMessage, Desc extends DescService, @@ -618,35 +460,272 @@ export class QueryClient extends TSQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: ResetOptions, - ) { - return this.resetQueries( + options?: ResetOptions + ): Promise; +} + +export function createConnectQueryClient(queryClient: TSQueryClient) { + const connectQueryClient: ConnectQueryClient = { + async invalidateConnectQueries( + params, + filterOptions, + options + ) { + return queryClient.invalidateQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }, + options + ); + }, + + async refetchConnectQueries( + params, + filterOptions, + options + ) { + return queryClient.refetchQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }, + options + ); + }, + + setConnectQueryData( + keyDescriptor, + updater, + options + ) { + return queryClient.setQueryData( + createConnectQueryKey({ + ...keyDescriptor, + // Since we are matching on the exact input, we match what connect-query does in createQueryOptions + input: keyDescriptor.input ?? {} + }), + keyDescriptor.cardinality === "finite" + ? createProtobufSafeUpdater( + keyDescriptor.schema, + updater as ConnectUpdater + ) + : createProtobufSafeInfiniteUpdater( + keyDescriptor.schema, + updater as ConnectInfiniteUpdater + ), + options + ); + }, + + getConnectQueryData(keyDescriptor) { + return queryClient.getQueryData(createConnectQueryKey(keyDescriptor)); + }, + + setConnectQueriesData( + keyDescriptor, + updater, + options + ) { + return queryClient.setQueriesData( + { + queryKey: createConnectQueryKey({ + ...keyDescriptor, + cardinality: keyDescriptor.cardinality, + }), + exact: options?.exact ?? false, + }, + keyDescriptor.cardinality === "finite" + ? createProtobufSafeUpdater( + keyDescriptor.schema, + updater + ) + : createProtobufSafeInfiniteUpdater( + keyDescriptor.schema, + updater + ), + options + ); + }, + + fetchConnectQuery( + schema, + input, + { + transport, + ...queryOptions + } + ) { + return queryClient.fetchQuery({ + ...createQueryOptions(schema, input, { transport }), + ...queryOptions, + }); + }, + fetchConnectInfiniteQuery( + schema, + input, + { + transport, + getNextPageParam, + pageParamKey, + ...queryOptions + } + ) { + return queryClient.fetchInfiniteQuery({ + ...createInfiniteQueryOptions(schema, input, { + transport, + pageParamKey, + getNextPageParam, + }), + ...queryOptions, + }); + }, + prefetchConnectQuery( + schema, + input, + { + transport, + ...queryOptions + } + ) { + return queryClient.prefetchQuery({ + ...createQueryOptions(schema, input, { transport }), + ...queryOptions, + }); + }, + + prefetchConnectInfiniteQuery( + schema, + input, + { + transport, + getNextPageParam, + pageParamKey, + ...queryOptions + } + ) { + return queryClient.prefetchInfiniteQuery({ + ...createInfiniteQueryOptions(schema, input, { + transport, + pageParamKey, + getNextPageParam, + }), + ...queryOptions, + }); + }, + getConnectQueryState(keyDescriptor) { + return queryClient.getQueryState(createConnectQueryKey(keyDescriptor)); + }, + + ensureConnectQueryData( + schema, + input, + { + transport, + ...queryOptions + } + ) { + return queryClient.ensureQueryData({ + ...createQueryOptions(schema, input, { transport }), + ...queryOptions, + }); + }, + ensureConnectInfiniteQueryData( + schema, + input, { + transport, + getNextPageParam, + pageParamKey, + ...queryOptions + } + ) { + return queryClient.ensureInfiniteQueryData({ + ...createInfiniteQueryOptions(schema, input, { + transport, + pageParamKey, + getNextPageParam, + }), + ...queryOptions, + }); + }, + getConnectQueriesData( + params, + filterOptions + ) { + return queryClient.getQueriesData({ ...filterOptions, queryKey: createConnectQueryKey({ ...params, cardinality: params.cardinality, }), - }, - options, - ); - } + }); + }, + cancelConnectQueries( + params, + filterOptions + ) { + return queryClient.cancelQueries({ + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }); + }, + removeConnectQueries( + params, + filterOptions + ) { + queryClient.removeQueries({ + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }); + return; + }, + resetConnectQueries( + params, + filterOptions, + options + ) { + return queryClient.resetQueries( + { + ...filterOptions, + queryKey: createConnectQueryKey({ + ...params, + cardinality: params.cardinality, + }), + }, + options + ); + }, + }; + return connectQueryClient; } type ConnectInfiniteUpdater = | InfiniteData> | undefined | (( - prev?: InfiniteData>, + prev?: InfiniteData> ) => InfiniteData> | undefined); const createProtobufSafeInfiniteUpdater = ( schema: Pick, "output">, - updater: ConnectInfiniteUpdater, + updater: ConnectInfiniteUpdater ) => ( - prev?: InfiniteData>, + prev?: InfiniteData> ): InfiniteData> | undefined => { if (typeof updater !== "function") { if (updater === undefined) { @@ -680,7 +759,7 @@ type ConnectUpdater = const createProtobufSafeUpdater = ( schema: Pick, "output">, - updater: ConnectUpdater, + updater: ConnectUpdater ) => (prev?: MessageShape): MessageShape | undefined => { if (typeof updater !== "function") { From e1f3302a3853ef516ac8e65c5602392baeb3b2e7 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 14 Apr 2025 12:35:33 -0400 Subject: [PATCH 12/15] Fix TS errors Signed-off-by: Paul Sachs --- .../connect-query-core/src/query-client.ts | 189 +++++++----------- 1 file changed, 70 insertions(+), 119 deletions(-) diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/query-client.ts index 6bb57b08..96ead059 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/query-client.ts @@ -35,6 +35,7 @@ import type { RefetchQueryFilters, ResetOptions, SetDataOptions, + Updater, } from "@tanstack/query-core"; import { QueryClient as TSQueryClient } from "@tanstack/query-core"; @@ -185,17 +186,6 @@ export interface ConnectQueryClient { updater: ConnectUpdater, options?: SetDataOptions ): O; - setConnectQueryData( - keyDescriptor: { - schema: DescMethodUnary; - input?: MessageInitShape; - transport: Transport; - cardinality: "finite" | "infinite"; - }, - updater: ConnectUpdater | ConnectInfiniteUpdater, - - options?: SetDataOptions - ): O; /** * Get the data for a single query. The query must match exactly the input provided, as well @@ -350,7 +340,9 @@ export interface ConnectQueryClient { input?: MessageInitShape; transport: Transport; cardinality: "infinite"; - }): QueryState>, ConnectError> | undefined; + }): + | QueryState>, ConnectError> + | undefined; /** * Ensure the query data for a single query. The query must match exactly the input provided, as well @@ -466,11 +458,7 @@ export interface ConnectQueryClient { export function createConnectQueryClient(queryClient: TSQueryClient) { const connectQueryClient: ConnectQueryClient = { - async invalidateConnectQueries( - params, - filterOptions, - options - ) { + async invalidateConnectQueries(params, filterOptions, options) { return queryClient.invalidateQueries( { ...filterOptions, @@ -483,11 +471,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { ); }, - async refetchConnectQueries( - params, - filterOptions, - options - ) { + async refetchConnectQueries(params, filterOptions, options) { return queryClient.refetchQueries( { ...filterOptions, @@ -500,26 +484,34 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { ); }, - setConnectQueryData( - keyDescriptor, - updater, - options - ) { + setConnectQueryData( + keyDescriptor: { + schema: DescMethodUnary; + input?: MessageInitShape; + transport: Transport; + cardinality: "finite" | "infinite"; + }, + updater: ConnectUpdater | ConnectInfiniteUpdater, + options?: SetDataOptions + ): O | undefined { + const safeUpdater = + keyDescriptor.cardinality === "infinite" + ? createProtobufSafeInfiniteUpdater( + keyDescriptor.schema, + updater as ConnectInfiniteUpdater + ) + : createProtobufSafeUpdater( + keyDescriptor.schema, + updater as ConnectUpdater + ); return queryClient.setQueryData( createConnectQueryKey({ ...keyDescriptor, // Since we are matching on the exact input, we match what connect-query does in createQueryOptions - input: keyDescriptor.input ?? {} + input: keyDescriptor.input ?? ({} as MessageInitShape), }), - keyDescriptor.cardinality === "finite" - ? createProtobufSafeUpdater( - keyDescriptor.schema, - updater as ConnectUpdater - ) - : createProtobufSafeInfiniteUpdater( - keyDescriptor.schema, - updater as ConnectInfiniteUpdater - ), + // Need this override to keep avoid issues with NoInfer type messing with type checks + safeUpdater as any, options ); }, @@ -528,11 +520,28 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { return queryClient.getQueryData(createConnectQueryKey(keyDescriptor)); }, - setConnectQueriesData( - keyDescriptor, - updater, - options - ) { + setConnectQueriesData( + keyDescriptor: { + schema: DescMethodUnary; + input?: MessageInitShape; + transport?: Transport; + cardinality: "infinite" | "finite"; + }, + updater: ConnectInfiniteUpdater | ConnectUpdater, + options?: SetDataOptions & { + exact?: boolean; + } + ): [readonly unknown[], unknown][] { + const safeUpdater = + keyDescriptor.cardinality === "finite" + ? createProtobufSafeUpdater( + keyDescriptor.schema, + updater as ConnectUpdater + ) + : createProtobufSafeInfiniteUpdater( + keyDescriptor.schema, + updater as ConnectInfiniteUpdater + ); return queryClient.setQueriesData( { queryKey: createConnectQueryKey({ @@ -541,27 +550,12 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { }), exact: options?.exact ?? false, }, - keyDescriptor.cardinality === "finite" - ? createProtobufSafeUpdater( - keyDescriptor.schema, - updater - ) - : createProtobufSafeInfiniteUpdater( - keyDescriptor.schema, - updater - ), + safeUpdater, options ); }, - fetchConnectQuery( - schema, - input, - { - transport, - ...queryOptions - } - ) { + fetchConnectQuery(schema, input, { transport, ...queryOptions }) { return queryClient.fetchQuery({ ...createQueryOptions(schema, input, { transport }), ...queryOptions, @@ -570,12 +564,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { fetchConnectInfiniteQuery( schema, input, - { - transport, - getNextPageParam, - pageParamKey, - ...queryOptions - } + { transport, getNextPageParam, pageParamKey, ...queryOptions } ) { return queryClient.fetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -586,29 +575,17 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { ...queryOptions, }); }, - prefetchConnectQuery( - schema, - input, - { - transport, - ...queryOptions - } - ) { + prefetchConnectQuery(schema, input, { transport, ...queryOptions }) { return queryClient.prefetchQuery({ ...createQueryOptions(schema, input, { transport }), ...queryOptions, }); }, - + prefetchConnectInfiniteQuery( schema, input, - { - transport, - getNextPageParam, - pageParamKey, - ...queryOptions - } + { transport, getNextPageParam, pageParamKey, ...queryOptions } ) { return queryClient.prefetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -622,15 +599,8 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { getConnectQueryState(keyDescriptor) { return queryClient.getQueryState(createConnectQueryKey(keyDescriptor)); }, - - ensureConnectQueryData( - schema, - input, - { - transport, - ...queryOptions - } - ) { + + ensureConnectQueryData(schema, input, { transport, ...queryOptions }) { return queryClient.ensureQueryData({ ...createQueryOptions(schema, input, { transport }), ...queryOptions, @@ -639,12 +609,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { ensureConnectInfiniteQueryData( schema, input, - { - transport, - getNextPageParam, - pageParamKey, - ...queryOptions - } + { transport, getNextPageParam, pageParamKey, ...queryOptions } ) { return queryClient.ensureInfiniteQueryData({ ...createInfiniteQueryOptions(schema, input, { @@ -655,10 +620,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { ...queryOptions, }); }, - getConnectQueriesData( - params, - filterOptions - ) { + getConnectQueriesData(params, filterOptions) { return queryClient.getQueriesData({ ...filterOptions, queryKey: createConnectQueryKey({ @@ -667,10 +629,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { }), }); }, - cancelConnectQueries( - params, - filterOptions - ) { + cancelConnectQueries(params, filterOptions) { return queryClient.cancelQueries({ ...filterOptions, queryKey: createConnectQueryKey({ @@ -679,10 +638,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { }), }); }, - removeConnectQueries( - params, - filterOptions - ) { + removeConnectQueries(params, filterOptions) { queryClient.removeQueries({ ...filterOptions, queryKey: createConnectQueryKey({ @@ -692,11 +648,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { }); return; }, - resetConnectQueries( - params, - filterOptions, - options - ) { + resetConnectQueries(params, filterOptions, options) { return queryClient.resetQueries( { ...filterOptions, @@ -725,7 +677,7 @@ const createProtobufSafeInfiniteUpdater = updater: ConnectInfiniteUpdater ) => ( - prev?: InfiniteData> + prev: InfiniteData> | undefined ): InfiniteData> | undefined => { if (typeof updater !== "function") { if (updater === undefined) { @@ -756,12 +708,11 @@ type ConnectUpdater = * is of the message type. If an init shape is returned, * we'll run it through create again. */ -const createProtobufSafeUpdater = - ( - schema: Pick, "output">, - updater: ConnectUpdater - ) => - (prev?: MessageShape): MessageShape | undefined => { +const createProtobufSafeUpdater: ( + schema: Pick, "output">, + updater: ConnectUpdater +) => Updater, MessageShape | undefined> = + (schema, updater) => (prev) => { if (typeof updater !== "function") { if (updater === undefined) { return undefined; From 216a580998c1d6053980ba2683ecc7bfef48be77 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Thu, 17 Apr 2025 15:19:12 -0400 Subject: [PATCH 13/15] Fix tests Signed-off-by: Paul Sachs --- .../src/query-client.test.ts | 98 ++++++++++--------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/query-client.test.ts index c9cc26a9..90c4c09f 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/query-client.test.ts @@ -19,9 +19,10 @@ import type { SayResponseSchema } from "test-utils/gen/eliza_pb.js"; import { ElizaService } from "test-utils/gen/eliza_pb.js"; import { ListService } from "test-utils/gen/list_pb.js"; import { describe, expect, it } from "vitest"; +import { QueryClient } from "@tanstack/query-core"; import { createConnectQueryKey } from "./connect-query-key.js"; -import { QueryClient } from "./query-client.js"; +import { createConnectQueryClient, type ConnectQueryClient } from "./query-client.js"; const sayMethodDescriptor = ElizaService.method.say; @@ -37,9 +38,14 @@ const queryDetails = { transport: mockedElizaTransport, }; +function enhanceQueryClient(queryClient: QueryClient) { + Object.assign(queryClient, createConnectQueryClient(queryClient)); + return queryClient as ConnectQueryClient & QueryClient; +} + describe("prefetch APIs", () => { it("populates a single query cache", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); const currentCacheItems = queryClient.getQueryCache().findAll(); expect(currentCacheItems).toHaveLength(0); @@ -52,19 +58,19 @@ describe("prefetch APIs", () => { ...queryDetails, cardinality: "finite", }); - expect(item.sentence).toBe("Hello Pablo"); + expect(item?.sentence).toBe("Hello Pablo"); const queryState = queryClient.getConnectQueryState({ ...queryDetails, cardinality: "finite", }); - expect(queryState.status).toBe("success"); - expect(queryState.fetchStatus).toBe("idle"); - expect(queryState.dataUpdateCount).toBe(1); + expect(queryState?.status).toBe("success"); + expect(queryState?.fetchStatus).toBe("idle"); + expect(queryState?.dataUpdateCount).toBe(1); }); it("populates an infinite query cache", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); const currentCacheItems = queryClient.getQueryCache().findAll(); expect(currentCacheItems).toHaveLength(0); @@ -94,18 +100,18 @@ describe("prefetch APIs", () => { const nextItems = queryClient.getQueryCache().findAll(); expect(nextItems).toHaveLength(1); - expect(item.pages[0].items).toHaveLength(3); + expect(item?.pages[0].items).toHaveLength(3); const queryState = queryClient.getConnectQueryState(details); - expect(queryState.status).toBe("success"); - expect(queryState.fetchStatus).toBe("idle"); - expect(queryState.dataUpdateCount).toBe(1); + expect(queryState?.status).toBe("success"); + expect(queryState?.fetchStatus).toBe("idle"); + expect(queryState?.dataUpdateCount).toBe(1); }); }); describe("invalidateConnectQueries", () => { it("invalidates a specific query", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, @@ -116,11 +122,11 @@ describe("invalidateConnectQueries", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState.isInvalidated).toBe(true); + expect(queryState?.isInvalidated).toBe(true); }); it("invalidate all methods for a given service", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, @@ -135,13 +141,13 @@ describe("invalidateConnectQueries", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState.isInvalidated).toBe(true); + expect(queryState?.isInvalidated).toBe(true); }); }); describe("refetchConnectQueries", () => { it("refetch a specific query", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, @@ -152,11 +158,11 @@ describe("refetchConnectQueries", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState.dataUpdateCount).toBe(2); + expect(queryState?.dataUpdateCount).toBe(2); }); it("refetch all methods for a given service", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, @@ -171,13 +177,13 @@ describe("refetchConnectQueries", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState.dataUpdateCount).toBe(2); + expect(queryState?.dataUpdateCount).toBe(2); }); }); describe("setConnectQueryData", () => { it("updates locally fetched data", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, @@ -188,8 +194,8 @@ describe("setConnectQueryData", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState.dataUpdateCount).toBe(1); - expect(queryState.data?.sentence).toBe("Hello Pablo"); + expect(queryState?.dataUpdateCount).toBe(1); + expect(queryState?.data?.sentence).toBe("Hello Pablo"); queryClient.setConnectQueryData( { @@ -206,12 +212,12 @@ describe("setConnectQueryData", () => { cardinality: "finite", }); - expect(newQueryState.dataUpdateCount).toBe(2); - expect(newQueryState.data?.sentence).toBe("Hello Stu"); + expect(newQueryState?.dataUpdateCount).toBe(2); + expect(newQueryState?.data?.sentence).toBe("Hello Stu"); }); it("updates locally fetched data with a callback", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, @@ -222,8 +228,8 @@ describe("setConnectQueryData", () => { ...queryDetails, cardinality: "finite", }); - expect(queryState.dataUpdateCount).toBe(1); - expect(queryState.data?.sentence).toBe("Hello Pablo"); + expect(queryState?.dataUpdateCount).toBe(1); + expect(queryState?.data?.sentence).toBe("Hello Pablo"); queryClient.setConnectQueryData( { @@ -246,15 +252,15 @@ describe("setConnectQueryData", () => { cardinality: "finite", }); - expect(newQueryState.dataUpdateCount).toBe(2); - expect(newQueryState.data?.sentence).toBe("Hello Stu"); - expect(newQueryState.data?.$typeName).toBe( + expect(newQueryState?.dataUpdateCount).toBe(2); + expect(newQueryState?.data?.sentence).toBe("Hello Stu"); + expect(newQueryState?.data?.$typeName).toBe( "connectrpc.eliza.v1.SayResponse", ); }); it("can update infinite paginated data", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectInfiniteQuery( ListService.method.list, { @@ -275,8 +281,8 @@ describe("setConnectQueryData", () => { page: 0n, }, }); - expect(queryState.dataUpdateCount).toBe(1); - expect(queryState.data?.pages).toHaveLength(1); + expect(queryState?.dataUpdateCount).toBe(1); + expect(queryState?.data?.pages).toHaveLength(1); queryClient.setConnectQueryData( { @@ -308,14 +314,14 @@ describe("setConnectQueryData", () => { }, }); - expect(newQueryState.dataUpdateCount).toBe(2); - expect(newQueryState.data?.pages).toHaveLength(2); + expect(newQueryState?.dataUpdateCount).toBe(2); + expect(newQueryState?.data?.pages).toHaveLength(2); }); }); describe("setConnectQueriesData", () => { it("update locally fetched data across multiple queries", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.prefetchConnectQuery( queryDetails.schema, queryDetails.input, @@ -365,7 +371,7 @@ describe("setConnectQueriesData", () => { describe("fetchConnectInfiniteQuery", () => { it("fetches infinite data", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); const result = await queryClient.fetchConnectInfiniteQuery( ListService.method.list, { @@ -390,7 +396,7 @@ describe("fetchConnectInfiniteQuery", () => { describe("getConnectQueryState", () => { it("can get state for infinite queries", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); await queryClient.fetchConnectInfiniteQuery( ListService.method.list, { @@ -415,15 +421,15 @@ describe("getConnectQueryState", () => { cardinality: "infinite", }); - expect(state.status).toBe("success"); - expect(state.fetchStatus).toBe("idle"); - expect(state.dataUpdateCount).toBe(1); + expect(state?.status).toBe("success"); + expect(state?.fetchStatus).toBe("idle"); + expect(state?.dataUpdateCount).toBe(1); }); }); describe("ensure APIs", () => { it("ensure data exists for infinite queries", async () => { - const queryClient = new QueryClient(); + const queryClient = enhanceQueryClient(new QueryClient()); const data = await queryClient.ensureConnectInfiniteQueryData( ListService.method.list, { @@ -448,9 +454,9 @@ describe("ensure APIs", () => { }, cardinality: "infinite", }); - expect(state.status).toBe("success"); - expect(state.fetchStatus).toBe("idle"); - expect(state.dataUpdateCount).toBe(1); - expect(data.pages[0]).toBe(state.data?.pages[0]); + expect(state?.status).toBe("success"); + expect(state?.fetchStatus).toBe("idle"); + expect(state?.dataUpdateCount).toBe(1); + expect(data.pages[0]).toBe(state?.data?.pages[0]); }); }); From a780dd9737e320503ac0af6603c1faa0f92aba7a Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Tue, 22 Apr 2025 09:57:14 -0400 Subject: [PATCH 14/15] Add export for useConnectQueryClient Signed-off-by: Paul Sachs --- ...t.test.ts => connect-query-client.test.ts} | 5 +- ...uery-client.ts => connect-query-client.ts} | 70 +++++++++---------- packages/connect-query-core/src/index.ts | 2 + packages/connect-query/src/index.ts | 1 + .../src/use-connect-query-client.ts | 25 +++++++ 5 files changed, 67 insertions(+), 36 deletions(-) rename packages/connect-query-core/src/{query-client.test.ts => connect-query-client.test.ts} (99%) rename packages/connect-query-core/src/{query-client.ts => connect-query-client.ts} (94%) create mode 100644 packages/connect-query/src/use-connect-query-client.ts diff --git a/packages/connect-query-core/src/query-client.test.ts b/packages/connect-query-core/src/connect-query-client.test.ts similarity index 99% rename from packages/connect-query-core/src/query-client.test.ts rename to packages/connect-query-core/src/connect-query-client.test.ts index 90c4c09f..65eb6cf4 100644 --- a/packages/connect-query-core/src/query-client.test.ts +++ b/packages/connect-query-core/src/connect-query-client.test.ts @@ -22,7 +22,10 @@ import { describe, expect, it } from "vitest"; import { QueryClient } from "@tanstack/query-core"; import { createConnectQueryKey } from "./connect-query-key.js"; -import { createConnectQueryClient, type ConnectQueryClient } from "./query-client.js"; +import { + createConnectQueryClient, + type ConnectQueryClient, +} from "./connect-query-client.js"; const sayMethodDescriptor = ElizaService.method.say; diff --git a/packages/connect-query-core/src/query-client.ts b/packages/connect-query-core/src/connect-query-client.ts similarity index 94% rename from packages/connect-query-core/src/query-client.ts rename to packages/connect-query-core/src/connect-query-client.ts index 96ead059..c9f7c661 100644 --- a/packages/connect-query-core/src/query-client.ts +++ b/packages/connect-query-core/src/connect-query-client.ts @@ -139,7 +139,7 @@ export interface ConnectQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: InvalidateOptions + options?: InvalidateOptions, ): Promise; /** @@ -157,7 +157,7 @@ export interface ConnectQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: RefetchOptions + options?: RefetchOptions, ): Promise; /** @@ -174,7 +174,7 @@ export interface ConnectQueryClient { cardinality: "infinite"; }, updater: ConnectInfiniteUpdater, - options?: SetDataOptions + options?: SetDataOptions, ): O; setConnectQueryData( keyDescriptor: { @@ -184,7 +184,7 @@ export interface ConnectQueryClient { cardinality: "finite"; }, updater: ConnectUpdater, - options?: SetDataOptions + options?: SetDataOptions, ): O; /** @@ -228,7 +228,7 @@ export interface ConnectQueryClient { updater: ConnectUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ): [readonly unknown[], unknown][]; setConnectQueriesData( keyDescriptor: { @@ -240,7 +240,7 @@ export interface ConnectQueryClient { updater: ConnectInfiniteUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ): [readonly unknown[], unknown][]; /** @@ -260,7 +260,7 @@ export interface ConnectQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ): Promise; /** @@ -280,7 +280,7 @@ export interface ConnectQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ): Promise>>; /** @@ -300,7 +300,7 @@ export interface ConnectQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ): Promise; /** @@ -320,7 +320,7 @@ export interface ConnectQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ): Promise; /** @@ -362,7 +362,7 @@ export interface ConnectQueryClient { ...queryOptions }: { transport: Transport; - } & FetchQueryOptions + } & FetchQueryOptions, ): Promise; /** @@ -383,7 +383,7 @@ export interface ConnectQueryClient { getNextPageParam, pageParamKey, ...queryOptions - }: FetchInfiniteQueryOptions + }: FetchInfiniteQueryOptions, ): Promise>>; /** @@ -400,7 +400,7 @@ export interface ConnectQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ): unknown; /** @@ -417,7 +417,7 @@ export interface ConnectQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ): Promise; /** @@ -434,7 +434,7 @@ export interface ConnectQueryClient { params: | KeyParamsForMethod> | KeyParamsForService, - filterOptions?: Omit + filterOptions?: Omit, ): void; /** @@ -452,7 +452,7 @@ export interface ConnectQueryClient { | KeyParamsForMethod> | KeyParamsForService, filterOptions?: Omit, - options?: ResetOptions + options?: ResetOptions, ): Promise; } @@ -467,7 +467,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { cardinality: params.cardinality, }), }, - options + options, ); }, @@ -480,7 +480,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { cardinality: params.cardinality, }), }, - options + options, ); }, @@ -492,17 +492,17 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { cardinality: "finite" | "infinite"; }, updater: ConnectUpdater | ConnectInfiniteUpdater, - options?: SetDataOptions + options?: SetDataOptions, ): O | undefined { const safeUpdater = keyDescriptor.cardinality === "infinite" ? createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater + updater as ConnectInfiniteUpdater, ) : createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater + updater as ConnectUpdater, ); return queryClient.setQueryData( createConnectQueryKey({ @@ -510,9 +510,9 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { // Since we are matching on the exact input, we match what connect-query does in createQueryOptions input: keyDescriptor.input ?? ({} as MessageInitShape), }), - // Need this override to keep avoid issues with NoInfer type messing with type checks + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- Need this override to keep avoid issues with NoInfer type messing with type checks safeUpdater as any, - options + options, ); }, @@ -530,17 +530,17 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { updater: ConnectInfiniteUpdater | ConnectUpdater, options?: SetDataOptions & { exact?: boolean; - } + }, ): [readonly unknown[], unknown][] { const safeUpdater = keyDescriptor.cardinality === "finite" ? createProtobufSafeUpdater( keyDescriptor.schema, - updater as ConnectUpdater + updater as ConnectUpdater, ) : createProtobufSafeInfiniteUpdater( keyDescriptor.schema, - updater as ConnectInfiniteUpdater + updater as ConnectInfiniteUpdater, ); return queryClient.setQueriesData( { @@ -551,7 +551,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { exact: options?.exact ?? false, }, safeUpdater, - options + options, ); }, @@ -564,7 +564,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { fetchConnectInfiniteQuery( schema, input, - { transport, getNextPageParam, pageParamKey, ...queryOptions } + { transport, getNextPageParam, pageParamKey, ...queryOptions }, ) { return queryClient.fetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -585,7 +585,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { prefetchConnectInfiniteQuery( schema, input, - { transport, getNextPageParam, pageParamKey, ...queryOptions } + { transport, getNextPageParam, pageParamKey, ...queryOptions }, ) { return queryClient.prefetchInfiniteQuery({ ...createInfiniteQueryOptions(schema, input, { @@ -609,7 +609,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { ensureConnectInfiniteQueryData( schema, input, - { transport, getNextPageParam, pageParamKey, ...queryOptions } + { transport, getNextPageParam, pageParamKey, ...queryOptions }, ) { return queryClient.ensureInfiniteQueryData({ ...createInfiniteQueryOptions(schema, input, { @@ -657,7 +657,7 @@ export function createConnectQueryClient(queryClient: TSQueryClient) { cardinality: params.cardinality, }), }, - options + options, ); }, }; @@ -668,16 +668,16 @@ type ConnectInfiniteUpdater = | InfiniteData> | undefined | (( - prev?: InfiniteData> + prev?: InfiniteData>, ) => InfiniteData> | undefined); const createProtobufSafeInfiniteUpdater = ( schema: Pick, "output">, - updater: ConnectInfiniteUpdater + updater: ConnectInfiniteUpdater, ) => ( - prev: InfiniteData> | undefined + prev: InfiniteData> | undefined, ): InfiniteData> | undefined => { if (typeof updater !== "function") { if (updater === undefined) { @@ -710,7 +710,7 @@ type ConnectUpdater = */ const createProtobufSafeUpdater: ( schema: Pick, "output">, - updater: ConnectUpdater + updater: ConnectUpdater, ) => Updater, MessageShape | undefined> = (schema, updater) => (prev) => { if (typeof updater !== "function") { diff --git a/packages/connect-query-core/src/index.ts b/packages/connect-query-core/src/index.ts index 7222a945..3ef338af 100644 --- a/packages/connect-query-core/src/index.ts +++ b/packages/connect-query-core/src/index.ts @@ -23,3 +23,5 @@ export { createQueryOptions } from "./create-query-options.js"; export { addStaticKeyToTransport } from "./transport-key.js"; export type { SkipToken } from "@tanstack/query-core"; export { skipToken } from "@tanstack/query-core"; +export type { ConnectQueryClient } from "./connect-query-client.js"; +export { createConnectQueryClient } from "./connect-query-client.js"; diff --git a/packages/connect-query/src/index.ts b/packages/connect-query/src/index.ts index 4f4dfe89..ba46f4d1 100644 --- a/packages/connect-query/src/index.ts +++ b/packages/connect-query/src/index.ts @@ -23,3 +23,4 @@ export type { UseMutationOptions } from "./use-mutation.js"; export { useMutation } from "./use-mutation.js"; export type { UseInfiniteQueryOptions } from "./use-infinite-query.js"; export type { UseQueryOptions } from "./use-query.js"; +export { useConnectQueryClient } from "./use-connect-query-client.js"; diff --git a/packages/connect-query/src/use-connect-query-client.ts b/packages/connect-query/src/use-connect-query-client.ts new file mode 100644 index 00000000..efaae465 --- /dev/null +++ b/packages/connect-query/src/use-connect-query-client.ts @@ -0,0 +1,25 @@ +// Copyright 2021-2023 The Connect Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { useQueryClient } from "@tanstack/react-query"; +import { useMemo } from "react"; +import { createConnectQueryClient } from "@connectrpc/connect-query-core"; +import type { ConnectQueryClient } from "@connectrpc/connect-query-core"; + +export function useConnectQueryClient(): ConnectQueryClient { + const queryClient = useQueryClient(); + return useMemo(() => { + return createConnectQueryClient(queryClient); + }, [queryClient]); +} \ No newline at end of file From ff5c0a4f5b98f37a4d7e1cc2f06bc099d9f5159a Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Tue, 29 Apr 2025 11:08:47 -0400 Subject: [PATCH 15/15] Fix use connect query client Signed-off-by: Paul Sachs --- packages/connect-query/src/use-connect-query-client.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/connect-query/src/use-connect-query-client.ts b/packages/connect-query/src/use-connect-query-client.ts index efaae465..a22e3ecc 100644 --- a/packages/connect-query/src/use-connect-query-client.ts +++ b/packages/connect-query/src/use-connect-query-client.ts @@ -18,8 +18,8 @@ import { createConnectQueryClient } from "@connectrpc/connect-query-core"; import type { ConnectQueryClient } from "@connectrpc/connect-query-core"; export function useConnectQueryClient(): ConnectQueryClient { - const queryClient = useQueryClient(); - return useMemo(() => { - return createConnectQueryClient(queryClient); - }, [queryClient]); -} \ No newline at end of file + const queryClient = useQueryClient(); + return useMemo(() => { + return createConnectQueryClient(queryClient); + }, [queryClient]); +}