use pgrx::pg_sys::Oid;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CascadeHop {
pub table_oid: Oid,
pub table_name: String,
pub lookup_col: String,
pub carry_col: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CascadePath {
pub source_oid: Oid,
pub source_table: String,
pub entity_name: String,
pub initial_col: String,
pub hops: Vec<CascadeHop>,
#[serde(default)]
pub unresolvable: bool,
#[serde(default)]
pub source_columns: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fanout: Option<FanoutPatch>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FanoutPatch {
pub lookup_col: String,
pub fields: Vec<(String, String)>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_single_hop_round_trip() {
let path = CascadePath {
source_oid: Oid::from(12345),
source_table: "tb_comment".to_string(),
entity_name: "post".to_string(),
initial_col: "fk_post".to_string(),
hops: vec![],
unresolvable: false,
source_columns: vec![],
fanout: None,
};
let json = serde_json::to_string(&path).unwrap();
let deserialized: CascadePath = serde_json::from_str(&json).unwrap();
assert_eq!(path, deserialized);
}
#[test]
fn test_multi_hop_round_trip() {
let path = CascadePath {
source_oid: Oid::from(11111),
source_table: "tb_item".to_string(),
entity_name: "order".to_string(),
initial_col: "fk_group".to_string(),
hops: vec![CascadeHop {
table_oid: Oid::from(22222),
table_name: "tb_group".to_string(),
lookup_col: "pk_group".to_string(),
carry_col: "fk_order".to_string(),
}],
unresolvable: false,
source_columns: vec![],
fanout: None,
};
let json = serde_json::to_string(&path).unwrap();
let deserialized: CascadePath = serde_json::from_str(&json).unwrap();
assert_eq!(path, deserialized);
assert_eq!(path.hops.len(), 1);
}
#[test]
fn test_unresolvable_defaults_to_false() {
let json =
r#"{"source_oid":1,"source_table":"t","entity_name":"e","initial_col":"c","hops":[]}"#;
let path: CascadePath = serde_json::from_str(json).unwrap();
assert!(!path.unresolvable);
}
#[test]
fn test_fanout_round_trip_and_absent_by_default() {
let json =
r#"{"source_oid":1,"source_table":"t","entity_name":"e","initial_col":"c","hops":[]}"#;
let mut path: CascadePath = serde_json::from_str(json).unwrap();
assert!(path.fanout.is_none());
assert!(!serde_json::to_string(&path).unwrap().contains("fanout"));
path.fanout = Some(FanoutPatch {
lookup_col: "fk_user".to_string(),
fields: vec![("name".to_string(), "author_name".to_string())],
});
let json = serde_json::to_string(&path).unwrap();
assert_eq!(serde_json::from_str::<CascadePath>(&json).unwrap(), path);
}
}