feat(knowledge): add search service

This commit is contained in:
Jason Woltje
2026-01-29 20:35:07 -06:00
parent c6a65869c6
commit c26b7d4e64
7 changed files with 1109 additions and 3 deletions

View File

@@ -3,3 +3,8 @@ export { UpdateEntryDto } from "./update-entry.dto";
export { EntryQueryDto } from "./entry-query.dto";
export { CreateTagDto } from "./create-tag.dto";
export { UpdateTagDto } from "./update-tag.dto";
export {
SearchQueryDto,
TagSearchDto,
RecentEntriesDto,
} from "./search-query.dto";

View File

@@ -0,0 +1,81 @@
import {
IsOptional,
IsString,
IsInt,
Min,
Max,
IsArray,
IsEnum,
} from "class-validator";
import { Type, Transform } from "class-transformer";
import { EntryStatus } from "@prisma/client";
/**
* DTO for full-text search query parameters
*/
export class SearchQueryDto {
@IsString({ message: "q (query) must be a string" })
q!: string;
@IsOptional()
@IsEnum(EntryStatus, { message: "status must be a valid EntryStatus" })
status?: EntryStatus;
@IsOptional()
@Type(() => Number)
@IsInt({ message: "page must be an integer" })
@Min(1, { message: "page must be at least 1" })
page?: number;
@IsOptional()
@Type(() => Number)
@IsInt({ message: "limit must be an integer" })
@Min(1, { message: "limit must be at least 1" })
@Max(100, { message: "limit must not exceed 100" })
limit?: number;
}
/**
* DTO for searching by tags
*/
export class TagSearchDto {
@Transform(({ value }) =>
typeof value === "string" ? value.split(",") : value
)
@IsArray({ message: "tags must be an array" })
@IsString({ each: true, message: "each tag must be a string" })
tags!: string[];
@IsOptional()
@IsEnum(EntryStatus, { message: "status must be a valid EntryStatus" })
status?: EntryStatus;
@IsOptional()
@Type(() => Number)
@IsInt({ message: "page must be an integer" })
@Min(1, { message: "page must be at least 1" })
page?: number;
@IsOptional()
@Type(() => Number)
@IsInt({ message: "limit must be an integer" })
@Min(1, { message: "limit must be at least 1" })
@Max(100, { message: "limit must not exceed 100" })
limit?: number;
}
/**
* DTO for recent entries query
*/
export class RecentEntriesDto {
@IsOptional()
@Type(() => Number)
@IsInt({ message: "limit must be an integer" })
@Min(1, { message: "limit must be at least 1" })
@Max(50, { message: "limit must not exceed 50" })
limit?: number;
@IsOptional()
@IsEnum(EntryStatus, { message: "status must be a valid EntryStatus" })
status?: EntryStatus;
}