get column gets converted to get column with index automatically now
This commit is contained in:
@@ -10,14 +10,13 @@ use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, error};
|
||||
use regex::Regex; // NEW
|
||||
|
||||
/// Represents different types of values that can be returned from Steel script execution.
|
||||
#[derive(Debug)]
|
||||
pub enum Value {
|
||||
Strings(Vec<String>),
|
||||
}
|
||||
|
||||
/// Errors that can occur during Steel script execution.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ExecutionError {
|
||||
#[error("Script execution failed: {0}")]
|
||||
@@ -28,7 +27,41 @@ pub enum ExecutionError {
|
||||
UnsupportedType(String),
|
||||
}
|
||||
|
||||
/// Creates a Steel execution context with proper boolean value conversion.
|
||||
// NEW: upgrade steel_get_column -> steel_get_column_with_index using FK present in row_data
|
||||
fn auto_promote_with_index(
|
||||
script: &str,
|
||||
current_table: &str,
|
||||
row_data: &HashMap<String, String>,
|
||||
) -> String {
|
||||
// Matches: (steel_get_column "table" "column")
|
||||
let re = Regex::new(
|
||||
r#"\(\s*steel_get_column\s+"([^"]+)"\s+"([^"]+)"\s*\)"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
re.replace_all(script, |caps: ®ex::Captures| {
|
||||
let table = caps.get(1).unwrap().as_str();
|
||||
let column = caps.get(2).unwrap().as_str();
|
||||
|
||||
// Only upgrade cross-table calls, if FK is present in the request data
|
||||
if table != current_table {
|
||||
let fk_key = format!("{}_id", table);
|
||||
if let Some(id_str) = row_data.get(&fk_key) {
|
||||
if let Ok(_) = id_str.parse::<i64>() {
|
||||
return format!(
|
||||
r#"(steel_get_column_with_index "{}" {} "{}")"#,
|
||||
table, id_str, column
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default: keep original call
|
||||
caps.get(0).unwrap().as_str().to_string()
|
||||
})
|
||||
.into_owned()
|
||||
}
|
||||
|
||||
pub async fn create_steel_context_with_boolean_conversion(
|
||||
current_table: String,
|
||||
schema_id: i64,
|
||||
@@ -36,7 +69,6 @@ pub async fn create_steel_context_with_boolean_conversion(
|
||||
mut row_data: HashMap<String, String>,
|
||||
db_pool: Arc<PgPool>,
|
||||
) -> Result<SteelContext, ExecutionError> {
|
||||
// Convert boolean values in row_data to Steel format
|
||||
convert_row_data_for_steel(&db_pool, schema_id, ¤t_table, &mut row_data)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -53,7 +85,6 @@ pub async fn create_steel_context_with_boolean_conversion(
|
||||
})
|
||||
}
|
||||
|
||||
/// Executes a Steel script with database context and type-safe result processing.
|
||||
pub async fn execute_script(
|
||||
script: String,
|
||||
target_type: &str,
|
||||
@@ -65,42 +96,40 @@ pub async fn execute_script(
|
||||
) -> Result<Value, ExecutionError> {
|
||||
let mut vm = Engine::new();
|
||||
|
||||
// Create execution context with proper boolean value conversion
|
||||
// Upgrade to with_index based on FK presence in the posted data
|
||||
let script = auto_promote_with_index(&script, ¤t_table, &row_data);
|
||||
|
||||
let context = create_steel_context_with_boolean_conversion(
|
||||
current_table,
|
||||
current_table.clone(),
|
||||
schema_id,
|
||||
schema_name,
|
||||
row_data,
|
||||
row_data.clone(),
|
||||
db_pool.clone(),
|
||||
).await?;
|
||||
)
|
||||
.await?;
|
||||
|
||||
let context = Arc::new(context);
|
||||
|
||||
// Register database access functions
|
||||
register_steel_functions(&mut vm, context.clone());
|
||||
|
||||
// Register decimal math operations
|
||||
register_decimal_math_functions(&mut vm);
|
||||
|
||||
// Register row data as variables in the Steel VM for get-var access
|
||||
let mut define_script = String::new();
|
||||
|
||||
for (key, value) in &context.row_data {
|
||||
// Register only bare variable names for get-var access
|
||||
define_script.push_str(&format!("(define {} \"{}\")\n", key, value));
|
||||
}
|
||||
|
||||
// Execute variable definitions if any exist
|
||||
if !define_script.is_empty() {
|
||||
vm.compile_and_run_raw_program(define_script)
|
||||
.map_err(|e| ExecutionError::RuntimeError(format!("Failed to register variables: {}", e)))?;
|
||||
.map_err(|e| ExecutionError::RuntimeError(format!(
|
||||
"Failed to register variables: {}",
|
||||
e
|
||||
)))?;
|
||||
}
|
||||
|
||||
// Also register variables using the decimal registry as backup method
|
||||
FunctionRegistry::register_variables(&mut vm, context.row_data.clone());
|
||||
|
||||
// Execute the main script
|
||||
let results = vm.compile_and_run_raw_program(script.clone())
|
||||
let results = vm
|
||||
.compile_and_run_raw_program(script.clone())
|
||||
.map_err(|e| {
|
||||
error!("Steel script execution failed: {}", e);
|
||||
error!("Script was: {}", script);
|
||||
@@ -108,22 +137,22 @@ pub async fn execute_script(
|
||||
ExecutionError::RuntimeError(e.to_string())
|
||||
})?;
|
||||
|
||||
// Convert results to the requested target type
|
||||
match target_type {
|
||||
"STRINGS" => process_string_results(results),
|
||||
_ => Err(ExecutionError::UnsupportedType(target_type.into()))
|
||||
_ => Err(ExecutionError::UnsupportedType(target_type.into())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers Steel functions for database access within the VM context.
|
||||
fn register_steel_functions(vm: &mut Engine, context: Arc<SteelContext>) {
|
||||
debug!("Registering Steel functions with context");
|
||||
|
||||
// Register column access function for current and related tables
|
||||
vm.register_fn("steel_get_column", {
|
||||
let ctx = context.clone();
|
||||
move |table: String, column: String| {
|
||||
debug!("steel_get_column called with table: '{}', column: '{}'", table, column);
|
||||
debug!(
|
||||
"steel_get_column called with table: '{}', column: '{}'",
|
||||
table, column
|
||||
);
|
||||
ctx.steel_get_column(&table, &column)
|
||||
.map_err(|e| {
|
||||
error!("steel_get_column failed: {:?}", e);
|
||||
@@ -132,11 +161,13 @@ fn register_steel_functions(vm: &mut Engine, context: Arc<SteelContext>) {
|
||||
}
|
||||
});
|
||||
|
||||
// Register indexed column access for comma-separated values
|
||||
vm.register_fn("steel_get_column_with_index", {
|
||||
let ctx = context.clone();
|
||||
move |table: String, index: i64, column: String| {
|
||||
debug!("steel_get_column_with_index called with table: '{}', index: {}, column: '{}'", table, index, column);
|
||||
debug!(
|
||||
"steel_get_column_with_index called with table: '{}', index: {}, column: '{}'",
|
||||
table, index, column
|
||||
);
|
||||
ctx.steel_get_column_with_index(&table, index, &column)
|
||||
.map_err(|e| {
|
||||
error!("steel_get_column_with_index failed: {:?}", e);
|
||||
@@ -145,13 +176,11 @@ fn register_steel_functions(vm: &mut Engine, context: Arc<SteelContext>) {
|
||||
}
|
||||
});
|
||||
|
||||
// Register safe SQL query execution
|
||||
vm.register_fn("steel_query_sql", {
|
||||
let ctx = context.clone();
|
||||
move |query: String| {
|
||||
debug!("steel_query_sql called with query: '{}'", query);
|
||||
ctx.steel_query_sql(&query)
|
||||
.map_err(|e| {
|
||||
ctx.steel_query_sql(&query).map_err(|e| {
|
||||
error!("steel_query_sql failed: {:?}", e);
|
||||
e.to_string()
|
||||
})
|
||||
@@ -159,13 +188,11 @@ fn register_steel_functions(vm: &mut Engine, context: Arc<SteelContext>) {
|
||||
});
|
||||
}
|
||||
|
||||
/// Registers decimal mathematics functions in the Steel VM.
|
||||
fn register_decimal_math_functions(vm: &mut Engine) {
|
||||
debug!("Registering decimal math functions");
|
||||
FunctionRegistry::register_all(vm);
|
||||
}
|
||||
|
||||
/// Processes Steel script results into string format for consistent output.
|
||||
fn process_string_results(results: Vec<SteelVal>) -> Result<Value, ExecutionError> {
|
||||
let mut strings = Vec::new();
|
||||
|
||||
@@ -178,7 +205,7 @@ fn process_string_results(results: Vec<SteelVal>) -> Result<Value, ExecutionErro
|
||||
_ => {
|
||||
error!("Unexpected result type: {:?}", result);
|
||||
return Err(ExecutionError::TypeConversionError(
|
||||
format!("Expected string-convertible type, got {:?}", result)
|
||||
format!("Expected string-convertible type, got {:?}", result),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user