better schema to original migration files
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
❯ grpcurl -plaintext -d '{
|
❯ grpcurl -plaintext -d '{
|
||||||
"table_name": "company_data",
|
"table_name": "company_data3",
|
||||||
"columns": [
|
"columns": [
|
||||||
{"name": "company_name", "field_type": "text"},
|
{"name": "company_name", "field_type": "text"},
|
||||||
{"name": "textfield", "field_type": "text"},
|
{"name": "textfield", "field_type": "text"},
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
}' localhost:50051 multieko2.table_definition.TableDefinition/PostTableDefinition
|
}' localhost:50051 multieko2.table_definition.TableDefinition/PostTableDefinition
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"sql": "CREATE TABLE \"2025_company_data\" (\n id BIGSERIAL PRIMARY KEY,\n deleted BOOLEAN NOT NULL DEFAULT FALSE,\n firma TEXT NOT NULL,\n \"2025_test_table_id\" BIGINT NOT NULL REFERENCES \"ud_2025_test_table\"(id),\n \"2025_company_name\" TEXT,\n \"2025_textfield\" TEXT,\n \"2025_textfield2\" TEXT,\n \"2025_textfield3\" TEXT,\n \"2025_headquarters_psc\" TEXT,\n \"2025_contact_phone\" VARCHAR(15),\n \"2025_office_address\" TEXT,\n \"2025_support_email\" VARCHAR(255),\n \"2025_is_active\" BOOLEAN,\n \"2025_last_updated\" TIMESTAMPTZ,\n created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP\n)\nCREATE INDEX idx_2025_company_data_firma ON \"2025_company_data\" (firma)\nCREATE INDEX idx_2025_company_data_2025_test_table_id ON \"2025_company_data\" (\"2025_test_table_id\")\nCREATE INDEX idx_2025_company_data_2025_company_name ON \"2025_company_data\" (\"2025_company_name\")\nCREATE INDEX idx_2025_company_data_2025_is_active ON \"2025_company_data\" (\"2025_is_active\")"
|
"sql": "CREATE TABLE \"2025_company_data3\" (\n id BIGSERIAL PRIMARY KEY,\n deleted BOOLEAN NOT NULL DEFAULT FALSE,\n firma TEXT NOT NULL,\n \"2025_test_table_id\" BIGINT NOT NULL REFERENCES \"ud_2025_test_table\"(id),\n \"company_name\" TEXT,\n \"textfield\" TEXT,\n \"textfield2\" TEXT,\n \"textfield3\" TEXT,\n \"headquarters_psc\" TEXT,\n \"contact_phone\" VARCHAR(15),\n \"office_address\" TEXT,\n \"support_email\" VARCHAR(255),\n \"is_active\" BOOLEAN,\n \"last_updated\" TIMESTAMPTZ,\n created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP\n)\nCREATE INDEX idx_2025_company_data3_firma ON \"2025_company_data3\" (firma)\nCREATE INDEX idx_2025_company_data3_2025_test_table_id ON \"2025_company_data3\" (\"2025_test_table_id\")"
|
||||||
}
|
}
|
||||||
❯ psql -U multi_psql_dev -d multi_rust_dev
|
❯ psql -U multi_psql_dev -d multi_rust_dev
|
||||||
psql (17.2)
|
psql (17.2)
|
||||||
@@ -29,6 +29,7 @@ multi_rust_dev=> \dt
|
|||||||
Schema | Name | Type | Owner
|
Schema | Name | Type | Owner
|
||||||
--------+--------------------------------+-------+----------------
|
--------+--------------------------------+-------+----------------
|
||||||
public | 2025_company_data | table | multi_psql_dev
|
public | 2025_company_data | table | multi_psql_dev
|
||||||
|
public | 2025_company_data3 | table | multi_psql_dev
|
||||||
public | 2025_multi_dependent_table3 | table | multi_psql_dev
|
public | 2025_multi_dependent_table3 | table | multi_psql_dev
|
||||||
public | 2025_multi_dependent_table4 | table | multi_psql_dev
|
public | 2025_multi_dependent_table4 | table | multi_psql_dev
|
||||||
public | 2025_multi_dependent_table5 | table | multi_psql_dev
|
public | 2025_multi_dependent_table5 | table | multi_psql_dev
|
||||||
@@ -45,34 +46,61 @@ multi_rust_dev=> \dt
|
|||||||
public | ud_2025_profile_table | table | multi_psql_dev
|
public | ud_2025_profile_table | table | multi_psql_dev
|
||||||
public | ud_2025_test_table | table | multi_psql_dev
|
public | ud_2025_test_table | table | multi_psql_dev
|
||||||
public | ud_2025_test_table_no_linked | table | multi_psql_dev
|
public | ud_2025_test_table_no_linked | table | multi_psql_dev
|
||||||
(17 rows)
|
(18 rows)
|
||||||
|
|
||||||
multi_rust_dev=> \d 2025_company_data
|
multi_rust_dev=> \d adresar
|
||||||
Table "public.2025_company_data"
|
Table "public.adresar"
|
||||||
Column | Type | Collation | Nullable | Default
|
Column | Type | Collation | Nullable | Default
|
||||||
-----------------------+--------------------------+-----------+----------+-------------------------------------------------
|
------------+--------------------------+-----------+----------+-------------------------------------
|
||||||
id | bigint | | not null | nextval('"2025_company_data_id_seq"'::regclass)
|
id | bigint | | not null | nextval('adresar_id_seq'::regclass)
|
||||||
deleted | boolean | | not null | false
|
deleted | boolean | | not null | false
|
||||||
firma | text | | not null |
|
firma | text | | not null |
|
||||||
2025_test_table_id | bigint | | not null |
|
kz | text | | |
|
||||||
2025_company_name | text | | |
|
drc | text | | |
|
||||||
2025_textfield | text | | |
|
ulica | text | | |
|
||||||
2025_textfield2 | text | | |
|
psc | text | | |
|
||||||
2025_textfield3 | text | | |
|
mesto | text | | |
|
||||||
2025_headquarters_psc | text | | |
|
stat | text | | |
|
||||||
2025_contact_phone | character varying(15) | | |
|
banka | text | | |
|
||||||
2025_office_address | text | | |
|
ucet | text | | |
|
||||||
2025_support_email | character varying(255) | | |
|
skladm | text | | |
|
||||||
2025_is_active | boolean | | |
|
ico | text | | |
|
||||||
2025_last_updated | timestamp with time zone | | |
|
kontakt | text | | |
|
||||||
created_at | timestamp with time zone | | | CURRENT_TIMESTAMP
|
telefon | text | | |
|
||||||
|
skladu | text | | |
|
||||||
|
fax | text | | |
|
||||||
|
created_at | timestamp with time zone | | | CURRENT_TIMESTAMP
|
||||||
Indexes:
|
Indexes:
|
||||||
"2025_company_data_pkey" PRIMARY KEY, btree (id)
|
"adresar_pkey" PRIMARY KEY, btree (id)
|
||||||
"idx_2025_company_data_2025_company_name" btree ("2025_company_name")
|
"idx_adresar_firma" btree (firma)
|
||||||
"idx_2025_company_data_2025_is_active" btree ("2025_is_active")
|
"idx_adresar_mesto" btree (mesto)
|
||||||
"idx_2025_company_data_2025_test_table_id" btree ("2025_test_table_id")
|
Referenced by:
|
||||||
"idx_2025_company_data_firma" btree (firma)
|
TABLE "uctovnictvo" CONSTRAINT "uctovnictvo_adresar_id_fkey" FOREIGN KEY (adresar_id) REFERENCES adresar(id)
|
||||||
|
|
||||||
|
multi_rust_dev=> \d 2025_company_data3
|
||||||
|
Table "public.2025_company_data3"
|
||||||
|
Column | Type | Collation | Nullable | Default
|
||||||
|
--------------------+--------------------------+-----------+----------+--------------------------------------------------
|
||||||
|
id | bigint | | not null | nextval('"2025_company_data3_id_seq"'::regclass)
|
||||||
|
deleted | boolean | | not null | false
|
||||||
|
firma | text | | not null |
|
||||||
|
2025_test_table_id | bigint | | not null |
|
||||||
|
company_name | text | | |
|
||||||
|
textfield | text | | |
|
||||||
|
textfield2 | text | | |
|
||||||
|
textfield3 | text | | |
|
||||||
|
headquarters_psc | text | | |
|
||||||
|
contact_phone | character varying(15) | | |
|
||||||
|
office_address | text | | |
|
||||||
|
support_email | character varying(255) | | |
|
||||||
|
is_active | boolean | | |
|
||||||
|
last_updated | timestamp with time zone | | |
|
||||||
|
created_at | timestamp with time zone | | | CURRENT_TIMESTAMP
|
||||||
|
Indexes:
|
||||||
|
"2025_company_data3_pkey" PRIMARY KEY, btree (id)
|
||||||
|
"idx_2025_company_data3_2025_test_table_id" btree ("2025_test_table_id")
|
||||||
|
"idx_2025_company_data3_firma" btree (firma)
|
||||||
Foreign-key constraints:
|
Foreign-key constraints:
|
||||||
"2025_company_data_2025_test_table_id_fkey" FOREIGN KEY ("2025_test_table_id") REFERENCES ud_2025_test_table(id)
|
"2025_company_data3_2025_test_table_id_fkey" FOREIGN KEY ("2025_test_table_id") REFERENCES ud_2025_test_table(id)
|
||||||
|
|
||||||
multi_rust_dev=>
|
multi_rust_dev=>
|
||||||
|
|||||||
@@ -22,16 +22,21 @@ fn is_valid_identifier(s: &str) -> bool {
|
|||||||
!s.chars().next().unwrap().is_ascii_digit()
|
!s.chars().next().unwrap().is_ascii_digit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sanitize_identifier(s: &str) -> String {
|
fn sanitize_table_name(s: &str) -> String {
|
||||||
let year = OffsetDateTime::now_utc().year();
|
let year = OffsetDateTime::now_utc().year();
|
||||||
let cleaned = s.replace(|c: char| !c.is_ascii_alphanumeric() && c != '_', "")
|
let cleaned = s.replace(|c: char| !c.is_ascii_alphanumeric() && c != '_', "")
|
||||||
.trim()
|
.trim()
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
|
|
||||||
// Format: "currentyear_tablename"
|
|
||||||
format!("{}_{}", year, cleaned)
|
format!("{}_{}", year, cleaned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sanitize_identifier(s: &str) -> String {
|
||||||
|
s.replace(|c: char| !c.is_ascii_alphanumeric() && c != '_', "")
|
||||||
|
.trim()
|
||||||
|
.to_lowercase()
|
||||||
|
}
|
||||||
|
|
||||||
fn map_field_type(field_type: &str) -> Result<&str, Status> {
|
fn map_field_type(field_type: &str) -> Result<&str, Status> {
|
||||||
PREDEFINED_FIELD_TYPES
|
PREDEFINED_FIELD_TYPES
|
||||||
.iter()
|
.iter()
|
||||||
@@ -44,8 +49,8 @@ pub async fn post_table_definition(
|
|||||||
db_pool: &PgPool,
|
db_pool: &PgPool,
|
||||||
mut request: PostTableDefinitionRequest,
|
mut request: PostTableDefinitionRequest,
|
||||||
) -> Result<TableDefinitionResponse, Status> {
|
) -> Result<TableDefinitionResponse, Status> {
|
||||||
// Validate and sanitize inputs
|
// Validate and sanitize table name
|
||||||
let table_name = sanitize_identifier(&request.table_name);
|
let table_name = sanitize_table_name(&request.table_name);
|
||||||
if !is_valid_identifier(&request.table_name) {
|
if !is_valid_identifier(&request.table_name) {
|
||||||
return Err(Status::invalid_argument("Invalid table name"));
|
return Err(Status::invalid_argument("Invalid table name"));
|
||||||
}
|
}
|
||||||
@@ -61,8 +66,10 @@ pub async fn post_table_definition(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| Status::internal(format!("Profile error: {}", e)))?;
|
.map_err(|e| Status::internal(format!("Profile error: {}", e)))?;
|
||||||
|
|
||||||
// Validate linked table if provided
|
// Declare linked_table_id here
|
||||||
let linked_table_id;
|
let linked_table_id;
|
||||||
|
|
||||||
|
// Validate linked table if provided
|
||||||
if let Some(lt_name) = &request.linked_table_name {
|
if let Some(lt_name) = &request.linked_table_name {
|
||||||
let lt_record = sqlx::query!(
|
let lt_record = sqlx::query!(
|
||||||
"SELECT id FROM table_definitions
|
"SELECT id FROM table_definitions
|
||||||
@@ -81,19 +88,28 @@ pub async fn post_table_definition(
|
|||||||
} else {
|
} else {
|
||||||
linked_table_id = None;
|
linked_table_id = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate columns and indexes
|
// Process columns without year prefix
|
||||||
let mut columns = Vec::new();
|
let mut columns = Vec::new();
|
||||||
for col_def in request.columns.drain(..) {
|
for col_def in request.columns.drain(..) {
|
||||||
let col_name = sanitize_identifier(&col_def.name);
|
let col_name = sanitize_identifier(&col_def.name); // No year prefix
|
||||||
if !is_valid_identifier(&col_def.name) {
|
if !is_valid_identifier(&col_def.name) {
|
||||||
return Err(Status::invalid_argument("Invalid column name"));
|
return Err(Status::invalid_argument("Invalid column name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let sql_type = map_field_type(&col_def.field_type)?;
|
let sql_type = map_field_type(&col_def.field_type)?;
|
||||||
columns.push(format!("\"{}\" {}", col_name, sql_type));
|
columns.push(format!("\"{}\" {}", col_name, sql_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process indexes without year prefix
|
||||||
|
let mut indexes = Vec::new();
|
||||||
|
for idx in request.indexes.drain(..) {
|
||||||
|
let idx_name = sanitize_identifier(&idx); // No year prefix
|
||||||
|
if !is_valid_identifier(&idx) {
|
||||||
|
return Err(Status::invalid_argument(format!("Invalid index name: {}", idx)));
|
||||||
|
}
|
||||||
|
indexes.push(idx_name);
|
||||||
|
}
|
||||||
|
|
||||||
let mut indexes = Vec::new();
|
let mut indexes = Vec::new();
|
||||||
for idx in request.indexes.drain(..) {
|
for idx in request.indexes.drain(..) {
|
||||||
let idx_name = sanitize_identifier(&idx);
|
let idx_name = sanitize_identifier(&idx);
|
||||||
|
|||||||
Reference in New Issue
Block a user