// src/table_definition/handlers/get_profile_tree.rs use tonic::{Request, Response, Status}; use sqlx::PgPool; use common::proto::multieko2::{ 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 profiles let profile_records = sqlx::query!("SELECT id, name FROM profiles") .fetch_all(db_pool) .await .map_err(|e| Status::internal(format!("Failed to fetch profiles: {}", e)))?; for profile in profile_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), '[]' ) 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.profile_id = $1 GROUP BY td.id, td.table_name "#, profile.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(); profiles.push(Profile { name: profile.name, tables: proto_tables }); } Ok(Response::new(ProfileTreeResponse { profiles })) }