90 lines
2.8 KiB
Rust
90 lines
2.8 KiB
Rust
// src/table_script/handlers/post_table_script.rs
|
|
use tonic::Status;
|
|
use sqlx::{PgPool, Error as SqlxError};
|
|
use common::proto::multieko2::table_script::{PostTableScriptRequest, TableScriptResponse};
|
|
use serde_json::Value;
|
|
|
|
const SYSTEM_COLUMNS: &[&str] = &["id", "deleted", "created_at"];
|
|
|
|
fn validate_target_column(
|
|
table_name: &str,
|
|
target: &str,
|
|
table_columns: &Value,
|
|
) -> Result<String, String> {
|
|
if SYSTEM_COLUMNS.contains(&target) {
|
|
return Err(format!("Cannot override system column: {}", target));
|
|
}
|
|
|
|
let columns: Vec<String> = serde_json::from_value(table_columns.clone())
|
|
.map_err(|e| format!("Invalid column data: {}", e))?;
|
|
|
|
// Extract column name and type
|
|
let column_info: Vec<(&str, &str)> = columns
|
|
.iter()
|
|
.filter_map(|c| {
|
|
let mut parts = c.split_whitespace();
|
|
let name = parts.next()?.trim_matches('"');
|
|
let data_type = parts.next()?;
|
|
Some((name, data_type))
|
|
})
|
|
.collect();
|
|
|
|
// Find the target column
|
|
let column_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())
|
|
}
|
|
|
|
pub async fn post_table_script(
|
|
db_pool: &PgPool,
|
|
request: PostTableScriptRequest,
|
|
) -> Result<TableScriptResponse, Status> {
|
|
let table_def = sqlx::query!(
|
|
r#"SELECT id, table_name, columns, profile_id
|
|
FROM table_definitions WHERE id = $1"#,
|
|
request.table_definition_id
|
|
)
|
|
.fetch_optional(db_pool)
|
|
.await
|
|
.map_err(|e| Status::internal(format!("Database error: {}", e)))?
|
|
.ok_or_else(|| Status::not_found("Table definition not found"))?;
|
|
|
|
// Validate target column and get its type
|
|
let column_type = validate_target_column(
|
|
&table_def.table_name,
|
|
&request.target_column,
|
|
&table_def.columns,
|
|
)
|
|
.map_err(|e| Status::invalid_argument(e))?;
|
|
|
|
// Store script in database with column type
|
|
let script_record = sqlx::query!(
|
|
r#"INSERT INTO table_scripts
|
|
(table_definitions_id, target_column, target_column_type, script, description)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING id"#,
|
|
request.table_definition_id,
|
|
request.target_column,
|
|
column_type,
|
|
request.script,
|
|
request.description
|
|
)
|
|
.fetch_one(db_pool)
|
|
.await
|
|
.map_err(|e| match e {
|
|
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)),
|
|
})?;
|
|
|
|
Ok(TableScriptResponse {
|
|
id: script_record.id,
|
|
warnings: String::new(),
|
|
})
|
|
}
|