85 lines
2.8 KiB
Rust
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 }))
|
|
}
|