Files
playzer/apps/backend/src/modules/sport/services/sport.service.ts
Jose Selesan c9ecdd2c77 Add interface design references and principles; implement sport service tests
- Introduced critique, example, principles, and validation documents for interface design.
- Enhanced backend service with coverage threshold and fixed variable declaration in sport service.
- Added comprehensive tests for create, update, and list sports functionalities.
2026-04-24 10:40:25 -03:00

107 lines
2.3 KiB
TypeScript

import { Prisma, Sport } from '@/generated/prisma/client';
import { Errors } from '@/lib/errors';
import { db } from '@/lib/prisma';
import { err, ok, Result } from '@/lib/result';
import { v7 as uuidv7 } from 'uuid';
export type CreateSportInput = {
name: string;
};
export type UpdateSportInput = {
name?: string;
isActive?: boolean;
};
function slugify(value: string): string {
return value
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase()
.trim()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-');
}
async function buildUniqueSlug(source: string, excludeSportId?: string): Promise<string> {
const base = slugify(source);
const fallback = base.length > 0 ? base : `sport-${uuidv7().slice(0, 8)}`;
let candidate = fallback;
let index = 1;
while (true) {
const existing = await db.sport.findFirst({
where: {
slug: candidate,
...(excludeSportId
? {
id: {
not: excludeSportId,
},
}
: {}),
},
select: { id: true },
});
if (!existing) return candidate;
index += 1;
candidate = `${fallback}-${index}`;
}
}
export async function listSports(): Promise<Result<Sport[]>> {
const sports = await db.sport.findMany({
orderBy: { name: 'asc' },
});
return ok(sports);
}
export async function createSport(input: CreateSportInput) {
const slug = await buildUniqueSlug(input.name);
const existing = await db.sport.count({
where: { slug },
});
if (existing > 0) {
return err(Errors.conflict('Ya existe un deporte con ese nombre.'));
}
const created = await db.sport.create({
data: {
id: uuidv7(),
name: input.name.trim(),
slug,
isActive: true,
},
});
return ok(created);
}
export async function getSportById(id: string) {
return db.sport.findUnique({ where: { id } });
}
export async function updateSport(id: string, input: UpdateSportInput) {
const data: Prisma.SportUncheckedUpdateInput = {};
if (input.name) {
data.name = input.name;
data.slug = await buildUniqueSlug(input.name, id);
}
if (input.isActive !== undefined) {
data.isActive = input.isActive;
}
return db.sport.update({
where: { id },
data,
});
}