compiled steel engine

This commit is contained in:
filipriec
2025-03-10 22:52:07 +01:00
parent e235fbd49b
commit fc6f033711
4 changed files with 70 additions and 45 deletions

View File

@@ -20,6 +20,7 @@ tracing = "0.1.41"
time = { version = "0.3.39", features = ["local-offset"] }
steel-derive = { git = "https://github.com/mattwparas/steel.git", branch = "master", package = "steel-derive" }
steel-core = { git = "https://github.com/mattwparas/steel.git", version = "0.6.0", features = ["anyhow", "dylibs", "sync"] }
thiserror = "2.0.12"
[lib]
name = "server"

View File

@@ -1,4 +1,49 @@
// src/steel/server/execution.rs
use std::fmt;
use std::collections::HashMap;
use sqlx::{PgPool, Row};
use steel::steel_vm::engine::Engine;
use steel::rvals::SteelVal;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ExecutionError {
#[error("Script execution failed: {0}")]
RuntimeError(String),
#[error("Type conversion error: {0}")]
TypeConversionError(String),
#[error("Unsupported target type: {0}")]
UnsupportedType(String),
}
#[derive(Debug)]
pub enum Value {
String(String),
}
// TODO LEAKING MEMORY NEEDS IMIDATE FIX BEFORE PROD
pub fn execute_script(
script: &str,
target_type: &str,
) -> Result<Value, ExecutionError> {
let mut vm = Engine::new();
// Convert to Box<str> then leak to get 'static lifetime
let static_script: &'static str = Box::leak(script.to_string().into_boxed_str());
let results = vm.compile_and_run_raw_program(static_script)
.map_err(|e| ExecutionError::RuntimeError(e.to_string()))?;
let last_result = results.last()
.ok_or_else(|| ExecutionError::TypeConversionError("Script returned no values".to_string()))?;
match target_type {
"STRING" => {
if let SteelVal::StringV(s) = last_result {
Ok(Value::String(s.to_string()))
} else {
Err(ExecutionError::TypeConversionError(
format!("Expected string, got {:?}", last_result)
))
}
}
_ => Err(ExecutionError::UnsupportedType(target_type.to_string())),
}
}

View File

@@ -1,4 +1,4 @@
// src/steel/server/mod.rs
// pub mod execution;
pub mod execution;
// pub use execution::*;
pub use execution::*;

View File

@@ -6,6 +6,8 @@ use chrono::{DateTime, Utc};
use common::proto::multieko2::tables_data::{PostTableDataRequest, PostTableDataResponse};
use std::collections::HashMap;
use crate::steel::server::execution::{self, Value};
pub async fn post_table_data(
db_pool: &PgPool,
request: PostTableDataRequest,
@@ -112,54 +114,31 @@ pub async fn post_table_data(
.await
.map_err(|e| Status::internal(format!("Failed to fetch scripts: {}", e)))?;
// TODO: Re-implement script validation logic
/*
// TODO SCRIPT EXECUTION NEEDS REDESING
for script_record in scripts {
let target_column = script_record.target_column;
if !data.contains_key(&target_column) {
return Err(Status::invalid_argument(
format!("Column '{}' is required due to an associated script", target_column)
));
}
let operation = execution::parse_script(&script_record.script, &target_column)
.map_err(|e| Status::invalid_argument(e.to_string()))?;
let source_column = match operation {
ScriptOperation::SetToLocalColumn { source } => source,
ScriptOperation::SetToExternalColumn { table, column } => {
let external_source = format!("@{}.{}", table, column);
let resolved_value = execution::resolve_value(
db_pool,
profile_id,
&table_name,
&data,
&external_source
).await.map_err(|e| Status::invalid_argument(e.to_string()))?;
resolved_value
}
};
let source_value = data.get(&source_column)
// Ensure target column exists in submitted data
let user_value = data.get(&target_column)
.ok_or_else(|| Status::invalid_argument(
format!("Source column '{}' required by script for '{}' is missing", source_column, target_column)
format!("Script target column '{}' is required", target_column)
))?;
let target_value = data.get(&target_column)
.ok_or_else(|| Status::invalid_argument(
format!("Target column '{}' is missing in data", target_column)
// Execute the script using your existing implementation
let script_result = execution::execute_script(&script_record.script, "STRING")
.map_err(|e| Status::invalid_argument(
format!("Script execution failed for '{}': {}", target_column, e)
))?;
if target_value != source_value {
return Err(Status::invalid_argument(
format!("Value for '{}' must match '{}' as per script. Expected '{}', got '{}'",
target_column, source_column, source_value, target_value)
));
}
// Compare script result with user input
let Value::String(expected_value) = script_result;
if user_value != &expected_value {
return Err(Status::invalid_argument(format!(
"Validation failed for '{}'. Expected: '{}', Received: '{}'",
target_column, expected_value, user_value
)));
}
}
*/
// Prepare SQL parameters
let mut params = PgArguments::default();