use std::collections::BTreeSet;
use crate::diff::change::Change;
use crate::diff::changeset::{ChangeSet, RevokeWithOwnerObservation, UnmanagedGrantObservation};
use crate::diff::destructiveness::Destructiveness;
use crate::diff::grants::diff_grants;
use crate::diff::owner_op::{AlterObjectOwner, CatalogObjectRef};
use crate::identifier::Identifier;
use crate::ir::grant::{Grant, GrantTarget};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ColumnGrantMode {
ObjectOnly,
ColumnAware,
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn diff_owner_and_grants(
object: &CatalogObjectRef,
target_owner: Option<&Identifier>,
source_owner: Option<&Identifier>,
target_grants: &[Grant],
source_grants: &[Grant],
managed_roles: &BTreeSet<Identifier>,
mode: ColumnGrantMode,
out: &mut ChangeSet,
) {
if let Some(source_owner) = source_owner
&& target_owner != Some(source_owner)
{
out.push(
Change::AlterObjectOwner(AlterObjectOwner {
object: object.clone(),
from: target_owner.cloned(),
to: source_owner.clone(),
}),
Destructiveness::Safe,
);
}
let object_label = object.observation_label();
let (to_add, to_revoke, unmanaged) = diff_grants(target_grants, source_grants, managed_roles);
for g in to_revoke {
if let Some(source_owner) = source_owner {
out.revokes_with_owner.push(RevokeWithOwnerObservation {
object_label: object_label.clone(),
privilege_label: g.privilege.sql_keyword().into(),
grantee: g.grantee.clone(),
owner: source_owner.clone(),
});
}
out.push(revoke_change(object, mode, g), Destructiveness::Safe);
}
for g in to_add {
out.push(grant_change(object, mode, g), Destructiveness::Safe);
}
for g in unmanaged {
if let GrantTarget::Role(role_name) = &g.grantee {
out.unmanaged_grants.push(UnmanagedGrantObservation {
object_label: object_label.clone(),
privilege_label: g.privilege.sql_keyword().into(),
role_name: role_name.clone(),
});
}
}
}
fn revoke_change(object: &CatalogObjectRef, mode: ColumnGrantMode, grant: Grant) -> Change {
if let Some(qname) = column_target(object, mode, &grant) {
Change::RevokeColumnPrivilege { qname, grant }
} else {
Change::RevokeObjectPrivilege {
object: object.clone(),
grant,
}
}
}
fn grant_change(object: &CatalogObjectRef, mode: ColumnGrantMode, grant: Grant) -> Change {
if let Some(qname) = column_target(object, mode, &grant) {
Change::GrantColumnPrivilege { qname, grant }
} else {
Change::GrantObjectPrivilege {
object: object.clone(),
grant,
}
}
}
fn column_target(
object: &CatalogObjectRef,
mode: ColumnGrantMode,
grant: &Grant,
) -> Option<crate::identifier::QualifiedName> {
if mode != ColumnGrantMode::ColumnAware || grant.columns.is_none() {
return None;
}
match object {
CatalogObjectRef::Table(q)
| CatalogObjectRef::View(q)
| CatalogObjectRef::MaterializedView(q) => Some(q.clone()),
_ => None,
}
}