feat: Enhance query builder with new condition methods and safe query execution

This commit is contained in:
MythEclipse
2025-09-22 16:09:22 +07:00
parent 8f981572cd
commit 8cdbca24ba
3 changed files with 96 additions and 8 deletions
+2 -1
View File
@@ -8,7 +8,8 @@ use imphnen_libs::{
};
use imphnen_utils::{
get_id, DetailQueryBuilder, QueryListBuilder, make_thing_from_enum,
build_thing_condition, build_multi_thing_condition, execute_safe_update_query, execute_safe_count_query
build_thing_condition, build_multi_thing_condition, execute_safe_update_query, execute_safe_count_query,
ListQueryBuilder
};
use surrealdb::sql::Thing;
use anyhow::{Result, bail};
-1
View File
@@ -31,4 +31,3 @@ pub use serde_helpers::{
};
pub use validator::*;
pub use csrf_token::*;
pub use surrealdb_helpers::*;
+94 -6
View File
@@ -1,8 +1,10 @@
use anyhow::Result;
use imphnen_libs::MetaRequestDto;
use serde_json::{Map, Value};
use surrealdb::engine::any;
use surrealdb::method::Query;
use surrealdb::sql::Thing;
use surrealdb::Surreal;
pub struct ListQueryBuilder {
resource: String,
@@ -129,12 +131,12 @@ impl ListQueryBuilder {
format!(
r#"
SELECT {} FROM {}
{}
{}
LIMIT {} START {}
{}
"#,
SELECT {} FROM {}
{}
{}
LIMIT {} START {}
{}
"#,
select_clause,
self.resource,
where_clause,
@@ -228,6 +230,18 @@ impl DetailQueryBuilder {
self
}
pub fn with_thing_condition(mut self, field: &str, thing: &Thing) -> Self {
let condition = build_thing_condition(field, thing);
self.conditions.push(condition);
self
}
pub fn with_multi_thing_condition(mut self, conditions: &[(&str, &Thing)]) -> Self {
let condition = build_multi_thing_condition(conditions);
self.conditions.push(condition);
self
}
pub fn with_select_fields(mut self, fields: Vec<&str>) -> Self {
self.select_fields = fields.into_iter().map(String::from).collect();
self
@@ -280,3 +294,77 @@ impl DetailQueryBuilder {
query
}
}
pub fn build_thing_condition(field: &str, thing: &Thing) -> String {
format!("{} = type::thing('{}', '{}')", field, thing.tb, thing.id.to_raw())
}
pub fn build_multi_thing_condition(conditions: &[(&str, &Thing)]) -> String {
conditions
.iter()
.map(|(field, thing)| build_thing_condition(field, thing))
.collect::<Vec<_>>()
.join(" AND ")
}
pub async fn execute_safe_update_query(
db: &Surreal<surrealdb::engine::any::Any>,
query: String,
) -> Result<()> {
let mut result = db.query(query).await?;
let _: Result<Vec<serde_json::Value>, _> = result.take(0);
Ok(())
}
pub async fn execute_safe_count_query(
db: &Surreal<surrealdb::engine::any::Any>,
table: &str,
conditions: &str,
) -> Result<u64> {
let query = format!("SELECT COUNT() AS member_count FROM {} WHERE {}", table, conditions);
let mut result = db.query(query).await?;
let count_result: Vec<serde_json::Value> = result.take(0).unwrap_or_default();
let count = if let Some(first_result) = count_result.first() {
if let Some(count_val) = first_result.get("member_count") {
count_val.as_u64().unwrap_or(0)
} else {
0
}
} else {
0
};
Ok(count)
}
#[cfg(test)]
mod query_builder_tests {
use super::*;
use crate::make_thing_from_enum;
use imphnen_libs::ResourceEnum;
#[test]
fn test_build_thing_condition() {
let team_thing = make_thing_from_enum(ResourceEnum::Teams, "test-id");
let condition = build_thing_condition("team_id", &team_thing);
assert_eq!(condition, "team_id = type::thing('app_teams', 'test-id')");
}
#[test]
fn test_build_multi_thing_condition() {
let team_thing = make_thing_from_enum(ResourceEnum::Teams, "team-id");
let user_thing = make_thing_from_enum(ResourceEnum::Users, "user-id");
let conditions = build_multi_thing_condition(&[
("team_id", &team_thing),
("user_id", &user_thing),
]);
assert_eq!(
conditions,
"team_id = type::thing('app_teams', 'team-id') AND user_id = type::thing('app_users', 'user-id')"
);
}
}