now working proper types
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use tonic::Status;
|
use tonic::Status;
|
||||||
|
|
||||||
|
// TODO in the future, remove database query on every request and implement caching for scalable
|
||||||
|
// solution with many data and requests
|
||||||
|
|
||||||
/// Qualifies a table name by checking for its existence in the table_definitions table.
|
/// Qualifies a table name by checking for its existence in the table_definitions table.
|
||||||
/// This is the robust, "source of truth" approach.
|
/// This is the robust, "source of truth" approach.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
use tonic::Status;
|
use tonic::Status;
|
||||||
use sqlx::{PgPool, Transaction, Postgres};
|
use sqlx::{PgPool, Transaction, Postgres};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use time::OffsetDateTime;
|
|
||||||
use common::proto::multieko2::table_definition::{PostTableDefinitionRequest, TableDefinitionResponse};
|
use common::proto::multieko2::table_definition::{PostTableDefinitionRequest, TableDefinitionResponse};
|
||||||
|
|
||||||
const GENERATED_SCHEMA_NAME: &str = "gen";
|
const GENERATED_SCHEMA_NAME: &str = "gen";
|
||||||
|
|
||||||
const PREDEFINED_FIELD_TYPES: &[(&str, &str)] = &[
|
const PREDEFINED_FIELD_TYPES: &[(&str, &str)] = &[
|
||||||
("text", "TEXT"),
|
("text", "TEXT"),
|
||||||
("psc", "TEXT"),
|
("string", "TEXT"),
|
||||||
("phone", "VARCHAR(15)"),
|
|
||||||
("address", "TEXT"),
|
|
||||||
("email", "VARCHAR(255)"),
|
|
||||||
("boolean", "BOOLEAN"),
|
("boolean", "BOOLEAN"),
|
||||||
("timestamp", "TIMESTAMPTZ"),
|
("timestamp", "TIMESTAMPTZ"),
|
||||||
|
("time", "TIMESTAMPTZ"),
|
||||||
|
("money", "NUMERIC(14, 4)"),
|
||||||
|
("integer", "INTEGER"),
|
||||||
|
("date", "DATE"),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn is_valid_identifier(s: &str) -> bool {
|
fn is_valid_identifier(s: &str) -> bool {
|
||||||
@@ -35,12 +35,60 @@ fn sanitize_identifier(s: &str) -> String {
|
|||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_field_type(field_type: &str) -> Result<&str, Status> {
|
fn map_field_type(field_type: &str) -> Result<String, Status> {
|
||||||
|
let lower_field_type = field_type.to_lowercase();
|
||||||
|
|
||||||
|
// Special handling for "decimal(precision, scale)"
|
||||||
|
if lower_field_type.starts_with("decimal(") && lower_field_type.ends_with(')') {
|
||||||
|
// Extract the part inside the parentheses, e.g., "10, 2"
|
||||||
|
let args = lower_field_type
|
||||||
|
.strip_prefix("decimal(")
|
||||||
|
.and_then(|s| s.strip_suffix(')'))
|
||||||
|
.unwrap_or(""); // Should always succeed due to the checks above
|
||||||
|
|
||||||
|
// Split into precision and scale parts
|
||||||
|
if let Some((p_str, s_str)) = args.split_once(',') {
|
||||||
|
// Parse precision, returning an error if it's not a valid number
|
||||||
|
let precision = p_str.trim().parse::<u32>().map_err(|_| {
|
||||||
|
Status::invalid_argument("Invalid precision in decimal type")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Parse scale, returning an error if it's not a valid number
|
||||||
|
let scale = s_str.trim().parse::<u32>().map_err(|_| {
|
||||||
|
Status::invalid_argument("Invalid scale in decimal type")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Add validation based on PostgreSQL rules
|
||||||
|
if precision < 1 {
|
||||||
|
return Err(Status::invalid_argument("Precision must be at least 1"));
|
||||||
|
}
|
||||||
|
if scale > precision {
|
||||||
|
return Err(Status::invalid_argument(
|
||||||
|
"Scale cannot be greater than precision",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If everything is valid, build and return the NUMERIC type string
|
||||||
|
return Ok(format!("NUMERIC({}, {})", precision, scale));
|
||||||
|
} else {
|
||||||
|
// The format was wrong, e.g., "decimal(10)" or "decimal()"
|
||||||
|
return Err(Status::invalid_argument(
|
||||||
|
"Invalid decimal format. Expected: decimal(precision, scale)",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not a decimal, fall back to the predefined list
|
||||||
PREDEFINED_FIELD_TYPES
|
PREDEFINED_FIELD_TYPES
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(key, _)| *key == field_type.to_lowercase().as_str())
|
.find(|(key, _)| *key == lower_field_type.as_str())
|
||||||
.map(|(_, sql_type)| *sql_type)
|
.map(|(_, sql_type)| sql_type.to_string()) // Convert to an owned String
|
||||||
.ok_or_else(|| Status::invalid_argument(format!("Invalid field type: {}", field_type)))
|
.ok_or_else(|| {
|
||||||
|
Status::invalid_argument(format!(
|
||||||
|
"Invalid field type: {}",
|
||||||
|
field_type
|
||||||
|
))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_invalid_table_name(table_name: &str) -> bool {
|
fn is_invalid_table_name(table_name: &str) -> bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user