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