use crate::api_request::QualifiedIdentifier;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Relationship {
ForeignKey {
table: QualifiedIdentifier,
foreign_table: QualifiedIdentifier,
is_self: bool,
cardinality: Cardinality,
table_is_view: bool,
foreign_table_is_view: bool,
constraint_name: String,
},
Computed {
function: QualifiedIdentifier,
table: QualifiedIdentifier,
foreign_table: QualifiedIdentifier,
table_alias: QualifiedIdentifier,
to_one: bool,
is_self: bool,
},
}
impl Relationship {
pub fn foreign_table(&self) -> &QualifiedIdentifier {
match self {
Self::ForeignKey { foreign_table, .. } => foreign_table,
Self::Computed { foreign_table, .. } => foreign_table,
}
}
pub fn is_to_one(&self) -> bool {
match self {
Self::ForeignKey { cardinality, .. } => matches!(
cardinality,
Cardinality::M2O { .. } | Cardinality::O2O { .. }
),
Self::Computed { to_one, .. } => *to_one,
}
}
pub fn join_columns(&self) -> Vec<(String, String)> {
match self {
Self::ForeignKey { cardinality, .. } => cardinality.columns(),
Self::Computed { .. } => vec![],
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Cardinality {
O2M {
constraint: String,
columns: Vec<(String, String)>,
},
M2O {
constraint: String,
columns: Vec<(String, String)>,
},
O2O {
constraint: String,
columns: Vec<(String, String)>,
is_parent: bool,
},
M2M(Junction),
}
impl Cardinality {
pub fn columns(&self) -> Vec<(String, String)> {
match self {
Self::O2M { columns, .. } => columns.clone(),
Self::M2O { columns, .. } => columns.clone(),
Self::O2O { columns, .. } => columns.clone(),
Self::M2M(junction) => junction.source_columns(),
}
}
pub fn constraint_name(&self) -> &str {
match self {
Self::O2M { constraint, .. } => constraint,
Self::M2O { constraint, .. } => constraint,
Self::O2O { constraint, .. } => constraint,
Self::M2M(junction) => &junction.constraint1,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Junction {
pub table: QualifiedIdentifier,
pub constraint1: String,
pub constraint2: String,
pub source_columns: Vec<(String, String)>,
pub target_columns: Vec<(String, String)>,
}
impl Junction {
pub fn source_columns(&self) -> Vec<(String, String)> {
self.source_columns.clone()
}
pub fn target_columns(&self) -> Vec<(String, String)> {
self.target_columns.clone()
}
}
pub type RelationshipsMap = HashMap<(QualifiedIdentifier, String), Vec<Relationship>>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_relationship_foreign_table() {
let rel = Relationship::ForeignKey {
table: QualifiedIdentifier::new("public", "orders"),
foreign_table: QualifiedIdentifier::new("public", "users"),
is_self: false,
cardinality: Cardinality::M2O {
constraint: "orders_user_id_fkey".into(),
columns: vec![("user_id".into(), "id".into())],
},
table_is_view: false,
foreign_table_is_view: false,
constraint_name: "orders_user_id_fkey".into(),
};
assert_eq!(rel.foreign_table().name, "users");
assert!(rel.is_to_one());
}
#[test]
fn test_cardinality_columns() {
let card = Cardinality::O2M {
constraint: "users_id_fkey".into(),
columns: vec![("id".into(), "user_id".into())],
};
let cols = card.columns();
assert_eq!(cols.len(), 1);
assert_eq!(cols[0], ("id".into(), "user_id".into()));
}
}