bb606f52f5
- Created src/core/tkg/ module with service, log, and models - Added tkg_operation_log table for tracking all TKG operations - TkgService: build, rebuild (with force option), delete, get_operations - Updated rebuild endpoint with force parameter - Added GET /api/v1/file/:file_uuid/tkg for operation history - Added DELETE /api/v1/file/:file_uuid/tkg for TKG deletion - TKG rebuild now always triggers Rule 2 (even with 0 edges) - Full audit trail for all TKG operations (create/update/delete/rebuild)
120 lines
4.1 KiB
Rust
120 lines
4.1 KiB
Rust
use crate::core::db::schema;
|
|
use crate::core::db::PostgresDb;
|
|
use anyhow::Result;
|
|
use sqlx::PgPool;
|
|
|
|
pub struct TkgLogger {
|
|
pool: PgPool,
|
|
pub log_id: Option<i64>,
|
|
}
|
|
|
|
impl TkgLogger {
|
|
pub fn new(pool: PgPool) -> Self {
|
|
Self { pool, log_id: None }
|
|
}
|
|
|
|
pub async fn start_operation(pool: &PgPool, file_uuid: &str, operation: &str) -> Result<i64> {
|
|
let table = schema::table_name("tkg_operation_log");
|
|
let id = sqlx::query_scalar::<_, i64>(&format!(
|
|
"INSERT INTO {table} (file_uuid, operation, status, started_at) \
|
|
VALUES ($1, $2, 'pending', NOW()) RETURNING id"
|
|
))
|
|
.bind(file_uuid)
|
|
.bind(operation)
|
|
.fetch_one(pool)
|
|
.await?;
|
|
tracing::info!("[TKG-Log] Started operation {} for {}", operation, file_uuid);
|
|
Ok(id)
|
|
}
|
|
|
|
pub async fn update_progress(
|
|
&self,
|
|
node_type: &str,
|
|
nodes_created: i32,
|
|
edges_created: i32,
|
|
) -> Result<()> {
|
|
if let Some(log_id) = self.log_id {
|
|
let table = schema::table_name("tkg_operation_log");
|
|
sqlx::query(&format!(
|
|
"UPDATE {table} \
|
|
SET nodes_created = nodes_created + $1, \
|
|
edges_created = edges_created + $2, \
|
|
node_type = COALESCE(node_type, $3) \
|
|
WHERE id = $4"
|
|
))
|
|
.bind(nodes_created)
|
|
.bind(edges_created)
|
|
.bind(node_type)
|
|
.bind(log_id)
|
|
.execute(&self.pool)
|
|
.await?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn complete_operation(&self, error: Option<&str>) -> Result<()> {
|
|
if let Some(log_id) = self.log_id {
|
|
let table = schema::table_name("tkg_operation_log");
|
|
let status = if error.is_some() { "failed" } else { "completed" };
|
|
sqlx::query(&format!(
|
|
"UPDATE {table} \
|
|
SET status = $1, \
|
|
error_message = $2, \
|
|
completed_at = NOW() \
|
|
WHERE id = $3"
|
|
))
|
|
.bind(status)
|
|
.bind(error)
|
|
.bind(log_id)
|
|
.execute(&self.pool)
|
|
.await?;
|
|
tracing::info!("[TKG-Log] Operation {} completed with status: {}", log_id, status);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_operations(pool: &PgPool, file_uuid: &str) -> Result<Vec<crate::core::tkg::models::TkgOperationLog>> {
|
|
let table = schema::table_name("tkg_operation_log");
|
|
let rows = sqlx::query_as::<_, (i64, String, String, Option<String>, Option<String>, i32, i32, i32, i32, i32, i32, String, Option<String>, String, Option<String>, Option<serde_json::Value>)>(&format!(
|
|
"SELECT id, file_uuid, operation, node_type, edge_type, \
|
|
nodes_created, nodes_updated, nodes_deleted, \
|
|
edges_created, edges_updated, edges_deleted, \
|
|
status, error_message, started_at::text, completed_at::text, properties \
|
|
FROM {table} WHERE file_uuid = $1 ORDER BY started_at DESC"
|
|
))
|
|
.bind(file_uuid)
|
|
.fetch_all(pool)
|
|
.await?;
|
|
|
|
Ok(rows.into_iter().map(|r| crate::core::tkg::models::TkgOperationLog {
|
|
id: r.0,
|
|
file_uuid: r.1,
|
|
operation: r.2,
|
|
node_type: r.3,
|
|
edge_type: r.4,
|
|
nodes_created: r.5,
|
|
nodes_updated: r.6,
|
|
nodes_deleted: r.7,
|
|
edges_created: r.8,
|
|
edges_updated: r.9,
|
|
edges_deleted: r.10,
|
|
status: r.11,
|
|
error_message: r.12,
|
|
started_at: r.13,
|
|
completed_at: r.14,
|
|
properties: r.15,
|
|
}).collect())
|
|
}
|
|
|
|
pub async fn delete_operations(pool: &PgPool, file_uuid: &str) -> Result<i64> {
|
|
let table = schema::table_name("tkg_operation_log");
|
|
let result = sqlx::query(&format!(
|
|
"DELETE FROM {table} WHERE file_uuid = $1"
|
|
))
|
|
.bind(file_uuid)
|
|
.execute(pool)
|
|
.await?;
|
|
Ok(result.rows_affected() as i64)
|
|
}
|
|
}
|