1use 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)]
17pub struct PropertyRelationship {
18 #[serde(rename = "type")]
20 pub relationship_type: String,
21 pub to: String,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
27#[serde(rename_all = "camelCase")]
28pub struct LogicalTypeOptions {
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub min_length: Option<i64>,
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub max_length: Option<i64>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub pattern: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub format: Option<String>,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub minimum: Option<serde_json::Value>,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub maximum: Option<serde_json::Value>,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub exclusive_minimum: Option<serde_json::Value>,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub exclusive_maximum: Option<serde_json::Value>,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub precision: Option<i32>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub scale: Option<i32>,
59}
60
61impl LogicalTypeOptions {
62 pub fn is_empty(&self) -> bool {
63 self.min_length.is_none()
64 && self.max_length.is_none()
65 && self.pattern.is_none()
66 && self.format.is_none()
67 && self.minimum.is_none()
68 && self.maximum.is_none()
69 && self.exclusive_minimum.is_none()
70 && self.exclusive_maximum.is_none()
71 && self.precision.is_none()
72 && self.scale.is_none()
73 }
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
78pub struct AuthoritativeDefinition {
79 #[serde(rename = "type")]
81 pub definition_type: String,
82 pub url: String,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
99#[serde(rename_all = "camelCase")]
100pub struct Column {
101 #[serde(skip_serializing_if = "Option::is_none")]
104 pub id: Option<String>,
105 pub name: String,
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub business_name: Option<String>,
110 #[serde(default)]
112 pub description: String,
113
114 #[serde(rename = "dataType")]
117 pub data_type: String,
118 #[serde(skip_serializing_if = "Option::is_none")]
120 pub physical_type: Option<String>,
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub physical_name: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub logical_type_options: Option<LogicalTypeOptions>,
127
128 #[serde(default)]
131 pub primary_key: bool,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub primary_key_position: Option<i32>,
135 #[serde(default)]
137 pub unique: bool,
138 #[serde(default = "default_true")]
140 pub nullable: bool,
141
142 #[serde(default)]
145 pub partitioned: bool,
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub partition_key_position: Option<i32>,
149 #[serde(default)]
151 pub clustered: bool,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
156 pub classification: Option<String>,
157 #[serde(default)]
159 pub critical_data_element: bool,
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub encrypted_name: Option<String>,
163
164 #[serde(default, skip_serializing_if = "Vec::is_empty")]
167 pub transform_source_objects: Vec<String>,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub transform_logic: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub transform_description: Option<String>,
174
175 #[serde(default, skip_serializing_if = "Vec::is_empty")]
178 pub examples: Vec<serde_json::Value>,
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub default_value: Option<serde_json::Value>,
182
183 #[serde(default, skip_serializing_if = "Vec::is_empty")]
186 pub relationships: Vec<PropertyRelationship>,
187 #[serde(default, skip_serializing_if = "Vec::is_empty")]
189 pub authoritative_definitions: Vec<AuthoritativeDefinition>,
190
191 #[serde(default)]
194 pub quality: Vec<HashMap<String, serde_json::Value>>,
195 #[serde(default)]
197 pub enum_values: Vec<String>,
198
199 #[serde(default, skip_serializing_if = "Vec::is_empty")]
202 pub tags: Vec<String>,
203 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
205 pub custom_properties: HashMap<String, serde_json::Value>,
206
207 #[serde(default)]
210 pub secondary_key: bool,
211 #[serde(skip_serializing_if = "Option::is_none")]
213 pub composite_key: Option<String>,
214 #[serde(skip_serializing_if = "Option::is_none")]
216 pub foreign_key: Option<ForeignKey>,
217 #[serde(default)]
219 pub constraints: Vec<String>,
220 #[serde(default)]
222 pub errors: Vec<HashMap<String, serde_json::Value>>,
223 #[serde(default)]
225 pub column_order: i32,
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub nested_data: Option<String>,
229}
230
231fn default_true() -> bool {
232 true
233}
234
235impl Default for Column {
236 fn default() -> Self {
237 Self {
238 id: None,
240 name: String::new(),
241 business_name: None,
242 description: String::new(),
243 data_type: String::new(),
245 physical_type: None,
246 physical_name: None,
247 logical_type_options: None,
248 primary_key: false,
250 primary_key_position: None,
251 unique: false,
252 nullable: true, partitioned: false,
255 partition_key_position: None,
256 clustered: false,
257 classification: None,
259 critical_data_element: false,
260 encrypted_name: None,
261 transform_source_objects: Vec::new(),
263 transform_logic: None,
264 transform_description: None,
265 examples: Vec::new(),
267 default_value: None,
268 relationships: Vec::new(),
270 authoritative_definitions: Vec::new(),
271 quality: Vec::new(),
273 enum_values: Vec::new(),
274 tags: Vec::new(),
276 custom_properties: HashMap::new(),
277 secondary_key: false,
279 composite_key: None,
280 foreign_key: None,
281 constraints: Vec::new(),
282 errors: Vec::new(),
283 column_order: 0,
284 nested_data: None,
285 }
286 }
287}
288
289impl Column {
290 #[allow(deprecated)]
309 pub fn new(name: String, data_type: String) -> Self {
310 Self {
311 id: None,
313 name,
314 business_name: None,
315 description: String::new(),
316 data_type: normalize_data_type(&data_type),
318 physical_type: None,
319 physical_name: None,
320 logical_type_options: None,
321 primary_key: false,
323 primary_key_position: None,
324 unique: false,
325 nullable: true,
326 partitioned: false,
328 partition_key_position: None,
329 clustered: false,
330 classification: None,
332 critical_data_element: false,
333 encrypted_name: None,
334 transform_source_objects: Vec::new(),
336 transform_logic: None,
337 transform_description: None,
338 examples: Vec::new(),
340 default_value: None,
341 relationships: Vec::new(),
343 authoritative_definitions: Vec::new(),
344 quality: Vec::new(),
346 enum_values: Vec::new(),
347 tags: Vec::new(),
349 custom_properties: HashMap::new(),
350 secondary_key: false,
352 composite_key: None,
353 foreign_key: None,
354 constraints: Vec::new(),
355 errors: Vec::new(),
356 column_order: 0,
357 nested_data: None,
358 }
359 }
360}
361
362fn normalize_data_type(data_type: &str) -> String {
363 if data_type.is_empty() {
364 return data_type.to_string();
365 }
366
367 let upper = data_type.to_uppercase();
368
369 if upper.starts_with("STRUCT") {
371 if let Some(start) = data_type.find('<')
372 && let Some(end) = data_type.rfind('>')
373 {
374 let inner = &data_type[start + 1..end];
375 return format!("STRUCT<{}>", inner);
376 }
377 return format!("STRUCT{}", &data_type[6..]);
378 } else if upper.starts_with("ARRAY") {
379 if let Some(start) = data_type.find('<')
380 && let Some(end) = data_type.rfind('>')
381 {
382 let inner = &data_type[start + 1..end];
383 return format!("ARRAY<{}>", inner);
384 }
385 return format!("ARRAY{}", &data_type[5..]);
386 } else if upper.starts_with("MAP") {
387 if let Some(start) = data_type.find('<')
388 && let Some(end) = data_type.rfind('>')
389 {
390 let inner = &data_type[start + 1..end];
391 return format!("MAP<{}>", inner);
392 }
393 return format!("MAP{}", &data_type[3..]);
394 }
395
396 upper
397}