diff options
Diffstat (limited to 'api/src/modules/categories/categories.controller.ts')
| -rw-r--r-- | api/src/modules/categories/categories.controller.ts | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/api/src/modules/categories/categories.controller.ts b/api/src/modules/categories/categories.controller.ts new file mode 100644 index 0000000..9327932 --- /dev/null +++ b/api/src/modules/categories/categories.controller.ts @@ -0,0 +1,127 @@ +/** + * categories.controller.ts + * Lógica de negócio do CRUD de categorias. + */ + +import type { FastifyReply, FastifyRequest } from 'fastify'; +import { + findAllCategories, + findCategoryById, + findCategoryBySlug, + createCategory, + updateCategory, + deleteCategory, +} from './categories.repository.js'; +import type { + CategoryParams, + CreateCategoryBody, + UpdateCategoryBody, +} from './categories.schema.js'; +import { eq, count } from 'drizzle-orm'; +import { tickets } from '@/db/schema.js'; + +// ─── GET /categories ────────────────────────────────────────────────────────── + +export async function listCategoriesHandler( + request: FastifyRequest, + reply: FastifyReply, +) { + const list = await findAllCategories(request.server.db); + return reply.send(list); +} + +// ─── GET /categories/:id ────────────────────────────────────────────────────── + +export async function getCategoryHandler( + request: FastifyRequest<{ Params: CategoryParams }>, + reply: FastifyReply, +) { + const category = await findCategoryById(request.server.db, request.params.id); + + if (!category) { + return reply.notFound(`Categoria #${request.params.id} não encontrada.`); + } + + return reply.send(category); +} + +// ─── POST /categories ───────────────────────────────────────────────────────── + +export async function createCategoryHandler( + request: FastifyRequest<{ Body: CreateCategoryBody }>, + reply: FastifyReply, +) { + const { name, slug, description } = request.body; + const db = request.server.db; + + // Slug deve ser único + const existing = await findCategoryBySlug(db, slug); + if (existing) { + return reply.conflict(`Já existe uma categoria com o slug "${slug}".`); + } + + const category = await createCategory(db, { + name, + slug, + description: description ?? null, + }); + + return reply.code(201).send(category); +} + +// ─── PATCH /categories/:id ──────────────────────────────────────────────────── + +export async function updateCategoryHandler( + request: FastifyRequest<{ Params: CategoryParams; Body: UpdateCategoryBody }>, + reply: FastifyReply, +) { + const { id } = request.params; + const db = request.server.db; + + const existing = await findCategoryById(db, id); + if (!existing) { + return reply.notFound(`Categoria #${id} não encontrada.`); + } + + // Se o slug está sendo alterado, verifica conflito com outro registro + if (request.body.slug && request.body.slug !== existing.slug) { + const slugConflict = await findCategoryBySlug(db, request.body.slug); + if (slugConflict) { + return reply.conflict(`Já existe uma categoria com o slug "${request.body.slug}".`); + } + } + + const updated = await updateCategory(db, id, request.body); + return reply.send(updated); +} + +// ─── DELETE /categories/:id ─────────────────────────────────────────────────── + +export async function deleteCategoryHandler( + request: FastifyRequest<{ Params: CategoryParams }>, + reply: FastifyReply, +) { + const { id } = request.params; + const db = request.server.db; + + const existing = await findCategoryById(db, id); + if (!existing) { + return reply.notFound(`Categoria #${id} não encontrada.`); + } + + // Protege contra deleção de categoria em uso + const [{ total }] = await db + .select({ total: count() }) + .from(tickets) + .where(eq(tickets.categoryId, id)); + + if (total > 0) { + return reply.conflict( + `Categoria em uso por ${total} chamado(s). Reclassifique-os antes de excluir.`, + ); + } + + await deleteCategory(db, id); + + return reply.code(204).send(); +} |