fix: tag feed returns full FeedEntry with author and counts
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 5m2s
test / unit (pull_request) Successful in 16m3s
test / integration (pull_request) Failing after 16m59s
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 5m2s
test / unit (pull_request) Successful in 16m3s
test / integration (pull_request) Failing after 16m59s
This commit is contained in:
@@ -141,6 +141,41 @@ impl FeedRepository for PgFeedRepository {
|
|||||||
|
|
||||||
Ok(Paginated { items: rows.into_iter().map(row_to_entry).collect(), total, page: page.page, per_page: page.per_page })
|
Ok(Paginated { items: rows.into_iter().map(row_to_entry).collect(), total, page: page.page, per_page: page.per_page })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn tag_feed(&self, tag_name: &str, page: &PageParams, _viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||||
|
let total: i64 = sqlx::query_scalar(
|
||||||
|
"SELECT COUNT(*) FROM thoughts t
|
||||||
|
JOIN thought_tags tt ON tt.thought_id = t.id
|
||||||
|
JOIN tags tg ON tg.id = tt.tag_id
|
||||||
|
WHERE tg.name = $1 AND t.visibility = 'public'"
|
||||||
|
)
|
||||||
|
.bind(tag_name)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| DomainError::Internal(e.to_string()))?;
|
||||||
|
|
||||||
|
let sql = format!(
|
||||||
|
"{FEED_SELECT}
|
||||||
|
JOIN thought_tags tt ON tt.thought_id = t.id
|
||||||
|
JOIN tags tg ON tg.id = tt.tag_id
|
||||||
|
WHERE tg.name = $1 AND t.visibility = 'public'
|
||||||
|
ORDER BY t.created_at DESC LIMIT $2 OFFSET $3"
|
||||||
|
);
|
||||||
|
let rows = sqlx::query_as::<_, FeedRow>(&sql)
|
||||||
|
.bind(tag_name)
|
||||||
|
.bind(page.limit())
|
||||||
|
.bind(page.offset())
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| DomainError::Internal(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(Paginated {
|
||||||
|
items: rows.into_iter().map(row_to_entry).collect(),
|
||||||
|
total,
|
||||||
|
page: page.page,
|
||||||
|
per_page: page.per_page,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ use domain::{
|
|||||||
errors::DomainError,
|
errors::DomainError,
|
||||||
models::{
|
models::{
|
||||||
feed::{FeedEntry, PageParams, Paginated, UserSummary},
|
feed::{FeedEntry, PageParams, Paginated, UserSummary},
|
||||||
thought::Thought,
|
|
||||||
user::User,
|
user::User,
|
||||||
},
|
},
|
||||||
ports::{FeedRepository, FollowRepository, TagRepository, ThoughtRepository, UserRepository},
|
ports::{FeedRepository, FollowRepository, ThoughtRepository, UserRepository},
|
||||||
value_objects::UserId,
|
value_objects::UserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,8 +29,8 @@ pub async fn get_following(follows: &dyn FollowRepository, user_id: &UserId, pag
|
|||||||
follows.list_following(user_id, &page).await
|
follows.list_following(user_id, &page).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_by_tag(tags: &dyn TagRepository, tag_name: &str, page: PageParams) -> Result<Paginated<Thought>, DomainError> {
|
pub async fn get_by_tag(feed: &dyn FeedRepository, tag_name: &str, page: PageParams) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||||
tags.list_thoughts_by_tag(tag_name, &page).await
|
feed.tag_feed(tag_name, &page, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn search(feed: &dyn FeedRepository, query: &str, page: PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError> {
|
pub async fn search(feed: &dyn FeedRepository, query: &str, page: PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ pub trait FeedRepository: Send + Sync {
|
|||||||
async fn home_feed(&self, following_ids: &[UserId], page: &PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError>;
|
async fn home_feed(&self, following_ids: &[UserId], 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 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 fn tag_feed(&self, tag_name: &str, page: &PageParams, viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -287,6 +287,9 @@ pub struct TestStore {
|
|||||||
async fn search(&self, _q: &str, _p: &PageParams, _v: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError> {
|
async fn search(&self, _q: &str, _p: &PageParams, _v: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||||
Ok(Paginated { items: vec![], total: 0, page: 1, per_page: 20 })
|
Ok(Paginated { items: vec![], total: 0, page: 1, per_page: 20 })
|
||||||
}
|
}
|
||||||
|
async fn tag_feed(&self, _tag_name: &str, _page: &PageParams, _viewer_id: Option<&UserId>) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||||
|
Ok(Paginated { items: vec![], total: 0, page: 1, per_page: 20 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait] impl SearchPort for TestStore {
|
#[async_trait] impl SearchPort for TestStore {
|
||||||
|
|||||||
@@ -161,21 +161,12 @@ pub async fn tag_thoughts_handler(
|
|||||||
Query(q): Query<PaginationQuery>,
|
Query(q): Query<PaginationQuery>,
|
||||||
) -> Result<Json<serde_json::Value>, ApiError> {
|
) -> Result<Json<serde_json::Value>, ApiError> {
|
||||||
let page = PageParams { page: q.page(), per_page: q.per_page() };
|
let page = PageParams { page: q.page(), per_page: q.per_page() };
|
||||||
let result = get_by_tag(&*s.tags, &tag_name, page).await?;
|
let result = get_by_tag(&*s.feed, &tag_name, page).await?;
|
||||||
Ok(Json(serde_json::json!({
|
Ok(Json(serde_json::json!({
|
||||||
"tag": tag_name,
|
"tag": tag_name,
|
||||||
"total": result.total,
|
"total": result.total,
|
||||||
"page": result.page,
|
"page": result.page,
|
||||||
"per_page": result.per_page,
|
"per_page": result.per_page,
|
||||||
"items": result.items.iter().map(|t| serde_json::json!({
|
"items": result.items.iter().map(to_thought_response).collect::<Vec<_>>(),
|
||||||
"id": t.id.as_uuid(),
|
|
||||||
"content": t.content.as_str(),
|
|
||||||
"in_reply_to_id": t.in_reply_to_id.as_ref().map(|id| id.as_uuid()),
|
|
||||||
"visibility": t.visibility.as_str(),
|
|
||||||
"content_warning": t.content_warning,
|
|
||||||
"sensitive": t.sensitive,
|
|
||||||
"created_at": t.created_at,
|
|
||||||
"updated_at": t.updated_at,
|
|
||||||
})).collect::<Vec<_>>()
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user