From 0e9b9e2199af879fb82210b3f8e0de992001fa73 Mon Sep 17 00:00:00 2001
From: EmirVildanov <reddog201030@gmail.com>
Date: Mon, 18 Sep 2023 17:51:01 +0300
Subject: [PATCH] feat: support DROP ROLE

---
 doc/sql/query.ebnf                            |  3 +-
 .../test_app/test/integration/acl_test.lua    | 13 +++++++++
 sbroad-core/src/frontend/sql.rs               | 28 +++++++++++++++++++
 sbroad-core/src/frontend/sql/ast.rs           |  7 +++--
 sbroad-core/src/frontend/sql/query.pest       |  3 +-
 sbroad-core/src/ir/acl.rs                     |  7 ++++-
 6 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/doc/sql/query.ebnf b/doc/sql/query.ebnf
index 9eee7fb662..a9921308bd 100644
--- a/doc/sql/query.ebnf
+++ b/doc/sql/query.ebnf
@@ -3,7 +3,7 @@ EXPLAIN     ::= 'EXPLAIN' ( DML | DQL )
 DQL         ::= (SELECT | SELECT UNION ALL SELECT | SELECT (EXCEPT 'DISTINCT'? ) SELECT ) Options?
 DML         ::= (DELETE | INSERT | UPDATE) Options?
 DDL         ::= CreateTable | DropTable
-ACL         ::= DropUser | CreateRole | CreateUser
+ACL         ::= DropRole | DropUser | CreateRole | CreateUser
 CreateRole  ::= `create role` role ('option' '(' ('timeout' '=' DOUBLE)')')?
 CreateTable ::= 'create table' table '(' Column (',' Column)* ',' PrimaryKey ')' ('using' ('memtx' | 'vinyl'))? Distribution ('option' '(' ('timeout' '=' DOUBLE)')')?
 CreateUser ::= 'create user' user 'with'? 'password' "'" password "'" ('using' ('chap-sha1' | 'ldap' | 'md5'))? ('option' '(' ('timeout' '=' DOUBLE)')')?
@@ -11,6 +11,7 @@ Column      ::= name ('Bool' | 'Decimal' | 'Double' | 'Int' | 'Number' | 'Scalar
 PrimaryKey  ::= 'primary key' '(' name (',' name)* ')'
 Distribution ::= 'global' | ('distributed by' '(' name (',' name)*  ')')
 DropTable   ::= 'drop table' table ('option' '(' ('timeout' '=' DOUBLE)')')?
+DropRole    ::= 'drop role' role ('option' '(' ('timeout' '=' DOUBLE)')')?
 DropUser    ::= 'drop user' user ('option' '(' ('timeout' '=' DOUBLE)')')?
 Options     ::= 'option' '(' ('vtable_max_rows' '=' UNSIGNED)? (',' 'sql_vdbe_max_steps' '=' UNSIGNED)? ')'
 SELECT      ::= 'SELECT' ((column (',' column)*) ) 'FROM' (table ('AS' name)? | '(' (SELECT | VALUES) ')' ('AS' name)?) ( ('INNER')? 'JOIN' (table ('AS' name)? | ('(' (SELECT | VALUES) ')' ('AS' name)?))  'ON' expression )? ( 'WHERE' expression )? ( 'GROUP BY' expression(',' expression)* )?
diff --git a/sbroad-cartridge/test_app/test/integration/acl_test.lua b/sbroad-cartridge/test_app/test/integration/acl_test.lua
index 08006e5ab4..55341f31cd 100644
--- a/sbroad-cartridge/test_app/test/integration/acl_test.lua
+++ b/sbroad-cartridge/test_app/test/integration/acl_test.lua
@@ -30,6 +30,19 @@ g.test_drop_user = function()
     )
 end
 
+g.test_drop_role = function()
+    local api = cluster:server("api-1").net_box
+
+    local _, err = api:call(
+            "sbroad.execute",
+            { [[ DROP ROLE role ]], {} }
+    )
+    t.assert_equals(
+            string.format("%s", err),
+            [[Sbroad Error: ACL queries are not supported]]
+    )
+end
+
 g.test_create_role = function()
     local api = cluster:server("api-1").net_box
 
diff --git a/sbroad-core/src/frontend/sql.rs b/sbroad-core/src/frontend/sql.rs
index 5e2eb38595..bf637378cf 100644
--- a/sbroad-core/src/frontend/sql.rs
+++ b/sbroad-core/src/frontend/sql.rs
@@ -1878,6 +1878,34 @@ impl Ast for AbstractSyntaxTree {
                     let plan_id = plan.nodes.push(Node::Ddl(create_sharded_table));
                     map.add(id, plan_id);
                 }
+                Type::DropRole => {
+                    let role_name_id = node.children.first().ok_or_else(|| {
+                        SbroadError::Invalid(
+                            Entity::ParseNode,
+                            Some(String::from("RoleName expected under DropRole node")),
+                        )
+                    })?;
+                    let role_name_node = self.nodes.get_node(*role_name_id)?;
+                    let role_name = normalize_name_for_space_api(
+                        role_name_node.value.as_ref().ok_or_else(|| {
+                            SbroadError::NotFound(
+                                Entity::Node,
+                                "role name in the drop role AST".into(),
+                            )
+                        })?,
+                    );
+
+                    let mut timeout = default_timeout;
+                    if let Some(timeout_child_id) = node.children.get(1) {
+                        timeout = get_timeout(self, *timeout_child_id)?;
+                    }
+                    let drop_role = Acl::DropRole {
+                        name: role_name,
+                        timeout,
+                    };
+                    let plan_id = plan.nodes.push(Node::Acl(drop_role));
+                    map.add(id, plan_id);
+                }
                 Type::DropTable => {
                     let mut table_name: String = String::new();
                     let mut timeout = default_timeout;
diff --git a/sbroad-core/src/frontend/sql/ast.rs b/sbroad-core/src/frontend/sql/ast.rs
index a77e391221..e5393d3e9a 100644
--- a/sbroad-core/src/frontend/sql/ast.rs
+++ b/sbroad-core/src/frontend/sql/ast.rs
@@ -38,9 +38,7 @@ pub enum Type {
     Cast,
     ChapSha1,
     Cmp,
-    CreateRole,
     CreateTable,
-    CreateUser,
     Column,
     Columns,
     ColumnDef,
@@ -51,6 +49,8 @@ pub enum Type {
     Concat,
     Condition,
     CountAsterisk,
+    CreateRole,
+    CreateUser,
     Decimal,
     Delete,
     DeleteFilter,
@@ -59,6 +59,7 @@ pub enum Type {
     Distribution,
     Divide,
     Double,
+    DropRole,
     DropTable,
     DropUser,
     Duration,
@@ -188,6 +189,7 @@ impl Type {
             Rule::DeletedTable => Ok(Type::DeletedTable),
             Rule::Divide => Ok(Type::Divide),
             Rule::Double => Ok(Type::Double),
+            Rule::DropRole => Ok(Type::DropRole),
             Rule::DropTable => Ok(Type::DropTable),
             Rule::DropUser => Ok(Type::DropUser),
             Rule::Duration => Ok(Type::Duration),
@@ -326,6 +328,7 @@ impl fmt::Display for Type {
             Type::Distribution => "Distribution".to_string(),
             Type::Divide => "Divide".to_string(),
             Type::Double => "Double".to_string(),
+            Type::DropRole => "DropRole".to_string(),
             Type::DropTable => "DropTable".to_string(),
             Type::DropUser => "DropUser".to_string(),
             Type::Duration => "Duration".to_string(),
diff --git a/sbroad-core/src/frontend/sql/query.pest b/sbroad-core/src/frontend/sql/query.pest
index 06bfa990d2..0eb0022ef6 100644
--- a/sbroad-core/src/frontend/sql/query.pest
+++ b/sbroad-core/src/frontend/sql/query.pest
@@ -1,6 +1,6 @@
 Command = _{ SOI ~ (ExplainQuery | Query | DDL | ACL) ~ EOF }
 
-ACL = _{ DropUser | CreateRole | CreateUser }
+ACL = _{ DropRole | DropUser | CreateRole | CreateUser }
     CreateUser = {
         ^"create" ~ ^"user" ~ UserName ~ (^"with")? ~ ^"password" ~ PasswordString ~
         AuthMethod? ~ Option?
@@ -15,6 +15,7 @@ ACL = _{ DropUser | CreateRole | CreateUser }
         UserName = @{ Name }
     CreateRole = { ^"create" ~ ^"role" ~ RoleName ~ Option? }
         RoleName = @{ Name }
+    DropRole = { ^"drop" ~ ^"role" ~ RoleName ~ Option? }
 
 DDL = _{ CreateTable | DropTable }
     CreateTable = {
diff --git a/sbroad-core/src/ir/acl.rs b/sbroad-core/src/ir/acl.rs
index 8d7bca5290..0d8d3a2a03 100644
--- a/sbroad-core/src/ir/acl.rs
+++ b/sbroad-core/src/ir/acl.rs
@@ -4,6 +4,10 @@ use tarantool::decimal::Decimal;
 
 #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub enum Acl {
+    DropRole {
+        name: String,
+        timeout: Decimal,
+    },
     DropUser {
         name: String,
         timeout: Decimal,
@@ -27,7 +31,8 @@ impl Acl {
     /// - timeout parsing error
     pub fn timeout(&self) -> Result<f64, SbroadError> {
         match self {
-            Acl::DropUser { ref timeout, .. }
+            Acl::DropRole { ref timeout, .. }
+            | Acl::DropUser { ref timeout, .. }
             | Acl::CreateRole { ref timeout, .. }
             | Acl::CreateUser { ref timeout, .. } => timeout,
         }
-- 
GitLab