working creation of profiles and tables for each profile

This commit is contained in:
filipriec
2025-03-01 19:08:52 +01:00
parent 87e465a36e
commit 4070348bee
3 changed files with 38 additions and 10 deletions

12
Cargo.lock generated
View File

@@ -1381,6 +1381,15 @@ dependencies = [
"libm",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.36.7"
@@ -1975,6 +1984,7 @@ dependencies = [
"serde",
"serde_json",
"sqlx",
"time",
"tokio",
"tonic",
"tonic-reflection",
@@ -2419,7 +2429,9 @@ checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",

View File

@@ -17,6 +17,7 @@ tokio = { version = "1.43.0", features = ["full", "macros"] }
tonic = "0.12.3"
tonic-reflection = "0.12.3"
tracing = "0.1.41"
time = { version = "0.3.37", features = ["local-offset"] }
[lib]
name = "server"

View File

@@ -2,6 +2,7 @@
use tonic::Status;
use sqlx::PgPool;
use serde_json::json;
use time::OffsetDateTime;
use common::proto::multieko2::table_definition::{PostTableDefinitionRequest, TableDefinitionResponse};
const VALID_DATA_TYPES: &[&str] = &["TEXT", "INTEGER", "BIGINT", "BOOLEAN", "TIMESTAMPTZ", "NUMERIC"];
@@ -11,16 +12,23 @@ fn is_valid_data_type(dt: &str) -> bool {
}
fn is_valid_identifier(s: &str) -> bool {
!s.is_empty() &&
s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') &&
!s.starts_with('_') &&
!s.chars().next().unwrap().is_ascii_digit()
let parts: Vec<&str> = s.split('_').collect();
parts.len() >= 3 &&
parts[0] == "ud" &&
parts[1].len() == 4 &&
parts[1].chars().all(|c| c.is_ascii_digit()) &&
parts[2..].iter().all(|p| !p.is_empty()) &&
s.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')
}
fn sanitize_identifier(s: &str) -> String {
s.replace(|c: char| !c.is_ascii_alphanumeric() && c != '_', "")
let year = OffsetDateTime::now_utc().year();
let cleaned = s.replace(|c: char| !c.is_ascii_alphanumeric() && c != '_', "")
.trim()
.to_lowercase()
.to_lowercase();
format!("ud_{}_{}", year, cleaned)
}
pub async fn post_table_definition(
@@ -49,10 +57,10 @@ pub async fn post_table_definition(
let linked_table_name = request.linked_table_name
.as_ref()
.map(|lt| sanitize_identifier(lt));
if let Some(lt_name) = &linked_table_name {
let lt_record = sqlx::query!(
"SELECT id FROM table_definitions
"SELECT id FROM table_definitions
WHERE profile_id = $1 AND table_name = $2",
profile.id,
lt_name
@@ -153,8 +161,15 @@ fn generate_table_sql(
];
if let Some(linked) = linked_table {
// Extract base name without prefix for relationship
let parts: Vec<&str> = linked.splitn(3, '_').collect();
let base_name = parts.get(2).unwrap_or(&linked);
system_columns.push(
format!("\"{}_id\" BIGINT NOT NULL REFERENCES \"{}\"(id)", linked, linked)
format!("\"{}_id\" BIGINT NOT NULL REFERENCES \"{}\"(id)",
base_name,
linked
)
);
}
@@ -184,7 +199,7 @@ fn generate_table_sql(
let all_indexes = system_indexes
.into_iter()
.chain(indexes.iter().map(|idx| {
format!("CREATE INDEX idx_{}_{} ON \"{}\" (\"{}\")",
format!("CREATE INDEX idx_{}_{} ON \"{}\" (\"{}\")",
table_name, idx, table_name, idx)
}))
.collect::<Vec<_>>();