refactor(file_tools): Enhance file modification and creation processes

- Implement robust line-based content modification for metric and dashboard files
- Add comprehensive error handling and validation for file modifications
- Improve modification tracking with detailed modification results
- Optimize file processing with batch insertion and validation
- Add extensive test coverage for modification and validation logic
This commit is contained in:
dal 2025-02-07 01:29:49 -07:00
parent 0e9075ca2c
commit 94c1635a34
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
2 changed files with 1069 additions and 139 deletions

View File

@ -62,38 +62,125 @@ impl ToolExecutor for CreateFilesTool {
};
let files = params.files;
let mut created_files = vec![];
let mut failed_files = vec![];
// Separate files by type and validate/prepare them
let mut metric_records = vec![];
let mut dashboard_records = vec![];
let mut metric_ymls = vec![];
let mut dashboard_ymls = vec![];
// First pass - validate and prepare all records
for file in files {
match file.file_type.as_str() {
"metric" => match create_metric_file(file.clone()).await {
Ok(f) => {
created_files.push(f);
continue;
"metric" => {
match MetricYml::new(file.yml_content.clone()) {
Ok(metric_yml) => {
if let Some(metric_id) = &metric_yml.id {
let metric_file = MetricFile {
id: metric_id.clone(),
name: metric_yml.title.clone(),
file_name: format!("{}.yml", file.name),
content: serde_json::to_value(metric_yml.clone()).unwrap(),
created_by: Uuid::new_v4(),
verification: Verification::NotRequested,
evaluation_obj: None,
evaluation_summary: None,
evaluation_score: None,
organization_id: Uuid::new_v4(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
};
metric_records.push(metric_file);
metric_ymls.push(metric_yml);
} else {
failed_files.push((file.name, "Metric YML file does not have an id. This should never happen.".to_string()));
}
}
Err(e) => {
failed_files.push((file.name, e.to_string()));
}
}
Err(e) => {
failed_files.push((file.name, e.to_string()));
continue;
}
"dashboard" => {
match DashboardYml::new(file.yml_content.clone()) {
Ok(dashboard_yml) => {
if let Some(dashboard_id) = &dashboard_yml.id {
let dashboard_file = DashboardFile {
id: dashboard_id.clone(),
name: dashboard_yml.name.clone().unwrap_or_else(|| "New Dashboard".to_string()),
file_name: format!("{}.yml", file.name),
content: serde_json::to_value(dashboard_yml.clone()).unwrap(),
filter: None,
organization_id: Uuid::new_v4(),
created_by: Uuid::new_v4(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
};
dashboard_records.push(dashboard_file);
dashboard_ymls.push(dashboard_yml);
} else {
failed_files.push((file.name, "Dashboard YML file does not have an id. This should never happen.".to_string()));
}
}
Err(e) => {
failed_files.push((file.name, e.to_string()));
}
}
},
"dashboard" => match create_dashboard_file(file.clone()).await {
Ok(f) => {
created_files.push(f);
continue;
}
Err(e) => {
failed_files.push((file.name, e.to_string()));
continue;
}
},
}
_ => {
failed_files.push((file.name, format!("Invalid file type: {}. Currently only `metric` and `dashboard` types are supported.", file.file_type)));
continue;
}
};
}
}
// Second pass - bulk insert records
let mut conn = match get_pg_pool().get().await {
Ok(conn) => conn,
Err(e) => return Err(anyhow::anyhow!(e)),
};
// Insert metric files
if !metric_records.is_empty() {
match insert_into(metric_files::table)
.values(&metric_records)
.execute(&mut conn)
.await
{
Ok(_) => {
created_files.extend(metric_ymls.into_iter().map(FileEnum::Metric));
}
Err(e) => {
failed_files.extend(
metric_records
.iter()
.map(|r| (r.file_name.clone(), format!("Failed to create metric file: {}", e))),
);
}
}
}
// Insert dashboard files
if !dashboard_records.is_empty() {
match insert_into(dashboard_files::table)
.values(&dashboard_records)
.execute(&mut conn)
.await
{
Ok(_) => {
created_files.extend(dashboard_ymls.into_iter().map(FileEnum::Dashboard));
}
Err(e) => {
failed_files.extend(
dashboard_records
.iter()
.map(|r| (r.file_name.clone(), format!("Failed to create dashboard file: {}", e))),
);
}
}
}
let message = if failed_files.is_empty() {
@ -164,103 +251,6 @@ impl ToolExecutor for CreateFilesTool {
}
}
async fn create_metric_file(file: FileParams) -> Result<FileEnum> {
let metric_yml = match MetricYml::new(file.yml_content) {
Ok(metric_file) => metric_file,
Err(e) => return Err(e),
};
let mut conn = match get_pg_pool().get().await {
Ok(conn) => conn,
Err(e) => return Err(anyhow::anyhow!(e)),
};
let metric_id = match &metric_yml.id {
Some(id) => id,
None => {
return Err(anyhow::anyhow!(
"Metric YML file does not have an id. This should never happen."
))
}
};
let metric_file_record = MetricFile {
id: metric_id.clone(),
name: metric_yml.title.clone(),
file_name: format!("{}.yml", file.name),
content: serde_json::to_value(metric_yml.clone()).unwrap(),
created_by: Uuid::new_v4(),
verification: Verification::NotRequested,
evaluation_obj: None,
evaluation_summary: None,
evaluation_score: None,
organization_id: Uuid::new_v4(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
};
match insert_into(metric_files::table)
.values(&metric_file_record)
.execute(&mut conn)
.await
{
Ok(metric_file_record) => metric_file_record,
Err(e) => return Err(anyhow::anyhow!("Failed to create metric file: {}", e)),
};
Ok(FileEnum::Metric(metric_yml))
}
async fn create_dashboard_file(file: FileParams) -> Result<FileEnum> {
let dashboard_yml = match DashboardYml::new(file.yml_content) {
Ok(dashboard_file) => dashboard_file,
Err(e) => return Err(e),
};
let mut conn = match get_pg_pool().get().await {
Ok(conn) => conn,
Err(e) => return Err(anyhow::anyhow!(e)),
};
let dashboard_id = match &dashboard_yml.id {
Some(id) => id,
None => {
return Err(anyhow::anyhow!(
"Dashboard YML file does not have an id. This should never happen."
))
}
};
let dashboard_file_record = DashboardFile {
id: dashboard_id.clone(),
name: dashboard_yml
.name
.clone()
.unwrap_or_else(|| "New Dashboard".to_string()),
file_name: format!("{}.yml", file.name),
content: serde_json::to_value(dashboard_yml.clone()).unwrap(),
filter: None,
organization_id: Uuid::new_v4(),
created_by: Uuid::new_v4(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
};
match insert_into(dashboard_files::table)
.values(&dashboard_file_record)
.returning(dashboard_files::all_columns)
.execute(&mut conn)
.await
{
Ok(_) => (),
Err(e) => return Err(anyhow::anyhow!(e)),
};
Ok(FileEnum::Dashboard(dashboard_yml))
}
#[cfg(test)]
mod tests {
use super::*;

File diff suppressed because it is too large Load Diff