saving steel script into the database

This commit is contained in:
filipriec
2025-03-07 20:37:32 +01:00
parent b01eeddfe0
commit 965ffee35a
8 changed files with 65 additions and 80 deletions

View File

@@ -2,17 +2,16 @@
use tonic::Status;
use sqlx::{PgPool, Error as SqlxError};
use common::proto::multieko2::table_script::{PostTableScriptRequest, TableScriptResponse};
use regex::Regex;
use std::collections::HashSet;
use crate::steel::handlers::evaluator::{validate_script, validate_target_column};
pub async fn post_table_script(
db_pool: &PgPool,
request: PostTableScriptRequest,
) -> Result<TableScriptResponse, Status> {
// Fetch table definition
// Basic validation
let table_def = sqlx::query!(
r#"SELECT table_name, columns, linked_table_id
FROM table_definitions WHERE id = $1"#,
r#"SELECT id, table_name, columns, profile_id
FROM table_definitions WHERE id = $1"#,
request.table_definition_id
)
.fetch_optional(db_pool)
@@ -20,22 +19,26 @@ pub async fn post_table_script(
.map_err(|e| Status::internal(format!("Database error: {}", e)))?
.ok_or_else(|| Status::not_found("Table definition not found"))?;
// Extract source tables and columns from the script
let (source_tables, source_columns) = extract_sources(&request.script, &db_pool).await
.map_err(|e| Status::invalid_argument(format!("Source extraction error: {}", e)))?;
// Call validation functions
validate_script(&request.script) // Changed from validate_syntax to validate_script
.map_err(|e| Status::invalid_argument(e))?;
validate_target_column(&table_def.table_name, &request.target_column, &table_def.columns)
.map_err(|e| Status::invalid_argument(e))?;
// Handle optional description
let description = request.description;
// Store script in database
let script_record = sqlx::query!(
r#"INSERT INTO table_scripts
(table_definitions_id, target_column, script, source_tables, source_columns, description)
VALUES ($1, $2, $3, $4, $5, $6)
(table_definitions_id, target_column, script, description)
VALUES ($1, $2, $3, $4)
RETURNING id"#,
request.table_definition_id,
request.target_column,
request.script,
&source_tables as &[String],
&source_columns as &[String],
request.description.unwrap_or_default()
description
)
.fetch_one(db_pool)
.await
@@ -51,61 +54,3 @@ pub async fn post_table_script(
warnings: String::new(),
})
}
// Extract source tables and columns from the script
async fn extract_sources(script: &str, pool: &PgPool) -> Result<(Vec<String>, Vec<String>), String> {
let mut tables = HashSet::new();
let mut columns = HashSet::new();
// Regular expression to find table/column references
// In Steel, we're looking for patterns like:
// - (get-table-column "table_name" "column_name")
// - column8 (for the current table)
// Pattern for explicit table.column references
let table_column_pattern = Regex::new(r#"\(get-table-column\s+"([^"]+)"\s+"([^"]+)"\)"#)
.map_err(|e| format!("Regex error: {}", e))?;
// Add current table's columns (simple column references)
let column_pattern = Regex::new(r#"column\d+"#)
.map_err(|e| format!("Regex error: {}", e))?;
// Find all table.column references
for cap in table_column_pattern.captures_iter(script) {
if let (Some(table_match), Some(column_match)) = (cap.get(1), cap.get(2)) {
let table_name = table_match.as_str().to_string();
let column_name = column_match.as_str().to_string();
// Verify table exists in the database
let table_exists = sqlx::query!(
"SELECT EXISTS(SELECT 1 FROM pg_tables WHERE tablename = $1) as exists",
table_name
)
.fetch_one(pool)
.await
.map_err(|e| format!("Database error: {}", e))?
.exists
.unwrap_or(false);
if !table_exists {
return Err(format!("Referenced table '{}' does not exist", table_name));
}
tables.insert(table_name);
columns.insert(format!("{}.{}", table_name, column_name));
}
}
// Find simple column references (assumed to be from the current table)
for column_match in column_pattern.find_iter(script) {
columns.insert(column_match.as_str().to_string());
}
// Ensure at least one table is identified
if tables.is_empty() {
// If no explicit tables found, assume it's using the current table
tables.insert("current".to_string());
}
Ok((tables.into_iter().collect(), columns.into_iter().collect()))
}