Files
imphnen-backend-service/imphnen-utils/src/query_list.rs
T

117 lines
2.8 KiB
Rust
Raw Normal View History

2025-03-23 20:42:38 +07:00
use crate::{CountResult, MetaRequestDto, MetaResponseDto, ResponseListSuccessDto};
2025-05-17 02:08:59 +07:00
use anyhow::Result;
use serde::{Serialize, de::DeserializeOwned};
use surrealdb::{Surreal, engine::remote::ws::Client};
2025-03-23 20:42:38 +07:00
2025-05-20 16:57:45 +07:00
pub struct QueryListBuilder<'a> {
db: &'a Surreal<Client>,
table: &'a str,
meta: &'a MetaRequestDto,
2025-03-23 20:42:38 +07:00
conditions: Vec<String>,
2025-05-20 16:57:45 +07:00
search_field: String,
select_fields: Option<Vec<&'a str>>,
fetch_fields: Option<Vec<&'a str>>,
}
2025-05-17 02:08:59 +07:00
2025-05-20 16:57:45 +07:00
impl<'a> QueryListBuilder<'a> {
pub fn new(
db: &'a Surreal<Client>,
table: &'a str,
meta: &'a MetaRequestDto,
) -> Self {
Self {
db,
2025-05-20 01:49:50 +07:00
table,
meta,
2025-05-20 16:57:45 +07:00
conditions: vec![],
search_field: "name".to_string(),
select_fields: None,
fetch_fields: None,
}
}
pub fn search_field(mut self, field: &'a str) -> Self {
self.search_field = field.to_string();
self
}
pub fn select_fields(mut self, fields: Vec<&'a str>) -> Self {
self.select_fields = Some(fields);
self
}
pub fn fetch_fields(mut self, fields: Vec<&'a str>) -> Self {
self.fetch_fields = Some(fields);
self
}
pub fn with_condition(mut self, condition: &str) -> Self {
self.conditions.push(condition.to_string());
self
}
pub async fn build<T>(self) -> Result<ResponseListSuccessDto<Vec<T>>>
where
T: DeserializeOwned + Serialize,
{
let page = self.meta.page.unwrap_or(1).max(1);
let per_page = self.meta.per_page.unwrap_or(10).max(1);
let start = (page - 1) * per_page;
let sql = crate::ListQueryBuilder::from_meta(
self.table,
self.meta,
&self.search_field,
self.select_fields,
self.fetch_fields,
2025-05-20 01:49:50 +07:00
)
2025-05-20 16:57:45 +07:00
.build();
2025-05-17 02:08:59 +07:00
2025-05-20 16:57:45 +07:00
let mut query_exec = self.db.query(sql);
if let Some(search) = &self.meta.search {
if !search.is_empty() {
query_exec = query_exec.bind(("search", search.to_lowercase()));
}
2025-03-23 20:42:38 +07:00
}
2025-05-20 16:57:45 +07:00
if let Some(filter_val) = &self.meta.filter {
query_exec = crate::bind_filter_value(query_exec, filter_val.clone());
2025-05-17 02:08:59 +07:00
}
2025-05-20 16:57:45 +07:00
query_exec = query_exec
.bind(("per_page", per_page))
.bind(("start", start));
2025-03-25 10:48:34 +07:00
2025-05-20 16:57:45 +07:00
let raw: Vec<T> = query_exec.await?.take(0)?;
let mut count_query = self.db.query(format!(
"SELECT count() FROM {} {}",
self.table,
if self.conditions.is_empty() {
"".into()
} else {
format!("WHERE {}", self.conditions.join(" AND "))
}
));
if let Some(search) = &self.meta.search {
if !search.is_empty() {
count_query = count_query.bind(("search", search.clone()));
}
}
if let Some(filter_val) = &self.meta.filter {
count_query = crate::bind_filter_value(count_query, filter_val.clone());
}
let count_result: Vec<CountResult> = count_query.await?.take(0)?;
let total = count_result.first().map(|c| c.count);
Ok(ResponseListSuccessDto {
data: raw,
meta: Some(MetaResponseDto {
page: Some(page),
per_page: Some(per_page),
total,
}),
})
}
2025-03-23 20:42:38 +07:00
}