import { Prisma } from '@prisma/client'; import { BadRequestException, ConflictException, Injectable, NotFoundException, } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import { CreateCountryDto } from './dto/create-country.dto'; import { UpdateCountryDto } from './dto/update-country.dto'; @Injectable() export class CountriesService { constructor(private readonly prisma: PrismaService) {} findAll() { return this.prisma.country.findMany({ orderBy: { id: 'asc' } }); } async findOne(id: bigint) { const country = await this.prisma.country.findUnique({ where: { id } }); if (!country) { throw new NotFoundException(`Country ${id} not found`); } return country; } async create(dto: CreateCountryDto) { try { return await this.prisma.country.create({ data: { countryName: dto.countryName, countryIcon: dto.countryIcon ?? null, }, }); } catch (err) { if ( err instanceof Prisma.PrismaClientKnownRequestError && err.code === 'P2002' ) { throw new ConflictException('Country name already exists'); } throw err; } } async update(id: bigint, dto: UpdateCountryDto) { await this.findOne(id); try { return await this.prisma.country.update({ where: { id }, data: { countryName: dto.countryName, countryIcon: dto.countryIcon === undefined ? undefined : dto.countryIcon, }, }); } catch (err) { if ( err instanceof Prisma.PrismaClientKnownRequestError && err.code === 'P2002' ) { throw new ConflictException('Country name already exists'); } throw err; } } async remove(id: bigint) { await this.findOne(id); try { return await this.prisma.country.delete({ where: { id } }); } catch (err) { if (this.isForeignKeyViolation(err)) { throw new BadRequestException( 'Country is referenced by goods or positions and cannot be deleted', ); } throw err; } } private isForeignKeyViolation(err: unknown): boolean { if (err instanceof Prisma.PrismaClientKnownRequestError) { // P2003 = FK constraint violation return err.code === 'P2003'; } // Fallback: Prisma sometimes surfaces FK violations as UnknownRequestError // when the constraint check happens server-side before the typed error // is mapped (e.g. cascading RESTRICT). if (err instanceof Prisma.PrismaClientUnknownRequestError) { const msg = err.message ?? ''; return ( msg.includes('foreign key constraint') || msg.includes('RESTRICT') || msg.includes('violates') ); } return false; } }