1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8#[serde(rename_all = "camelCase")]
9pub struct ForeignKey {
10 #[serde(alias = "table_id")]
12 pub table_id: String,
13 #[serde(alias = "column_name")]
15 pub column_name: String,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
20#[serde(rename_all = "camelCase")]
21pub struct PropertyRelationship {
22 #[serde(rename = "type", alias = "relationship_type")]
24 pub relationship_type: String,
25 pub to: String,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
31#[serde(rename_all = "camelCase")]
32pub struct LogicalTypeOptions {
33 #[serde(skip_serializing_if = "Option::is_none", alias = "min_length")]
35 pub min_length: Option<i64>,
36 #[serde(skip_serializing_if = "Option::is_none", alias = "max_length")]
38 pub max_length: Option<i64>,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub pattern: Option<String>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub format: Option<String>,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub minimum: Option<serde_json::Value>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub maximum: Option<serde_json::Value>,
51 #[serde(skip_serializing_if = "Option::is_none", alias = "exclusive_minimum")]
53 pub exclusive_minimum: Option<serde_json::Value>,
54 #[serde(skip_serializing_if = "Option::is_none", alias = "exclusive_maximum")]
56 pub exclusive_maximum: Option<serde_json::Value>,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub precision: Option<i32>,
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub scale: Option<i32>,
63}
64
65impl LogicalTypeOptions {
66 pub fn is_empty(&self) -> bool {
67 self.min_length.is_none()
68 && self.max_length.is_none()
69 && self.pattern.is_none()
70 && self.format.is_none()
71 && self.minimum.is_none()
72 && self.maximum.is_none()
73 && self.exclusive_minimum.is_none()
74 && self.exclusive_maximum.is_none()
75 && self.precision.is_none()
76 && self.scale.is_none()
77 }
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
82#[serde(rename_all = "camelCase")]
83pub struct AuthoritativeDefinition {
84 #[serde(rename = "type", alias = "definition_type")]
86 pub definition_type: String,
87 pub url: String,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
104#[serde(rename_all = "camelCase")]
105pub struct Column {
106 #[serde(skip_serializing_if = "Option::is_none")]
109 pub id: Option<String>,
110 pub name: String,
112 #[serde(skip_serializing_if = "Option::is_none", alias = "business_name")]
114 pub business_name: Option<String>,
115 #[serde(default)]
117 pub description: String,
118
119 #[serde(rename = "dataType", alias = "data_type")]
122 pub data_type: String,
123 #[serde(skip_serializing_if = "Option::is_none", alias = "physical_type")]
125 pub physical_type: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none", alias = "physical_name")]
128 pub physical_name: Option<String>,
129 #[serde(
131 skip_serializing_if = "Option::is_none",
132 alias = "logical_type_options"
133 )]
134 pub logical_type_options: Option<LogicalTypeOptions>,
135
136 #[serde(default, alias = "primary_key")]
139 pub primary_key: bool,
140 #[serde(
142 skip_serializing_if = "Option::is_none",
143 alias = "primary_key_position"
144 )]
145 pub primary_key_position: Option<i32>,
146 #[serde(default)]
148 pub unique: bool,
149 #[serde(default = "default_true")]
151 pub nullable: bool,
152
153 #[serde(default)]
156 pub partitioned: bool,
157 #[serde(
159 skip_serializing_if = "Option::is_none",
160 alias = "partition_key_position"
161 )]
162 pub partition_key_position: Option<i32>,
163 #[serde(default)]
165 pub clustered: bool,
166
167 #[serde(skip_serializing_if = "Option::is_none")]
170 pub classification: Option<String>,
171 #[serde(default, alias = "critical_data_element")]
173 pub critical_data_element: bool,
174 #[serde(skip_serializing_if = "Option::is_none", alias = "encrypted_name")]
176 pub encrypted_name: Option<String>,
177
178 #[serde(
181 default,
182 skip_serializing_if = "Vec::is_empty",
183 alias = "transform_source_objects"
184 )]
185 pub transform_source_objects: Vec<String>,
186 #[serde(skip_serializing_if = "Option::is_none", alias = "transform_logic")]
188 pub transform_logic: Option<String>,
189 #[serde(
191 skip_serializing_if = "Option::is_none",
192 alias = "transform_description"
193 )]
194 pub transform_description: Option<String>,
195
196 #[serde(default, skip_serializing_if = "Vec::is_empty")]
199 pub examples: Vec<serde_json::Value>,
200 #[serde(skip_serializing_if = "Option::is_none", alias = "default_value")]
202 pub default_value: Option<serde_json::Value>,
203
204 #[serde(default, skip_serializing_if = "Vec::is_empty")]
207 pub relationships: Vec<PropertyRelationship>,
208 #[serde(
210 default,
211 skip_serializing_if = "Vec::is_empty",
212 alias = "authoritative_definitions"
213 )]
214 pub authoritative_definitions: Vec<AuthoritativeDefinition>,
215
216 #[serde(default)]
219 pub quality: Vec<HashMap<String, serde_json::Value>>,
220 #[serde(default, alias = "enum_values")]
222 pub enum_values: Vec<String>,
223
224 #[serde(default, skip_serializing_if = "Vec::is_empty")]
227 pub tags: Vec<String>,
228 #[serde(
230 default,
231 skip_serializing_if = "HashMap::is_empty",
232 alias = "custom_properties"
233 )]
234 pub custom_properties: HashMap<String, serde_json::Value>,
235
236 #[serde(default, alias = "secondary_key")]
239 pub secondary_key: bool,
240 #[serde(skip_serializing_if = "Option::is_none", alias = "composite_key")]
242 pub composite_key: Option<String>,
243 #[serde(skip_serializing_if = "Option::is_none", alias = "foreign_key")]
245 pub foreign_key: Option<ForeignKey>,
246 #[serde(default)]
248 pub constraints: Vec<String>,
249 #[serde(default)]
251 pub errors: Vec<HashMap<String, serde_json::Value>>,
252 #[serde(default, alias = "column_order")]
254 pub column_order: i32,
255 #[serde(skip_serializing_if = "Option::is_none", alias = "nested_data")]
257 pub nested_data: Option<String>,
258}
259
260fn default_true() -> bool {
261 true
262}
263
264impl Default for Column {
265 fn default() -> Self {
266 Self {
267 id: None,
269 name: String::new(),
270 business_name: None,
271 description: String::new(),
272 data_type: String::new(),
274 physical_type: None,
275 physical_name: None,
276 logical_type_options: None,
277 primary_key: false,
279 primary_key_position: None,
280 unique: false,
281 nullable: true, partitioned: false,
284 partition_key_position: None,
285 clustered: false,
286 classification: None,
288 critical_data_element: false,
289 encrypted_name: None,
290 transform_source_objects: Vec::new(),
292 transform_logic: None,
293 transform_description: None,
294 examples: Vec::new(),
296 default_value: None,
297 relationships: Vec::new(),
299 authoritative_definitions: Vec::new(),
300 quality: Vec::new(),
302 enum_values: Vec::new(),
303 tags: Vec::new(),
305 custom_properties: HashMap::new(),
306 secondary_key: false,
308 composite_key: None,
309 foreign_key: None,
310 constraints: Vec::new(),
311 errors: Vec::new(),
312 column_order: 0,
313 nested_data: None,
314 }
315 }
316}
317
318impl Column {
319 #[allow(deprecated)]
338 pub fn new(name: String, data_type: String) -> Self {
339 Self {
340 id: None,
342 name,
343 business_name: None,
344 description: String::new(),
345 data_type: normalize_data_type(&data_type),
347 physical_type: None,
348 physical_name: None,
349 logical_type_options: None,
350 primary_key: false,
352 primary_key_position: None,
353 unique: false,
354 nullable: true,
355 partitioned: false,
357 partition_key_position: None,
358 clustered: false,
359 classification: None,
361 critical_data_element: false,
362 encrypted_name: None,
363 transform_source_objects: Vec::new(),
365 transform_logic: None,
366 transform_description: None,
367 examples: Vec::new(),
369 default_value: None,
370 relationships: Vec::new(),
372 authoritative_definitions: Vec::new(),
373 quality: Vec::new(),
375 enum_values: Vec::new(),
376 tags: Vec::new(),
378 custom_properties: HashMap::new(),
379 secondary_key: false,
381 composite_key: None,
382 foreign_key: None,
383 constraints: Vec::new(),
384 errors: Vec::new(),
385 column_order: 0,
386 nested_data: None,
387 }
388 }
389}
390
391fn normalize_data_type(data_type: &str) -> String {
392 if data_type.is_empty() {
393 return data_type.to_string();
394 }
395
396 let upper = data_type.to_uppercase();
397
398 if upper.starts_with("STRUCT") {
400 if let Some(start) = data_type.find('<')
401 && let Some(end) = data_type.rfind('>')
402 {
403 let inner = &data_type[start + 1..end];
404 return format!("STRUCT<{}>", inner);
405 }
406 return format!("STRUCT{}", &data_type[6..]);
407 } else if upper.starts_with("ARRAY") {
408 if let Some(start) = data_type.find('<')
409 && let Some(end) = data_type.rfind('>')
410 {
411 let inner = &data_type[start + 1..end];
412 return format!("ARRAY<{}>", inner);
413 }
414 return format!("ARRAY{}", &data_type[5..]);
415 } else if upper.starts_with("MAP") {
416 if let Some(start) = data_type.find('<')
417 && let Some(end) = data_type.rfind('>')
418 {
419 let inner = &data_type[start + 1..end];
420 return format!("MAP<{}>", inner);
421 }
422 return format!("MAP{}", &data_type[3..]);
423 }
424
425 upper
426}