Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

search impl #4

Merged
merged 3 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions blog-server-api/src/endpoints/authors/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,25 @@ use screw_api::response::ApiResponse;
use std::sync::Arc;

async fn handler(
query: Option<String>,
offset: Option<i64>,
limit: Option<i64>,
author_service: Arc<Box<dyn AuthorService>>,
) -> Result<AuthorsResponseContentSuccess, AuthorsResponseContentFailure> {
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 {
Expand Down Expand Up @@ -49,6 +57,7 @@ where
{
ApiResponse::from(
handler(
request.content.query,
request.content.offset,
request.content.limit,
request.content.author_service,
Expand Down
2 changes: 2 additions & 0 deletions blog-server-api/src/endpoints/authors/request_content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use screw_api::request::{ApiRequestContent, ApiRequestOriginContent};
use std::sync::Arc;

pub struct AuthorsRequestContent {
pub(super) query: Option<String>,
pub(super) offset: Option<i64>,
pub(super) limit: Option<i64>,
pub(super) author_service: Arc<Box<dyn AuthorService>>,
Expand All @@ -17,6 +18,7 @@ where

fn create(origin_content: ApiRequestOriginContent<Self::Data, Extensions>) -> Self {
Self {
query: origin_content.path.get("query").map(|n| n.to_owned()),
offset: origin_content
.query
.get("offset")
Expand Down
18 changes: 13 additions & 5 deletions blog-server-api/src/endpoints/posts/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,27 @@ 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<String>,
offset: Option<i64>,
limit: Option<i64>,
post_service: Arc<Box<dyn PostService>>,
) -> Result<PostsResponseContentSuccess, PostsResponseContentFailure> {
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 {
Expand Down Expand Up @@ -50,6 +57,7 @@ where
{
ApiResponse::from(
handler(
request.content.query,
request.content.offset,
request.content.limit,
request.content.post_service,
Expand Down
2 changes: 2 additions & 0 deletions blog-server-api/src/endpoints/posts/request_content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use screw_api::request::{ApiRequestContent, ApiRequestOriginContent};
use std::sync::Arc;

pub struct PostsRequestContent {
pub(super) query: Option<String>,
pub(super) offset: Option<i64>,
pub(super) limit: Option<i64>,
pub(super) post_service: Arc<Box<dyn PostService>>,
Expand All @@ -17,6 +18,7 @@ where

fn create(origin_content: ApiRequestOriginContent<Self::Data, Extensions>) -> Self {
Self {
query: origin_content.path.get("query").map(|n| n.to_owned()),
offset: origin_content
.query
.get("offset")
Expand Down
30 changes: 29 additions & 1 deletion blog-server-api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<rbs::Value>,
) -> 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<dyn rbatis::intercept::Intercept>,
> = 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")
Expand Down
12 changes: 12 additions & 0 deletions blog-server-api/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ pub fn make_router<Extensions: ExtensionsProviderType>(
.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:[^/]*}")
Expand Down
38 changes: 35 additions & 3 deletions blog-server-services/src/impls/rbatis_author_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ pub fn create_rbatis_author_service(rb: RBatis) -> Box<dyn AuthorService> {
}

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_offset_and_limit(query: &String, offset: &i64, limit: &i64) =>
"`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}`"});
tikitko marked this conversation as resolved.
Show resolved Hide resolved

impl Author {
#[py_sql(
Expand All @@ -21,6 +26,16 @@ impl Author {
async fn count(rb: &RBatis) -> rbatis::Result<i64> {
impled!()
}
#[py_sql(
"
SELECT COUNT(1) \
FROM author \
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<i64> {
impled!()
}
}

struct RbatisAuthorService {
Expand All @@ -29,6 +44,23 @@ struct RbatisAuthorService {

#[async_trait]
impl AuthorService for RbatisAuthorService {
async fn authors_count_by_query(&self, query: &String) -> DResult<i64> {
Ok(Author::count_by_query(&self.rb, query).await?)
}
async fn authors_by_query(
&self,
query: &String,
offset: &i64,
limit: &i64,
) -> DResult<Vec<Author>> {
Ok(Author::select_all_by_query_with_offset_and_limit(
&mut self.rb.clone(),
query,
offset,
limit,
)
.await?)
}
async fn authors_count(&self) -> DResult<i64> {
Ok(Author::count(&self.rb).await?)
}
Expand Down
4 changes: 2 additions & 2 deletions blog-server-services/src/impls/rbatis_comment_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -59,7 +59,7 @@ impl CommentService for RbatisCommentService {
limit: &i64,
) -> DResult<Vec<Comment>> {
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?,
)
}
Expand Down
47 changes: 47 additions & 0 deletions blog-server-services/src/impls/rbatis_post_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ impl Post {
async fn count(rb: &RBatis) -> rbatis::Result<i64> {
impled!()
}
#[py_sql(
"
SELECT COUNT(1) \
FROM post \
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<i64> {
impled!()
}
#[py_sql(
"
SELECT \
Expand Down Expand Up @@ -82,6 +92,32 @@ impl Post {
) -> rbatis::Result<Vec<Post>> {
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 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} \
"
)]
async fn select_all_by_query_with_limit_and_offset(
rb: &RBatis,
query: &String,
limit: &i64,
offset: &i64,
) -> rbatis::Result<Vec<Post>> {
impled!()
}
}

struct RbatisPostService {
Expand All @@ -90,6 +126,17 @@ struct RbatisPostService {

#[async_trait]
impl PostService for RbatisPostService {
async fn posts_count_by_query(&self, query: &String) -> DResult<i64> {
Ok(Post::count_by_query(&self.rb, query).await?)
}
async fn posts_by_query(
&self,
query: &String,
offset: &i64,
limit: &i64,
) -> DResult<Vec<Post>> {
Ok(Post::select_all_by_query_with_limit_and_offset(&self.rb, query, limit, offset).await?)
}
async fn posts_count(&self) -> DResult<i64> {
Ok(Post::count(&self.rb).await?)
}
Expand Down
7 changes: 7 additions & 0 deletions blog-server-services/src/traits/author_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ pub struct Author {

#[async_trait]
pub trait AuthorService: Send + Sync {
async fn authors_count_by_query(&self, query: &String) -> DResult<i64>;
async fn authors_by_query(
&self,
query: &String,
offset: &i64,
limit: &i64,
) -> DResult<Vec<Author>>;
async fn authors_count(&self) -> DResult<i64>;
async fn authors(&self, offset: &i64, limit: &i64) -> DResult<Vec<Author>>;
async fn author_by_id(&self, id: &i64) -> DResult<Option<Author>>;
Expand Down
3 changes: 3 additions & 0 deletions blog-server-services/src/traits/post_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ pub struct Post {

#[async_trait]
pub trait PostService: Send + Sync {
async fn posts_count_by_query(&self, query: &String) -> DResult<i64>;
async fn posts_by_query(&self, query: &String, offset: &i64, limit: &i64)
-> DResult<Vec<Post>>;
async fn posts_count(&self) -> DResult<i64>;
async fn posts(&self, offset: &i64, limit: &i64) -> DResult<Vec<Post>>;
async fn post_by_id(&self, id: &i64) -> DResult<Option<Post>>;
Expand Down