use std::path::Path;
use anyhow::Result;
use pgevolve_core::diff::cluster::ClusterChange;
use crate::api::cluster::build_cluster_plan;
use crate::cluster_config::ClusterConfig;
pub async fn run(project_root: &Path, cfg: &ClusterConfig) -> Result<i32> {
let plan = build_cluster_plan(project_root, cfg)
.await
.map_err(|e| anyhow::anyhow!("{e}"))?;
if plan.changes.is_empty() {
println!("No changes.");
return Ok(0);
}
for entry in &plan.changes.entries {
println!("{}", describe(&entry.change));
}
for finding in &plan.advisory_findings {
eprintln!(
"pgevolve cluster diff: advisory [{}]: {}",
finding.rule, finding.message
);
}
Ok(0)
}
fn describe(change: &ClusterChange) -> String {
match change {
ClusterChange::CreateRole(r) => format!("+ CREATE ROLE {}", r.name),
ClusterChange::DropRole { name } => format!("- DROP ROLE {name}"),
ClusterChange::AlterRoleAttributes { name, .. } => format!("~ ALTER ROLE {name}"),
ClusterChange::GrantRoleMembership { member, role } => {
format!("+ GRANT {role} TO {member}")
}
ClusterChange::RevokeRoleMembership { member, role } => {
format!("- REVOKE {role} FROM {member}")
}
ClusterChange::CommentOnRole { name, .. } => format!("~ COMMENT ON ROLE {name}"),
ClusterChange::CreateTablespace(ts) => format!("+ CREATE TABLESPACE {}", ts.name),
ClusterChange::DropTablespace { name } => format!("- DROP TABLESPACE {name}"),
ClusterChange::AlterTablespaceOwner { name, owner } => {
format!("~ ALTER TABLESPACE {name} OWNER TO {owner}")
}
ClusterChange::SetTablespaceOptions { name, .. } => {
format!("~ ALTER TABLESPACE {name} SET (...)")
}
ClusterChange::CommentOnTablespace { name, .. } => {
format!("~ COMMENT ON TABLESPACE {name}")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pgevolve_core::diff::cluster::ClusterChange;
use pgevolve_core::identifier::Identifier;
use pgevolve_core::ir::cluster::role::{Role, RoleAttributes};
fn id(s: &str) -> Identifier {
Identifier::from_unquoted(s).unwrap()
}
#[test]
fn describe_create_role() {
let r = Role {
name: id("app_user"),
attributes: RoleAttributes::default(),
member_of: vec![],
comment: None,
};
let s = describe(&ClusterChange::CreateRole(r));
assert_eq!(s, "+ CREATE ROLE app_user");
}
#[test]
fn describe_drop_role() {
let s = describe(&ClusterChange::DropRole { name: id("old") });
assert_eq!(s, "- DROP ROLE old");
}
#[test]
fn describe_grant() {
let s = describe(&ClusterChange::GrantRoleMembership {
member: id("app"),
role: id("readers"),
});
assert_eq!(s, "+ GRANT readers TO app");
}
#[test]
fn describe_revoke() {
let s = describe(&ClusterChange::RevokeRoleMembership {
member: id("app"),
role: id("readers"),
});
assert_eq!(s, "- REVOKE readers FROM app");
}
}