1use crate::catalog::id::DbObjectId;
4use crate::diff::operations::GrantOperation;
5use crate::render::{RenderedSql, SqlRenderer};
6
7impl SqlRenderer for GrantOperation {
8 fn to_sql(&self) -> Vec<RenderedSql> {
9 match self {
10 GrantOperation::Grant { grant } => {
11 vec![RenderedSql::new(
12 crate::render::sql::render_grant_statement(grant),
13 )]
14 }
15 GrantOperation::Revoke { grant } => {
16 vec![RenderedSql::new(
17 crate::render::sql::render_revoke_statement(grant),
18 )]
19 }
20 GrantOperation::GrantColumns(cg) => {
21 vec![RenderedSql::new(
22 crate::render::sql::render_column_grant_statement(cg),
23 )]
24 }
25 GrantOperation::RevokeColumns(cg) => {
26 vec![RenderedSql::new(
27 crate::render::sql::render_column_revoke_statement(cg),
28 )]
29 }
30 }
31 }
32
33 fn db_object_id(&self) -> DbObjectId {
34 match self {
35 GrantOperation::Grant { grant } => DbObjectId::Grant { id: grant.id() },
36 GrantOperation::Revoke { grant } => DbObjectId::Grant { id: grant.id() },
37 GrantOperation::GrantColumns(cg) => DbObjectId::Grant {
38 id: cg.rep_id.clone(),
39 },
40 GrantOperation::RevokeColumns(cg) => DbObjectId::Grant {
41 id: cg.rep_id.clone(),
42 },
43 }
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use crate::catalog::grant::{Grant, GranteeType};
51 use crate::catalog::id::DbObjectId;
52 use crate::catalog::target::AttrTarget;
53 use crate::render::Safety;
54
55 fn create_table_grant() -> Grant {
56 Grant {
57 grantee: GranteeType::Role("app_user".to_string()),
58 target: AttrTarget::object(DbObjectId::Table {
59 schema: "public".to_string(),
60 name: "users".to_string(),
61 }),
62 privileges: vec!["SELECT".to_string(), "INSERT".to_string()],
63 with_grant_option: false,
64 depends_on: vec![],
65 object_owner: "admin".to_string(),
66 is_default_acl: false,
67 }
68 }
69
70 #[test]
71 fn test_render_grant() {
72 let grant = create_table_grant();
73 let op = GrantOperation::Grant { grant };
74 let rendered = op.to_sql();
75 assert_eq!(rendered.len(), 1);
76 assert!(rendered[0].sql.contains("GRANT"));
77 assert!(rendered[0].sql.contains("SELECT"));
78 assert!(rendered[0].sql.contains("INSERT"));
79 assert!(rendered[0].sql.contains("app_user"));
80 }
81
82 #[test]
83 fn test_render_revoke() {
84 let grant = create_table_grant();
85 let op = GrantOperation::Revoke { grant };
86 let rendered = op.to_sql();
87 assert_eq!(rendered.len(), 1);
88 assert!(rendered[0].sql.contains("REVOKE"));
89 }
90
91 #[test]
92 fn test_render_grant_to_public() {
93 let grant = Grant {
94 grantee: GranteeType::Public,
95 target: AttrTarget::object(DbObjectId::Function {
96 schema: "public".to_string(),
97 name: "my_func".to_string(),
98 arguments: "integer".to_string(),
99 }),
100 privileges: vec!["EXECUTE".to_string()],
101 with_grant_option: false,
102 depends_on: vec![],
103 object_owner: "admin".to_string(),
104 is_default_acl: false,
105 };
106 let op = GrantOperation::Grant { grant };
107 let rendered = op.to_sql();
108 assert!(rendered[0].sql.contains("PUBLIC"));
109 }
110
111 #[test]
112 fn test_has_destructive_sql() {
113 let grant = create_table_grant();
114 let grant_op = GrantOperation::Grant {
115 grant: grant.clone(),
116 };
117 let revoke_op = GrantOperation::Revoke { grant };
118
119 assert!(
121 !grant_op
122 .to_sql()
123 .iter()
124 .any(|s| s.safety == Safety::Destructive)
125 );
126 assert!(
127 !revoke_op
128 .to_sql()
129 .iter()
130 .any(|s| s.safety == Safety::Destructive)
131 );
132 }
133
134 #[test]
135 fn test_db_object_id() {
136 let grant = create_table_grant();
137 let op = GrantOperation::Grant {
138 grant: grant.clone(),
139 };
140 let expected_id = grant.id();
141 assert_eq!(op.db_object_id(), DbObjectId::Grant { id: expected_id });
142 }
143}