From 00ca4db4c3977a4f88ce9ea77cf946f3d16a07c4 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 10 Feb 2025 14:21:03 -0500 Subject: [PATCH 1/6] Add createProtobufSafeInfiniteUpdater Signed-off-by: Paul Sachs --- packages/connect-query-core/src/utils.ts | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) 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 2bbf3f16d37a575a021cdcd013ed44098a0738db Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 10 Feb 2025 14:21:34 -0500 Subject: [PATCH 2/6] Add test Signed-off-by: Paul Sachs --- packages/connect-query-core/src/utils.test.ts | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/packages/connect-query-core/src/utils.test.ts b/packages/connect-query-core/src/utils.test.ts index db621562..1ffdb478 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"; @@ -184,3 +185,70 @@ 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(); + }); + }); +}); From fcb4732fc671f15f97b869b37c19e22f4438d9f7 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 10 Feb 2025 14:23:55 -0500 Subject: [PATCH 3/6] Updated readme Signed-off-by: Paul Sachs --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 0174f92c..4e5d571b 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Connect-Query is an wrapper around [TanStack Query](https://tanstack.com/query) - [`createConnectQueryKey`](#createconnectquerykey) - [`callUnaryMethod`](#callunarymethod) - [`createProtobufSafeUpdater`](#createprotobufsafeupdater) + - [`createProtobufSafeInfiniteUpdater`](#createprotobufsafeinfiniteupdater) - [`createQueryOptions`](#createqueryoptions) - [`createInfiniteQueryOptions`](#createinfinitequeryoptions) - [`addStaticKeyToTransport`](#addstatickeytotransport) @@ -387,6 +388,10 @@ queryClient.setQueryData( ``` +### `createProtobufSafeInfiniteUpdater` + +Creates a typesafe updater for infinite queries. Identical to `createProtobufSafeUpdater` except the data recieved must be of the shape expected for infinite data. + ### `createQueryOptions` ```ts From 19da48119061c778b9aec223e19f463286f4ce0a Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 10 Feb 2025 14:26:38 -0500 Subject: [PATCH 4/6] Fix typo Signed-off-by: Paul Sachs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e5d571b..4e6c3d88 100644 --- a/README.md +++ b/README.md @@ -390,7 +390,7 @@ queryClient.setQueryData( ### `createProtobufSafeInfiniteUpdater` -Creates a typesafe updater for infinite queries. Identical to `createProtobufSafeUpdater` except the data recieved must be of the shape expected for infinite data. +Creates a typesafe updater for infinite queries. Identical to `createProtobufSafeUpdater` except the data received must be of the shape expected for infinite data. ### `createQueryOptions` From b4834150aa44bd5a2e5a05c46e35860e613484c7 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 10 Feb 2025 14:46:28 -0500 Subject: [PATCH 5/6] Make test actually useful Signed-off-by: Paul Sachs --- packages/connect-query-core/src/utils.test.ts | 20 +++++++++++++++++-- packages/connect-query-core/src/utils.ts | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/connect-query-core/src/utils.test.ts b/packages/connect-query-core/src/utils.test.ts index 1ffdb478..0d81cb83 100644 --- a/packages/connect-query-core/src/utils.test.ts +++ b/packages/connect-query-core/src/utils.test.ts @@ -242,13 +242,29 @@ describe("createProtobufSafeInfiniteUpdater", () => { return undefined; } return { - ...prev, - int32Field: 999, + pageParams: [...prev.pageParams, 44], + pages: [ + ...prev.pages, + { + int32Field: 33, + stringField: "whatever" + } + ] }; }); it("accepts undefined", () => { const next = safeUpdater(undefined); expect(next).toBeUndefined(); }); + it("can add a new page", () => { + const next = safeUpdater({ + pageParams: [], + pages: [] + }); + + expect(next?.pageParams).toHaveLength(1); + expect(next?.pages).toHaveLength(1); + + }) }); }); diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index 0e07c2fa..9baabcb2 100644 --- a/packages/connect-query-core/src/utils.ts +++ b/packages/connect-query-core/src/utils.ts @@ -65,7 +65,7 @@ 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. From fed86acdd11057c9c762154ccee2fdd993ea20d7 Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 10 Feb 2025 14:52:22 -0500 Subject: [PATCH 6/6] Format Signed-off-by: Paul Sachs --- packages/connect-query-core/src/utils.test.ts | 12 ++--- packages/connect-query-core/src/utils.ts | 47 ++++++++++--------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/connect-query-core/src/utils.test.ts b/packages/connect-query-core/src/utils.test.ts index 0d81cb83..5a24a268 100644 --- a/packages/connect-query-core/src/utils.test.ts +++ b/packages/connect-query-core/src/utils.test.ts @@ -186,7 +186,6 @@ describe("createProtobufSafeUpdater", () => { }); }); - describe("createProtobufSafeInfiniteUpdater", () => { describe("with update message", () => { const schema = { output: Proto2MessageSchema }; @@ -247,9 +246,9 @@ describe("createProtobufSafeInfiniteUpdater", () => { ...prev.pages, { int32Field: 33, - stringField: "whatever" - } - ] + stringField: "whatever", + }, + ], }; }); it("accepts undefined", () => { @@ -259,12 +258,11 @@ describe("createProtobufSafeInfiniteUpdater", () => { it("can add a new page", () => { const next = safeUpdater({ pageParams: [], - pages: [] + pages: [], }); expect(next?.pageParams).toHaveLength(1); expect(next?.pages).toHaveLength(1); - - }) + }); }); }); diff --git a/packages/connect-query-core/src/utils.ts b/packages/connect-query-core/src/utils.ts index 9baabcb2..97151059 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)), + }; + };