generalization on the way, needs fixes

This commit is contained in:
filipriec
2025-03-08 16:25:36 +01:00
parent 48c614084d
commit 4a43097773
3 changed files with 70 additions and 10 deletions

View File

@@ -1,10 +1,12 @@
// src/steel/execution.rs
// src/steel/handlers/execution.rs
use std::fmt;
use std::collections::HashMap;
use sqlx::{PgPool, Row};
#[derive(Debug)]
pub enum ScriptOperation {
SetToColumn { source: String },
// Future operations can be added here
SetToLocalColumn { source: String },
SetToExternalColumn { table: String, column: String },
}
#[derive(Debug)]
@@ -12,6 +14,10 @@ pub enum ScriptExecutionError {
ParseError(String),
MissingSourceColumn(String),
Mismatch { expected: String, actual: String },
InvalidReference(String),
MissingLinkKey(String),
DatabaseError(String),
MissingExternalData(String),
}
impl fmt::Display for ScriptExecutionError {
@@ -24,6 +30,10 @@ impl fmt::Display for ScriptExecutionError {
"Value does not match script expectation. Expected: {}, Actual: {}",
expected, actual
),
Self::InvalidReference(msg) => write!(f, "Invalid reference: {}", msg),
Self::MissingLinkKey(key) => write!(f, "Missing link key: {}", key),
Self::DatabaseError(msg) => write!(f, "Database error: {}", msg),
Self::MissingExternalData(msg) => write!(f, "External data not found: {}", msg),
}
}
}
@@ -60,7 +70,57 @@ pub fn parse_script(script: &str, expected_target: &str) -> Result<ScriptOperati
)));
}
Ok(ScriptOperation::SetToColumn {
source: source.to_string(),
})
// Check if source is an external reference
if source.starts_with('@') {
let (table, column) = source.split_once('.')
.ok_or_else(|| ScriptExecutionError::InvalidReference(
format!("Invalid external reference format: {}", source)
))?;
Ok(ScriptOperation::SetToExternalColumn {
table: table.to_string(),
column: column.to_string(),
})
} else {
Ok(ScriptOperation::SetToLocalColumn {
source: source.to_string(),
})
}
}
pub async fn resolve_value(
db_pool: &PgPool,
profile_id: i64,
current_table: &str,
current_data: &HashMap<String, String>,
source: &str,
) -> Result<String, ScriptExecutionError> {
if let Some((table, column)) = source.split_once('.') {
// External table reference
let external_table = table.strip_prefix('@')
.ok_or_else(|| ScriptExecutionError::InvalidReference(format!("Invalid external reference: {}", source)))?;
// Get linking key (assuming firma is the common key)
let firma = current_data.get("firma")
.ok_or_else(|| ScriptExecutionError::MissingLinkKey("firma".into()))?;
// Query external table
let query = format!("SELECT {} FROM \"{}\" WHERE firma = $1 AND profile_id = $2", column, external_table);
let result: Option<String> = sqlx::query(&query)
.bind(firma)
.bind(profile_id)
.fetch_optional(db_pool)
.await
.map_err(|e| ScriptExecutionError::DatabaseError(e.to_string()))?
.and_then(|row| row.try_get(0).ok());
result.ok_or_else(|| ScriptExecutionError::MissingExternalData(
format!("No data found for {} in {}", column, external_table)
))
} else {
// Local column reference
current_data.get(source)
.cloned()
.ok_or_else(|| ScriptExecutionError::MissingSourceColumn(source.into()))
}
}

View File

@@ -21,7 +21,7 @@ pub fn validate_script(script: &str) -> Result<(), ScriptValidationError> {
if script.trim().is_empty() {
return Err(ScriptValidationError::EmptyScript);
}
// If we get here, the script passed basic validation
Ok(())
}

View File

@@ -6,8 +6,7 @@ use crate::steel::validation::script::validate_script;
use serde_json::Value;
// Add these imports for the execution module and ScriptOperation
use crate::steel::handlers::execution;
use crate::steel::handlers::ScriptOperation;
use crate::steel::handlers::execution::{self, ScriptOperation};
const SYSTEM_COLUMNS: &[&str] = &["id", "deleted", "created_at"];
@@ -61,7 +60,8 @@ pub async fn post_table_script(
// Ensure the operation is valid (additional checks if needed)
match operation {
ScriptOperation::SetToColumn { .. } => {}, // Use directly without 'execution::'
ScriptOperation::SetToLocalColumn { .. } => {},
ScriptOperation::SetToExternalColumn { .. } => {},
}
// Call validation functions