From 8cdbca24bad2db8b4512b4a1b6f059b30e5d357d Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Mon, 22 Sep 2025 16:09:22 +0700 Subject: [PATCH] feat: Enhance query builder with new condition methods and safe query execution --- imphnen-iam/src/v1/teams/teams_repository.rs | 3 +- imphnen-utils/src/lib.rs | 1 - imphnen-utils/src/query_builder.rs | 100 +++++++++++++++++-- 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/imphnen-iam/src/v1/teams/teams_repository.rs b/imphnen-iam/src/v1/teams/teams_repository.rs index 041e31e..5e69426 100644 --- a/imphnen-iam/src/v1/teams/teams_repository.rs +++ b/imphnen-iam/src/v1/teams/teams_repository.rs @@ -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}; diff --git a/imphnen-utils/src/lib.rs b/imphnen-utils/src/lib.rs index 78dacd4..c386e8c 100644 --- a/imphnen-utils/src/lib.rs +++ b/imphnen-utils/src/lib.rs @@ -31,4 +31,3 @@ pub use serde_helpers::{ }; pub use validator::*; pub use csrf_token::*; -pub use surrealdb_helpers::*; diff --git a/imphnen-utils/src/query_builder.rs b/imphnen-utils/src/query_builder.rs index cbebdff..1949a14 100644 --- a/imphnen-utils/src/query_builder.rs +++ b/imphnen-utils/src/query_builder.rs @@ -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::>() + .join(" AND ") +} + +pub async fn execute_safe_update_query( + db: &Surreal, + query: String, +) -> Result<()> { + let mut result = db.query(query).await?; + let _: Result, _> = result.take(0); + Ok(()) +} + +pub async fn execute_safe_count_query( + db: &Surreal, + table: &str, + conditions: &str, +) -> Result { + let query = format!("SELECT COUNT() AS member_count FROM {} WHERE {}", table, conditions); + let mut result = db.query(query).await?; + + let count_result: Vec = 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')" + ); + } +}