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};
|
2025-06-29 23:23:18 +07:00
|
|
|
use surrealdb::Surreal;
|
|
|
|
|
use surrealdb::engine::any;
|
2025-03-23 20:42:38 +07:00
|
|
|
|
2025-05-20 16:57:45 +07:00
|
|
|
pub struct QueryListBuilder<'a> {
|
2025-06-29 23:23:18 +07:00
|
|
|
db: &'a Surreal<any::Any>,
|
2025-05-20 16:57:45 +07:00
|
|
|
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(
|
2025-06-29 23:23:18 +07:00
|
|
|
db: &'a Surreal<any::Any>,
|
2025-05-20 16:57:45 +07:00
|
|
|
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
|
|
|
}
|