diff --git a/apps/api/src/knowledge/dto/entry-query.dto.ts b/apps/api/src/knowledge/dto/entry-query.dto.ts index 5a5f97b..c455838 100644 --- a/apps/api/src/knowledge/dto/entry-query.dto.ts +++ b/apps/api/src/knowledge/dto/entry-query.dto.ts @@ -1,6 +1,6 @@ -import { IsOptional, IsEnum, IsString, IsInt, Min, Max } from "class-validator"; +import { IsOptional, IsEnum, IsString, IsInt, IsIn, Min, Max } from "class-validator"; import { Type } from "class-transformer"; -import { EntryStatus } from "@prisma/client"; +import { EntryStatus, Visibility } from "@prisma/client"; /** * DTO for querying knowledge entries (list endpoint) @@ -10,10 +10,28 @@ export class EntryQueryDto { @IsEnum(EntryStatus, { message: "status must be a valid EntryStatus" }) status?: EntryStatus; + @IsOptional() + @IsEnum(Visibility, { message: "visibility must be a valid Visibility" }) + visibility?: Visibility; + @IsOptional() @IsString({ message: "tag must be a string" }) tag?: string; + @IsOptional() + @IsString({ message: "search must be a string" }) + search?: string; + + @IsOptional() + @IsIn(["updatedAt", "createdAt", "title"], { + message: "sortBy must be updatedAt, createdAt, or title", + }) + sortBy?: "updatedAt" | "createdAt" | "title"; + + @IsOptional() + @IsIn(["asc", "desc"], { message: "sortOrder must be asc or desc" }) + sortOrder?: "asc" | "desc"; + @IsOptional() @Type(() => Number) @IsInt({ message: "page must be an integer" }) diff --git a/apps/api/src/knowledge/knowledge.service.ts b/apps/api/src/knowledge/knowledge.service.ts index f004d91..e1ef04c 100644 --- a/apps/api/src/knowledge/knowledge.service.ts +++ b/apps/api/src/knowledge/knowledge.service.ts @@ -48,6 +48,10 @@ export class KnowledgeService { where.status = query.status; } + if (query.visibility) { + where.visibility = query.visibility; + } + if (query.tag) { where.tags = { some: { @@ -58,6 +62,20 @@ export class KnowledgeService { }; } + if (query.search) { + where.OR = [ + { title: { contains: query.search, mode: "insensitive" } }, + { content: { contains: query.search, mode: "insensitive" } }, + ]; + } + + // Build orderBy + const sortField = query.sortBy ?? "updatedAt"; + const sortDirection = query.sortOrder ?? "desc"; + const orderBy: Prisma.KnowledgeEntryOrderByWithRelationInput = { + [sortField]: sortDirection, + }; + // Get total count const total = await this.prisma.knowledgeEntry.count({ where }); @@ -71,9 +89,7 @@ export class KnowledgeService { }, }, }, - orderBy: { - updatedAt: "desc", - }, + orderBy, skip, take: limit, });