feat(domain): SearchPort trait with thought and user search
This commit is contained in:
@@ -136,3 +136,21 @@ pub trait FeedRepository: Send + Sync {
|
|||||||
async fn public_feed(&self, page: &PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError>;
|
async fn public_feed(&self, page: &PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError>;
|
||||||
async fn search(&self, query: &str, page: &PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError>;
|
async fn search(&self, query: &str, page: &PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait SearchPort: Send + Sync {
|
||||||
|
/// Full-text search over public thoughts, ranked by trigram similarity.
|
||||||
|
async fn search_thoughts(
|
||||||
|
&self,
|
||||||
|
query: &str,
|
||||||
|
page: &PageParams,
|
||||||
|
viewer_id: Option<&UserId>,
|
||||||
|
) -> Result<Paginated<FeedEntry>, DomainError>;
|
||||||
|
|
||||||
|
/// Search users by username or display_name, ranked by trigram similarity.
|
||||||
|
async fn search_users(
|
||||||
|
&self,
|
||||||
|
query: &str,
|
||||||
|
page: &PageParams,
|
||||||
|
) -> Result<Paginated<User>, DomainError>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -282,6 +282,15 @@ pub struct TestStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait] impl SearchPort for TestStore {
|
||||||
|
async fn search_thoughts(&self, _q: &str, _p: &PageParams, _v: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||||
|
Ok(Paginated { items: vec![], total: 0, page: 1, per_page: 20 })
|
||||||
|
}
|
||||||
|
async fn search_users(&self, _q: &str, _p: &PageParams) -> Result<Paginated<User>, DomainError> {
|
||||||
|
Ok(Paginated { items: vec![], total: 0, page: 1, per_page: 20 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait] impl EventPublisher for TestStore {
|
#[async_trait] impl EventPublisher for TestStore {
|
||||||
async fn publish(&self, event: &DomainEvent) -> Result<(), DomainError> {
|
async fn publish(&self, event: &DomainEvent) -> Result<(), DomainError> {
|
||||||
self.events.lock().unwrap().push(event.clone());
|
self.events.lock().unwrap().push(event.clone());
|
||||||
@@ -293,3 +302,23 @@ pub struct NoOpEventPublisher;
|
|||||||
#[async_trait] impl EventPublisher for NoOpEventPublisher {
|
#[async_trait] impl EventPublisher for NoOpEventPublisher {
|
||||||
async fn publish(&self, _e: &DomainEvent) -> Result<(), DomainError> { Ok(()) }
|
async fn publish(&self, _e: &DomainEvent) -> Result<(), DomainError> { Ok(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod search_tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::models::feed::PageParams;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_store_search_thoughts_returns_empty() {
|
||||||
|
let store = TestStore::default();
|
||||||
|
let result = store.search_thoughts("hello", &PageParams { page: 1, per_page: 20 }, None).await.unwrap();
|
||||||
|
assert_eq!(result.total, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_store_search_users_returns_empty() {
|
||||||
|
let store = TestStore::default();
|
||||||
|
let result = store.search_users("alice", &PageParams { page: 1, per_page: 20 }).await.unwrap();
|
||||||
|
assert_eq!(result.total, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user