data_modelling_sdk/models/
column.rs1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8pub struct ForeignKey {
9 pub table_id: String,
11 pub column_name: String,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28pub struct Column {
29 pub name: String,
31 pub data_type: String,
33 #[serde(default = "default_true")]
35 pub nullable: bool,
36 #[serde(default)]
38 pub primary_key: bool,
39 #[serde(default)]
41 pub secondary_key: bool,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub composite_key: Option<String>,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub foreign_key: Option<ForeignKey>,
48 #[serde(default)]
50 pub constraints: Vec<String>,
51 #[serde(default)]
53 pub description: String,
54 #[serde(default)]
56 pub errors: Vec<HashMap<String, serde_json::Value>>,
57 #[serde(default)]
59 pub quality: Vec<HashMap<String, serde_json::Value>>,
60 #[serde(skip_serializing_if = "Option::is_none", rename = "$ref")]
62 pub ref_path: Option<String>,
63 #[serde(default)]
65 pub enum_values: Vec<String>,
66 #[serde(default)]
68 pub column_order: i32,
69}
70
71fn default_true() -> bool {
72 true
73}
74
75impl Column {
76 pub fn new(name: String, data_type: String) -> Self {
95 Self {
96 name,
97 data_type: normalize_data_type(&data_type),
98 nullable: true,
99 primary_key: false,
100 secondary_key: false,
101 composite_key: None,
102 foreign_key: None,
103 constraints: Vec::new(),
104 description: String::new(),
105 errors: Vec::new(),
106 quality: Vec::new(),
107 ref_path: None,
108 enum_values: Vec::new(),
109 column_order: 0,
110 }
111 }
112}
113
114fn normalize_data_type(data_type: &str) -> String {
115 if data_type.is_empty() {
116 return data_type.to_string();
117 }
118
119 let upper = data_type.to_uppercase();
120
121 if upper.starts_with("STRUCT") {
123 if let Some(start) = data_type.find('<')
124 && let Some(end) = data_type.rfind('>')
125 {
126 let inner = &data_type[start + 1..end];
127 return format!("STRUCT<{}>", inner);
128 }
129 return format!("STRUCT{}", &data_type[6..]);
130 } else if upper.starts_with("ARRAY") {
131 if let Some(start) = data_type.find('<')
132 && let Some(end) = data_type.rfind('>')
133 {
134 let inner = &data_type[start + 1..end];
135 return format!("ARRAY<{}>", inner);
136 }
137 return format!("ARRAY{}", &data_type[5..]);
138 } else if upper.starts_with("MAP") {
139 if let Some(start) = data_type.find('<')
140 && let Some(end) = data_type.rfind('>')
141 {
142 let inner = &data_type[start + 1..end];
143 return format!("MAP<{}>", inner);
144 }
145 return format!("MAP{}", &data_type[3..]);
146 }
147
148 upper
149}