postrust_core/schema_cache/
relationship.rs1use crate::api_request::QualifiedIdentifier;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Clone, Debug, Serialize, Deserialize)]
9pub enum Relationship {
10 ForeignKey {
12 table: QualifiedIdentifier,
14 foreign_table: QualifiedIdentifier,
16 is_self: bool,
18 cardinality: Cardinality,
20 table_is_view: bool,
22 foreign_table_is_view: bool,
24 constraint_name: String,
26 },
27 Computed {
29 function: QualifiedIdentifier,
31 table: QualifiedIdentifier,
33 foreign_table: QualifiedIdentifier,
35 table_alias: QualifiedIdentifier,
37 to_one: bool,
39 is_self: bool,
41 },
42}
43
44impl Relationship {
45 pub fn foreign_table(&self) -> &QualifiedIdentifier {
47 match self {
48 Self::ForeignKey { foreign_table, .. } => foreign_table,
49 Self::Computed { foreign_table, .. } => foreign_table,
50 }
51 }
52
53 pub fn is_to_one(&self) -> bool {
55 match self {
56 Self::ForeignKey { cardinality, .. } => matches!(
57 cardinality,
58 Cardinality::M2O { .. } | Cardinality::O2O { .. }
59 ),
60 Self::Computed { to_one, .. } => *to_one,
61 }
62 }
63
64 pub fn join_columns(&self) -> Vec<(String, String)> {
66 match self {
67 Self::ForeignKey { cardinality, .. } => cardinality.columns(),
68 Self::Computed { .. } => vec![],
69 }
70 }
71}
72
73#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
75pub enum Cardinality {
76 O2M {
78 constraint: String,
79 columns: Vec<(String, String)>,
80 },
81 M2O {
83 constraint: String,
84 columns: Vec<(String, String)>,
85 },
86 O2O {
88 constraint: String,
89 columns: Vec<(String, String)>,
90 is_parent: bool,
92 },
93 M2M(Junction),
95}
96
97impl Cardinality {
98 pub fn columns(&self) -> Vec<(String, String)> {
104 match self {
105 Self::O2M { columns, .. } => columns.clone(),
106 Self::M2O { columns, .. } => columns.clone(),
107 Self::O2O { columns, .. } => columns.clone(),
108 Self::M2M(junction) => junction.source_columns(),
109 }
110 }
111
112 pub fn constraint_name(&self) -> &str {
114 match self {
115 Self::O2M { constraint, .. } => constraint,
116 Self::M2O { constraint, .. } => constraint,
117 Self::O2O { constraint, .. } => constraint,
118 Self::M2M(junction) => &junction.constraint1,
119 }
120 }
121}
122
123#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
125pub struct Junction {
126 pub table: QualifiedIdentifier,
128 pub constraint1: String,
130 pub constraint2: String,
132 pub source_columns: Vec<(String, String)>,
134 pub target_columns: Vec<(String, String)>,
136}
137
138impl Junction {
139 pub fn source_columns(&self) -> Vec<(String, String)> {
141 self.source_columns.clone()
142 }
143
144 pub fn target_columns(&self) -> Vec<(String, String)> {
146 self.target_columns.clone()
147 }
148}
149
150pub type RelationshipsMap = HashMap<(QualifiedIdentifier, String), Vec<Relationship>>;
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_relationship_foreign_table() {
159 let rel = Relationship::ForeignKey {
160 table: QualifiedIdentifier::new("public", "orders"),
161 foreign_table: QualifiedIdentifier::new("public", "users"),
162 is_self: false,
163 cardinality: Cardinality::M2O {
164 constraint: "orders_user_id_fkey".into(),
165 columns: vec![("user_id".into(), "id".into())],
166 },
167 table_is_view: false,
168 foreign_table_is_view: false,
169 constraint_name: "orders_user_id_fkey".into(),
170 };
171
172 assert_eq!(rel.foreign_table().name, "users");
173 assert!(rel.is_to_one());
174 }
175
176 #[test]
177 fn test_cardinality_columns() {
178 let card = Cardinality::O2M {
179 constraint: "users_id_fkey".into(),
180 columns: vec![("id".into(), "user_id".into())],
181 };
182
183 let cols = card.columns();
184 assert_eq!(cols.len(), 1);
185 assert_eq!(cols[0], ("id".into(), "user_id".into()));
186 }
187}