mirror of https://github.com/buster-so/buster.git
update version param on updates for dashboard and metric pushed up
This commit is contained in:
parent
7448967a7d
commit
6adf84b8d3
|
@ -73,6 +73,30 @@ impl VersionHistory {
|
|||
pub fn get_latest_version(&self) -> Option<&Version> {
|
||||
self.0.values().max_by_key(|v| v.version_number)
|
||||
}
|
||||
|
||||
/// Updates the content of the latest version without creating a new version
|
||||
///
|
||||
/// This is used when we want to overwrite the current version instead of creating a new one.
|
||||
/// If there are no versions yet, this will create a new version with number 1.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `content` - The new content to replace the latest version's content
|
||||
pub fn update_latest_version(&mut self, content: impl Into<VersionContent>) {
|
||||
if let Some(latest_version) = self.get_latest_version() {
|
||||
let version_number = latest_version.version_number;
|
||||
self.0.insert(
|
||||
version_number.to_string(),
|
||||
Version {
|
||||
content: content.into(),
|
||||
version_number,
|
||||
updated_at: Utc::now(),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// If there are no versions yet, create a new one with version 1
|
||||
self.add_version(1, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<Jsonb, Pg> for VersionHistory {
|
||||
|
|
|
@ -31,6 +31,7 @@ pub struct DashboardUpdateRequest {
|
|||
pub public: Option<bool>,
|
||||
pub public_expiry_date: Option<String>,
|
||||
pub public_password: Option<String>,
|
||||
pub update_version: Option<bool>,
|
||||
}
|
||||
|
||||
/// Updates an existing dashboard by ID
|
||||
|
@ -140,15 +141,23 @@ pub async fn update_dashboard_handler(
|
|||
.first::<VersionHistory>(&mut conn)
|
||||
.await
|
||||
.unwrap_or_else(|_| VersionHistory::new(0, dashboard_yml.clone()));
|
||||
|
||||
|
||||
// Calculate the next version number
|
||||
let next_version = current_version_history.get_latest_version()
|
||||
.map(|v| v.version_number + 1)
|
||||
.unwrap_or(1);
|
||||
|
||||
// Add the new version to the version history
|
||||
// Add the new version to the version history only if update_version is true (defaults to true)
|
||||
let should_update_version = request.update_version.unwrap_or(true);
|
||||
|
||||
// Only add a new version if has_changes and should_update_version
|
||||
if has_changes {
|
||||
current_version_history.add_version(next_version, dashboard_yml.clone());
|
||||
if should_update_version {
|
||||
current_version_history.add_version(next_version, dashboard_yml.clone());
|
||||
} else {
|
||||
// Overwrite the current version instead of creating a new one
|
||||
current_version_history.update_latest_version(dashboard_yml.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert content to JSON for storage
|
||||
|
@ -171,8 +180,13 @@ pub async fn update_dashboard_handler(
|
|||
if let Some(name) = request.name {
|
||||
// First update the dashboard_yml.name to keep them in sync
|
||||
dashboard_yml.name = name.clone();
|
||||
// Update version history with the updated dashboard_yml
|
||||
current_version_history.add_version(next_version, dashboard_yml.clone());
|
||||
|
||||
// Update version history with the updated dashboard_yml based on should_update_version
|
||||
if should_update_version {
|
||||
current_version_history.add_version(next_version, dashboard_yml.clone());
|
||||
} else {
|
||||
current_version_history.update_latest_version(dashboard_yml.clone());
|
||||
}
|
||||
|
||||
diesel::update(dashboard_files::table)
|
||||
.filter(dashboard_files::id.eq(dashboard_id))
|
||||
|
|
|
@ -12,11 +12,11 @@ use uuid::Uuid;
|
|||
|
||||
/// Recursively merges two JSON objects.
|
||||
/// The second object (update) takes precedence over the first (base) where there are conflicts.
|
||||
///
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base` - The base JSON value, typically the existing configuration
|
||||
/// * `update` - The update JSON value containing fields to update
|
||||
///
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Result<Value>` - The merged JSON value or an error
|
||||
fn merge_json_objects(base: Value, update: Value) -> Result<Value> {
|
||||
|
@ -58,21 +58,22 @@ pub struct UpdateMetricRequest {
|
|||
pub verification: Option<database::enums::Verification>,
|
||||
pub file: Option<String>,
|
||||
pub sql: Option<String>,
|
||||
pub update_version: Option<bool>,
|
||||
}
|
||||
|
||||
/// Handler to update a metric by ID
|
||||
///
|
||||
///
|
||||
/// This handler updates a metric file in the database and increments its version number.
|
||||
/// Each time a metric is updated, the previous version is saved in the version history.
|
||||
///
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `metric_id` - The UUID of the metric to update
|
||||
/// * `user_id` - The UUID of the user making the update
|
||||
/// * `request` - The update request containing the fields to modify
|
||||
///
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Result<BusterMetric>` - The updated metric on success, or an error
|
||||
///
|
||||
///
|
||||
/// # Versioning
|
||||
/// The function automatically handles versioning:
|
||||
/// 1. Retrieves the current metric and extracts its content
|
||||
|
@ -86,7 +87,9 @@ pub async fn update_metric_handler(
|
|||
user_id: &Uuid,
|
||||
request: UpdateMetricRequest,
|
||||
) -> Result<BusterMetric> {
|
||||
let mut conn = get_pg_pool().get().await
|
||||
let mut conn = get_pg_pool()
|
||||
.get()
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to get database connection: {}", e))?;
|
||||
|
||||
// Check if metric exists and user has access - use the latest version
|
||||
|
@ -108,13 +111,13 @@ pub async fn update_metric_handler(
|
|||
if let Some(chart_config) = request.chart_config {
|
||||
// Instead of trying to deserialize directly, we'll merge the JSON objects first
|
||||
// and then deserialize the combined result
|
||||
|
||||
|
||||
// Convert existing chart_config to Value for merging
|
||||
let existing_config = serde_json::to_value(&content.chart_config)?;
|
||||
|
||||
|
||||
// Merge the incoming chart_config with the existing one
|
||||
let merged_config = merge_json_objects(existing_config, chart_config)?;
|
||||
|
||||
|
||||
// Convert merged JSON back to ChartConfig
|
||||
content.chart_config = serde_json::from_value(merged_config)?;
|
||||
}
|
||||
|
@ -143,13 +146,24 @@ pub async fn update_metric_handler(
|
|||
.first::<VersionHistory>(&mut conn)
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to get version history: {}", e))?;
|
||||
|
||||
|
||||
// Calculate the next version number
|
||||
let next_version = metric.versions.len() as i32 + 1;
|
||||
current_version_history.add_version(next_version, content.clone());
|
||||
|
||||
|
||||
// Only add a new version if update_version is true (defaults to true)
|
||||
let should_update_version = request.update_version.unwrap_or(true);
|
||||
|
||||
// Add the new version to the version history or update the latest version
|
||||
if should_update_version {
|
||||
current_version_history.add_version(next_version, content.clone());
|
||||
} else {
|
||||
// Overwrite the current version instead of creating a new one
|
||||
current_version_history.update_latest_version(content.clone());
|
||||
}
|
||||
|
||||
// Convert content to JSON for storage
|
||||
let content_json = serde_json::to_value(content.clone())?;
|
||||
|
||||
|
||||
// Build update query - only verification is handled separately from the YAML content
|
||||
let builder = diesel::update(metric_files::table)
|
||||
.filter(metric_files::id.eq(metric_id))
|
||||
|
@ -177,7 +191,8 @@ pub async fn update_metric_handler(
|
|||
))
|
||||
.execute(&mut conn)
|
||||
.await
|
||||
}.map_err(|e| anyhow!("Failed to update metric: {}", e))?;
|
||||
}
|
||||
.map_err(|e| anyhow!("Failed to update metric: {}", e))?;
|
||||
|
||||
// Return the updated metric - latest version
|
||||
get_metric_handler(metric_id, user_id, None).await
|
||||
|
@ -190,7 +205,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_update_metric_request_validation() {
|
||||
// Test the request struct validation without making actual DB calls
|
||||
|
||||
|
||||
// Create a request with valid UUID format for dataset_ids
|
||||
let valid_request = UpdateMetricRequest {
|
||||
name: Some("Valid Title".to_string()),
|
||||
|
@ -204,22 +219,23 @@ mod tests {
|
|||
verification: Some(database::enums::Verification::NotRequested),
|
||||
file: None,
|
||||
sql: None,
|
||||
update_version: None,
|
||||
};
|
||||
|
||||
|
||||
// Verify the request fields are properly structured
|
||||
assert_eq!(valid_request.name.unwrap(), "Valid Title");
|
||||
assert_eq!(valid_request.description.unwrap(), "Valid Description");
|
||||
assert_eq!(valid_request.time_frame.unwrap(), "daily");
|
||||
assert!(valid_request.chart_config.is_some());
|
||||
assert!(valid_request.dataset_ids.unwrap()[0].len() == 36);
|
||||
|
||||
|
||||
// Actual validation logic is tested in integration tests
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_chart_config_partial_update() {
|
||||
// This test verifies that partial chart_config updates only change specified fields
|
||||
|
||||
|
||||
// Create a mock existing chart_config
|
||||
let existing_config = serde_json::json!({
|
||||
"selectedChartType": "bar",
|
||||
|
@ -241,7 +257,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Create a partial chart_config update that only changes specific fields
|
||||
let partial_config = serde_json::json!({
|
||||
"selectedChartType": "bar", // Same as before
|
||||
|
@ -254,31 +270,44 @@ mod tests {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Apply the deep merge
|
||||
let updated_config = merge_json_objects(existing_config.clone(), partial_config.clone()).unwrap();
|
||||
|
||||
let updated_config =
|
||||
merge_json_objects(existing_config.clone(), partial_config.clone()).unwrap();
|
||||
|
||||
// Verify the updated config has the expected changes
|
||||
|
||||
|
||||
// Changed fields should have new values
|
||||
assert_eq!(updated_config["colors"][0], "#ff0000");
|
||||
assert_eq!(updated_config["colors"][1], "#00ff00");
|
||||
assert_eq!(updated_config["show_legend"], false);
|
||||
|
||||
|
||||
// Unchanged fields should retain original values
|
||||
assert_eq!(updated_config["grid_lines"], true);
|
||||
assert_eq!(updated_config["bar_and_line_axis"]["x"][0], "date");
|
||||
assert_eq!(updated_config["bar_and_line_axis"]["y"][0], "value");
|
||||
|
||||
|
||||
// Verify nested column formats are correctly merged
|
||||
assert_eq!(updated_config["columnLabelFormats"]["date"]["columnType"], "date");
|
||||
assert_eq!(updated_config["columnLabelFormats"]["date"]["style"], "date");
|
||||
|
||||
assert_eq!(
|
||||
updated_config["columnLabelFormats"]["date"]["columnType"],
|
||||
"date"
|
||||
);
|
||||
assert_eq!(
|
||||
updated_config["columnLabelFormats"]["date"]["style"],
|
||||
"date"
|
||||
);
|
||||
|
||||
// This entry should be partially updated - style changed but columnType preserved
|
||||
assert_eq!(updated_config["columnLabelFormats"]["value"]["columnType"], "number");
|
||||
assert_eq!(updated_config["columnLabelFormats"]["value"]["style"], "currency");
|
||||
assert_eq!(
|
||||
updated_config["columnLabelFormats"]["value"]["columnType"],
|
||||
"number"
|
||||
);
|
||||
assert_eq!(
|
||||
updated_config["columnLabelFormats"]["value"]["style"],
|
||||
"currency"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_merge_json_objects() {
|
||||
// Test basic object merging
|
||||
|
@ -290,12 +319,12 @@ mod tests {
|
|||
"b": 3,
|
||||
"c": 4
|
||||
});
|
||||
|
||||
|
||||
let result = merge_json_objects(base, update).unwrap();
|
||||
assert_eq!(result["a"], 1);
|
||||
assert_eq!(result["b"], 3);
|
||||
assert_eq!(result["c"], 4);
|
||||
|
||||
|
||||
// Test nested object merging
|
||||
let base = serde_json::json!({
|
||||
"nested": {
|
||||
|
@ -310,13 +339,13 @@ mod tests {
|
|||
"z": 4
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let result = merge_json_objects(base, update).unwrap();
|
||||
assert_eq!(result["nested"]["x"], 1); // Preserved from base
|
||||
assert_eq!(result["nested"]["y"], 3); // Updated
|
||||
assert_eq!(result["nested"]["z"], 4); // Added from update
|
||||
assert_eq!(result["other"], "value"); // Preserved from base
|
||||
|
||||
assert_eq!(result["nested"]["x"], 1); // Preserved from base
|
||||
assert_eq!(result["nested"]["y"], 3); // Updated
|
||||
assert_eq!(result["nested"]["z"], 4); // Added from update
|
||||
assert_eq!(result["other"], "value"); // Preserved from base
|
||||
|
||||
// Test array replacement
|
||||
let base = serde_json::json!({
|
||||
"arr": [1, 2, 3]
|
||||
|
@ -324,8 +353,8 @@ mod tests {
|
|||
let update = serde_json::json!({
|
||||
"arr": [4, 5]
|
||||
});
|
||||
|
||||
|
||||
let result = merge_json_objects(base, update).unwrap();
|
||||
assert_eq!(result["arr"], serde_json::json!([4, 5])); // Array is replaced, not merged
|
||||
assert_eq!(result["arr"], serde_json::json!([4, 5])); // Array is replaced, not merged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,27 @@
|
|||
use anyhow::Result;
|
||||
use database::{
|
||||
enums::Verification,
|
||||
pool::get_pg_pool,
|
||||
schema::metric_files,
|
||||
types::MetricYml,
|
||||
};
|
||||
use database::{enums::Verification, pool::get_pg_pool, schema::metric_files, types::MetricYml};
|
||||
use diesel::{ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use handlers::metrics::{update_metric_handler, UpdateMetricRequest};
|
||||
use uuid::Uuid;
|
||||
|
||||
// Import the common setup and test data functions
|
||||
use super::{
|
||||
cleanup_test_data, create_test_metric, insert_test_metric, setup_test_environment,
|
||||
};
|
||||
use super::{cleanup_test_data, create_test_metric, insert_test_metric, setup_test_environment};
|
||||
|
||||
/// Integration test for updating a metric that exists in the database
|
||||
#[tokio::test]
|
||||
async fn test_update_metric_integration() -> Result<()> {
|
||||
// Setup test environment
|
||||
setup_test_environment().await?;
|
||||
|
||||
|
||||
// Create test organization and user IDs
|
||||
let organization_id = Uuid::new_v4();
|
||||
let user_id = Uuid::new_v4();
|
||||
|
||||
|
||||
// Create a test metric
|
||||
let test_metric = create_test_metric(organization_id, user_id).await?;
|
||||
let metric_id = test_metric.id;
|
||||
|
||||
|
||||
// Insert the test metric into the database
|
||||
match insert_test_metric(&test_metric).await {
|
||||
Ok(_) => println!("Successfully inserted test metric with ID: {}", metric_id),
|
||||
|
@ -37,7 +30,7 @@ async fn test_update_metric_integration() -> Result<()> {
|
|||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create an update request with various fields to change
|
||||
let update_request = UpdateMetricRequest {
|
||||
name: Some("Updated Test Metric".to_string()),
|
||||
|
@ -55,8 +48,9 @@ async fn test_update_metric_integration() -> Result<()> {
|
|||
verification: Some(Verification::Verified),
|
||||
file: None,
|
||||
sql: Some("SELECT updated_value FROM updated_table".to_string()),
|
||||
update_version: None,
|
||||
};
|
||||
|
||||
|
||||
// Call the handler function to update the metric
|
||||
match update_metric_handler(&metric_id, &user_id, update_request).await {
|
||||
Ok(updated_metric) => {
|
||||
|
@ -64,53 +58,64 @@ async fn test_update_metric_integration() -> Result<()> {
|
|||
assert_eq!(updated_metric.name, "Updated Test Metric");
|
||||
assert_eq!(updated_metric.status, Verification::Verified);
|
||||
assert_eq!(updated_metric.time_frame, "weekly");
|
||||
|
||||
|
||||
// Verify the metric was updated in the database
|
||||
let mut conn = get_pg_pool().get().await?;
|
||||
let db_metric = metric_files::table
|
||||
.filter(metric_files::id.eq(metric_id))
|
||||
.first::<database::models::MetricFile>(&mut conn)
|
||||
.await?;
|
||||
|
||||
|
||||
// Verify database values match the expected updates
|
||||
assert_eq!(db_metric.name, "Updated Test Metric");
|
||||
assert_eq!(db_metric.verification, Verification::Verified);
|
||||
|
||||
|
||||
// Verify the content field was updated
|
||||
let content: MetricYml = db_metric.content;
|
||||
assert_eq!(content.time_frame, "weekly");
|
||||
assert_eq!(content.description, Some("Updated test description".to_string()));
|
||||
assert_eq!(
|
||||
content.description,
|
||||
Some("Updated test description".to_string())
|
||||
);
|
||||
assert_eq!(content.sql, "SELECT updated_value FROM updated_table");
|
||||
|
||||
|
||||
// Verify version history was updated
|
||||
assert!(db_metric.version_history.0.contains_key(&"1".to_string()));
|
||||
assert!(db_metric.version_history.0.contains_key(&"2".to_string()));
|
||||
|
||||
|
||||
// Get the latest version from the version history
|
||||
let latest_version = db_metric.version_history.get_latest_version().unwrap();
|
||||
assert_eq!(latest_version.version_number, 2);
|
||||
|
||||
|
||||
// Verify the latest version's content matches the current content
|
||||
if let database::types::VersionContent::MetricYml(latest_content) = &latest_version.content {
|
||||
if let database::types::VersionContent::MetricYml(latest_content) =
|
||||
&latest_version.content
|
||||
{
|
||||
assert_eq!(latest_content.time_frame, "weekly");
|
||||
assert_eq!(latest_content.description, Some("Updated test description".to_string()));
|
||||
assert_eq!(latest_content.sql, "SELECT updated_value FROM updated_table");
|
||||
assert_eq!(
|
||||
latest_content.description,
|
||||
Some("Updated test description".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
latest_content.sql,
|
||||
"SELECT updated_value FROM updated_table"
|
||||
);
|
||||
} else {
|
||||
panic!("Expected MetricYml content in version history");
|
||||
}
|
||||
|
||||
|
||||
println!("Update metric test passed with ID: {}", metric_id);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
// Clean up the test data regardless of test outcome
|
||||
cleanup_test_data(Some(metric_id), None).await?;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clean up the test data
|
||||
cleanup_test_data(Some(metric_id), None).await?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -119,11 +124,11 @@ async fn test_update_metric_integration() -> Result<()> {
|
|||
async fn test_update_nonexistent_metric() -> Result<()> {
|
||||
// Setup test environment
|
||||
setup_test_environment().await?;
|
||||
|
||||
|
||||
// Generate random UUIDs for test
|
||||
let metric_id = Uuid::new_v4();
|
||||
let user_id = Uuid::new_v4();
|
||||
|
||||
|
||||
// Create a basic update request
|
||||
let update_request = UpdateMetricRequest {
|
||||
name: Some("Updated Test Metric".to_string()),
|
||||
|
@ -134,17 +139,17 @@ async fn test_update_nonexistent_metric() -> Result<()> {
|
|||
verification: None,
|
||||
file: None,
|
||||
sql: None,
|
||||
update_version: None,
|
||||
};
|
||||
|
||||
|
||||
// Attempt to update a nonexistent metric
|
||||
let result = update_metric_handler(&metric_id, &user_id, update_request).await;
|
||||
|
||||
|
||||
// Verify the operation fails with an appropriate error
|
||||
assert!(result.is_err());
|
||||
let error = result.err().unwrap();
|
||||
assert!(error.to_string().contains("not found") ||
|
||||
error.to_string().contains("Failed to get"));
|
||||
|
||||
assert!(error.to_string().contains("not found") || error.to_string().contains("Failed to get"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -153,15 +158,15 @@ async fn test_update_nonexistent_metric() -> Result<()> {
|
|||
async fn test_update_specific_metric_fields() -> Result<()> {
|
||||
// Setup test environment
|
||||
setup_test_environment().await?;
|
||||
|
||||
|
||||
// Create test organization and user IDs
|
||||
let organization_id = Uuid::new_v4();
|
||||
let user_id = Uuid::new_v4();
|
||||
|
||||
|
||||
// Create a test metric
|
||||
let test_metric = create_test_metric(organization_id, user_id).await?;
|
||||
let metric_id = test_metric.id;
|
||||
|
||||
|
||||
// Insert the test metric into the database
|
||||
match insert_test_metric(&test_metric).await {
|
||||
Ok(_) => println!("Successfully inserted test metric with ID: {}", metric_id),
|
||||
|
@ -170,7 +175,7 @@ async fn test_update_specific_metric_fields() -> Result<()> {
|
|||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test 1: Update only title
|
||||
let title_request = UpdateMetricRequest {
|
||||
name: Some("Title Only Update".to_string()),
|
||||
|
@ -181,16 +186,17 @@ async fn test_update_specific_metric_fields() -> Result<()> {
|
|||
verification: None,
|
||||
file: None,
|
||||
sql: None,
|
||||
update_version: None,
|
||||
};
|
||||
|
||||
|
||||
match update_metric_handler(&metric_id, &user_id, title_request).await {
|
||||
Ok(metric) => {
|
||||
assert_eq!(metric.name, "Title Only Update");
|
||||
|
||||
|
||||
// Verify other fields were not changed
|
||||
assert_eq!(metric.time_frame, "daily");
|
||||
assert_eq!(metric.status, Verification::NotRequested);
|
||||
|
||||
|
||||
// Verify version number was incremented
|
||||
assert_eq!(metric.version_number, 2);
|
||||
|
||||
|
@ -200,22 +206,22 @@ async fn test_update_specific_metric_fields() -> Result<()> {
|
|||
.filter(metric_files::id.eq(metric_id))
|
||||
.first::<database::models::MetricFile>(&mut conn)
|
||||
.await?;
|
||||
|
||||
|
||||
// Check version history has exactly 2 versions
|
||||
assert_eq!(db_metric.version_history.0.len(), 2);
|
||||
assert!(db_metric.version_history.0.contains_key(&"1".to_string()));
|
||||
assert!(db_metric.version_history.0.contains_key(&"2".to_string()));
|
||||
|
||||
|
||||
// Get the latest version
|
||||
let latest_version = db_metric.version_history.get_latest_version().unwrap();
|
||||
assert_eq!(latest_version.version_number, 2);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
cleanup_test_data(Some(metric_id), None).await?;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test 2: Update only verification
|
||||
let verification_request = UpdateMetricRequest {
|
||||
name: None,
|
||||
|
@ -226,41 +232,42 @@ async fn test_update_specific_metric_fields() -> Result<()> {
|
|||
verification: Some(Verification::Verified),
|
||||
file: None,
|
||||
sql: None,
|
||||
update_version: None,
|
||||
};
|
||||
|
||||
|
||||
match update_metric_handler(&metric_id, &user_id, verification_request).await {
|
||||
Ok(metric) => {
|
||||
assert_eq!(metric.status, Verification::Verified);
|
||||
|
||||
|
||||
// Verify title remains from previous update
|
||||
assert_eq!(metric.name, "Title Only Update");
|
||||
|
||||
|
||||
// Verify version number increased again
|
||||
assert_eq!(metric.version_number, 3);
|
||||
|
||||
|
||||
// Verify in the database
|
||||
let mut conn = get_pg_pool().get().await?;
|
||||
let db_metric = metric_files::table
|
||||
.filter(metric_files::id.eq(metric_id))
|
||||
.first::<database::models::MetricFile>(&mut conn)
|
||||
.await?;
|
||||
|
||||
|
||||
// Check version history has exactly 3 versions
|
||||
assert_eq!(db_metric.version_history.0.len(), 3);
|
||||
assert!(db_metric.version_history.0.contains_key(&"1".to_string()));
|
||||
assert!(db_metric.version_history.0.contains_key(&"2".to_string()));
|
||||
assert!(db_metric.version_history.0.contains_key(&"3".to_string()));
|
||||
|
||||
|
||||
// Get the latest version
|
||||
let latest_version = db_metric.version_history.get_latest_version().unwrap();
|
||||
assert_eq!(latest_version.version_number, 3);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
cleanup_test_data(Some(metric_id), None).await?;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test 3: Update only SQL
|
||||
let sql_request = UpdateMetricRequest {
|
||||
name: None,
|
||||
|
@ -271,60 +278,66 @@ async fn test_update_specific_metric_fields() -> Result<()> {
|
|||
verification: None,
|
||||
file: None,
|
||||
sql: Some("SELECT new_value FROM new_table".to_string()),
|
||||
update_version: None,
|
||||
};
|
||||
|
||||
|
||||
match update_metric_handler(&metric_id, &user_id, sql_request).await {
|
||||
Ok(metric) => {
|
||||
// Parse the YAML content to verify SQL update
|
||||
let content: MetricYml = serde_yaml::from_str(&metric.file).unwrap();
|
||||
assert_eq!(content.sql, "SELECT new_value FROM new_table");
|
||||
|
||||
|
||||
// Verify other fields remain unchanged
|
||||
assert_eq!(metric.name, "Title Only Update");
|
||||
assert_eq!(metric.status, Verification::Verified);
|
||||
|
||||
|
||||
// Verify version number increased to 4
|
||||
assert_eq!(metric.version_number, 4);
|
||||
|
||||
|
||||
// Verify in the database
|
||||
let mut conn = get_pg_pool().get().await?;
|
||||
let db_metric = metric_files::table
|
||||
.filter(metric_files::id.eq(metric_id))
|
||||
.first::<database::models::MetricFile>(&mut conn)
|
||||
.await?;
|
||||
|
||||
|
||||
// Check version history now has 4 versions
|
||||
assert_eq!(db_metric.version_history.0.len(), 4);
|
||||
|
||||
|
||||
// Verify all version numbers are present
|
||||
for i in 1..=4 {
|
||||
assert!(db_metric.version_history.0.contains_key(&i.to_string()),
|
||||
"Version {} missing from history", i);
|
||||
assert!(
|
||||
db_metric.version_history.0.contains_key(&i.to_string()),
|
||||
"Version {} missing from history",
|
||||
i
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Get the latest version
|
||||
let latest_version = db_metric.version_history.get_latest_version().unwrap();
|
||||
assert_eq!(latest_version.version_number, 4);
|
||||
|
||||
|
||||
// Check the content of the latest version
|
||||
if let database::types::VersionContent::MetricYml(latest_content) = &latest_version.content {
|
||||
if let database::types::VersionContent::MetricYml(latest_content) =
|
||||
&latest_version.content
|
||||
{
|
||||
assert_eq!(latest_content.sql, "SELECT new_value FROM new_table");
|
||||
|
||||
|
||||
// The title should be preserved from earlier updates
|
||||
let yaml = serde_yaml::to_string(latest_content).unwrap();
|
||||
assert!(yaml.contains("Title Only Update"));
|
||||
} else {
|
||||
panic!("Expected MetricYml content in version history");
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
cleanup_test_data(Some(metric_id), None).await?;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clean up the test data
|
||||
cleanup_test_data(Some(metric_id), None).await?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue