data_modelling_sdk/models/
relationship.rs

1//! Relationship model for the SDK
2
3use super::enums::{Cardinality, RelationshipType};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use uuid::Uuid;
7
8/// Foreign key column mapping details
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10pub struct ForeignKeyDetails {
11    /// Column name in the source table
12    pub source_column: String,
13    /// Column name in the target table
14    pub target_column: String,
15}
16
17/// ETL job metadata for data flow relationships
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19pub struct ETLJobMetadata {
20    /// Name of the ETL job that creates this relationship
21    pub job_name: String,
22    /// Optional notes about the ETL job
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub notes: Option<String>,
25    /// Job execution frequency (e.g., "daily", "hourly")
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub frequency: Option<String>,
28}
29
30/// Connection point coordinates for relationship visualization
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
32pub struct ConnectionPoint {
33    /// X coordinate
34    pub x: f64,
35    /// Y coordinate
36    pub y: f64,
37}
38
39/// Visual metadata for relationship rendering on canvas
40#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
41pub struct VisualMetadata {
42    /// Connection point identifier on source table
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub source_connection_point: Option<String>,
45    /// Connection point identifier on target table
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub target_connection_point: Option<String>,
48    /// Waypoints for routing the relationship line
49    #[serde(default)]
50    pub routing_waypoints: Vec<ConnectionPoint>,
51    /// Position for the relationship label
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub label_position: Option<ConnectionPoint>,
54}
55
56/// Relationship model representing a connection between two tables
57///
58/// Relationships can represent foreign keys, data flows, dependencies, or ETL transformations.
59/// They connect a source table to a target table with optional metadata about cardinality,
60/// foreign key details, and ETL job information.
61///
62/// # Example
63///
64/// ```rust
65/// use data_modelling_sdk::models::Relationship;
66///
67/// let source_id = uuid::Uuid::new_v4();
68/// let target_id = uuid::Uuid::new_v4();
69/// let relationship = Relationship::new(source_id, target_id);
70/// ```
71#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
72pub struct Relationship {
73    /// Unique identifier for the relationship (UUIDv4)
74    pub id: Uuid,
75    /// ID of the source table
76    pub source_table_id: Uuid,
77    /// ID of the target table
78    pub target_table_id: Uuid,
79    /// Cardinality (OneToOne, OneToMany, ManyToMany)
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub cardinality: Option<Cardinality>,
82    /// Whether the source side is optional (nullable foreign key)
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub source_optional: Option<bool>,
85    /// Whether the target side is optional
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub target_optional: Option<bool>,
88    /// Foreign key column mapping details
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub foreign_key_details: Option<ForeignKeyDetails>,
91    /// ETL job metadata for data flow relationships
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub etl_job_metadata: Option<ETLJobMetadata>,
94    /// Type of relationship (ForeignKey, DataFlow, Dependency, ETL)
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub relationship_type: Option<RelationshipType>,
97    /// Optional notes about the relationship
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub notes: Option<String>,
100    /// Visual metadata for canvas rendering
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub visual_metadata: Option<VisualMetadata>,
103    /// Draw.io edge ID for diagram integration
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub drawio_edge_id: Option<String>,
106    /// Creation timestamp
107    pub created_at: DateTime<Utc>,
108    /// Last update timestamp
109    pub updated_at: DateTime<Utc>,
110}
111
112impl Relationship {
113    /// Create a new relationship between two tables
114    ///
115    /// # Arguments
116    ///
117    /// * `source_table_id` - UUID of the source table
118    /// * `target_table_id` - UUID of the target table
119    ///
120    /// # Returns
121    ///
122    /// A new `Relationship` instance with a generated UUIDv4 ID and current timestamps.
123    ///
124    /// # Example
125    ///
126    /// ```rust
127    /// use data_modelling_sdk::models::Relationship;
128    ///
129    /// let source_id = uuid::Uuid::new_v4();
130    /// let target_id = uuid::Uuid::new_v4();
131    /// let rel = Relationship::new(source_id, target_id);
132    /// ```
133    pub fn new(source_table_id: Uuid, target_table_id: Uuid) -> Self {
134        let now = Utc::now();
135        let id = Self::generate_id(source_table_id, target_table_id);
136        Self {
137            id,
138            source_table_id,
139            target_table_id,
140            cardinality: None,
141            source_optional: None,
142            target_optional: None,
143            foreign_key_details: None,
144            etl_job_metadata: None,
145            relationship_type: None,
146            notes: None,
147            visual_metadata: None,
148            drawio_edge_id: None,
149            created_at: now,
150            updated_at: now,
151        }
152    }
153
154    /// Generate a UUIDv4 for a new relationship id.
155    ///
156    /// Note: params are retained for backward-compatibility with previous deterministic-v5 API.
157    pub fn generate_id(_source_table_id: Uuid, _target_table_id: Uuid) -> Uuid {
158        Uuid::new_v4()
159    }
160}