Files
komp_ac/server/src/table_definition/handlers/get_profile_tree.rs
2025-07-25 18:18:00 +02:00

85 lines
2.8 KiB
Rust

// src/table_definition/handlers/get_profile_tree.rs
use tonic::{Request, Response, Status};
use sqlx::PgPool;
use common::proto::komp_ac::{
common::Empty,
table_definition::{
ProfileTreeResponse,
profile_tree_response::{Table, Profile}
}
};
pub async fn get_profile_tree(
db_pool: &PgPool,
_request: Request<Empty>,
) -> Result<Response<ProfileTreeResponse>, Status> {
let mut profiles = Vec::new();
// Get all schemas (internally changed from profiles to schemas)
let schema_records = sqlx::query!(
"SELECT id, name FROM schemas ORDER BY name"
)
.fetch_all(db_pool)
.await
.map_err(|e| Status::internal(format!("Failed to fetch schemas: {}", e)))?;
for schema in schema_records {
// Get all tables with their dependencies from the links table
let tables = sqlx::query!(
r#"
SELECT
td.id as table_id,
td.table_name,
COALESCE(
json_agg(
json_build_object(
'linked_name', ltd.table_name,
'required', tdl.is_required
)
) FILTER (WHERE ltd.id IS NOT NULL),
'[]'::json
) as dependencies
FROM table_definitions td
LEFT JOIN table_definition_links tdl ON td.id = tdl.source_table_id
LEFT JOIN table_definitions ltd ON tdl.linked_table_id = ltd.id
WHERE td.schema_id = $1
GROUP BY td.id, td.table_name
ORDER BY td.table_name
"#,
schema.id
)
.fetch_all(db_pool)
.await
.map_err(|e| Status::internal(format!("Failed to fetch tables: {}", e)))?;
// Convert to protobuf format
let proto_tables = tables.into_iter()
.map(|record| {
// Handle the Option<Value> properly
let dependencies = record.dependencies
.map(|val| serde_json::from_value::<Vec<serde_json::Value>>(val))
.transpose()
.unwrap_or_else(|_| Some(Vec::new()))
.unwrap_or_default();
Table {
id: record.table_id,
name: record.table_name,
depends_on: dependencies
.into_iter()
.filter_map(|d| d["linked_name"].as_str().map(|s| s.to_string()))
.collect()
}
})
.collect();
// External API still returns "profiles" for compatibility
profiles.push(Profile {
name: schema.name,
tables: proto_tables
});
}
Ok(Response::new(ProfileTreeResponse { profiles }))
}