From 60ebcf79cd260f007aa46a6d76977791b3df5b43 Mon Sep 17 00:00:00 2001 From: dal Date: Wed, 19 Mar 2025 10:49:56 -0600 Subject: [PATCH] created get_metric_handler_version_query_param --- .../src/dashboards/get_dashboard_handler.rs | 4 +- .../src/metrics/get_metric_data_handler.rs | 4 +- .../src/metrics/get_metric_handler.rs | 52 +++++++++++++------ .../src/metrics/update_metric_handler.rs | 8 +-- .../routes/rest/routes/metrics/get_metric.rs | 22 ++++++-- api/src/routes/ws/metrics/get_metric.rs | 21 ++++++-- 6 files changed, 78 insertions(+), 33 deletions(-) diff --git a/api/libs/handlers/src/dashboards/get_dashboard_handler.rs b/api/libs/handlers/src/dashboards/get_dashboard_handler.rs index a8489f16b..baf3e2b70 100644 --- a/api/libs/handlers/src/dashboards/get_dashboard_handler.rs +++ b/api/libs/handlers/src/dashboards/get_dashboard_handler.rs @@ -89,10 +89,10 @@ pub async fn get_dashboard_handler(dashboard_id: &Uuid, user_id: &Uuid) -> Resul }) .collect(); - // Fetch all metrics concurrently + // Fetch all metrics concurrently (latest versions) let metric_futures: Vec<_> = metric_ids .iter() - .map(|metric_id| get_metric_handler(metric_id, user_id)) + .map(|metric_id| get_metric_handler(metric_id, user_id, None)) .collect(); let metric_results = join_all(metric_futures).await; diff --git a/api/libs/handlers/src/metrics/get_metric_data_handler.rs b/api/libs/handlers/src/metrics/get_metric_data_handler.rs index 4ab6d109f..361bc2f48 100644 --- a/api/libs/handlers/src/metrics/get_metric_data_handler.rs +++ b/api/libs/handlers/src/metrics/get_metric_data_handler.rs @@ -103,8 +103,8 @@ pub async fn get_metric_data_handler( let user_id = user.id; - // Retrieve the metric definition - let metric = get_metric_handler(&request.metric_id, &user_id).await?; + // Retrieve the metric definition (latest version) + let metric = get_metric_handler(&request.metric_id, &user_id, None).await?; // Parse the metric definition from YAML to get SQL and dataset IDs let metric_yml = serde_yaml::from_str::(&metric.file)?; diff --git a/api/libs/handlers/src/metrics/get_metric_handler.rs b/api/libs/handlers/src/metrics/get_metric_handler.rs index f24c59810..fb13925f5 100644 --- a/api/libs/handlers/src/metrics/get_metric_handler.rs +++ b/api/libs/handlers/src/metrics/get_metric_handler.rs @@ -48,8 +48,11 @@ struct UserInfo { avatar_url: Option, } -/// Handler to retrieve a metric by ID -pub async fn get_metric_handler(metric_id: &Uuid, user_id: &Uuid) -> Result { +/// Handler to retrieve a metric by ID with optional version number +/// +/// If version_number is provided, returns that specific version of the metric. +/// If version_number is None, returns the latest version of the metric. +pub async fn get_metric_handler(metric_id: &Uuid, user_id: &Uuid, version_number: Option) -> Result { let mut conn = match get_pg_pool().get().await { Ok(conn) => conn, Err(e) => return Err(anyhow!("Failed to get database connection: {}", e)), @@ -91,16 +94,38 @@ pub async fn get_metric_handler(metric_id: &Uuid, user_id: &Uuid) -> Result (content.clone(), v.version_number), + _ => return Err(anyhow!("Invalid version content type")) + } + } else { + return Err(anyhow!("Version {} not found", version)); + } + } else { + // Get the latest version + if let Some(v) = metric_file.version_history.get_latest_version() { + match &v.content { + database::types::VersionContent::MetricYml(content) => (content.clone(), v.version_number), + _ => return Err(anyhow!("Invalid version content type")) + } + } else { + // Fall back to current content if no version history + (metric_file.content.clone(), 1) + } + }; // Convert content to pretty YAML - let file = match serde_yaml::to_string(&metric_file.content) { + let file = match serde_yaml::to_string(&metric_content) { Ok(yaml) => yaml, Err(e) => return Err(anyhow!("Failed to convert content to YAML: {}", e)), }; - // Parse data metadata from MetricYml - let data_metadata = metric_yml.data_metadata.map(|metadata| { + // Parse data metadata from the selected version's MetricYml + let data_metadata = metric_content.data_metadata.map(|metadata| { DataMetadata { column_count: metadata.len() as i32, column_metadata: metadata @@ -132,7 +157,7 @@ pub async fn get_metric_handler(metric_id: &Uuid, user_id: &Uuid) -> Result Result, +} + pub async fn get_metric_rest_handler( Extension(user): Extension, Path(id): Path, + Query(params): Query, ) -> Result, (StatusCode, &'static str)> { tracing::info!( - "Processing GET request for metric with ID: {}, user_id: {}", + "Processing GET request for metric with ID: {}, user_id: {}, version_number: {:?}", id, - user.id + user.id, + params.version_number ); - let metric = match get_metric_handler(&id, &user.id).await { + let metric = match get_metric_handler(&id, &user.id, params.version_number).await { Ok(response) => response, Err(e) => { tracing::error!("Error getting metric: {}", e); + let error_message = e.to_string(); + // Return 404 if version not found, otherwise 500 + if error_message.contains("Version") && error_message.contains("not found") { + return Err((StatusCode::NOT_FOUND, "Version not found")); + } return Err((StatusCode::INTERNAL_SERVER_ERROR, "Failed to get metric")); } }; diff --git a/api/src/routes/ws/metrics/get_metric.rs b/api/src/routes/ws/metrics/get_metric.rs index 684c25855..5051d2259 100644 --- a/api/src/routes/ws/metrics/get_metric.rs +++ b/api/src/routes/ws/metrics/get_metric.rs @@ -14,25 +14,36 @@ use crate::routes::ws::{ #[derive(Deserialize)] pub struct GetMetricWsRequest { pub id: Uuid, + #[serde(rename = "version_number")] + pub version_number: Option, } pub async fn get_metric(user: &AuthenticatedUser, request: GetMetricWsRequest) -> Result<()> { tracing::info!( - "Processing WebSocket GET request for metric with ID: {}, user_id: {}", + "Processing WebSocket GET request for metric with ID: {}, user_id: {}, version_number: {:?}", request.id, - user.id + user.id, + request.version_number ); - let metric = match get_metric_handler(&request.id, &user.id).await { + let metric = match get_metric_handler(&request.id, &user.id, request.version_number).await { Ok(metric) => metric, Err(e) => { tracing::error!("Error getting metric: {}", e); + let error_message = e.to_string(); + // Use appropriate error code based on the error + let error_code = if error_message.contains("Version") && error_message.contains("not found") { + WsErrorCode::NotFound + } else { + WsErrorCode::InternalServerError + }; + send_error_message( &user.id.to_string(), WsRoutes::Metrics(MetricRoute::Get), WsEvent::Metrics(MetricEvent::GetMetric), - WsErrorCode::InternalServerError, - "Failed to get metric.".to_string(), + error_code, + format!("Failed to get metric: {}", error_message), user, ) .await?;