diff --git a/backend/server/src/modules/blog/api/posts/count_tag_filtered_posts.sql b/backend/server/src/modules/blog/api/posts/count_tag_filtered_posts.sql new file mode 100644 index 0000000..8cdd760 --- /dev/null +++ b/backend/server/src/modules/blog/api/posts/count_tag_filtered_posts.sql @@ -0,0 +1,20 @@ +WITH filtered_posts AS + (SELECT p.id, p.date_created + FROM posts p + WHERE $1::text[] IS NULL + OR ( + CASE + WHEN $4 THEN (SELECT COUNT(DISTINCT t.name) + FROM post_tag pt + JOIN tags t ON pt.tag = t.id + WHERE pt.post = p.id + AND t.name = ANY ($1::text[])) = cardinality($1) + ELSE EXISTS (SELECT 1 + FROM post_tag pt + JOIN tags t ON pt.tag = t.id + WHERE pt.post = p.id + AND t.name = ANY ($1::text[])) + END + )) +SELECT COUNT(*) AS total_count +FROM filtered_posts; diff --git a/backend/server/src/modules/blog/api/posts/get.rs b/backend/server/src/modules/blog/api/posts/get.rs index 30841f1..b6ddb58 100644 --- a/backend/server/src/modules/blog/api/posts/get.rs +++ b/backend/server/src/modules/blog/api/posts/get.rs @@ -106,20 +106,25 @@ struct UuidRow { id: Uuid, } -const GET_POST_WITH_BRIEF_MODEL: &str = include_str!("get_post_with_brief_model.sql"); +const I32_PLACEHOLDER: i32 = 0; + +const COUNT_TAG_FILTERED_POSTS: &str = include_str!("count_tag_filtered_posts.sql"); const SELECT_POST_WITH_TAG_FILTER_PAGINATED: &str = include_str!("select_post_with_tag_filter_paginated.sql"); +const GET_POST_WITH_BRIEF_MODEL: &str = include_str!("get_post_with_brief_model.sql"); pub async fn handler( State(db): State, Query(search_params): Query, ) -> impl IntoResponse { - dbg!(&search_params.tags); - dbg!(&search_params.match_all); - let page = search_params.page.unwrap_or(1); let page_size = search_params.page_size.unwrap_or(PAGE_SIZE); - let page_count = match sqlx::query_scalar::<_, i64>("SELECT COUNT(*) FROM posts") + + let page_count = match sqlx::query_scalar::<_, i64>(COUNT_TAG_FILTERED_POSTS) + .bind(&search_params.tags) + .bind(I32_PLACEHOLDER) // not used, but help sqlx/psql hit cache + .bind(I32_PLACEHOLDER) + .bind(search_params.match_all) .fetch_one(&db) .await { diff --git a/backend/server/src/modules/blog/api/posts/select_post_with_tag_filter_paginated.sql b/backend/server/src/modules/blog/api/posts/select_post_with_tag_filter_paginated.sql index b5fa96e..4ad75cd 100644 --- a/backend/server/src/modules/blog/api/posts/select_post_with_tag_filter_paginated.sql +++ b/backend/server/src/modules/blog/api/posts/select_post_with_tag_filter_paginated.sql @@ -1,21 +1,22 @@ -SELECT p.id -FROM posts p -WHERE $1::text[] IS NULL - OR ( - CASE - WHEN $4 THEN (SELECT COUNT(DISTINCT t.name) - FROM post_tag pt - JOIN tags t ON pt.tag = t.id - WHERE pt.post = p.id - AND t.name = ANY ($1::text[])) - = cardinality($1) - ELSE - EXISTS (SELECT 1 - FROM post_tag pt - JOIN tags t ON pt.tag = t.id - WHERE pt.post = p.id - AND t.name = ANY ($1::text[])) - END - ) -ORDER BY p.date_created DESC +WITH filtered_posts AS + (SELECT p.id, p.date_created + FROM posts p + WHERE $1::text[] IS NULL + OR ( + CASE + WHEN $4 THEN (SELECT COUNT(DISTINCT t.name) + FROM post_tag pt + JOIN tags t ON pt.tag = t.id + WHERE pt.post = p.id + AND t.name = ANY ($1::text[])) = cardinality($1) + ELSE EXISTS (SELECT 1 + FROM post_tag pt + JOIN tags t ON pt.tag = t.id + WHERE pt.post = p.id + AND t.name = ANY ($1::text[])) + END + )) +SELECT id +FROM filtered_posts +ORDER BY date_created DESC LIMIT $2 OFFSET $3;