feat: add logging for SurrealDB queries across multiple repositories

This commit is contained in:
MythEclipse
2025-07-31 16:51:08 +07:00
parent ac06224ed1
commit 86116b8157
9 changed files with 90 additions and 3 deletions
@@ -4,6 +4,7 @@ use imphnen_libs::{AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDt
use imphnen_utils::{DetailQueryBuilder, ListQueryBuilder, get_id, get_iso_date};
use std::time::Instant;
use tracing::instrument;
use tracing::info;
pub struct EventsRepository<'a> {
state: &'a AppState,
@@ -25,6 +26,7 @@ impl<'a> EventsRepository<'a> {
.with_pagination(meta.page, Some(10))
.with_sorting(meta.sort_by.as_deref(), meta.order.as_deref())
.build();
info!(query = %query, "Executing SurrealDB query");
let res: Vec<EventsQueryDto> =
self.state.surrealdb_ws.query(query).await?.take(0)?;
let elapsed = now.elapsed();
@@ -48,6 +50,7 @@ impl<'a> EventsRepository<'a> {
.with_id(&id)
.with_select_fields(vec!["*"]);
let sql = builder.build();
info!(query = %sql, "Executing SurrealDB query");
let result: Option<EventsQueryDto> =
builder.apply_bindings(db.query(sql)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -72,6 +75,8 @@ impl<'a> EventsRepository<'a> {
pub async fn query_create_event(&self, data: EventsSchema) -> Result<String> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
let query_str = format!("CREATE {} CONTENT ...", ResourceEnum::Events.to_string());
info!(query = %query_str, "Executing SurrealDB query");
let record: Option<EventsSchema> = db
.create(ResourceEnum::Events.to_string())
.content(data)
@@ -106,6 +111,8 @@ impl<'a> EventsRepository<'a> {
};
let record_key = get_id(&merged.id)?;
let query_str = format!("UPDATE {:?} MERGE ...", record_key);
info!(query = %query_str, "Executing SurrealDB query");
let record: Option<EventsSchema> = db.update(record_key).merge(merged).await?;
let elapsed = now.elapsed();
if std::env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string())
@@ -130,6 +137,8 @@ impl<'a> EventsRepository<'a> {
}
let record_key = get_id(&event.id)?;
let query_str = format!("UPDATE {:?} MERGE {{ is_deleted: true }}", record_key);
info!(query = %query_str, "Executing SurrealDB query");
let record: Option<EventsSchema> = db
.update(record_key)
.merge(serde_json::json!({ "is_deleted": true }))
@@ -7,6 +7,7 @@ use imphnen_utils::{DetailQueryBuilder, ListQueryBuilder, get_id, get_iso_date};
use serde_json;
use std::time::Instant;
use tracing::instrument;
use tracing::info;
pub struct TestimonialsRepository<'a> {
state: &'a AppState,
@@ -28,6 +29,7 @@ impl<'a> TestimonialsRepository<'a> {
.with_pagination(meta.page, Some(10))
.with_sorting(meta.sort_by.as_deref(), meta.order.as_deref())
.build();
info!(query = %query, "Executing SurrealDB query");
let res: Vec<TestimonialsQueryDto> =
self.state.surrealdb_ws.query(query).await?.take(0)?;
let elapsed = now.elapsed();
@@ -55,6 +57,7 @@ impl<'a> TestimonialsRepository<'a> {
.with_condition("is_deleted = false")
.with_select_fields(vec!["*", "user.* as user"]);
let sql = builder.build();
info!(query = %sql, "Executing SurrealDB query");
let result: Option<TestimonialsQueryDto> =
builder.apply_bindings(db.query(sql)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -82,6 +85,11 @@ impl<'a> TestimonialsRepository<'a> {
) -> Result<String> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
info!(
resource = %ResourceEnum::Testimonials.to_string(),
payload = ?data,
"Executing SurrealDB create"
);
let record: Option<TestimonialsSchema> = db
.create(ResourceEnum::Testimonials.to_string())
.content(data)
@@ -120,6 +128,11 @@ impl<'a> TestimonialsRepository<'a> {
};
let record_key = get_id(&merged.id)?;
info!(
record_key = ?record_key,
payload = ?merged,
"Executing SurrealDB update"
);
let record: Option<TestimonialsSchema> =
db.update(record_key).merge(merged).await?;
let elapsed = now.elapsed();
@@ -145,6 +158,10 @@ impl<'a> TestimonialsRepository<'a> {
}
let record_key = get_id(&testimonial.id)?;
info!(
record_key = ?record_key,
"Executing SurrealDB soft delete"
);
let record: Option<TestimonialsSchema> = db
.update(record_key)
.merge(serde_json::json!({ "is_deleted": true }))
@@ -8,6 +8,7 @@ use imphnen_utils::{DetailQueryBuilder, QueryListBuilder, get_iso_date};
use serde_json::{Map, Value};
use std::time::Instant;
use tracing::instrument;
use tracing::info;
pub struct MentorsRepository<'a> {
pub state: &'a AppState,
@@ -114,6 +115,7 @@ impl<'a> MentorsRepository<'a> {
}
let sql = builder.build();
info!(query = %sql, "Executing SurrealDB query in query_mentor_by_email");
let mentor_opt: Option<MentorDetailWithUserDto> =
builder.apply_bindings(db.query(sql)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -172,6 +174,7 @@ impl<'a> MentorsRepository<'a> {
}
let sql = builder.build();
info!(query = %sql, "Executing SurrealDB query in query_mentor_by_id");
let mentor_opt: Option<MentorDetailWithUserDto> =
builder.apply_bindings(db.query(sql)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -194,8 +197,10 @@ impl<'a> MentorsRepository<'a> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
let dto: MentorInsertDto = data.into();
let resource = ResourceEnum::Mentors.to_string();
info!(query = %resource, "Executing SurrealDB create in query_create_mentor");
let record: Option<MentorSchema> = db
.create(ResourceEnum::Mentors.to_string())
.create(resource)
.content(dto.clone())
.await?;
let elapsed = now.elapsed();
@@ -237,6 +242,7 @@ impl<'a> MentorsRepository<'a> {
merged_data_json.insert("updated_at".to_string(), Value::String(get_iso_date()));
info!(query = ?record_key, "Executing SurrealDB update in query_update_mentor");
let record: Option<MentorSchema> =
db.update(record_key).merge(merged_data_json).await?;
let elapsed = now.elapsed();
@@ -282,6 +288,7 @@ impl<'a> MentorsRepository<'a> {
patch.insert("is_deleted".to_string(), Value::Bool(true));
patch.insert("updated_at".to_string(), Value::String(get_iso_date()));
info!(query = ?record_key, "Executing SurrealDB soft delete in query_delete_mentor");
let record: Option<MentorSchema> = db.update(record_key).merge(patch).await?;
let elapsed = now.elapsed();
if std::env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string())
@@ -3,7 +3,7 @@ use crate::{AppState, ResourceEnum};
use anyhow::{Result, bail};
use imphnen_iam::DetailQueryBuilder;
use std::time::Instant;
use tracing::instrument;
use tracing::{instrument, info};
pub struct GachaClaimRepository<'a> {
state: &'a AppState,
@@ -27,6 +27,7 @@ impl<'a> GachaClaimRepository<'a> {
.with_fetch("item")
.with_fetch("user");
let sql = builder.build();
info!(query = %sql, "Executing SurrealDB query");
let result: Option<GachaClaimQueryDto> =
builder.apply_bindings(db.query(sql)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -48,6 +49,11 @@ impl<'a> GachaClaimRepository<'a> {
) -> Result<String> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
info!(
resource = %ResourceEnum::GachaClaims.to_string(),
content = ?data,
"Executing SurrealDB create query"
);
let record: Option<GachaClaimSchema> = db
.create(ResourceEnum::GachaClaims.to_string())
.content(data)
@@ -4,7 +4,7 @@ use anyhow::{Result, bail};
use imphnen_iam::make_thing;
use std::time::Instant;
use surrealdb::Uuid;
use tracing::instrument;
use tracing::{instrument, info};
pub struct GachaCreditRepository<'a> {
state: &'a AppState,
@@ -27,6 +27,7 @@ impl<'a> GachaCreditRepository<'a> {
ResourceEnum::GachaCredits,
ResourceEnum::Users
);
info!(query = %sql, "Executing SurrealDB query");
let result: Vec<GachaCreditSchema> =
db.query(sql).bind(("user_id", user_id)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -66,6 +67,7 @@ impl<'a> GachaCreditRepository<'a> {
bail!("No extra roll credits remaining");
}
credit.available_rolls -= 1;
info!(operation = "update", table = %ResourceEnum::GachaCredits.to_string(), id = %credit.id.id.to_raw(), "Executing SurrealDB update for consume_credit");
let _: Option<GachaCreditSchema> = db
.update((
&ResourceEnum::GachaCredits.to_string(),
@@ -91,6 +93,7 @@ impl<'a> GachaCreditRepository<'a> {
let db = &self.state.surrealdb_ws;
if let Some(mut credit) = self.query_by_user_id(payload.user_id.clone()).await? {
credit.available_rolls += payload.amount;
info!(operation = "update", table = %ResourceEnum::GachaCredits.to_string(), id = %credit.id.id.to_raw(), "Executing SurrealDB update for add_credit");
let _: Option<GachaCreditSchema> = db
.update((
&ResourceEnum::GachaCredits.to_string(),
@@ -108,6 +111,7 @@ impl<'a> GachaCreditRepository<'a> {
available_rolls: payload.amount,
..Default::default()
};
info!(operation = "create", table = %ResourceEnum::GachaCredits.to_string(), "Executing SurrealDB create for add_credit");
let _: Option<GachaCreditSchema> = db
.create(ResourceEnum::GachaCredits.to_string())
.content(data)
@@ -9,6 +9,7 @@ use imphnen_utils::get_iso_date;
use serde_json::{Map, Value};
use std::time::Instant;
use tracing::instrument;
use tracing::info;
pub struct GachaItemRepository<'a> {
state: &'a AppState,
@@ -25,6 +26,11 @@ impl<'a> GachaItemRepository<'a> {
meta: MetaRequestDto,
) -> Result<ResponseListSuccessDto<Vec<GachaItemDto>>> {
let now = Instant::now();
let surreal_query = format!(
"SELECT * FROM {} WHERE is_deleted = false AND name LIKE ?",
ResourceEnum::GachaItems.to_string()
);
info!(query = %surreal_query, "Executing SurrealDB query");
let raw_result: ResponseListSuccessDto<Vec<GachaItemSchema>> =
QueryListBuilder::new(
&self.state.surrealdb_ws,
@@ -57,6 +63,8 @@ impl<'a> GachaItemRepository<'a> {
pub async fn query_gacha_item_by_id(&self, id: String) -> Result<GachaItemSchema> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
let surreal_query = format!("SELECT * FROM {} WHERE id = '{}'", ResourceEnum::GachaItems.to_string(), id);
info!(query = %surreal_query, "Executing SurrealDB query");
let result: Option<GachaItemSchema> = db
.select((ResourceEnum::GachaItems.to_string(), id.clone()))
.await?;
@@ -79,6 +87,8 @@ impl<'a> GachaItemRepository<'a> {
) -> Result<String> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
let surreal_query = format!("CREATE {} CONTENT ...", ResourceEnum::GachaItems.to_string());
info!(query = %surreal_query, "Executing SurrealDB query");
let record: Option<GachaItemSchema> = db
.create(ResourceEnum::GachaItems.to_string())
.content(data)
@@ -111,6 +121,8 @@ impl<'a> GachaItemRepository<'a> {
created_at: existing.created_at,
..data.clone()
};
let surreal_query = format!("UPDATE {:?} MERGE ...", record_key);
info!(query = %surreal_query, "Executing SurrealDB query");
let record: Option<GachaItemSchema> =
db.update(record_key).merge(merged).await?;
let elapsed = now.elapsed();
@@ -139,6 +151,8 @@ impl<'a> GachaItemRepository<'a> {
patch.insert("is_deleted".to_string(), Value::Bool(true));
patch.insert("updated_at".to_string(), Value::String(get_iso_date()));
let surreal_query = format!("UPDATE {:?} MERGE ...", record_key);
info!(query = %surreal_query, "Executing SurrealDB query");
let record: Option<GachaItemSchema> = db.update(record_key).merge(patch).await?;
let elapsed = now.elapsed();
if std::env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string())
@@ -10,6 +10,7 @@ use rand_distr::weighted::WeightedIndex;
use serde_json::{Map, Value};
use std::time::Instant;
use tracing::instrument;
use tracing::info;
pub struct GachaRollRepository<'a> {
state: &'a AppState,
@@ -33,6 +34,7 @@ impl<'a> GachaRollRepository<'a> {
.with_select_fields(vec!["*"])
.with_fetch("item");
let sql = builder.build();
info!(query = %sql, "Executing SurrealDB query");
let result: Option<GachaRollQueryDto> =
builder.apply_bindings(db.query(sql)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -54,6 +56,7 @@ impl<'a> GachaRollRepository<'a> {
) -> Result<String> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
info!(query = "CREATE", "Executing SurrealDB create operation for GachaRolls");
let record: Option<GachaRollSchema> = db
.create(ResourceEnum::GachaRolls.to_string())
.content(data)
@@ -77,6 +80,7 @@ impl<'a> GachaRollRepository<'a> {
let table_name = ResourceEnum::GachaRolls.to_string();
let sql =
format!("SELECT * FROM {table_name} WHERE is_deleted = false FETCH item");
info!(query = %sql, "Executing SurrealDB query");
let result: Vec<GachaRollQueryDto> = db.query(sql).await?.take(0)?;
let elapsed = now.elapsed();
if std::env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string())
@@ -87,6 +91,7 @@ impl<'a> GachaRollRepository<'a> {
Ok(result)
}
#[instrument]
pub fn roll_once(rolls: &[GachaRollQueryDto]) -> Option<GachaRollQueryDto> {
let filtered: Vec<_> = rolls
.iter()
@@ -120,6 +125,7 @@ impl<'a> GachaRollRepository<'a> {
patch.insert("is_deleted".to_string(), Value::Bool(true));
patch.insert("updated_at".to_string(), Value::String(get_iso_date()));
info!(query = "UPDATE", record_key = ?record_key, "Executing SurrealDB update operation for GachaRolls");
let record: Option<GachaRollSchema> = db.update(record_key).merge(patch).await?;
let elapsed = now.elapsed();
if std::env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string())
@@ -7,6 +7,8 @@ use crate::{
use anyhow::{Result, anyhow, bail};
use chrono::{Duration, Utc};
use surrealdb::sql::Thing;
use tracing::instrument;
use tracing::info;
pub struct AuthRepository<'a> {
pub state: &'a AppState,
@@ -17,6 +19,7 @@ impl<'a> AuthRepository<'a> {
Self { state }
}
#[instrument(skip(self, user), err)]
pub async fn query_store_user(&self, user: UsersDetailQueryDto) -> Result<String> {
if user.email.trim().is_empty() {
bail!("Email is required");
@@ -30,12 +33,14 @@ impl<'a> AuthRepository<'a> {
permissions,
};
info!(query = %format!("DELETE FROM {} WHERE id = '{}'", table, user_id), "Executing SurrealDB query");
let _record: Option<UserCacheSchema> = self
.state
.surrealdb_mem
.delete::<Option<UserCacheSchema>>((table.clone(), user_id.clone()))
.await?;
info!(query = %format!("CREATE {}:{}", table, user_id), "Executing SurrealDB query");
let record: Option<UserCacheSchema> = self
.state
.surrealdb_mem
@@ -49,10 +54,12 @@ impl<'a> AuthRepository<'a> {
}
}
#[instrument(skip(self, email), err)]
pub async fn query_get_stored_user(
&self,
email: String,
) -> Result<UsersDetailQueryDto> {
info!(query = %format!("SELECT FROM {} WHERE id = '{}'", ResourceEnum::UsersCache.to_string(), email), "Executing SurrealDB query");
let user_cache: Option<UserCacheSchema> = self
.state
.surrealdb_mem
@@ -105,7 +112,9 @@ impl<'a> AuthRepository<'a> {
}
}
#[instrument(skip(self, email), err)]
pub async fn query_delete_stored_user(&self, email: String) -> Result<String> {
info!(query = %format!("DELETE FROM {} WHERE id = '{}'", ResourceEnum::UsersCache.to_string(), email), "Executing SurrealDB query");
let record: Option<UsersDetailQueryDto> = self
.state
.surrealdb_mem
@@ -117,13 +126,16 @@ impl<'a> AuthRepository<'a> {
}
}
#[instrument(skip(self, email), err)]
pub async fn query_get_stored_otp(&self, email: String) -> Result<u32> {
let table = ResourceEnum::OtpCache.to_string();
let key = (table.as_str(), email.as_str());
info!(query = %format!("SELECT FROM {} WHERE id = '{}'", table, email), "Executing SurrealDB query");
let result: Option<AuthOtpSchema> = self.state.surrealdb_mem.select(key).await?;
match result {
Some(data) => match Utc::now() > data.expires_at {
true => {
info!(query = %format!("DELETE FROM {} WHERE id = '{}'", table, email), "Executing SurrealDB query");
let _ = self
.state
.surrealdb_mem
@@ -137,9 +149,11 @@ impl<'a> AuthRepository<'a> {
}
}
#[instrument(skip(self, email, otp), err)]
pub async fn query_store_otp(&self, email: String, otp: u32) -> Result<String> {
let expires_at = Utc::now() + Duration::seconds(300);
let table: String = ResourceEnum::OtpCache.to_string();
info!(query = %format!("CREATE {}:{}", table, email), "Executing SurrealDB query");
let record: Option<AuthOtpSchema> = self
.state
.surrealdb_mem
@@ -152,7 +166,9 @@ impl<'a> AuthRepository<'a> {
}
}
#[instrument(skip(self, email), err)]
pub async fn query_delete_stored_otp(&self, email: String) -> Result<String> {
info!(query = %format!("DELETE FROM {} WHERE id = '{}'", ResourceEnum::OtpCache.to_string(), email), "Executing SurrealDB query");
let record: Option<AuthOtpSchema> = self
.state
.surrealdb_mem
@@ -7,6 +7,7 @@ use imphnen_utils::{DetailQueryBuilder, QueryListBuilder, extract_id};
use serde_json;
use std::time::Instant;
use tracing::instrument;
use tracing::info;
pub struct PermissionsRepository<'a> {
state: &'a AppState,
@@ -23,6 +24,7 @@ impl<'a> PermissionsRepository<'a> {
meta: MetaRequestDto,
) -> Result<ResponseListSuccessDto<Vec<PermissionsItemDto>>> {
let now = Instant::now();
info!("Executing SurrealDB query: QueryListBuilder for Permissions with meta: {:?}", meta);
let raw_result: ResponseListSuccessDto<Vec<PermissionsSchema>> =
QueryListBuilder::new(
&self.state.surrealdb_ws,
@@ -61,6 +63,7 @@ impl<'a> PermissionsRepository<'a> {
) -> Result<PermissionsSchema> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
info!(id = %id, "Executing SurrealDB select for Permissions");
let result: Option<PermissionsSchema> = db
.select((ResourceEnum::Permissions.to_string(), id.clone()))
.await?;
@@ -82,6 +85,7 @@ impl<'a> PermissionsRepository<'a> {
id: String,
) -> Result<PermissionsItemDto> {
let now = Instant::now();
info!(id = %id, "Executing transformed_query_permission_by_id (delegates to query_permission_by_id)");
let raw_result = self.query_permission_by_id(id.clone()).await?;
let elapsed = now.elapsed();
if std::env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string())
@@ -109,6 +113,7 @@ impl<'a> PermissionsRepository<'a> {
.with_where("name", Some(name.clone()))
.with_select_fields(vec!["*"]);
let sql = builder.build();
info!(query = %sql, "Executing SurrealDB query");
let result: Option<PermissionsSchema> =
builder.apply_bindings(db.query(sql)).await?.take(0)?;
let elapsed = now.elapsed();
@@ -130,6 +135,7 @@ impl<'a> PermissionsRepository<'a> {
) -> Result<String> {
let now = Instant::now();
let db = &self.state.surrealdb_ws;
info!("Executing SurrealDB create for Permissions with data: {:?}", data);
let record: Option<PermissionsSchema> = db
.create(ResourceEnum::Permissions.to_string())
.content(data)
@@ -162,6 +168,7 @@ impl<'a> PermissionsRepository<'a> {
created_at: existing.created_at,
..data.clone()
};
info!(record_key = ?record_key, "Executing SurrealDB update for Permissions");
let record: Option<PermissionsSchema> =
db.update(record_key).merge(merged).await?;
let elapsed = now.elapsed();
@@ -188,6 +195,7 @@ impl<'a> PermissionsRepository<'a> {
bail!("Permission already deleted");
}
let record_key = get_id(&permission.id)?;
info!(record_key = ?record_key, "Executing SurrealDB soft delete for Permissions");
let record: Option<PermissionsSchema> = db
.update(record_key)
.merge(serde_json::json!({ "is_deleted": true }))