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

111 lines
2.8 KiB
Rust
Raw Normal View History

2025-03-23 20:42:38 +07:00
use crate::{CountResult, MetaRequestDto, MetaResponseDto, ResponseListSuccessDto};
use anyhow::{bail, Result};
use serde::{de::DeserializeOwned, Serialize};
2025-03-26 13:06:34 +07:00
use serde_json::Value;
use surrealdb::sql::Thing;
2025-03-23 20:42:38 +07:00
use surrealdb::{engine::remote::ws::Client, Surreal};
use super::bind_filter_value;
2025-03-26 13:06:34 +07:00
fn thing_to_string(thing: &Thing) -> String {
format!("{}", thing.id)
}
2025-03-23 20:42:38 +07:00
pub async fn query_list_with_meta<T>(
db: &Surreal<Client>,
table: &str,
meta: &MetaRequestDto,
conditions: Vec<String>,
2025-03-26 13:06:34 +07:00
custom_select: Option<String>,
2025-03-23 20:42:38 +07:00
) -> Result<ResponseListSuccessDto<Vec<T>>>
where
T: DeserializeOwned + Serialize,
{
let page = meta.page.unwrap_or(1);
let per_page = meta.per_page.unwrap_or(10);
if page < 1 || per_page < 1 {
bail!("Invalid pagination: page and per_page must be greater than 0");
}
let start = (page - 1) * per_page;
2025-03-25 10:48:34 +07:00
2025-03-26 13:06:34 +07:00
// SELECT QUERY
let sql = custom_select.unwrap_or_else(|| {
let mut s = format!("SELECT * FROM {}", table);
if !conditions.is_empty() {
s.push_str(" WHERE ");
s.push_str(&conditions.join(" AND "));
}
if let Some(sort_by) = &meta.sort_by {
let order = match meta
.order
.clone()
.unwrap_or_default()
.to_uppercase()
.as_str()
{
"DESC" => "DESC",
_ => "ASC",
};
s.push_str(&format!(" ORDER BY {} {}", sort_by, order));
}
s.push_str(" LIMIT $per_page START $start");
s
});
2025-03-25 10:48:34 +07:00
2025-03-26 13:06:34 +07:00
let mut query_exec = db.query(sql);
2025-03-23 20:42:38 +07:00
if let Some(search) = &meta.search {
if !search.is_empty() {
2025-03-26 13:06:34 +07:00
query_exec = query_exec.bind(("search", search.clone()));
2025-03-23 20:42:38 +07:00
}
}
if let Some(filter_val) = meta.filter.clone() {
2025-03-26 13:06:34 +07:00
query_exec = bind_filter_value(query_exec, filter_val);
2025-03-23 20:42:38 +07:00
}
2025-03-26 13:06:34 +07:00
query_exec = query_exec
.bind(("per_page", per_page))
.bind(("start", start));
2025-03-25 10:48:34 +07:00
2025-03-26 13:06:34 +07:00
let raw: Vec<Value> = query_exec.await?.take(0)?;
let mapped: Vec<T> = raw
.into_iter()
.map(|mut item| {
if let Some(id) = item.get("id").cloned() {
if let Ok(thing) = serde_json::from_value::<Thing>(id.clone()) {
item["id"] = Value::String(thing_to_string(&thing));
}
}
serde_json::from_value(item).unwrap()
})
.collect();
2025-03-25 10:48:34 +07:00
// COUNT QUERY
2025-03-23 20:42:38 +07:00
let mut count_sql = format!("SELECT count() FROM {}", table);
if !conditions.is_empty() {
count_sql.push_str(" WHERE ");
count_sql.push_str(&conditions.join(" AND "));
}
let mut count_query = db.query(count_sql);
2025-03-25 10:48:34 +07:00
if let Some(search) = &meta.search {
if !search.is_empty() {
count_query = count_query.bind(("search", search.clone()));
}
}
2025-03-23 20:42:38 +07:00
if let Some(filter_val) = meta.filter.clone() {
count_query = bind_filter_value(count_query, filter_val);
}
let count_result: Vec<CountResult> = count_query.await?.take(0)?;
let total = count_result.first().map(|c| c.count);
2025-03-25 10:48:34 +07:00
2025-03-23 20:42:38 +07:00
let meta = MetaResponseDto {
page: Some(page),
per_page: Some(per_page),
total,
};
2025-03-25 10:48:34 +07:00
2025-03-23 20:42:38 +07:00
Ok(ResponseListSuccessDto {
2025-03-26 13:06:34 +07:00
data: mapped,
2025-03-23 20:42:38 +07:00
meta: Some(meta),
})
}