data_modelling_sdk/models/
table.rs

1//! Table model for the SDK
2
3use super::column::Column;
4use super::enums::{
5    DataVaultClassification, DatabaseType, MedallionLayer, ModelingLevel, SCDPattern,
6};
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use uuid::Uuid;
11
12/// Position coordinates for table placement on canvas
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct Position {
15    /// X coordinate
16    pub x: f64,
17    /// Y coordinate
18    pub y: f64,
19}
20
21/// Table model representing a database table or data contract
22///
23/// A table represents a structured data entity with columns, metadata, and relationships.
24/// Tables can be imported from various formats (SQL, ODCS, JSON Schema, etc.) and exported
25/// to multiple formats.
26///
27/// # Example
28///
29/// ```rust
30/// use data_modelling_sdk::models::{Table, Column};
31///
32/// let table = Table::new(
33///     "users".to_string(),
34///     vec![
35///         Column::new("id".to_string(), "INT".to_string()),
36///         Column::new("name".to_string(), "VARCHAR(100)".to_string()),
37///     ],
38/// );
39/// ```
40#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
41pub struct Table {
42    /// Unique identifier for the table (UUIDv4)
43    pub id: Uuid,
44    /// Table name (must be unique within database_type/catalog/schema scope)
45    pub name: String,
46    /// List of columns in the table
47    pub columns: Vec<Column>,
48    /// Database type (PostgreSQL, MySQL, etc.) if applicable
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub database_type: Option<DatabaseType>,
51    /// Catalog name (database name in some systems)
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub catalog_name: Option<String>,
54    /// Schema name (namespace within catalog)
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub schema_name: Option<String>,
57    /// Medallion architecture layers (Bronze, Silver, Gold)
58    #[serde(default)]
59    pub medallion_layers: Vec<MedallionLayer>,
60    /// Slowly Changing Dimension pattern (Type 1, Type 2, etc.)
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub scd_pattern: Option<SCDPattern>,
63    /// Data Vault classification (Hub, Link, Satellite)
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub data_vault_classification: Option<DataVaultClassification>,
66    /// Modeling level (Conceptual, Logical, Physical)
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub modeling_level: Option<ModelingLevel>,
69    /// Tags for categorization and filtering
70    #[serde(default)]
71    pub tags: Vec<String>,
72    /// ODCL/ODCS metadata (legacy format support)
73    #[serde(default)]
74    pub odcl_metadata: HashMap<String, serde_json::Value>,
75    /// Canvas position for visual representation
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub position: Option<Position>,
78    /// Path to YAML file if loaded from file system
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub yaml_file_path: Option<String>,
81    /// Draw.io cell ID for diagram integration
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub drawio_cell_id: Option<String>,
84    /// Quality rules and checks
85    #[serde(default)]
86    pub quality: Vec<HashMap<String, serde_json::Value>>,
87    /// Validation errors and warnings
88    #[serde(default)]
89    pub errors: Vec<HashMap<String, serde_json::Value>>,
90    /// Creation timestamp
91    pub created_at: DateTime<Utc>,
92    /// Last update timestamp
93    pub updated_at: DateTime<Utc>,
94}
95
96impl Table {
97    /// Create a new table with the given name and columns
98    ///
99    /// # Arguments
100    ///
101    /// * `name` - The table name (must be valid according to naming conventions)
102    /// * `columns` - Vector of columns for the table
103    ///
104    /// # Returns
105    ///
106    /// A new `Table` instance with a generated UUIDv4 ID and current timestamps.
107    ///
108    /// # Example
109    ///
110    /// ```rust
111    /// use data_modelling_sdk::models::{Table, Column};
112    ///
113    /// let table = Table::new(
114    ///     "users".to_string(),
115    ///     vec![Column::new("id".to_string(), "INT".to_string())],
116    /// );
117    /// ```
118    pub fn new(name: String, columns: Vec<Column>) -> Self {
119        let now = Utc::now();
120        // UUIDv4 everywhere (do not derive ids from natural keys like name).
121        let id = Self::generate_id(&name, None, None, None);
122        Self {
123            id,
124            name,
125            columns,
126            database_type: None,
127            catalog_name: None,
128            schema_name: None,
129            medallion_layers: Vec::new(),
130            scd_pattern: None,
131            data_vault_classification: None,
132            modeling_level: None,
133            tags: Vec::new(),
134            odcl_metadata: HashMap::new(),
135            position: None,
136            yaml_file_path: None,
137            drawio_cell_id: None,
138            quality: Vec::new(),
139            errors: Vec::new(),
140            created_at: now,
141            updated_at: now,
142        }
143    }
144
145    /// Get the unique key tuple for this table
146    ///
147    /// Returns a tuple of (database_type, name, catalog_name, schema_name) that uniquely
148    /// identifies this table within its scope. Used for detecting naming conflicts.
149    ///
150    /// # Returns
151    ///
152    /// A tuple containing the database type (as string), name, catalog name, and schema name.
153    pub fn get_unique_key(&self) -> (Option<String>, String, Option<String>, Option<String>) {
154        (
155            self.database_type.as_ref().map(|dt| format!("{:?}", dt)),
156            self.name.clone(),
157            self.catalog_name.clone(),
158            self.schema_name.clone(),
159        )
160    }
161
162    /// Generate a UUIDv4 for a new table id.
163    ///
164    /// Note: params are retained for backward-compatibility with previous deterministic-v5 API.
165    pub fn generate_id(
166        _name: &str,
167        _database_type: Option<&DatabaseType>,
168        _catalog_name: Option<&str>,
169        _schema_name: Option<&str>,
170    ) -> Uuid {
171        Uuid::new_v4()
172    }
173}