use crate::catalog::cast::Cast;
use crate::diff::operations::{CastIdentifier, CastOperation, MigrationStep};
pub fn diff(old: Option<&Cast>, new: Option<&Cast>) -> Vec<MigrationStep> {
match (old, new) {
(None, Some(new_cast)) => {
vec![MigrationStep::Cast(CastOperation::Create {
cast: Box::new(new_cast.clone()),
})]
}
(Some(old_cast), None) => {
vec![MigrationStep::Cast(CastOperation::Drop {
identifier: CastIdentifier::from_cast(old_cast),
})]
}
(Some(old_cast), Some(new_cast)) => {
let mut steps = Vec::new();
if casts_differ_structurally(old_cast, new_cast) {
steps.push(MigrationStep::Cast(CastOperation::Replace {
old_cast: Box::new(old_cast.clone()),
new_cast: Box::new(new_cast.clone()),
}));
}
steps
}
(None, None) => vec![],
}
}
fn casts_differ_structurally(old: &Cast, new: &Cast) -> bool {
old.definition != new.definition
}
#[cfg(test)]
mod tests {
use super::*;
use crate::catalog::id::DbObjectId;
fn test_cast(target: &str) -> Cast {
Cast {
source: "celsius".to_string(),
target: target.to_string(),
definition: format!(
"CREATE CAST (celsius AS {}) WITH FUNCTION public.c_to_x(celsius)",
target
),
comment: None,
depends_on: vec![DbObjectId::Type {
schema: "public".to_string(),
name: "celsius".to_string(),
}],
}
}
#[test]
fn test_diff_no_changes() {
let c = test_cast("fahrenheit");
assert!(diff(Some(&c), Some(&c)).is_empty());
}
#[test]
fn test_diff_create() {
let c = test_cast("fahrenheit");
let steps = diff(None, Some(&c));
assert_eq!(steps.len(), 1);
assert!(matches!(
&steps[0],
MigrationStep::Cast(CastOperation::Create { .. })
));
}
#[test]
fn test_diff_drop() {
let c = test_cast("fahrenheit");
let steps = diff(Some(&c), None);
assert_eq!(steps.len(), 1);
match &steps[0] {
MigrationStep::Cast(CastOperation::Drop { identifier }) => {
assert_eq!(identifier.source, "celsius");
assert_eq!(identifier.target, "fahrenheit");
}
_ => panic!("expected CastOperation::Drop"),
}
}
#[test]
fn test_diff_replace_on_structural_change() {
let old = test_cast("fahrenheit");
let mut new = test_cast("fahrenheit");
new.definition.push_str(" AS ASSIGNMENT");
let steps = diff(Some(&old), Some(&new));
assert_eq!(steps.len(), 1);
assert!(matches!(
&steps[0],
MigrationStep::Cast(CastOperation::Replace { .. })
));
}
}