// 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, ) -> Result, 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 properly let dependencies = record.dependencies .map(|val| serde_json::from_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 })) }