import { Resolver, Query, Mutation, Args, ID, Int, ResolveField, Parent } from '@nestjs/graphql'; import { GraphQLUpload } from 'graphql-upload-ts'; import type { FileUpload } from 'graphql-upload-ts'; import { CasesService } from './cases.service'; import { CaseLaw } from './entities/case-law.entity'; import { StorageService } from '../common/storage/storage.service'; import { CaseFileValidationPipe } from '../common/pipes/file-validation.pipe'; import { CaseStatus } from '../generated/prisma/client.js'; @Resolver(() => CaseLaw) export class CasesResolver { constructor( private readonly casesService: CasesService, private readonly storage: StorageService, ) {} @Query(() => CaseLaw, { name: 'caseLaw', nullable: true }) async findOne( @Args('id', { type: () => String, nullable: true }) id?: string, @Args('caseNumber', { type: () => String, nullable: true }) caseNumber?: string, ) { return this.casesService.findOne(id, caseNumber); } @ResolveField(() => String, { name: 'downloadUrl', nullable: true }) async getDownloadUrl(@Parent() caseLaw: CaseLaw): Promise { const key = caseLaw.storageKey; if (!key) return null; return this.storage.getPresignedUrl(key); } @Mutation(() => CaseLaw) async uploadCase( @Args({ name: 'file', type: () => GraphQLUpload }, CaseFileValidationPipe) { createReadStream, filename, mimetype }: FileUpload, ) { const chunks: any[] = []; for await (const chunk of createReadStream()) { chunks.push(chunk); } const buffer = Buffer.concat(chunks); // Buffering into memory like this might not be perfectly "scalable" for 1GB files, // but for this project and 10MB limit it's simpler to handle than passing a stream. return this.casesService.processAndSave(buffer, mimetype, filename); } // An additional simple fetch all endpoint to demonstrate pagination @Query(() => [CaseLaw], { name: 'caseLaws' }) async findAll( @Args('status', { type: () => CaseStatus, nullable: true }) status?: CaseStatus, @Args('take', { type: () => Int, nullable: true, defaultValue: 20 }) take?: number, @Args('skip', { type: () => Int, nullable: true, defaultValue: 0 }) skip?: number, ) { return this.casesService.findAll(status, take, skip); } }