systemprompt_content/services/search/
mod.rs1use crate::error::ContentError;
2use crate::models::{SearchRequest, SearchResponse, SearchResult};
3use crate::repository::{ContentRepository, SearchRepository};
4use systemprompt_database::DbPool;
5use systemprompt_identifiers::CategoryId;
6
7const DEFAULT_SEARCH_LIMIT: i64 = 10;
8
9#[derive(Debug)]
10pub struct SearchService {
11 search_repo: SearchRepository,
12 content_repo: ContentRepository,
13}
14
15impl SearchService {
16 pub fn new(db: &DbPool) -> Result<Self, ContentError> {
17 Ok(Self {
18 search_repo: SearchRepository::new(db)?,
19 content_repo: ContentRepository::new(db)?,
20 })
21 }
22
23 pub async fn search(&self, request: &SearchRequest) -> Result<SearchResponse, ContentError> {
24 let limit = request.limit.unwrap_or(DEFAULT_SEARCH_LIMIT);
25
26 let results = if let Some(filters) = &request.filters {
27 if let Some(category_id) = &filters.category_id {
28 self.search_repo
29 .search_by_category(category_id, limit)
30 .await?
31 } else {
32 vec![]
33 }
34 } else {
35 let content_list = self.content_repo.list_all(limit, 0).await?;
36 content_list
37 .into_iter()
38 .map(Self::content_to_search_result)
39 .collect()
40 };
41
42 Ok(SearchResponse {
43 total: results.len(),
44 results,
45 })
46 }
47
48 pub async fn search_by_category(
49 &self,
50 category_id: &CategoryId,
51 limit: i64,
52 ) -> Result<Vec<SearchResult>, ContentError> {
53 Ok(self
54 .search_repo
55 .search_by_category(category_id, limit)
56 .await?)
57 }
58
59 fn content_to_search_result(content: crate::models::Content) -> SearchResult {
60 SearchResult {
61 id: content.id,
62 title: content.title,
63 slug: content.slug,
64 description: content.description,
65 image: content.image,
66 view_count: 0,
67 source_id: content.source_id,
68 category_id: content.category_id,
69 }
70 }
71}