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)> {
100 match self {
101 Self::O2M { columns, .. } => columns.clone(),
102 Self::M2O { columns, .. } => columns.clone(),
103 Self::O2O { columns, .. } => columns.clone(),
104 Self::M2M(junction) => junction.source_columns(),
105 }
106 }
107
108 pub fn constraint_name(&self) -> &str {
110 match self {
111 Self::O2M { constraint, .. } => constraint,
112 Self::M2O { constraint, .. } => constraint,
113 Self::O2O { constraint, .. } => constraint,
114 Self::M2M(junction) => &junction.constraint1,
115 }
116 }
117}
118
119#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
121pub struct Junction {
122 pub table: QualifiedIdentifier,
124 pub constraint1: String,
126 pub constraint2: String,
128 pub source_columns: Vec<(String, String)>,
130 pub target_columns: Vec<(String, String)>,
132}
133
134impl Junction {
135 pub fn source_columns(&self) -> Vec<(String, String)> {
137 self.source_columns.clone()
138 }
139
140 pub fn target_columns(&self) -> Vec<(String, String)> {
142 self.target_columns.clone()
143 }
144}
145
146pub type RelationshipsMap = HashMap<(QualifiedIdentifier, String), Vec<Relationship>>;
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn test_relationship_foreign_table() {
155 let rel = Relationship::ForeignKey {
156 table: QualifiedIdentifier::new("public", "orders"),
157 foreign_table: QualifiedIdentifier::new("public", "users"),
158 is_self: false,
159 cardinality: Cardinality::M2O {
160 constraint: "orders_user_id_fkey".into(),
161 columns: vec![("user_id".into(), "id".into())],
162 },
163 table_is_view: false,
164 foreign_table_is_view: false,
165 constraint_name: "orders_user_id_fkey".into(),
166 };
167
168 assert_eq!(rel.foreign_table().name, "users");
169 assert!(rel.is_to_one());
170 }
171
172 #[test]
173 fn test_cardinality_columns() {
174 let card = Cardinality::O2M {
175 constraint: "users_id_fkey".into(),
176 columns: vec![("id".into(), "user_id".into())],
177 };
178
179 let cols = card.columns();
180 assert_eq!(cols.len(), 1);
181 assert_eq!(cols[0], ("id".into(), "user_id".into()));
182 }
183}