pandektes-challenge/src/cases/cases.resolver.ts
2026-03-01 13:05:49 +01:00

60 lines
2.3 KiB
TypeScript

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<string | null> {
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);
}
}