From 0887b467826fbb4941e61a5ba833d5bb0ae47c12 Mon Sep 17 00:00:00 2001 From: filipriec Date: Mon, 17 Mar 2025 12:28:09 +0100 Subject: [PATCH] steel script working perfectly well --- server/src/steel/server/execution.rs | 5 +- server/src/steel/server/functions.rs | 59 +++++++++++-------- .../handlers/post_table_script.rs | 32 ++++++---- .../tables_data/handlers/post_table_data.rs | 2 +- 4 files changed, 55 insertions(+), 43 deletions(-) diff --git a/server/src/steel/server/execution.rs b/server/src/steel/server/execution.rs index a957a87..6bf9df3 100644 --- a/server/src/steel/server/execution.rs +++ b/server/src/steel/server/execution.rs @@ -28,11 +28,8 @@ pub fn execute_script( script: String, target_type: &str, _db_pool: Arc, // Passed to the SteelContext - mut context: SteelContext, // Make mutable to inject runtime + context: SteelContext, ) -> Result { - // Inject the current runtime handle - context.runtime = tokio::runtime::Handle::current(); - let mut vm = Engine::new(); let context = Arc::new(context); diff --git a/server/src/steel/server/functions.rs b/server/src/steel/server/functions.rs index eb9d6c1..e004e29 100644 --- a/server/src/steel/server/functions.rs +++ b/server/src/steel/server/functions.rs @@ -5,7 +5,6 @@ use std::collections::HashMap; use std::sync::Arc; use thiserror::Error; use sqlx::Row; -use tokio::runtime::Handle; #[derive(Debug, Error)] pub enum FunctionError { @@ -25,7 +24,6 @@ pub struct SteelContext { pub profile_id: i64, pub row_data: HashMap, pub db_pool: Arc, - pub runtime: Handle, // Add runtime handle } impl SteelContext { @@ -59,19 +57,23 @@ impl SteelContext { let fk_value = self.row_data.get(&fk_column) .ok_or_else(|| SteelVal::StringV(format!("Foreign key {} not found", fk_column).into()))?; - // Use the injected runtime handle - let result = self.runtime.block_on(async { - let actual_table = self.get_related_table_name(base_name).await - .map_err(|e| SteelVal::StringV(e.to_string().into()))?; + // Use `tokio::task::block_in_place` to safely block the thread + let result = tokio::task::block_in_place(|| { + let handle = tokio::runtime::Handle::current(); + handle.block_on(async { + let actual_table = self.get_related_table_name(base_name).await + .map_err(|e| SteelVal::StringV(e.to_string().into()))?; - sqlx::query_scalar::<_, String>( - &format!("SELECT {} FROM {} WHERE id = $1", column, actual_table) - ) - .bind(fk_value.parse::().map_err(|_| - SteelVal::StringV("Invalid foreign key format".into()))?) - .fetch_one(&*self.db_pool) - .await - .map_err(|e| SteelVal::StringV(e.to_string().into())) + // Add quotes around the table name + sqlx::query_scalar::<_, String>( + &format!("SELECT {} FROM \"{}\" WHERE id = $1", column, actual_table) + ) + .bind(fk_value.parse::().map_err(|_| + SteelVal::StringV("Invalid foreign key format".into()))?) + .fetch_one(&*self.db_pool) + .await + .map_err(|e| SteelVal::StringV(e.to_string().into())) + }) }); result.map(|v| SteelVal::StringV(v.into())) @@ -103,21 +105,26 @@ impl SteelContext { } let pool = self.db_pool.clone(); - let result = self.runtime.block_on(async { - // Execute and get first column of all rows as strings - let rows = sqlx::query(query) - .fetch_all(&*pool) - .await - .map_err(|e| SteelVal::StringV(e.to_string().into()))?; - let mut results = Vec::new(); - for row in rows { - let val: String = row.try_get(0) + // Use `tokio::task::block_in_place` to safely block the thread + let result = tokio::task::block_in_place(|| { + let handle = tokio::runtime::Handle::current(); + handle.block_on(async { + // Execute and get first column of all rows as strings + let rows = sqlx::query(query) + .fetch_all(&*pool) + .await .map_err(|e| SteelVal::StringV(e.to_string().into()))?; - results.push(val); - } - Ok(results.join(",")) + let mut results = Vec::new(); + for row in rows { + let val: String = row.try_get(0) + .map_err(|e| SteelVal::StringV(e.to_string().into()))?; + results.push(val); + } + + Ok(results.join(",")) + }) }); result.map(|s| SteelVal::StringV(s.into())) diff --git a/server/src/table_script/handlers/post_table_script.rs b/server/src/table_script/handlers/post_table_script.rs index 5d0b2e6..1b6fa5b 100644 --- a/server/src/table_script/handlers/post_table_script.rs +++ b/server/src/table_script/handlers/post_table_script.rs @@ -7,6 +7,8 @@ use crate::steel::server::syntax_parser::SyntaxParser; const SYSTEM_COLUMNS: &[&str] = &["id", "deleted", "created_at"]; +/// Validates the target column and ensures it is not a system column. +/// Returns the column type if valid. fn validate_target_column( table_name: &str, target: &str, @@ -16,9 +18,11 @@ fn validate_target_column( return Err(format!("Cannot override system column: {}", target)); } + // Parse the columns JSON into a vector of strings let columns: Vec = serde_json::from_value(table_columns.clone()) .map_err(|e| format!("Invalid column data: {}", e))?; + // Extract column names and types let column_info: Vec<(&str, &str)> = columns .iter() .filter_map(|c| { @@ -29,19 +33,20 @@ fn validate_target_column( }) .collect(); - let column_type = column_info + // Find the target column and return its type + column_info .iter() .find(|(name, _)| *name == target) - .map(|(_, dt)| *dt) - .ok_or_else(|| format!("Target column {} not defined in table {}", target, table_name))?; - - Ok(column_type.to_string()) + .map(|(_, dt)| dt.to_string()) + .ok_or_else(|| format!("Target column '{}' not defined in table '{}'", target, table_name)) } +/// Handles the creation of a new table script. pub async fn post_table_script( db_pool: &PgPool, request: PostTableScriptRequest, ) -> Result { + // Fetch the table definition let table_def = sqlx::query!( r#"SELECT id, table_name, columns, profile_id FROM table_definitions WHERE id = $1"#, @@ -49,10 +54,12 @@ pub async fn post_table_script( ) .fetch_optional(db_pool) .await - .map_err(|e| Status::internal(format!("Database error: {}", e)))? + .map_err(|e| { + Status::internal(format!("Failed to fetch table definition: {}", e)) + })? .ok_or_else(|| Status::not_found("Table definition not found"))?; - // Validate target column and get its type + // Validate the target column and get its type let column_type = validate_target_column( &table_def.table_name, &request.target_column, @@ -60,14 +67,14 @@ pub async fn post_table_script( ) .map_err(|e| Status::invalid_argument(e))?; - // Parse and transform the script + // Parse and transform the script using the syntax parser let parser = SyntaxParser::new(); let parsed_script = parser.parse(&request.script, &table_def.table_name); - // Store script in database with automatic target_table + // Insert the script into the database let script_record = sqlx::query!( r#"INSERT INTO table_scripts - (table_definitions_id, target_table, target_column, + (table_definitions_id, target_table, target_column, target_column_type, script, description, profile_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id"#, @@ -85,11 +92,12 @@ pub async fn post_table_script( SqlxError::Database(db_err) if db_err.constraint() == Some("table_scripts_table_definitions_id_target_column_key") => { Status::already_exists("Script already exists for this column") } - _ => Status::internal(format!("Database error: {}", e)), + _ => Status::internal(format!("Failed to insert script: {}", e)), })?; + // Return the response with the new script ID Ok(TableScriptResponse { id: script_record.id, - warnings: String::new(), + warnings: String::new(), // No warnings for now }) } diff --git a/server/src/tables_data/handlers/post_table_data.rs b/server/src/tables_data/handlers/post_table_data.rs index 299829d..a18fcae 100644 --- a/server/src/tables_data/handlers/post_table_data.rs +++ b/server/src/tables_data/handlers/post_table_data.rs @@ -128,9 +128,9 @@ pub async fn post_table_data( profile_id, row_data: data.clone(), db_pool: Arc::new(db_pool.clone()), - runtime: Handle::current(), }; + // Execute validation script let script_result = execution::execute_script( script_record.script,