import { ReturnTypeFunc, MutationOptions, Mutation, Args } from '@nestjs/graphql'; import { MetadataStorage } from '../common/metadata-storage.class'; import { InputArgFactory } from './input-arg'; import { PayloadTypeFactory } from './payload-type'; import { getClientMutationId } from './utils'; import { ensurePromise } from './utils/ensure-promise'; export type RelayMutationOptions = Omit<MutationOptions, 'nullable'>; export function RelayMutation<T>( typeFunc: ReturnTypeFunc, options?: RelayMutationOptions, ): MethodDecorator { return (target: Record<string, any>, key: string | symbol, descriptor: PropertyDescriptor) => { const mutationName = options?.name ? options.name : String(key); /** * Resolver Interceptor */ const originalMethod = descriptor.value; descriptor.value = async function (...args: any[]) { const clientMutationId = getClientMutationId(args); const methodResult = await ensurePromise(originalMethod.apply(this, args)); return { ...methodResult, clientMutationId }; }; /** * Input Type */ const params = MetadataStorage.getMethodMetadata({ target, key }); const { paramIndex, ...argOptions } = InputArgFactory.create({ params, mutationName }); const inputArgOptions = { name: 'input', nullable: false, ...argOptions, }; Args(inputArgOptions)(target, key, paramIndex); /** * Payload Type */ const payloadType = PayloadTypeFactory.create({ typeFunc, mutationName }); const mutationOptions: MutationOptions = { ...options, name: mutationName, nullable: true, }; Mutation(() => payloadType, mutationOptions)(target, key, descriptor); }; }