149 lines
5.0 KiB
Rust
149 lines
5.0 KiB
Rust
// src/tui/functions/common/form.rs
|
|
use crate::services::grpc_client::GrpcClient;
|
|
use crate::state::app::state::AppState;
|
|
use crate::utils::data_converter;
|
|
use anyhow::{anyhow, Context, Result};
|
|
use std::collections::HashMap;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum SaveOutcome {
|
|
NoChange,
|
|
UpdatedExisting,
|
|
CreatedNew(i64),
|
|
}
|
|
|
|
pub async fn save(
|
|
app_state: &mut AppState,
|
|
grpc_client: &mut GrpcClient,
|
|
) -> Result<SaveOutcome> {
|
|
if let Some(fs) = app_state.form_state_mut() {
|
|
if !fs.has_unsaved_changes {
|
|
return Ok(SaveOutcome::NoChange);
|
|
}
|
|
|
|
// Copy out what we need before dropping the mutable borrow
|
|
let profile_name = fs.profile_name.clone();
|
|
let table_name = fs.table_name.clone();
|
|
let fields = fs.fields.clone();
|
|
let values = fs.values.clone();
|
|
let id = fs.id;
|
|
let total_count = fs.total_count;
|
|
let current_position = fs.current_position;
|
|
|
|
let cache_key = format!("{}.{}", profile_name, table_name);
|
|
let schema = app_state
|
|
.schema_cache
|
|
.get(&cache_key)
|
|
.ok_or_else(|| {
|
|
anyhow!(
|
|
"Schema for table '{}' not found in cache. Cannot save.",
|
|
table_name
|
|
)
|
|
})?;
|
|
|
|
let data_map: HashMap<String, String> = fields
|
|
.iter()
|
|
.zip(values.iter())
|
|
.map(|(field_def, value)| (field_def.data_key.clone(), value.clone()))
|
|
.collect();
|
|
|
|
let converted_data =
|
|
data_converter::convert_and_validate_data(&data_map, schema)
|
|
.map_err(|user_error| anyhow!(user_error))?;
|
|
|
|
let is_new_entry = id == 0
|
|
|| (total_count > 0 && current_position > total_count)
|
|
|| (total_count == 0 && current_position == 1);
|
|
|
|
let outcome = if is_new_entry {
|
|
let response = grpc_client
|
|
.post_table_data(profile_name.clone(), table_name.clone(), converted_data)
|
|
.await
|
|
.context("Failed to post new table data")?;
|
|
|
|
if response.success {
|
|
if let Some(fs) = app_state.form_state_mut() {
|
|
fs.id = response.inserted_id;
|
|
fs.total_count += 1;
|
|
fs.current_position = fs.total_count;
|
|
fs.has_unsaved_changes = false;
|
|
}
|
|
SaveOutcome::CreatedNew(response.inserted_id)
|
|
} else {
|
|
return Err(anyhow!("Server failed to insert data: {}", response.message));
|
|
}
|
|
} else {
|
|
if id == 0 {
|
|
return Err(anyhow!(
|
|
"Cannot update record: ID is 0, but not classified as new entry."
|
|
));
|
|
}
|
|
let response = grpc_client
|
|
.put_table_data(profile_name.clone(), table_name.clone(), id, converted_data)
|
|
.await
|
|
.context("Failed to put (update) table data")?;
|
|
|
|
if response.success {
|
|
if let Some(fs) = app_state.form_state_mut() {
|
|
fs.has_unsaved_changes = false;
|
|
}
|
|
SaveOutcome::UpdatedExisting
|
|
} else {
|
|
return Err(anyhow!("Server failed to update data: {}", response.message));
|
|
}
|
|
};
|
|
|
|
Ok(outcome)
|
|
} else {
|
|
Ok(SaveOutcome::NoChange)
|
|
}
|
|
}
|
|
|
|
pub async fn revert(
|
|
app_state: &mut AppState,
|
|
grpc_client: &mut GrpcClient,
|
|
) -> Result<String> {
|
|
if let Some(fs) = app_state.form_state_mut() {
|
|
if fs.id == 0
|
|
|| (fs.total_count > 0 && fs.current_position > fs.total_count)
|
|
|| (fs.total_count == 0 && fs.current_position == 1)
|
|
{
|
|
let old_total_count = fs.total_count;
|
|
fs.reset_to_empty();
|
|
fs.total_count = old_total_count;
|
|
if fs.total_count > 0 {
|
|
fs.current_position = fs.total_count + 1;
|
|
} else {
|
|
fs.current_position = 1;
|
|
}
|
|
return Ok("New entry cleared".to_string());
|
|
}
|
|
|
|
if fs.current_position == 0 || fs.current_position > fs.total_count {
|
|
if fs.total_count > 0 {
|
|
fs.current_position = 1;
|
|
} else {
|
|
fs.reset_to_empty();
|
|
return Ok("No saved data to revert to; form cleared.".to_string());
|
|
}
|
|
}
|
|
|
|
let response = grpc_client
|
|
.get_table_data_by_position(
|
|
fs.profile_name.clone(),
|
|
fs.table_name.clone(),
|
|
fs.current_position as i32,
|
|
)
|
|
.await
|
|
.context(format!(
|
|
"Failed to get table data by position {} for table {}.{}",
|
|
fs.current_position, fs.profile_name, fs.table_name
|
|
))?;
|
|
|
|
fs.update_from_response(&response.data, fs.current_position);
|
|
Ok("Changes discarded, reloaded last saved version".to_string())
|
|
} else {
|
|
Ok("Nothing to revert".to_string())
|
|
}
|
|
}
|