fixed push data to the tables

This commit is contained in:
filipriec
2025-03-08 20:06:34 +01:00
parent b0daa4ff18
commit 6f9887a303

View File

@@ -14,18 +14,17 @@ pub async fn post_table_data(
let profile_name = request.profile_name; let profile_name = request.profile_name;
let table_name = request.table_name; let table_name = request.table_name;
let mut data = HashMap::new(); let mut data = HashMap::new();
// Process and validate all data values // Process and validate all data values
for (key, value) in request.data { for (key, value) in request.data {
let trimmed = value.trim().to_string(); let trimmed = value.trim().to_string();
// Handle firma specially - it cannot be empty // Handle firma specially - it cannot be empty
if key == "firma" && trimmed.is_empty() { if key == "firma" && trimmed.is_empty() {
return Err(Status::invalid_argument("Firma cannot be empty")); return Err(Status::invalid_argument("Firma cannot be empty"));
} }
// Add trimmed non-empty values to data map // Add trimmed non-empty values to data map
// Empty optional fields will be skipped in SQL generation
if !trimmed.is_empty() || key == "firma" { if !trimmed.is_empty() || key == "firma" {
data.insert(key, trimmed); data.insert(key, trimmed);
} }
@@ -44,7 +43,7 @@ pub async fn post_table_data(
// Lookup table_definition // Lookup table_definition
let table_def = sqlx::query!( let table_def = sqlx::query!(
r#"SELECT id, columns, linked_table_id FROM table_definitions r#"SELECT id, columns FROM table_definitions
WHERE profile_id = $1 AND table_name = $2"#, WHERE profile_id = $1 AND table_name = $2"#,
profile_id, profile_id,
table_name table_name
@@ -70,18 +69,22 @@ pub async fn post_table_data(
columns.push((name, sql_type)); columns.push((name, sql_type));
} }
// Check required system columns // Get required relationships
let mut required_columns = vec!["firma".to_string()]; let required_links = sqlx::query!(
if let Some(linked_table_id) = table_def.linked_table_id { r#"SELECT ltd.table_name
let linked_table = sqlx::query!( FROM table_definition_links tdl
"SELECT table_name FROM table_definitions WHERE id = $1", JOIN table_definitions ltd ON tdl.linked_table_id = ltd.id
linked_table_id WHERE tdl.source_table_id = $1 AND tdl.is_required = true"#,
) table_def.id
.fetch_one(db_pool) )
.await .fetch_all(db_pool)
.map_err(|e| Status::internal(format!("Linked table error: {}", e)))?; .await
.map_err(|e| Status::internal(format!("Link lookup error: {}", e)))?;
let base_name = linked_table.table_name.splitn(2, '_').last().unwrap_or(&linked_table.table_name); // Build required columns list
let mut required_columns = vec!["firma".to_string()];
for link in required_links {
let base_name = link.table_name.split('_').last().unwrap_or(&link.table_name);
required_columns.push(format!("{}_id", base_name)); required_columns.push(format!("{}_id", base_name));
} }
@@ -101,7 +104,6 @@ pub async fn post_table_data(
} }
} }
// Validate Steel scripts // Validate Steel scripts
let scripts = sqlx::query!( let scripts = sqlx::query!(
"SELECT target_column, script FROM table_scripts WHERE table_definitions_id = $1", "SELECT target_column, script FROM table_scripts WHERE table_definitions_id = $1",
@@ -114,50 +116,41 @@ pub async fn post_table_data(
for script_record in scripts { for script_record in scripts {
let target_column = script_record.target_column; let target_column = script_record.target_column;
// Check if target column is present in data
if !data.contains_key(&target_column) { if !data.contains_key(&target_column) {
return Err(Status::invalid_argument( return Err(Status::invalid_argument(
format!("Column '{}' is required due to an associated script", target_column) format!("Column '{}' is required due to an associated script", target_column)
)); ));
} }
// Parse the script
let operation = execution::parse_script(&script_record.script, &target_column) let operation = execution::parse_script(&script_record.script, &target_column)
.map_err(|e| Status::invalid_argument(e.to_string()))?; .map_err(|e| Status::invalid_argument(e.to_string()))?;
// Get source column from operation let source_column = match operation {
let source_column = ScriptOperation::SetToLocalColumn { source } => source,
match operation { ScriptOperation::SetToExternalColumn { table, column } => {
ScriptOperation::SetToLocalColumn { source } => source, let external_source = format!("@{}.{}", table, column);
ScriptOperation::SetToExternalColumn { table, column } => { let resolved_value = execution::resolve_value(
// For external columns, we need to resolve the value from the external table db_pool,
let external_source = format!("@{}.{}", table, column); profile_id,
let resolved_value = execution::resolve_value( &table_name,
db_pool, &data,
profile_id, &external_source
&table_name, ).await.map_err(|e| Status::invalid_argument(e.to_string()))?;
&data,
&external_source resolved_value
).await.map_err(|e| Status::invalid_argument(e.to_string()))?; }
};
// Return the resolved value
resolved_value
}
};
// Check source column presence
let source_value = data.get(&source_column) let source_value = data.get(&source_column)
.ok_or_else(|| Status::invalid_argument( .ok_or_else(|| Status::invalid_argument(
format!("Source column '{}' required by script for '{}' is missing", source_column, target_column) format!("Source column '{}' required by script for '{}' is missing", source_column, target_column)
))?; ))?;
// Get target value
let target_value = data.get(&target_column) let target_value = data.get(&target_column)
.ok_or_else(|| Status::invalid_argument( .ok_or_else(|| Status::invalid_argument(
format!("Target column '{}' is missing in data", target_column) format!("Target column '{}' is missing in data", target_column)
))?; ))?;
// Validate value match
if target_value != source_value { if target_value != source_value {
return Err(Status::invalid_argument( return Err(Status::invalid_argument(
format!("Value for '{}' must match '{}' as per script. Expected '{}', got '{}'", format!("Value for '{}' must match '{}' as per script. Expected '{}', got '{}'",
@@ -186,8 +179,6 @@ pub async fn post_table_data(
.ok_or_else(|| Status::invalid_argument(format!("Column not found: {}", col)))? .ok_or_else(|| Status::invalid_argument(format!("Column not found: {}", col)))?
}; };
// TODO This needs heavy adjustement. More stuff to be added for user to only pick
// preprogrammed functions
match sql_type { match sql_type {
"TEXT" | "VARCHAR(15)" | "VARCHAR(255)" => { "TEXT" | "VARCHAR(15)" | "VARCHAR(255)" => {
if let Some(max_len) = sql_type.strip_prefix("VARCHAR(") if let Some(max_len) = sql_type.strip_prefix("VARCHAR(")
@@ -221,7 +212,6 @@ pub async fn post_table_data(
param_idx += 1; param_idx += 1;
} }
// Ensure we have at least one column to insert
if columns_list.is_empty() { if columns_list.is_empty() {
return Err(Status::invalid_argument("No valid columns to insert")); return Err(Status::invalid_argument("No valid columns to insert"));
} }