use crate::catalog::view::{View, ViewColumn};
use crate::diff::comment_utils;
use crate::diff::operations::{
CommentOperation, MigrationStep, ViewColumnIdentifier, ViewIdentifier, ViewOperation,
ViewOption,
};
fn emit_initial_column_comments(view: &View) -> Vec<MigrationStep> {
view.columns
.iter()
.filter_map(|col| {
col.comment.as_ref().map(|c| {
MigrationStep::View(ViewOperation::ColumnComment(CommentOperation::Set {
target: ViewColumnIdentifier {
schema: view.schema.clone(),
view: view.name.clone(),
name: col.name.clone(),
},
comment: c.clone(),
}))
})
})
.collect()
}
fn diff_column_comments(old: &View, new: &View) -> Vec<MigrationStep> {
let mut steps = Vec::new();
let by_name_old: std::collections::HashMap<&str, &ViewColumn> =
old.columns.iter().map(|c| (c.name.as_str(), c)).collect();
for new_col in &new.columns {
let Some(old_col) = by_name_old.get(new_col.name.as_str()) else {
continue;
};
let target = || ViewColumnIdentifier {
schema: new.schema.clone(),
view: new.name.clone(),
name: new_col.name.clone(),
};
match (&old_col.comment, &new_col.comment) {
(None, Some(c)) => {
steps.push(MigrationStep::View(ViewOperation::ColumnComment(
CommentOperation::Set {
target: target(),
comment: c.clone(),
},
)));
}
(Some(old_c), Some(new_c)) if old_c != new_c => {
steps.push(MigrationStep::View(ViewOperation::ColumnComment(
CommentOperation::Set {
target: target(),
comment: new_c.clone(),
},
)));
}
(Some(_), None) => {
steps.push(MigrationStep::View(ViewOperation::ColumnComment(
CommentOperation::Drop { target: target() },
)));
}
_ => {}
}
}
steps
}
pub fn diff(old: Option<&View>, new: Option<&View>) -> Vec<MigrationStep> {
match (old, new) {
(None, Some(n)) => {
let mut steps = vec![MigrationStep::View(ViewOperation::Create {
schema: n.schema.clone(),
name: n.name.clone(),
definition: n.definition.clone(),
security_invoker: n.security_invoker,
security_barrier: n.security_barrier,
})];
if let Some(comment_op) = comment_utils::handle_comment_creation(
&n.comment,
ViewIdentifier {
schema: n.schema.clone(),
name: n.name.clone(),
},
) {
steps.push(MigrationStep::View(ViewOperation::Comment(comment_op)));
}
steps.extend(emit_initial_column_comments(n));
steps
}
(Some(o), None) => {
vec![MigrationStep::View(ViewOperation::Drop {
schema: o.schema.clone(),
name: o.name.clone(),
})]
}
(Some(o), Some(n)) => {
let mut steps = Vec::new();
let structural_columns_changed = o.columns.len() != n.columns.len()
|| o.columns
.iter()
.zip(n.columns.iter())
.any(|(a, b)| a.name != b.name || a.type_ != b.type_);
if structural_columns_changed {
steps.extend(vec![
MigrationStep::View(ViewOperation::Drop {
schema: o.schema.clone(),
name: o.name.clone(),
}),
MigrationStep::View(ViewOperation::Create {
schema: n.schema.clone(),
name: n.name.clone(),
definition: n.definition.clone(),
security_invoker: n.security_invoker,
security_barrier: n.security_barrier,
}),
]);
if let Some(comment_op) = comment_utils::handle_comment_creation(
&n.comment,
ViewIdentifier {
schema: n.schema.clone(),
name: n.name.clone(),
},
) {
steps.push(MigrationStep::View(ViewOperation::Comment(comment_op)));
}
steps.extend(emit_initial_column_comments(n));
} else if o.definition != n.definition {
steps.push(MigrationStep::View(ViewOperation::Replace {
schema: n.schema.clone(),
name: n.name.clone(),
definition: n.definition.clone(),
security_invoker: n.security_invoker,
security_barrier: n.security_barrier,
}));
let comment_ops =
comment_utils::handle_comment_diff(Some(o), Some(n), || ViewIdentifier {
schema: n.schema.clone(),
name: n.name.clone(),
});
for comment_op in comment_ops {
steps.push(MigrationStep::View(ViewOperation::Comment(comment_op)));
}
steps.extend(diff_column_comments(o, n));
} else {
if o.security_invoker != n.security_invoker {
steps.push(MigrationStep::View(ViewOperation::SetOption {
schema: n.schema.clone(),
name: n.name.clone(),
option: ViewOption::SecurityInvoker,
enabled: n.security_invoker,
}));
}
if o.security_barrier != n.security_barrier {
steps.push(MigrationStep::View(ViewOperation::SetOption {
schema: n.schema.clone(),
name: n.name.clone(),
option: ViewOption::SecurityBarrier,
enabled: n.security_barrier,
}));
}
let comment_ops =
comment_utils::handle_comment_diff(Some(o), Some(n), || ViewIdentifier {
schema: n.schema.clone(),
name: n.name.clone(),
});
for comment_op in comment_ops {
steps.push(MigrationStep::View(ViewOperation::Comment(comment_op)));
}
steps.extend(diff_column_comments(o, n));
}
steps
}
(None, None) => {
Vec::new() }
}
}