uqa_sql/catalog/roles/memberships/command/
revoke.rs1use super::{
10 super::{clear_membership_admin, revoke_membership},
11 BTreeMap, MembershipTarget, MembershipUpdate, RoleBinding, RoleDefinition, RoleMembership,
12 RoleMembershipKey, RoleMembershipOptions, SQLError,
13};
14
15pub struct MembershipRevocation<'a> {
16 target: &'a MembershipTarget,
17 before: BTreeMap<RoleMembershipKey, RoleMembership>,
18 after: BTreeMap<RoleMembershipKey, RoleMembership>,
19}
20
21impl<'a> MembershipRevocation<'a> {
22 pub fn new(
23 target: &'a MembershipTarget,
24 memberships: &BTreeMap<RoleMembershipKey, RoleMembership>,
25 ) -> Self {
26 let before = memberships
27 .iter()
28 .filter(|(key, _)| key.role == target.role.identity())
29 .map(|(key, value)| (*key, value.clone()))
30 .collect::<BTreeMap<_, _>>();
31 Self {
32 target,
33 after: before.clone(),
34 before,
35 }
36 }
37
38 pub fn member(
40 &mut self,
41 roles: &BTreeMap<String, RoleDefinition>,
42 member: &RoleBinding,
43 ) -> Result<Option<String>, SQLError> {
44 let key = RoleMembershipKey {
45 role: self.target.role.identity(),
46 member: member.identity(),
47 grantor: self.target.grantor.identity(),
48 };
49 if !self.before.contains_key(&key) {
50 return self
51 .target
52 .membership_notice(roles, member, "has not been granted")
53 .map(Some);
54 }
55 let options = self.target.options;
56 if options == RoleMembershipOptions::default() {
57 revoke_membership(&mut self.after, &key, self.target.cascade, true)?;
58 } else {
59 if options.admin == Some(false)
60 && self.after.get(&key).is_some_and(|row| row.admin_option)
61 {
62 clear_membership_admin(&mut self.after, &key, self.target.cascade)?;
63 }
64 if let Some(row) = self.after.get_mut(&key) {
65 if options.inherit == Some(false) {
66 row.inherit_option = false;
67 }
68 if options.set == Some(false) {
69 row.set_option = false;
70 }
71 }
72 }
73 Ok(None)
74 }
75
76 pub fn into_updates(self) -> Vec<MembershipUpdate> {
77 self.before
78 .into_iter()
79 .filter_map(|(key, before)| {
80 let after = self.after.get(&key).cloned();
81 (after.as_ref() != Some(&before)).then_some(MembershipUpdate { before, after })
82 })
83 .collect()
84 }
85}