we got a full passer now

This commit is contained in:
filipriec
2025-07-20 14:58:39 +02:00
parent 84871faad4
commit 7e54b2fe43
2 changed files with 79 additions and 62 deletions

View File

@@ -15,8 +15,8 @@ use crate::table_script::handlers::dependency_analyzer::DependencyAnalyzer;
const SYSTEM_COLUMNS: &[&str] = &["id", "deleted", "created_at"]; const SYSTEM_COLUMNS: &[&str] = &["id", "deleted", "created_at"];
// Define prohibited data types for Steel scripts (boolean is explicitly allowed) // Define prohibited data types for Steel scripts (boolean is explicitly allowed)
const PROHIBITED_TYPES: &[&str] = &["DATE", "TIMESTAMPTZ"]; const PROHIBITED_TYPES: &[&str] = &["BIGINT", "DATE", "TIMESTAMPTZ"];
const MATH_PROHIBITED_TYPES: &[&str] = &["BIGINT", "TEXT", "BOOLEAN"]; const MATH_PROHIBITED_TYPES: &[&str] = &["BIGINT", "TEXT", "BOOLEAN", "DATE", "TIMESTAMPTZ"];
// Math operations that Steel Decimal will transform // Math operations that Steel Decimal will transform
const MATH_OPERATIONS: &[&str] = &[ const MATH_OPERATIONS: &[&str] = &[
@@ -616,12 +616,12 @@ pub async fn post_table_script(
) )
.map_err(|e| Status::invalid_argument(e))?; .map_err(|e| Status::invalid_argument(e))?;
// Validate that script doesn't reference prohibited column types by checking actual DB schema // REORDER: Math validation FIRST so we get specific error messages for math operations
validate_script_column_references(db_pool, table_def.schema_id, &request.script).await?;
// NEW: Validate that mathematical operations don't use TEXT or BOOLEAN columns
validate_math_operations_column_types(db_pool, table_def.schema_id, &request.script).await?; validate_math_operations_column_types(db_pool, table_def.schema_id, &request.script).await?;
// THEN general column validation (catches non-math prohibited access)
validate_script_column_references(db_pool, table_def.schema_id, &request.script).await?;
// Validate SQL queries in script for prohibited type operations // Validate SQL queries in script for prohibited type operations
validate_sql_queries_in_script(&request.script) validate_sql_queries_in_script(&request.script)
.map_err(|e| Status::invalid_argument(e))?; .map_err(|e| Status::invalid_argument(e))?;

View File

@@ -218,59 +218,76 @@ async fn test_advanced_validation_scenarios(
// Don't assert failure here - these are edge cases that might be handled differently // Don't assert failure here - these are edge cases that might be handled differently
} }
async fn create_table_link(pool: &PgPool, source_table_id: i64, linked_table_id: i64) {
sqlx::query!(
"INSERT INTO table_definition_links (source_table_id, linked_table_id, is_required)
VALUES ($1, $2, false)",
source_table_id,
linked_table_id
)
.execute(pool)
.await
.expect("Failed to create table link");
}
#[tokio::test] #[tokio::test]
async fn test_dependency_cycle_detection() { async fn test_dependency_cycle_detection() {
let pool = setup_isolated_db().await; let pool = setup_isolated_db().await;
let schema_id = get_default_schema_id(&pool).await; let schema_id = get_default_schema_id(&pool).await;
// Create two tables for dependency testing // Create table_b first
let table_a_columns = vec![
("value_a", "NUMERIC(10, 2)"),
("result_a", "NUMERIC(10, 2)"),
];
let table_a_id = create_test_table(&pool, schema_id, "table_a", table_a_columns).await;
let table_b_columns = vec![ let table_b_columns = vec![
("value_b", "NUMERIC(10, 2)"), ("value_b", "NUMERIC(10, 2)"),
("result_b", "NUMERIC(10, 2)"), ("result_b", "NUMERIC(10, 2)"),
]; ];
let table_b_id = create_test_table(&pool, schema_id, "table_b", table_b_columns).await; let table_b_id = create_test_table(&pool, schema_id, "table_b", table_b_columns).await;
// Create first dependency: table_a.result_a depends on table_b.value_b // Create table_a
let table_a_columns = vec![
("value_a", "NUMERIC(10, 2)"),
("result_a", "NUMERIC(10, 2)"),
];
let table_a_id = create_test_table(&pool, schema_id, "table_a", table_a_columns).await;
// CREATE BOTH LINKS for circular dependency testing
create_table_link(&pool, table_a_id, table_b_id).await; // table_a -> table_b
create_table_link(&pool, table_b_id, table_a_id).await; // table_b -> table_a
// First dependency should work
let script_a = r#"(+ (steel_get_column "table_b" "value_b") "10")"#; let script_a = r#"(+ (steel_get_column "table_b" "value_b") "10")"#;
let request_a = PostTableScriptRequest { let request_a = PostTableScriptRequest {
table_definition_id: table_a_id, table_definition_id: table_a_id,
target_column: "result_a".to_string(), target_column: "result_a".to_string(),
script: script_a.to_string(), script: script_a.to_string(),
description: "First dependency".to_string(), // Fixed: removed Some() description: "First dependency".to_string(),
}; };
let result_a = post_table_script(&pool, request_a).await; let result_a = post_table_script(&pool, request_a).await;
assert!(result_a.is_ok(), "First dependency should succeed"); assert!(result_a.is_ok(), "First dependency should succeed");
// Try to create circular dependency: table_b.result_b depends on table_a.result_a // Try circular dependency - should now work since links exist both ways
let script_b = r#"(* (steel_get_column "table_a" "result_a") "2")"#; let script_b = r#"(* (steel_get_column "table_a" "result_a") "2")"#;
let request_b = PostTableScriptRequest { let request_b = PostTableScriptRequest {
table_definition_id: table_b_id, table_definition_id: table_b_id,
target_column: "result_b".to_string(), target_column: "result_b".to_string(),
script: script_b.to_string(), script: script_b.to_string(),
description: "Circular dependency attempt".to_string(), // Fixed: removed Some() description: "Circular dependency attempt".to_string(),
}; };
let result_b = post_table_script(&pool, request_b).await; let result_b = post_table_script(&pool, request_b).await;
// Depending on implementation, this should either succeed or detect the cycle // This should either succeed or detect the cycle
match result_b { match result_b {
Ok(_) => { Ok(_) => {
// Implementation allows this pattern // Implementation allows this pattern
} }
Err(error) => { Err(error) => {
// Implementation detects circular dependencies // Implementation detects circular dependencies
let error_msg = error.to_string(); let error_msg = error.to_string().to_lowercase();
assert!( assert!(
error_msg.contains("cycle") || error_msg.contains("circular"), error_msg.contains("cycle") || error_msg.contains("circular"),
"Circular dependency should be detected properly: {}", "Circular dependency should be detected properly: {}",
error_msg error.to_string()
); );
} }
} }