post table data validating now steel
This commit is contained in:
@@ -28,8 +28,11 @@ pub fn execute_script(
|
|||||||
script: String,
|
script: String,
|
||||||
target_type: &str,
|
target_type: &str,
|
||||||
_db_pool: Arc<PgPool>, // Passed to the SteelContext
|
_db_pool: Arc<PgPool>, // Passed to the SteelContext
|
||||||
context: SteelContext, // Contains row_data, profile_id, etc.
|
mut context: SteelContext, // Make mutable to inject runtime
|
||||||
) -> Result<Value, ExecutionError> {
|
) -> Result<Value, ExecutionError> {
|
||||||
|
// Inject the current runtime handle
|
||||||
|
context.runtime = tokio::runtime::Handle::current();
|
||||||
|
|
||||||
let mut vm = Engine::new();
|
let mut vm = Engine::new();
|
||||||
let context = Arc::new(context);
|
let context = Arc::new(context);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use sqlx::Row;
|
use sqlx::Row;
|
||||||
|
use tokio::runtime::Handle;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum FunctionError {
|
pub enum FunctionError {
|
||||||
@@ -18,11 +19,13 @@ pub enum FunctionError {
|
|||||||
DatabaseError(String),
|
DatabaseError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SteelContext {
|
pub struct SteelContext {
|
||||||
pub current_table: String,
|
pub current_table: String,
|
||||||
pub profile_id: i64,
|
pub profile_id: i64,
|
||||||
pub row_data: HashMap<String, String>,
|
pub row_data: HashMap<String, String>,
|
||||||
pub db_pool: Arc<PgPool>,
|
pub db_pool: Arc<PgPool>,
|
||||||
|
pub runtime: Handle, // Add runtime handle
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SteelContext {
|
impl SteelContext {
|
||||||
@@ -51,20 +54,20 @@ impl SteelContext {
|
|||||||
let base_name = table.split_once('_')
|
let base_name = table.split_once('_')
|
||||||
.map(|(_, rest)| rest)
|
.map(|(_, rest)| rest)
|
||||||
.unwrap_or(table);
|
.unwrap_or(table);
|
||||||
|
|
||||||
let fk_column = format!("{}_id", base_name);
|
let fk_column = format!("{}_id", base_name);
|
||||||
let fk_value = self.row_data.get(&fk_column)
|
let fk_value = self.row_data.get(&fk_column)
|
||||||
.ok_or_else(|| SteelVal::StringV(format!("Foreign key {} not found", fk_column).into()))?;
|
.ok_or_else(|| SteelVal::StringV(format!("Foreign key {} not found", fk_column).into()))?;
|
||||||
|
|
||||||
// Convert to async block for database access
|
// Use the injected runtime handle
|
||||||
let result = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
let result = self.runtime.block_on(async {
|
||||||
let actual_table = self.get_related_table_name(base_name).await
|
let actual_table = self.get_related_table_name(base_name).await
|
||||||
.map_err(|e| SteelVal::StringV(e.to_string().into()))?;
|
.map_err(|e| SteelVal::StringV(e.to_string().into()))?;
|
||||||
|
|
||||||
sqlx::query_scalar::<_, String>(
|
sqlx::query_scalar::<_, String>(
|
||||||
&format!("SELECT {} FROM {} WHERE id = $1", column, actual_table)
|
&format!("SELECT {} FROM {} WHERE id = $1", column, actual_table)
|
||||||
)
|
)
|
||||||
.bind(fk_value.parse::<i64>().map_err(|_|
|
.bind(fk_value.parse::<i64>().map_err(|_|
|
||||||
SteelVal::StringV("Invalid foreign key format".into()))?)
|
SteelVal::StringV("Invalid foreign key format".into()))?)
|
||||||
.fetch_one(&*self.db_pool)
|
.fetch_one(&*self.db_pool)
|
||||||
.await
|
.await
|
||||||
@@ -100,7 +103,7 @@ impl SteelContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let pool = self.db_pool.clone();
|
let pool = self.db_pool.clone();
|
||||||
let result = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
let result = self.runtime.block_on(async {
|
||||||
// Execute and get first column of all rows as strings
|
// Execute and get first column of all rows as strings
|
||||||
let rows = sqlx::query(query)
|
let rows = sqlx::query(query)
|
||||||
.fetch_all(&*pool)
|
.fetch_all(&*pool)
|
||||||
@@ -113,10 +116,10 @@ impl SteelContext {
|
|||||||
.map_err(|e| SteelVal::StringV(e.to_string().into()))?;
|
.map_err(|e| SteelVal::StringV(e.to_string().into()))?;
|
||||||
results.push(val);
|
results.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(results.join(","))
|
Ok(results.join(","))
|
||||||
});
|
});
|
||||||
|
|
||||||
result.map(|s| SteelVal::StringV(s.into()))
|
result.map(|s| SteelVal::StringV(s.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ use sqlx::postgres::PgArguments;
|
|||||||
use chrono::{DateTime, Utc};
|
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 std::sync::Arc;
|
||||||
|
use tokio::runtime::Handle;
|
||||||
|
|
||||||
use crate::steel::server::execution::{self, Value};
|
use crate::steel::server::execution::{self, Value};
|
||||||
|
use crate::steel::server::functions::SteelContext;
|
||||||
|
|
||||||
pub async fn post_table_data(
|
pub async fn post_table_data(
|
||||||
db_pool: &PgPool,
|
db_pool: &PgPool,
|
||||||
@@ -26,7 +29,7 @@ pub async fn post_table_data(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add trimmed non-empty values to data map
|
// Add trimmed non-empty values to data map
|
||||||
if !trimmed.is_empty(){
|
if !trimmed.is_empty() {
|
||||||
data.insert(key, trimmed);
|
data.insert(key, trimmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +75,7 @@ pub async fn post_table_data(
|
|||||||
|
|
||||||
// Get required relationships
|
// Get required relationships
|
||||||
let required_links = sqlx::query!(
|
let required_links = sqlx::query!(
|
||||||
r#"SELECT ltd.table_name
|
r#"SELECT ltd.table_name
|
||||||
FROM table_definition_links tdl
|
FROM table_definition_links tdl
|
||||||
JOIN table_definitions ltd ON tdl.linked_table_id = ltd.id
|
JOIN table_definitions ltd ON tdl.linked_table_id = ltd.id
|
||||||
WHERE tdl.source_table_id = $1 AND tdl.is_required = true"#,
|
WHERE tdl.source_table_id = $1 AND tdl.is_required = true"#,
|
||||||
@@ -105,7 +108,6 @@ pub async fn post_table_data(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Validate Steel scripts
|
// Validate Steel scripts
|
||||||
let scripts = sqlx::query!(
|
let scripts = sqlx::query!(
|
||||||
"SELECT target_column, script FROM table_scripts WHERE table_definitions_id = $1",
|
"SELECT target_column, script FROM table_scripts WHERE table_definitions_id = $1",
|
||||||
@@ -124,22 +126,41 @@ pub async fn post_table_data(
|
|||||||
format!("Script target column '{}' is required", target_column)
|
format!("Script target column '{}' is required", target_column)
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Execute the script using the owned String
|
// Create execution context
|
||||||
let script_result = execution::execute_script(script_record.script.clone(), "STRING") // Changed here
|
let context = SteelContext {
|
||||||
.map_err(|e| Status::invalid_argument(
|
current_table: table_name.clone(),
|
||||||
format!("Script execution failed for '{}': {}", target_column, e)
|
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,
|
||||||
|
"STRINGS",
|
||||||
|
Arc::new(db_pool.clone()),
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
.map_err(|e| Status::invalid_argument(
|
||||||
|
format!("Script execution failed for '{}': {}", target_column, e)
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// Validate script output
|
||||||
|
let Value::Strings(mut script_output) = script_result else {
|
||||||
|
return Err(Status::internal("Script must return string values"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_value = script_output.pop()
|
||||||
|
.ok_or_else(|| Status::internal("Script returned no values"))?;
|
||||||
|
|
||||||
// Compare script result with user input
|
|
||||||
let Value::String(expected_value) = script_result;
|
|
||||||
if user_value != &expected_value {
|
if user_value != &expected_value {
|
||||||
return Err(Status::invalid_argument(format!(
|
return Err(Status::invalid_argument(format!(
|
||||||
"Validation failed for '{}'. Expected: '{}', Received: '{}'",
|
"Validation failed for column '{}': Expected '{}', Got '{}'",
|
||||||
target_column, expected_value, user_value
|
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