From 8127f1da8fdd2e60ea663594138825ecf4cf4a29 Mon Sep 17 00:00:00 2001 From: tikitko Date: Sun, 9 Jul 2023 21:58:17 +0300 Subject: [PATCH 1/3] search impl --- .../src/endpoints/authors/handler.rs | 17 +++++-- .../src/endpoints/authors/request_content.rs | 2 + .../src/endpoints/posts/handler.rs | 18 +++++-- .../src/endpoints/posts/request_content.rs | 2 + blog-server-api/src/main.rs | 30 +++++++++++- blog-server-api/src/router.rs | 12 +++++ .../src/impls/rbatis_author_service.rs | 38 +++++++++++++-- .../src/impls/rbatis_comment_service.rs | 4 +- .../src/impls/rbatis_post_service.rs | 47 +++++++++++++++++++ .../src/traits/author_service.rs | 7 +++ .../src/traits/post_service.rs | 3 ++ 11 files changed, 165 insertions(+), 15 deletions(-) diff --git a/blog-server-api/src/endpoints/authors/handler.rs b/blog-server-api/src/endpoints/authors/handler.rs index beb269e..392005e 100644 --- a/blog-server-api/src/endpoints/authors/handler.rs +++ b/blog-server-api/src/endpoints/authors/handler.rs @@ -9,6 +9,7 @@ use screw_api::response::ApiResponse; use std::sync::Arc; async fn handler( + query: Option, offset: Option, limit: Option, author_service: Arc>, @@ -16,10 +17,17 @@ async fn handler( let offset = offset.unwrap_or(0).max(0); let limit = limit.unwrap_or(50).max(0).min(50); - let (authors_result, total_result) = tokio::join!( - author_service.authors(&offset, &limit), - author_service.authors_count(), - ); + let (authors_result, total_result) = if let Some(query) = query { + tokio::join!( + author_service.authors_by_query(&query, &offset, &limit), + author_service.authors_count_by_query(&query), + ) + } else { + tokio::join!( + author_service.authors(&offset, &limit), + author_service.authors_count(), + ) + }; let authors = authors_result .map_err(|e| DatabaseError { @@ -49,6 +57,7 @@ where { ApiResponse::from( handler( + request.content.query, request.content.offset, request.content.limit, request.content.author_service, diff --git a/blog-server-api/src/endpoints/authors/request_content.rs b/blog-server-api/src/endpoints/authors/request_content.rs index 4d5f867..a9ec6a3 100644 --- a/blog-server-api/src/endpoints/authors/request_content.rs +++ b/blog-server-api/src/endpoints/authors/request_content.rs @@ -4,6 +4,7 @@ use screw_api::request::{ApiRequestContent, ApiRequestOriginContent}; use std::sync::Arc; pub struct AuthorsRequestContent { + pub(super) query: Option, pub(super) offset: Option, pub(super) limit: Option, pub(super) author_service: Arc>, @@ -17,6 +18,7 @@ where fn create(origin_content: ApiRequestOriginContent) -> Self { Self { + query: origin_content.path.get("query").map(|n| n.to_owned()), offset: origin_content .query .get("offset") diff --git a/blog-server-api/src/endpoints/posts/handler.rs b/blog-server-api/src/endpoints/posts/handler.rs index aca5cee..43cc57b 100644 --- a/blog-server-api/src/endpoints/posts/handler.rs +++ b/blog-server-api/src/endpoints/posts/handler.rs @@ -7,9 +7,9 @@ use blog_server_services::traits::post_service::PostService; use screw_api::request::ApiRequest; use screw_api::response::ApiResponse; use std::sync::Arc; -use tokio::join; async fn handler( + query: Option, offset: Option, limit: Option, post_service: Arc>, @@ -17,10 +17,17 @@ async fn handler( let offset = offset.unwrap_or(0).max(0); let limit = limit.unwrap_or(50).max(0).min(50); - let (posts_result, total_result) = join!( - post_service.posts(&offset, &limit), - post_service.posts_count(), - ); + let (posts_result, total_result) = if let Some(query) = query { + tokio::join!( + post_service.posts_by_query(&query, &offset, &limit), + post_service.posts_count_by_query(&query), + ) + } else { + tokio::join!( + post_service.posts(&offset, &limit), + post_service.posts_count(), + ) + }; let posts = posts_result .map_err(|e| DatabaseError { @@ -50,6 +57,7 @@ where { ApiResponse::from( handler( + request.content.query, request.content.offset, request.content.limit, request.content.post_service, diff --git a/blog-server-api/src/endpoints/posts/request_content.rs b/blog-server-api/src/endpoints/posts/request_content.rs index 816e0bf..de11b0c 100644 --- a/blog-server-api/src/endpoints/posts/request_content.rs +++ b/blog-server-api/src/endpoints/posts/request_content.rs @@ -4,6 +4,7 @@ use screw_api::request::{ApiRequestContent, ApiRequestOriginContent}; use std::sync::Arc; pub struct PostsRequestContent { + pub(super) query: Option, pub(super) offset: Option, pub(super) limit: Option, pub(super) post_service: Arc>, @@ -17,6 +18,7 @@ where fn create(origin_content: ApiRequestOriginContent) -> Self { Self { + query: origin_content.path.get("query").map(|n| n.to_owned()), offset: origin_content .query .get("offset") diff --git a/blog-server-api/src/main.rs b/blog-server-api/src/main.rs index 274cdbe..d58000b 100644 --- a/blog-server-api/src/main.rs +++ b/blog-server-api/src/main.rs @@ -26,8 +26,36 @@ async fn main() -> screw_components::dyn_result::DResult<()> { Ok(()) } +#[derive(Debug)] +struct DbgRbatisIntercept; + +impl rbatis::intercept::Intercept for DbgRbatisIntercept { + fn before( + &self, + _task_id: i64, + _rb: &dyn rbatis::executor::Executor, + sql: &mut String, + args: &mut Vec, + ) -> Result<(), rbatis::Error> { + dbg!(sql); + dbg!(args); + Ok(()) + } +} + pub async fn init_db() -> rbatis::RBatis { - let rb = rbatis::RBatis::new(); + let opt = rbatis::RBatisOption { + intercepts: { + let intercepts: rbatis::dark_std::sync::SyncVec< + std::sync::Arc, + > = rbatis::dark_std::sync::SyncVec::new(); + if cfg!(debug_assertions) { + intercepts.push(std::sync::Arc::new(DbgRbatisIntercept)); + } + intercepts + }, + }; + let rb = rbatis::RBatis::new_with_opt(opt); rb.init( rbdc_pg::driver::PgDriver {}, std::env::var("PG_URL") diff --git a/blog-server-api/src/router.rs b/blog-server-api/src/router.rs index 97ba42c..02128a8 100644 --- a/blog-server-api/src/router.rs +++ b/blog-server-api/src/router.rs @@ -80,6 +80,18 @@ pub fn make_router( .and_path("/posts") .and_handler(posts::http_handler), ) + .scoped("/search", |r| { + r.route( + route::first::Route::with_method(&hyper::Method::GET) + .and_path("/posts/{query:[^/]*}") + .and_handler(posts::http_handler), + ) + .route( + route::first::Route::with_method(&hyper::Method::GET) + .and_path("/authors/{query:[^/]*}") + .and_handler(authors::http_handler), + ) + }) .route( route::first::Route::with_method(&hyper::Method::GET) .and_path("/comments/{post_slug:[^/]*}") diff --git a/blog-server-services/src/impls/rbatis_author_service.rs b/blog-server-services/src/impls/rbatis_author_service.rs index 005347c..1a90e89 100644 --- a/blog-server-services/src/impls/rbatis_author_service.rs +++ b/blog-server-services/src/impls/rbatis_author_service.rs @@ -7,9 +7,14 @@ pub fn create_rbatis_author_service(rb: RBatis) -> Box { } impl_insert!(BaseAuthor {}, "author"); -impl_select!(Author {select_by_id(id: &i64) -> Option => "`WHERE id = #{id} LIMIT 1`"}); -impl_select!(Author {select_by_slug(slug: &String) -> Option => "`WHERE slug = #{slug} LIMIT 1`"}); -impl_select!(Author {select_all_with_offset_and_limit(offset: &i64, limit: &i64) => "`LIMIT #{limit} OFFSET #{offset}`"}); +impl_select!(Author {select_by_id(id: &i64) -> Option => + "`WHERE id = #{id} LIMIT 1`"}); +impl_select!(Author {select_by_slug(slug: &String) -> Option => + "`WHERE slug = #{slug} LIMIT 1`"}); +impl_select!(Author {select_all_with_offset_and_limit(offset: &i64, limit: &i64) => + "`LIMIT #{limit} OFFSET #{offset}`"}); +impl_select!(Author {select_all_by_query_with_limit_and_offset(query: &String, offset: &i64, limit: &i64) => + "`WHERE author.slug LIKE '%#{query}%' OR author.first_name LIKE '%#{query}%' OR author.middle_name LIKE '%#{query}%' OR author.last_name LIKE '%#{query}%' LIMIT #{limit} OFFSET #{offset}`"}); impl Author { #[py_sql( @@ -21,6 +26,16 @@ impl Author { async fn count(rb: &RBatis) -> rbatis::Result { impled!() } + #[py_sql( + " + SELECT COUNT(1) \ + FROM author \ + WHERE author.slug LIKE '%#{query}%' OR author.first_name LIKE '%#{query}%' OR author.middle_name LIKE '%#{query}%' OR author.last_name LIKE '%#{query}%' \ + " + )] + async fn count_by_query(rb: &RBatis, query: &String) -> rbatis::Result { + impled!() + } } struct RbatisAuthorService { @@ -29,6 +44,23 @@ struct RbatisAuthorService { #[async_trait] impl AuthorService for RbatisAuthorService { + async fn authors_count_by_query(&self, query: &String) -> DResult { + Ok(Author::count_by_query(&self.rb, query).await?) + } + async fn authors_by_query( + &self, + query: &String, + offset: &i64, + limit: &i64, + ) -> DResult> { + Ok(Author::select_all_by_query_with_limit_and_offset( + &mut self.rb.clone(), + query, + offset, + limit, + ) + .await?) + } async fn authors_count(&self) -> DResult { Ok(Author::count(&self.rb).await?) } diff --git a/blog-server-services/src/impls/rbatis_comment_service.rs b/blog-server-services/src/impls/rbatis_comment_service.rs index 7104be6..762ac02 100644 --- a/blog-server-services/src/impls/rbatis_comment_service.rs +++ b/blog-server-services/src/impls/rbatis_comment_service.rs @@ -33,7 +33,7 @@ impl Comment { OFFSET #{offset} \ " )] - async fn select_all_with_post_id_and_limit_and_offset( + async fn select_all_by_post_id_with_limit_and_offset( rb: &RBatis, post_id: &i64, limit: &i64, @@ -59,7 +59,7 @@ impl CommentService for RbatisCommentService { limit: &i64, ) -> DResult> { Ok( - Comment::select_all_with_post_id_and_limit_and_offset(&self.rb, post_id, limit, offset) + Comment::select_all_by_post_id_with_limit_and_offset(&self.rb, post_id, limit, offset) .await?, ) } diff --git a/blog-server-services/src/impls/rbatis_post_service.rs b/blog-server-services/src/impls/rbatis_post_service.rs index 8c79b63..518457e 100644 --- a/blog-server-services/src/impls/rbatis_post_service.rs +++ b/blog-server-services/src/impls/rbatis_post_service.rs @@ -18,6 +18,16 @@ impl Post { async fn count(rb: &RBatis) -> rbatis::Result { impled!() } + #[py_sql( + " + SELECT COUNT(1) \ + FROM post \ + WHERE post.title LIKE '%#{query}%' OR post.summary LIKE '%#{query}%' OR post.content LIKE '%#{query}%' \ + " + )] + async fn count_by_query(rb: &RBatis, query: &String) -> rbatis::Result { + impled!() + } #[py_sql( " SELECT \ @@ -82,6 +92,32 @@ impl Post { ) -> rbatis::Result> { impled!() } + #[py_sql( + " + SELECT \ + post.*, \ + author.slug AS author_slug, \ + author.first_name AS author_first_name, \ + author.last_name AS author_last_name, \ + string_agg(concat_ws(',', tag.slug, tag.title), ';') as tags \ + FROM post \ + JOIN author ON post.author_id = author.id \ + LEFT JOIN post_tag ON post_tag.post_id = post.id \ + LEFT JOIN tag ON tag.id = post_tag.tag_id \ + WHERE post.title LIKE '%#{query}%' OR post.summary LIKE '%#{query}%' OR post.content LIKE '%#{query}%' \ + GROUP BY post.id, author.slug, author.first_name, author.last_name \ + LIMIT #{limit} \ + OFFSET #{offset} \ + " + )] + async fn select_all_by_query_with_limit_and_offset( + rb: &RBatis, + query: &String, + limit: &i64, + offset: &i64, + ) -> rbatis::Result> { + impled!() + } } struct RbatisPostService { @@ -90,6 +126,17 @@ struct RbatisPostService { #[async_trait] impl PostService for RbatisPostService { + async fn posts_count_by_query(&self, query: &String) -> DResult { + Ok(Post::count_by_query(&self.rb, query).await?) + } + async fn posts_by_query( + &self, + query: &String, + offset: &i64, + limit: &i64, + ) -> DResult> { + Ok(Post::select_all_by_query_with_limit_and_offset(&self.rb, query, limit, offset).await?) + } async fn posts_count(&self) -> DResult { Ok(Post::count(&self.rb).await?) } diff --git a/blog-server-services/src/traits/author_service.rs b/blog-server-services/src/traits/author_service.rs index b80e8af..2acf0f4 100644 --- a/blog-server-services/src/traits/author_service.rs +++ b/blog-server-services/src/traits/author_service.rs @@ -25,6 +25,13 @@ pub struct Author { #[async_trait] pub trait AuthorService: Send + Sync { + async fn authors_count_by_query(&self, query: &String) -> DResult; + async fn authors_by_query( + &self, + query: &String, + offset: &i64, + limit: &i64, + ) -> DResult>; async fn authors_count(&self) -> DResult; async fn authors(&self, offset: &i64, limit: &i64) -> DResult>; async fn author_by_id(&self, id: &i64) -> DResult>; diff --git a/blog-server-services/src/traits/post_service.rs b/blog-server-services/src/traits/post_service.rs index 033a151..9fd4e03 100644 --- a/blog-server-services/src/traits/post_service.rs +++ b/blog-server-services/src/traits/post_service.rs @@ -27,6 +27,9 @@ pub struct Post { #[async_trait] pub trait PostService: Send + Sync { + async fn posts_count_by_query(&self, query: &String) -> DResult; + async fn posts_by_query(&self, query: &String, offset: &i64, limit: &i64) + -> DResult>; async fn posts_count(&self) -> DResult; async fn posts(&self, offset: &i64, limit: &i64) -> DResult>; async fn post_by_id(&self, id: &i64) -> DResult>; From 4c4dbd96a0470d491d8db84a76c75d8d1121b93b Mon Sep 17 00:00:00 2001 From: tikitko Date: Sun, 9 Jul 2023 22:11:15 +0300 Subject: [PATCH 2/3] typo --- blog-server-services/src/impls/rbatis_author_service.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blog-server-services/src/impls/rbatis_author_service.rs b/blog-server-services/src/impls/rbatis_author_service.rs index 1a90e89..251f7e7 100644 --- a/blog-server-services/src/impls/rbatis_author_service.rs +++ b/blog-server-services/src/impls/rbatis_author_service.rs @@ -13,7 +13,7 @@ impl_select!(Author {select_by_slug(slug: &String) -> Option => "`WHERE slug = #{slug} LIMIT 1`"}); impl_select!(Author {select_all_with_offset_and_limit(offset: &i64, limit: &i64) => "`LIMIT #{limit} OFFSET #{offset}`"}); -impl_select!(Author {select_all_by_query_with_limit_and_offset(query: &String, offset: &i64, limit: &i64) => +impl_select!(Author {select_all_by_query_with_offset_and_limit(query: &String, offset: &i64, limit: &i64) => "`WHERE author.slug LIKE '%#{query}%' OR author.first_name LIKE '%#{query}%' OR author.middle_name LIKE '%#{query}%' OR author.last_name LIKE '%#{query}%' LIMIT #{limit} OFFSET #{offset}`"}); impl Author { @@ -53,7 +53,7 @@ impl AuthorService for RbatisAuthorService { offset: &i64, limit: &i64, ) -> DResult> { - Ok(Author::select_all_by_query_with_limit_and_offset( + Ok(Author::select_all_by_query_with_offset_and_limit( &mut self.rb.clone(), query, offset, From 7e57752f7f6daa4fdf10de759a6e5b62c308c226 Mon Sep 17 00:00:00 2001 From: tikitko Date: Mon, 10 Jul 2023 10:47:54 +0300 Subject: [PATCH 3/3] fixed sqls --- blog-server-services/src/impls/rbatis_author_service.rs | 4 ++-- blog-server-services/src/impls/rbatis_post_service.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/blog-server-services/src/impls/rbatis_author_service.rs b/blog-server-services/src/impls/rbatis_author_service.rs index 251f7e7..ac537c1 100644 --- a/blog-server-services/src/impls/rbatis_author_service.rs +++ b/blog-server-services/src/impls/rbatis_author_service.rs @@ -14,7 +14,7 @@ impl_select!(Author {select_by_slug(slug: &String) -> Option => impl_select!(Author {select_all_with_offset_and_limit(offset: &i64, limit: &i64) => "`LIMIT #{limit} OFFSET #{offset}`"}); impl_select!(Author {select_all_by_query_with_offset_and_limit(query: &String, offset: &i64, limit: &i64) => - "`WHERE author.slug LIKE '%#{query}%' OR author.first_name LIKE '%#{query}%' OR author.middle_name LIKE '%#{query}%' OR author.last_name LIKE '%#{query}%' LIMIT #{limit} OFFSET #{offset}`"}); + "`WHERE author.slug ILIKE '%' || #{query} || '%' OR author.first_name ILIKE '%' || #{query} || '%' OR author.middle_name ILIKE '%' || #{query} || '%' OR author.last_name ILIKE '%' || #{query} || '%' LIMIT #{limit} OFFSET #{offset}`"}); impl Author { #[py_sql( @@ -30,7 +30,7 @@ impl Author { " SELECT COUNT(1) \ FROM author \ - WHERE author.slug LIKE '%#{query}%' OR author.first_name LIKE '%#{query}%' OR author.middle_name LIKE '%#{query}%' OR author.last_name LIKE '%#{query}%' \ + WHERE author.slug ILIKE '%' || #{query} || '%' OR author.first_name ILIKE '%' || #{query} || '%' OR author.middle_name ILIKE '%' || #{query} || '%' OR author.last_name ILIKE '%' || #{query} || '%' \ " )] async fn count_by_query(rb: &RBatis, query: &String) -> rbatis::Result { diff --git a/blog-server-services/src/impls/rbatis_post_service.rs b/blog-server-services/src/impls/rbatis_post_service.rs index 518457e..1a16f00 100644 --- a/blog-server-services/src/impls/rbatis_post_service.rs +++ b/blog-server-services/src/impls/rbatis_post_service.rs @@ -22,7 +22,7 @@ impl Post { " SELECT COUNT(1) \ FROM post \ - WHERE post.title LIKE '%#{query}%' OR post.summary LIKE '%#{query}%' OR post.content LIKE '%#{query}%' \ + WHERE post.title ILIKE '%' || #{query} || '%' OR post.summary ILIKE '%' || #{query} || '%' OR post.content ILIKE '%' || #{query} || '%' \ " )] async fn count_by_query(rb: &RBatis, query: &String) -> rbatis::Result { @@ -104,7 +104,7 @@ impl Post { JOIN author ON post.author_id = author.id \ LEFT JOIN post_tag ON post_tag.post_id = post.id \ LEFT JOIN tag ON tag.id = post_tag.tag_id \ - WHERE post.title LIKE '%#{query}%' OR post.summary LIKE '%#{query}%' OR post.content LIKE '%#{query}%' \ + WHERE post.title ILIKE '%' || #{query} || '%' OR post.summary ILIKE '%' || #{query} || '%' OR post.content ILIKE '%' || #{query} || '%' \ GROUP BY post.id, author.slug, author.first_name, author.last_name \ LIMIT #{limit} \ OFFSET #{offset} \