removal of hardcoded fix, now working in general

This commit is contained in:
filipriec
2025-07-24 21:56:07 +02:00
parent 089d728cc7
commit 4df6c40034
2 changed files with 42 additions and 43 deletions

View File

@@ -106,7 +106,11 @@ impl DependencyAnalyzer {
/// Analyzes a Steel script to extract all table dependencies /// Analyzes a Steel script to extract all table dependencies
/// Uses regex patterns to find function calls that create dependencies /// Uses regex patterns to find function calls that create dependencies
pub fn analyze_script_dependencies(&self, script: &str) -> Result<Vec<Dependency>, DependencyError> { ///
/// # Arguments
/// * `script` - The Steel script to analyze
/// * `current_table_name` - Name of the table this script belongs to (for self-references)
pub fn analyze_script_dependencies(&self, script: &str, current_table_name: &str) -> Result<Vec<Dependency>, DependencyError> {
let mut dependencies = Vec::new(); let mut dependencies = Vec::new();
// Extract function calls and SQL dependencies using regex // Extract function calls and SQL dependencies using regex
@@ -114,10 +118,10 @@ impl DependencyAnalyzer {
dependencies.extend(self.extract_sql_dependencies(script)?); dependencies.extend(self.extract_sql_dependencies(script)?);
// Extract get-var calls (for transformed scripts with variables) // Extract get-var calls (for transformed scripts with variables)
dependencies.extend(self.extract_get_var_calls(script)?); dependencies.extend(self.extract_get_var_calls(script, current_table_name)?);
// Extract direct variable references like @price, @quantity // Extract direct variable references like @price, @quantity
dependencies.extend(self.extract_variable_references(script)?); dependencies.extend(self.extract_variable_references(script, current_table_name)?);
Ok(dependencies) Ok(dependencies)
} }
@@ -160,7 +164,8 @@ impl DependencyAnalyzer {
} }
/// Extract get-var calls as dependencies (for transformed scripts with variables) /// Extract get-var calls as dependencies (for transformed scripts with variables)
fn extract_get_var_calls(&self, script: &str) -> Result<Vec<Dependency>, DependencyError> { /// These are self-references to the current table
fn extract_get_var_calls(&self, script: &str, current_table_name: &str) -> Result<Vec<Dependency>, DependencyError> {
let mut dependencies = Vec::new(); let mut dependencies = Vec::new();
// Look for get-var patterns in transformed scripts: (get-var "variable") // Look for get-var patterns in transformed scripts: (get-var "variable")
@@ -170,7 +175,7 @@ impl DependencyAnalyzer {
for caps in get_var_pattern.captures_iter(script) { for caps in get_var_pattern.captures_iter(script) {
let variable_name = caps[1].to_string(); let variable_name = caps[1].to_string();
dependencies.push(Dependency { dependencies.push(Dependency {
target_table: "SAME_TABLE".to_string(), // Special marker for same-table references target_table: current_table_name.to_string(), // Use actual table name
dependency_type: DependencyType::ColumnAccess { column: variable_name }, dependency_type: DependencyType::ColumnAccess { column: variable_name },
context: None, context: None,
}); });
@@ -180,7 +185,8 @@ impl DependencyAnalyzer {
} }
/// Extract direct variable references like @price, @quantity /// Extract direct variable references like @price, @quantity
fn extract_variable_references(&self, script: &str) -> Result<Vec<Dependency>, DependencyError> { /// These are self-references to the current table
fn extract_variable_references(&self, script: &str, current_table_name: &str) -> Result<Vec<Dependency>, DependencyError> {
let mut dependencies = Vec::new(); let mut dependencies = Vec::new();
// Look for @variable patterns: @price, @quantity, etc. // Look for @variable patterns: @price, @quantity, etc.
@@ -190,7 +196,7 @@ impl DependencyAnalyzer {
for caps in variable_pattern.captures_iter(script) { for caps in variable_pattern.captures_iter(script) {
let variable_name = caps[1].to_string(); let variable_name = caps[1].to_string();
dependencies.push(Dependency { dependencies.push(Dependency {
target_table: "SAME_TABLE".to_string(), // Same table reference target_table: current_table_name.to_string(), // Use actual table name
dependency_type: DependencyType::ColumnAccess { column: variable_name }, dependency_type: DependencyType::ColumnAccess { column: variable_name },
context: None, context: None,
}); });
@@ -286,11 +292,8 @@ impl DependencyAnalyzer {
// Add new dependencies to test - EXCLUDE self-references // Add new dependencies to test - EXCLUDE self-references
for dep in new_dependencies { for dep in new_dependencies {
// Look up target table ID // Look up target table ID using the actual table name
let target_id = if dep.target_table == "SAME_TABLE" { let target_id = sqlx::query_scalar!(
table_id // Same table reference
} else {
sqlx::query_scalar!(
"SELECT id FROM table_definitions WHERE schema_id = $1 AND table_name = $2", "SELECT id FROM table_definitions WHERE schema_id = $1 AND table_name = $2",
self.schema_id, self.schema_id,
dep.target_table dep.target_table
@@ -301,8 +304,7 @@ impl DependencyAnalyzer {
.ok_or_else(|| DependencyError::InvalidTableReference { .ok_or_else(|| DependencyError::InvalidTableReference {
table_name: dep.target_table.clone(), table_name: dep.target_table.clone(),
script_context: format!("table_id_{}", table_id), script_context: format!("table_id_{}", table_id),
})? })?;
};
// Only add to cycle detection graph if it's NOT a self-reference // Only add to cycle detection graph if it's NOT a self-reference
if table_id != target_id { if table_id != target_id {
@@ -444,8 +446,8 @@ impl DependencyAnalyzer {
match &dep.dependency_type { match &dep.dependency_type {
// Structured access must respect link constraints (but self-references are always allowed) // Structured access must respect link constraints (but self-references are always allowed)
DependencyType::ColumnAccess { column } | DependencyType::IndexedAccess { column, .. } => { DependencyType::ColumnAccess { column } | DependencyType::IndexedAccess { column, .. } => {
// Skip validation for SAME_TABLE marker (these are always allowed) // Self-references are always allowed (compare table names directly)
if dep.target_table == "SAME_TABLE" { if dep.target_table == current_table_name {
continue; continue;
} }
@@ -522,10 +524,8 @@ impl DependencyAnalyzer {
// Insert new dependencies // Insert new dependencies
for dep in dependencies { for dep in dependencies {
let target_id = if dep.target_table == "SAME_TABLE" { // Look up target table ID using actual table name (no magic strings!)
table_id // Use the same table as the script let target_id = sqlx::query_scalar!(
} else {
sqlx::query_scalar!(
"SELECT id FROM table_definitions WHERE schema_id = $1 AND table_name = $2", "SELECT id FROM table_definitions WHERE schema_id = $1 AND table_name = $2",
self.schema_id, self.schema_id,
dep.target_table dep.target_table
@@ -536,8 +536,7 @@ impl DependencyAnalyzer {
.ok_or_else(|| DependencyError::InvalidTableReference { .ok_or_else(|| DependencyError::InvalidTableReference {
table_name: dep.target_table.clone(), table_name: dep.target_table.clone(),
script_context: format!("script_id_{}", script_id), script_context: format!("script_id_{}", script_id),
})? })?;
};
sqlx::query!( sqlx::query!(
r#"INSERT INTO script_dependencies r#"INSERT INTO script_dependencies

View File

@@ -631,7 +631,7 @@ pub async fn post_table_script(
// Analyze script dependencies // Analyze script dependencies
let dependencies = analyzer let dependencies = analyzer
.analyze_script_dependencies(&request.script) .analyze_script_dependencies(&request.script, &table_def.table_name)
.map_err(|e| Status::from(e))?; .map_err(|e| Status::from(e))?;
// Check for circular dependencies BEFORE making any changes // Check for circular dependencies BEFORE making any changes