From fe371df87da08bff1447d239a5ebeb1f72289f80 Mon Sep 17 00:00:00 2001 From: Toki <55911995+tokio-k@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:53:38 +0900 Subject: [PATCH 1/2] feature: Add transformer option to use-query --- .../src/query/build-query-opts.ts | 27 +++++-- .../src/query/use-query.ts | 75 ++++++++++++------- 2 files changed, 71 insertions(+), 31 deletions(-) diff --git a/packages/postgrest-react-query/src/query/build-query-opts.ts b/packages/postgrest-react-query/src/query/build-query-opts.ts index 1aee911a..7738b091 100644 --- a/packages/postgrest-react-query/src/query/build-query-opts.ts +++ b/packages/postgrest-react-query/src/query/build-query-opts.ts @@ -8,13 +8,23 @@ import type { UseQueryOptions as UseReactQueryOptions } from '@tanstack/react-qu import { encode } from '../lib/key'; -export function buildQueryOpts( +export function buildQueryOpts( query: PromiseLike>, config?: Omit< - UseReactQueryOptions, PostgrestError>, + UseReactQueryOptions< + AnyPostgrestResponse, + PostgrestError + >, 'queryKey' | 'queryFn' - >, -): UseReactQueryOptions, PostgrestError> { + > & { + transformer?: ( + data: AnyPostgrestResponse['data'] + ) => TransformedResult; + } +): UseReactQueryOptions< + AnyPostgrestResponse, + PostgrestError +> { return { queryKey: encode(query, false), queryFn: async ({ signal }) => { @@ -24,7 +34,14 @@ export function buildQueryOpts( if (isPostgrestBuilder(query)) { query = query.throwOnError(); } - return await query; + const result = await query; + if (config?.transformer && result.error === null) { + return { + ...result, + data: config.transformer(result.data), + }; + } + return result as AnyPostgrestResponse; }, ...config, }; diff --git a/packages/postgrest-react-query/src/query/use-query.ts b/packages/postgrest-react-query/src/query/use-query.ts index e83aa7a5..cf9c1e6f 100644 --- a/packages/postgrest-react-query/src/query/use-query.ts +++ b/packages/postgrest-react-query/src/query/use-query.ts @@ -76,65 +76,88 @@ export type UseQueryAnyReturn = Omit< * React hook to execute a PostgREST query and return a single item response. * * @param {PromiseLike>} query A promise that resolves to a PostgREST single item response. - * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. - * @returns {UseQuerySingleReturn} The hook result containing the single item response data. + * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. + * @returns {UseQuerySingleReturn} The hook result containing the single item response data. */ -function useQuery( +function useQuery( query: PromiseLike>, config?: Omit< - UseReactQueryOptions, PostgrestError>, + UseReactQueryOptions< + PostgrestSingleResponse, + PostgrestError + >, 'queryKey' | 'queryFn' - >, -): UseQuerySingleReturn; + > & { + transformer?: ( + data: PostgrestSingleResponse['data'] + ) => TransformedResult; + } +): UseQuerySingleReturn; /** * React hook to execute a PostgREST query and return a maybe single item response. * * @param {PromiseLike>} query A promise that resolves to a PostgREST maybe single item response. - * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. - * @returns {UseQueryMaybeSingleReturn} The hook result containing the maybe single item response data. + * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. + * @returns {UseQueryMaybeSingleReturn} The hook result containing the maybe single item response data. */ -function useQuery( +function useQuery( query: PromiseLike>, config?: Omit< - UseReactQueryOptions, PostgrestError>, + UseReactQueryOptions< + PostgrestMaybeSingleResponse, + PostgrestError + >, 'queryKey' | 'queryFn' - >, -): UseQueryMaybeSingleReturn; + > & { + transformer?: ( + data: PostgrestMaybeSingleResponse['data'] + ) => TransformedResult; + } +): UseQueryMaybeSingleReturn; /** * React hook to execute a PostgREST query. * * @template Result The expected response data type. * @param {PromiseLike>} query A promise that resolves to a PostgREST response. - * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. - * @returns {UseQueryReturn} The hook result containing the response data. + * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. + * @returns {UseQueryReturn} The hook result containing the response data. */ -function useQuery( +function useQuery( query: PromiseLike>, config?: Omit< - UseReactQueryOptions, PostgrestError>, + UseReactQueryOptions, PostgrestError>, 'queryKey' | 'queryFn' - >, -): UseQueryReturn; + > & { + transformer?: (data: PostgrestResponse['data']) => TransformedResult; + } +): UseQueryReturn; /** * React hook to execute a PostgREST query. * * @template Result The expected response data type. * @param {PromiseLike>} query A promise that resolves to a PostgREST response of any kind. - * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. - * @returns {UseQueryAnyReturn} The hook result containing the response data. + * @param {Omit, PostgrestError>, 'queryKey' | 'queryFn'>} [config] The React Query options. + * @returns {UseQueryAnyReturn} The hook result containing the response data. */ -function useQuery( +function useQuery( query: PromiseLike>, config?: Omit< - UseReactQueryOptions, PostgrestError>, + UseReactQueryOptions< + AnyPostgrestResponse, + PostgrestError + >, 'queryKey' | 'queryFn' - >, -): UseQueryAnyReturn { + > & { + transformer?: ( + data: AnyPostgrestResponse['data'] + ) => TransformedResult; + } +): UseQueryAnyReturn { const { data, ...rest } = useReactQuery< - AnyPostgrestResponse, + AnyPostgrestResponse, PostgrestError - >(buildQueryOpts(query, config)); + >(buildQueryOpts(query, config)); return { data: data?.data, count: data?.count ?? null, ...rest }; } From 5d7ae4e0044098e1fec32b9a08c05bb84308a640 Mon Sep 17 00:00:00 2001 From: Toki <55911995+tokio-k@users.noreply.github.com> Date: Sun, 29 Sep 2024 14:20:43 +0900 Subject: [PATCH 2/2] fix: add transformer option to mutation hooks --- packages/postgrest-core/src/mutate-item.ts | 12 +++++++++++- packages/postgrest-core/src/upsert-item.ts | 12 +++++++++++- .../src/mutate/use-insert-mutation.ts | 2 +- .../src/mutate/use-update-mutation.ts | 2 +- .../src/mutate/use-upsert-mutation.ts | 2 +- .../src/query/build-query-opts.ts | 4 ++-- .../src/query/use-query.ts | 18 ++++++++++-------- 7 files changed, 37 insertions(+), 15 deletions(-) diff --git a/packages/postgrest-core/src/mutate-item.ts b/packages/postgrest-core/src/mutate-item.ts index b9025ce5..18361f1b 100644 --- a/packages/postgrest-core/src/mutate-item.ts +++ b/packages/postgrest-core/src/mutate-item.ts @@ -23,6 +23,7 @@ export const mutateOperation = >( primaryKeys: (keyof Type)[], filter: Pick, 'apply'>, orderBy?: OrderDefinition[], + transformer?: (v: Type) => Type, ) => { // find item const itemIdx = currentData.findIndex((oldItem) => @@ -52,7 +53,11 @@ export const mutateOperation = >( // check that new item is still a valid member of the list and has all required paths if (filter.apply(newItem)) { - currentData.splice(newItemIdx, 0, newItem); + currentData.splice( + newItemIdx, + 0, + transformer ? transformer(newItem) : newItem, + ); } return currentData; @@ -64,6 +69,7 @@ export type MutateItemOperation> = { input: Partial; mutate: (current: Type) => Type; primaryKeys: (keyof Type)[]; + transformer?: (v: Type) => Type; } & RevalidateOpts; export type MutateItemCache> = { @@ -113,6 +119,7 @@ export const mutateItem = async >( schema, table, primaryKeys, + transformer, } = op; const { cacheKeys, decode, getPostgrestFilter, mutate, revalidate } = cache; @@ -165,6 +172,7 @@ export const mutateItem = async >( primaryKeys, filter, orderBy, + transformer, ), currentData, limit, @@ -178,6 +186,7 @@ export const mutateItem = async >( primaryKeys, filter, orderBy, + transformer, ), limit, ); @@ -207,6 +216,7 @@ export const mutateItem = async >( primaryKeys, filter, orderBy, + transformer, ); return { diff --git a/packages/postgrest-core/src/upsert-item.ts b/packages/postgrest-core/src/upsert-item.ts index dcc57a20..3567e071 100644 --- a/packages/postgrest-core/src/upsert-item.ts +++ b/packages/postgrest-core/src/upsert-item.ts @@ -30,6 +30,7 @@ export const upsert = >( filter: Pick, 'apply'>, mergeFn?: MergeFn, orderBy?: OrderDefinition[], + transformer?: (v: Type) => Type, ) => { const merge = mergeFn ?? (mergeAnything as MergeFn); @@ -59,7 +60,11 @@ export const upsert = >( // check that new item is still a valid member of the list and has all required paths if (filter.apply(newItem)) { - currentData.splice(newItemIdx, 0, newItem); + currentData.splice( + newItemIdx, + 0, + transformer ? transformer(newItem) : newItem, + ); } return currentData; @@ -71,6 +76,7 @@ export type UpsertItemOperation> = { input: Type; primaryKeys: (keyof Type)[]; merge?: (current: Type, input: Type) => Type; + transformer?: (v: Type) => Type; } & RevalidateOpts; export type UpsertItemCache> = { @@ -118,6 +124,7 @@ export const upsertItem = async >( schema, table, primaryKeys, + transformer, } = op; const { cacheKeys, decode, getPostgrestFilter, mutate, revalidate } = cache; @@ -167,6 +174,7 @@ export const upsertItem = async >( filter, merge, orderBy, + transformer, ), currentData, limit, @@ -180,6 +188,7 @@ export const upsertItem = async >( filter, merge, orderBy, + transformer, ), limit, ); @@ -209,6 +218,7 @@ export const upsertItem = async >( filter, merge, orderBy, + transformer, ); return { diff --git a/packages/postgrest-react-query/src/mutate/use-insert-mutation.ts b/packages/postgrest-react-query/src/mutate/use-insert-mutation.ts index 4de12f06..bd993a2f 100644 --- a/packages/postgrest-react-query/src/mutate/use-insert-mutation.ts +++ b/packages/postgrest-react-query/src/mutate/use-insert-mutation.ts @@ -37,7 +37,7 @@ function useInsertMutation< opts?: Omit< UsePostgrestMutationOpts, 'mutationFn' - >, + > & { transformer?: (v: T['Row']) => Record }, ) { const queriesForTable = useQueriesForTableLoader(getTable(qb)); const upsertItem = useUpsertItem({ diff --git a/packages/postgrest-react-query/src/mutate/use-update-mutation.ts b/packages/postgrest-react-query/src/mutate/use-update-mutation.ts index 419743c1..e14106c5 100644 --- a/packages/postgrest-react-query/src/mutate/use-update-mutation.ts +++ b/packages/postgrest-react-query/src/mutate/use-update-mutation.ts @@ -36,7 +36,7 @@ function useUpdateMutation< opts?: Omit< UsePostgrestMutationOpts, 'mutationFn' - >, + > & { transformer?: (v: T['Row']) => Record }, ) { const queriesForTable = useQueriesForTableLoader(getTable(qb)); const upsertItem = useUpsertItem({ diff --git a/packages/postgrest-react-query/src/mutate/use-upsert-mutation.ts b/packages/postgrest-react-query/src/mutate/use-upsert-mutation.ts index 8501e2fa..f3c64e45 100644 --- a/packages/postgrest-react-query/src/mutate/use-upsert-mutation.ts +++ b/packages/postgrest-react-query/src/mutate/use-upsert-mutation.ts @@ -37,7 +37,7 @@ function useUpsertMutation< opts?: Omit< UsePostgrestMutationOpts, 'mutationFn' - >, + > & { transformer?: (v: T['Row']) => Record }, ) { const queriesForTable = useQueriesForTableLoader(getTable(qb)); const upsertItem = useUpsertItem({ diff --git a/packages/postgrest-react-query/src/query/build-query-opts.ts b/packages/postgrest-react-query/src/query/build-query-opts.ts index 7738b091..bbc3089e 100644 --- a/packages/postgrest-react-query/src/query/build-query-opts.ts +++ b/packages/postgrest-react-query/src/query/build-query-opts.ts @@ -18,9 +18,9 @@ export function buildQueryOpts( 'queryKey' | 'queryFn' > & { transformer?: ( - data: AnyPostgrestResponse['data'] + data: AnyPostgrestResponse['data'], ) => TransformedResult; - } + }, ): UseReactQueryOptions< AnyPostgrestResponse, PostgrestError diff --git a/packages/postgrest-react-query/src/query/use-query.ts b/packages/postgrest-react-query/src/query/use-query.ts index cf9c1e6f..7dcfb87e 100644 --- a/packages/postgrest-react-query/src/query/use-query.ts +++ b/packages/postgrest-react-query/src/query/use-query.ts @@ -89,9 +89,9 @@ function useQuery( 'queryKey' | 'queryFn' > & { transformer?: ( - data: PostgrestSingleResponse['data'] + data: PostgrestSingleResponse['data'], ) => TransformedResult; - } + }, ): UseQuerySingleReturn; /** * React hook to execute a PostgREST query and return a maybe single item response. @@ -110,9 +110,9 @@ function useQuery( 'queryKey' | 'queryFn' > & { transformer?: ( - data: PostgrestMaybeSingleResponse['data'] + data: PostgrestMaybeSingleResponse['data'], ) => TransformedResult; - } + }, ): UseQueryMaybeSingleReturn; /** * React hook to execute a PostgREST query. @@ -128,8 +128,10 @@ function useQuery( UseReactQueryOptions, PostgrestError>, 'queryKey' | 'queryFn' > & { - transformer?: (data: PostgrestResponse['data']) => TransformedResult; - } + transformer?: ( + data: PostgrestResponse['data'], + ) => TransformedResult; + }, ): UseQueryReturn; /** @@ -150,9 +152,9 @@ function useQuery( 'queryKey' | 'queryFn' > & { transformer?: ( - data: AnyPostgrestResponse['data'] + data: AnyPostgrestResponse['data'], ) => TransformedResult; - } + }, ): UseQueryAnyReturn { const { data, ...rest } = useReactQuery< AnyPostgrestResponse,