compiled steel engine
This commit is contained in:
@@ -20,6 +20,7 @@ tracing = "0.1.41"
|
|||||||
time = { version = "0.3.39", features = ["local-offset"] }
|
time = { version = "0.3.39", features = ["local-offset"] }
|
||||||
steel-derive = { git = "https://github.com/mattwparas/steel.git", branch = "master", package = "steel-derive" }
|
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"] }
|
steel-core = { git = "https://github.com/mattwparas/steel.git", version = "0.6.0", features = ["anyhow", "dylibs", "sync"] }
|
||||||
|
thiserror = "2.0.12"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "server"
|
name = "server"
|
||||||
|
|||||||
@@ -1,4 +1,49 @@
|
|||||||
// src/steel/server/execution.rs
|
// src/steel/server/execution.rs
|
||||||
use std::fmt;
|
use steel::steel_vm::engine::Engine;
|
||||||
use std::collections::HashMap;
|
use steel::rvals::SteelVal;
|
||||||
use sqlx::{PgPool, Row};
|
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())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// src/steel/server/mod.rs
|
// src/steel/server/mod.rs
|
||||||
// pub mod execution;
|
pub mod execution;
|
||||||
|
|
||||||
// pub use execution::*;
|
pub use execution::*;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use chrono::{DateTime, Utc};
|
|||||||
use common::proto::multieko2::tables_data::{PostTableDataRequest, PostTableDataResponse};
|
use common::proto::multieko2::tables_data::{PostTableDataRequest, PostTableDataResponse};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::steel::server::execution::{self, Value};
|
||||||
|
|
||||||
pub async fn post_table_data(
|
pub async fn post_table_data(
|
||||||
db_pool: &PgPool,
|
db_pool: &PgPool,
|
||||||
request: PostTableDataRequest,
|
request: PostTableDataRequest,
|
||||||
@@ -112,54 +114,31 @@ pub async fn post_table_data(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| Status::internal(format!("Failed to fetch scripts: {}", e)))?;
|
.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 {
|
for script_record in scripts {
|
||||||
let target_column = script_record.target_column;
|
let target_column = script_record.target_column;
|
||||||
|
|
||||||
if !data.contains_key(&target_column) {
|
// Ensure target column exists in submitted data
|
||||||
return Err(Status::invalid_argument(
|
let user_value = data.get(&target_column)
|
||||||
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)
|
|
||||||
.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!("Script target column '{}' is required", target_column)
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let target_value = data.get(&target_column)
|
// Execute the script using your existing implementation
|
||||||
.ok_or_else(|| Status::invalid_argument(
|
let script_result = execution::execute_script(&script_record.script, "STRING")
|
||||||
format!("Target column '{}' is missing in data", target_column)
|
.map_err(|e| Status::invalid_argument(
|
||||||
|
format!("Script execution failed for '{}': {}", target_column, e)
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
if target_value != source_value {
|
// Compare script result with user input
|
||||||
return Err(Status::invalid_argument(
|
let Value::String(expected_value) = script_result;
|
||||||
format!("Value for '{}' must match '{}' as per script. Expected '{}', got '{}'",
|
if user_value != &expected_value {
|
||||||
target_column, source_column, source_value, target_value)
|
return Err(Status::invalid_argument(format!(
|
||||||
));
|
"Validation failed for '{}'. Expected: '{}', Received: '{}'",
|
||||||
}
|
target_column, expected_value, user_value
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Prepare SQL parameters
|
// Prepare SQL parameters
|
||||||
let mut params = PgArguments::default();
|
let mut params = PgArguments::default();
|
||||||
|
|||||||
Reference in New Issue
Block a user