From 2b2e2b72bf748f3db5af9fdc8495d4e4b2d0a94b Mon Sep 17 00:00:00 2001 From: anymaniax Date: Tue, 23 May 2023 12:37:05 +0200 Subject: [PATCH] feat(query): add useMutation options --- packages/core/src/types.ts | 2 + packages/orval/src/utils/options.ts | 4 + packages/query/src/index.ts | 186 ++++++++++-------- .../petstoreFromFileSpecWithTransformer.ts | 18 ++ samples/react-query/basic/tsconfig.json | 2 +- 5 files changed, 124 insertions(+), 88 deletions(-) diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index fa7bb80cd..64ff72739 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -289,6 +289,7 @@ export type OverrideOutputContentType = { export type NormalizedQueryOptions = { useQuery?: boolean; + useMutation?: boolean; useInfinite?: boolean; useInfiniteQueryParam?: string; options?: any; @@ -300,6 +301,7 @@ export type NormalizedQueryOptions = { export type QueryOptions = { useQuery?: boolean; + useMutation?: boolean; useInfinite?: boolean; useInfiniteQueryParam?: string; options?: any; diff --git a/packages/orval/src/utils/options.ts b/packages/orval/src/utils/options.ts index 33805f66f..48e1e31c6 100644 --- a/packages/orval/src/utils/options.ts +++ b/packages/orval/src/utils/options.ts @@ -180,6 +180,7 @@ export const normalizeOptions = async ( }, query: { useQuery: true, + useMutation: true, signal: true, ...normalizeQueryOptions(outputOptions.override?.query, workspace), }, @@ -361,6 +362,9 @@ const normalizeQueryOptions = ( ...(!isUndefined(queryOptions.useQuery) ? { useQuery: queryOptions.useQuery } : {}), + ...(!isUndefined(queryOptions.useMutation) + ? { useMutation: queryOptions.useMutation } + : {}), ...(!isUndefined(queryOptions.useInfinite) ? { useInfinite: queryOptions.useInfinite } : {}), diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts index d4e898ce4..e94ba9c31 100644 --- a/packages/query/src/index.ts +++ b/packages/query/src/index.ts @@ -931,11 +931,16 @@ const generateQueryHook = async ( const doc = jsDoc({ summary, deprecated }); - if ( - verb === Verbs.GET || + let implementation = ''; + let mutators = undefined; + + const isQuery = + (Verbs.GET === verb && + (override.query.useQuery || override.query.useInfinite)) || operationQueryOptions?.useInfinite || - operationQueryOptions?.useQuery - ) { + operationQueryOptions?.useQuery; + + if (isQuery) { const queryKeyMutator = query.queryKey ? await generateMutator({ output, @@ -1009,7 +1014,7 @@ const generateQueryHook = async ( queryParams ? ', ...(params ? [params]: [])' : '' }${body.implementation ? `, ${body.implementation}` : ''}] as const;`; - const implementation = `${!queryKeyMutator ? queryKeyFn : ''} + implementation += `${!queryKeyMutator ? queryKeyFn : ''} ${queries.reduce( @@ -1040,82 +1045,84 @@ const generateQueryHook = async ( )} `; - return { - implementation, - mutators: - queryOptionsMutator || queryKeyMutator - ? [ - ...(queryOptionsMutator ? [queryOptionsMutator] : []), - ...(queryKeyMutator ? [queryKeyMutator] : []), - ] - : undefined, - }; + mutators = + queryOptionsMutator || queryKeyMutator + ? [ + ...(queryOptionsMutator ? [queryOptionsMutator] : []), + ...(queryKeyMutator ? [queryKeyMutator] : []), + ] + : undefined; } - const mutationOptionsMutator = query.mutationOptions - ? await generateMutator({ - output, - mutator: query.mutationOptions, - name: `${operationName}MutationOptions`, - workspace: context.workspace, - tsconfig: context.tsconfig, - }) - : undefined; - - const definitions = props - .map(({ definition, type }) => - type === GetterPropType.BODY - ? mutator?.bodyTypeName - ? `data: ${mutator.bodyTypeName}<${body.definition}>` - : `data: ${body.definition}` - : definition, - ) - .join(';'); - - const properties = props - .map(({ name, type }) => (type === GetterPropType.BODY ? 'data' : name)) - .join(','); + const isMutation = + (verb !== Verbs.GET && override.query.useMutation) || + operationQueryOptions?.useMutation; - let errorType = `AxiosError<${response.definition.errors || 'unknown'}>`; + if (isMutation) { + const mutationOptionsMutator = query.mutationOptions + ? await generateMutator({ + output, + mutator: query.mutationOptions, + name: `${operationName}MutationOptions`, + workspace: context.workspace, + tsconfig: context.tsconfig, + }) + : undefined; - if (mutator) { - errorType = mutator.hasErrorType - ? `${mutator.default ? pascal(operationName) : ''}ErrorType<${ - response.definition.errors || 'unknown' - }>` - : response.definition.errors || 'unknown'; - } + const definitions = props + .map(({ definition, type }) => + type === GetterPropType.BODY + ? mutator?.bodyTypeName + ? `data: ${mutator.bodyTypeName}<${body.definition}>` + : `data: ${body.definition}` + : definition, + ) + .join(';'); - const dataType = mutator?.isHook - ? `ReturnType` - : `typeof ${operationName}`; + const properties = props + .map(({ name, type }) => (type === GetterPropType.BODY ? 'data' : name)) + .join(','); - const mutationOptionFnReturnType = getQueryOptionsDefinition({ - operationName, - definitions, - mutator, - hasSvelteQueryV4, - }); + let errorType = `AxiosError<${response.definition.errors || 'unknown'}>`; - const mutationArguments = generateQueryArguments({ - operationName, - definitions, - mutator, - isRequestOptions, - hasSvelteQueryV4, - }); + if (mutator) { + errorType = mutator.hasErrorType + ? `${mutator.default ? pascal(operationName) : ''}ErrorType<${ + response.definition.errors || 'unknown' + }>` + : response.definition.errors || 'unknown'; + } - const mutationOptionsFnName = camel( - mutationOptionsMutator || mutator?.isHook - ? `use-${operationName}-mutationOptions` - : `get-${operationName}-mutationOptions`, - ); + const dataType = mutator?.isHook + ? `ReturnType` + : `typeof ${operationName}`; - const mutationOptionsVarName = isRequestOptions - ? 'mutationOptions' - : 'options'; + const mutationOptionFnReturnType = getQueryOptionsDefinition({ + operationName, + definitions, + mutator, + hasSvelteQueryV4, + }); - const mutationOptionsFn = `export const ${mutationOptionsFnName} = (${mutationArguments}): ${mutationOptionFnReturnType} => { ${ @@ -1138,19 +1145,19 @@ const generateQueryHook = async ( const mutationFn: MutationFunction>, ${ - definitions ? `{${definitions}}` : 'TVariables' - }> = (${properties ? 'props' : ''}) => { + definitions ? `{${definitions}}` : 'TVariables' + }> = (${properties ? 'props' : ''}) => { ${properties ? `const {${properties}} = props ?? {};` : ''} return ${operationName}(${properties}${properties ? ',' : ''}${ - isRequestOptions - ? !mutator - ? `axiosOptions` - : mutator?.hasSecondArg - ? 'requestOptions' + isRequestOptions + ? !mutator + ? `axiosOptions` + : mutator?.hasSecondArg + ? 'requestOptions' + : '' : '' - : '' - }) + }) } ${ @@ -1172,9 +1179,9 @@ const generateQueryHook = async ( : 'customOptions' }}`; - const operationPrefix = hasSvelteQueryV4 ? 'create' : 'use'; + const operationPrefix = hasSvelteQueryV4 ? 'create' : 'use'; - const implementation = ` + implementation += ` ${mutationOptionsFn} export type ${pascal( @@ -1192,22 +1199,27 @@ ${mutationOptionsFn} export type ${pascal(operationName)}MutationError = ${errorType} ${doc}export const ${camel( - `${operationPrefix}-${operationName}`, - )} = (${mutationArguments}) => { const ${mutationOptionsVarName} = ${mutationOptionsFnName}(${ - isRequestOptions ? 'options' : 'mutationOptions' - }); + isRequestOptions ? 'options' : 'mutationOptions' + }); return ${operationPrefix}Mutation(${mutationOptionsVarName}); } `; + mutators = mutationOptionsMutator + ? [...(mutators ?? []), mutationOptionsMutator] + : mutators; + } + return { implementation, - mutators: mutationOptionsMutator ? [mutationOptionsMutator] : undefined, + mutators, }; }; diff --git a/samples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.ts b/samples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.ts index 6a419f6a8..fb1647259 100644 --- a/samples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.ts +++ b/samples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.ts @@ -115,6 +115,9 @@ export type ListPetsInfiniteQueryResult = NonNullable< >; export type ListPetsInfiniteQueryError = ErrorType; +/** + * @summary List all pets + */ export const useListPetsInfinite = < TData = Awaited>, TError = ErrorType, @@ -178,6 +181,9 @@ export type ListPetsQueryResult = NonNullable< >; export type ListPetsQueryError = ErrorType; +/** + * @summary List all pets + */ export const useListPets = < TData = Awaited>, TError = ErrorType, @@ -251,6 +257,9 @@ export type CreatePetsMutationResult = NonNullable< export type CreatePetsMutationBody = CreatePetsBody; export type CreatePetsMutationError = ErrorType; +/** + * @summary Create a pet + */ export const useCreatePets = < TError = ErrorType, TContext = unknown, @@ -315,6 +324,9 @@ export type UpdatePetsMutationResult = NonNullable< export type UpdatePetsMutationBody = NonReadonly; export type UpdatePetsMutationError = ErrorType; +/** + * @summary Update a pet + */ export const useUpdatePets = < TError = ErrorType, TContext = unknown, @@ -384,6 +396,9 @@ export type ShowPetByIdInfiniteQueryResult = NonNullable< >; export type ShowPetByIdInfiniteQueryError = ErrorType; +/** + * @summary Info for a specific pet + */ export const useShowPetByIdInfinite = < TData = Awaited>, TError = ErrorType, @@ -447,6 +462,9 @@ export type ShowPetByIdQueryResult = NonNullable< >; export type ShowPetByIdQueryError = ErrorType; +/** + * @summary Info for a specific pet + */ export const useShowPetById = < TData = Awaited>, TError = ErrorType, diff --git a/samples/react-query/basic/tsconfig.json b/samples/react-query/basic/tsconfig.json index cc6f564df..af362ffaf 100644 --- a/samples/react-query/basic/tsconfig.json +++ b/samples/react-query/basic/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true,