query-builder: Refactor expression interface
authorSangwan Kwon <sangwan.kwon@samsung.com>
Tue, 4 Feb 2020 12:23:11 +0000 (21:23 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Mon, 17 Feb 2020 11:16:16 +0000 (20:16 +0900)
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/vist/policy/policy-storage.cpp
src/vist/query-builder.hpp
src/vist/query-builder/column.hpp
src/vist/query-builder/condition.hpp [deleted file]
src/vist/query-builder/crud.hpp
src/vist/query-builder/database.hpp
src/vist/query-builder/expression.hpp
src/vist/query-builder/tests/expression.cpp [new file with mode: 0644]
src/vist/query-builder/tests/query-builder.cpp

index d5cae2c..6fe7a7c 100644 (file)
@@ -177,7 +177,7 @@ void PolicyStorage::disenroll(const std::string& name)
                this->admins.erase(name);
        }
 
-       std::string query = schema::AdminTable.remove().where(expr(&Admin::name) == name);
+       std::string query = schema::AdminTable.remove().where(Admin::Name == name);
        database::Statement stmt(*database, query);
        stmt.bind(1, name);
        if (!stmt.exec())
@@ -195,7 +195,7 @@ void PolicyStorage::activate(const std::string& admin, bool state)
        DEBUG(VIST) << "Activate admin: " << admin;
        /// Admin::Activated
        std::string query = schema::AdminTable.update(Admin::Activated)
-                                                                                 .where(expr(&Admin::name) == admin);
+                                                                                 .where(Admin::Name == admin);
        database::Statement stmt(*this->database, query);
        stmt.bind(1, static_cast<int>(state));
        stmt.bind(2, admin);
@@ -237,8 +237,8 @@ void PolicyStorage::update(const std::string& admin,
                THROW(ErrCode::LogicError) << "Not exist policy: " << policy;
 
        std::string query = schema::PolicyManagedTable.update(PolicyManaged::Value)
-                                                                                                 .where(expr(&PolicyManaged::admin) == admin &&
-                                                                                                       expr(&PolicyManaged::policy) == policy);
+                                                                                                 .where(PolicyManaged::Admin == admin &&
+                                                                                                                PolicyManaged::Policy == policy);
        database::Statement stmt(*this->database, query);
        stmt.bind(1, value.dump());
        stmt.bind(2, admin);
index 50963d8..b957b33 100644 (file)
@@ -20,7 +20,6 @@
 #pragma once
 
 #include "query-builder/column.hpp"
-#include "query-builder/condition.hpp"
 #include "query-builder/database.hpp"
 #include "query-builder/expression.hpp"
 #include "query-builder/macro.hpp"
index 5782fa2..b37b514 100644 (file)
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "expression.hpp"
+
 #include <string>
 #include <tuple>
 
@@ -34,7 +36,35 @@ struct Column final {
 
        std::string name;
        Type type;
+
+       template<typename Value>
+       Equal<Column<Object, Field>, Value> operator==(Value value) const;
+       template<typename Value>
+       Greater<Column<Object, Field>, Value> operator>(Value value) const;
+       template<typename Value>
+       Lesser<Column<Object, Field>, Value> operator<(Value value) const;
 };
 
+template<typename Object, typename Field>
+template<typename Value>
+Equal<Column<Object, Field>, Value> Column<Object, Field>::operator==(Value value) const
+{
+       return {*this, value};
+}
+
+template<typename Object, typename Field>
+template<typename Value>
+Greater<Column<Object, Field>, Value> Column<Object, Field>::operator>(Value value) const
+{
+       return {*this, value};
+}
+
+template<typename Object, typename Field>
+template<typename Value>
+Lesser<Column<Object, Field>, Value> Column<Object, Field>::operator<(Value value) const
+{
+       return {*this, value};
+}
+
 } // namespace tsqb
 } // namespace vist
diff --git a/src/vist/query-builder/condition.hpp b/src/vist/query-builder/condition.hpp
deleted file mode 100644 (file)
index 54fdcce..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *  Copyright (c) 2017-present Samsung Electronics Co., Ltd All Rights Reserved
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-
-#pragma once
-
-#include "type.hpp"
-
-namespace vist {
-namespace tsqb {
-namespace condition {
-
-struct Base {};
-
-template<typename L, typename R>
-struct And : public Base {
-       L l;
-       R r;
-
-       And(L l, R r) : l(l), r(r) {}
-       operator std::string() const
-       {
-               return "AND";
-       }
-};
-
-template<typename L, typename R>
-struct Or : public Base {
-       L l;
-       R r;
-
-       Or(L l, R r) : l(l), r(r) {}
-       operator std::string() const
-       {
-               return "OR";
-       }
-};
-
-template<typename L, typename R>
-struct Binary : public Base {
-       L l;
-       R r;
-
-       Binary(L l, R r) : l(l), r(r)
-       {
-               using FieldType = typename L::FieldType;
-               type::assert_compare(FieldType(), r);
-       }
-};
-
-template<typename L>
-struct Binary<L, const char*> : public Base {
-       L l;
-       std::string r;
-
-       Binary(L l, const char* r) : l(l), r(r)
-       {
-               using FieldType = typename L::FieldType;
-               type::assert_compare(FieldType(), std::string());
-       }
-};
-
-enum class Join : int {
-       INNER,
-       CROSS,
-       LEFT_OUTER,
-       RIGHT_OUTER,
-       FULL_OUTER
-};
-
-inline std::string to_string(Join type)
-{
-       switch (type) {
-       case Join::CROSS: return "CROSS";
-       case Join::LEFT_OUTER: return "LEFT OUTER";
-       case Join::RIGHT_OUTER: return "RIGHT OUTER";
-       case Join::FULL_OUTER: return "FULL OUTER";
-       case Join::INNER:
-       default:
-               return "INNER";
-       }
-}
-
-} // namespace condition
-} // namespace tsqb
-} // namespace vist
index 72805cf..80c1b81 100644 (file)
@@ -50,10 +50,10 @@ public:
 
 private:
        template<typename L, typename R>
-       std::string processWhere(condition::And<L,R>& expr);
+       std::string processWhere(And<L,R>& expr);
 
        template<typename L, typename R>
-       std::string processWhere(condition::Or<L,R>& expr);
+       std::string processWhere(Or<L,R>& expr);
 
        template<typename Expr>
        std::string processWhere(Expr expr);
@@ -210,7 +210,7 @@ T& Crud<T>::where(Expr expr)
 
 template<typename T>
 template<typename L, typename R>
-std::string Crud<T>::processWhere(condition::And<L,R>& expr)
+std::string Crud<T>::processWhere(And<L,R>& expr)
 {
        std::stringstream ss;
        ss << this->processWhere(expr.l) << " ";
@@ -222,7 +222,7 @@ std::string Crud<T>::processWhere(condition::And<L,R>& expr)
 
 template<typename T>
 template<typename L, typename R>
-std::string Crud<T>::processWhere(condition::Or<L,R>& expr)
+std::string Crud<T>::processWhere(Or<L,R>& expr)
 {
        std::stringstream ss;
        ss << this->processWhere(expr.l) << " ";
index 6de1be0..f9e5466 100644 (file)
@@ -17,7 +17,6 @@
 #pragma once
 
 #include "column.hpp"
-#include "condition.hpp"
 #include "crud.hpp"
 #include "expression.hpp"
 #include "util.hpp"
@@ -40,12 +39,6 @@ public:
        explicit Database(const std::string& name, Tables ...tables) :
                name(name), tables(tables...) {}
 
-       template<typename Table>
-       Self& join(condition::Join type = condition::Join::INNER);
-
-       template<typename Expr>
-       Self& on(Expr expr);
-
        std::size_t size() const noexcept;
 
        operator std::string();
@@ -69,38 +62,6 @@ private:
 };
 
 template<typename... Tables>
-template<typename Table>
-Database<Tables...>& Database<Tables...>::join(condition::Join type)
-{
-       std::stringstream ss;
-       ss << condition::to_string(type) << " ";
-       ss << "JOIN ";
-       ss << this->getTableName(Table());
-
-       this->cache.emplace_back(ss.str());
-       return *this;
-}
-
-template<typename... Tables>
-template<typename Expr>
-Database<Tables...>& Database<Tables...>::on(Expr expr)
-{
-       std::stringstream ss;
-       ss << "ON ";
-
-       auto lname = this->getColumnName(std::move(expr.l.type));
-       ss << lname << " ";
-
-       ss << std::string(expr) << " ";
-
-       auto rname = this->getColumnName(std::move(expr.r.type));
-       ss << rname;
-
-       this->cache.emplace_back(ss.str());
-       return *this;
-}
-
-template<typename... Tables>
 Database<Tables...>::operator std::string()
 {
        std::stringstream ss;
index a1525f5..583b41e 100644 (file)
 
 #include "column.hpp"
 #include "type.hpp"
-#include "condition.hpp"
 
+#include <string>
 #include <type_traits>
 
 namespace vist {
 namespace tsqb {
 
-template<typename Type>
-struct Expression {
-       Type value;
-};
+struct Expression {};
 
-template<typename O, typename F>
-Expression<Column<O, F>> expr(F O::*field)
-{
-       Column<O, F> anonymous = {"anonymous", field};
-       return {anonymous};
-}
+template<typename T>
+using is_expression = typename std::is_base_of<Expression, T>;
 
 template<typename L, typename R>
-struct Lesser : public condition::Binary<L, R> {
-       using condition::Binary<L, R>::Binary;
+struct Binary : public Expression {
+       L l;
+       R r;
 
-       operator std::string() const
+       /// L is Column and R is Value
+       Binary(L l, R r) : l(l), r(r)
        {
-               return "<";
+               /// preventing logical expressions like &&, || and ==
+               if constexpr(!is_expression<L>::value) {
+                       using FieldType = typename L::FieldType;
+                       type::assert_compare(FieldType(), r);
+               }
        }
 };
 
-template<typename L, typename R>
-Lesser<L, R> operator<(Expression<L> expr, R r)
-{
-       return {expr.value, r};
-}
+template<typename L>
+struct Binary<L, const char*> : public Expression {
+       L l;
+       std::string r;
+
+       Binary(L l, const char* r) : l(l), r(r)
+       {
+               using FieldType = typename L::FieldType;
+               type::assert_compare(FieldType(), std::string());
+       }
+};
 
 template<typename L, typename R>
-struct Equal : public condition::Binary<L, R>
-{
-       using condition::Binary<L, R>::Binary;
+struct Greater : public Binary<L, R> {
+       using Binary<L, R>::Binary;
 
        operator std::string() const
        {
-               return "=";
+               return ">";
        }
 };
 
 template<typename L, typename R>
-Equal<L, R> operator==(Expression<L> expr, R r)
-{
-       return {expr.value, r};
-}
+struct Lesser : public Binary<L, R> {
+       using Binary<L, R>::Binary;
 
-namespace join {
+       operator std::string() const
+       {
+               return "<";
+       }
+};
 
 template<typename L, typename R>
-struct Equal
-{
-       L l;
-       R r;
+struct Equal : public Binary<L, R> {
+       using Binary<L, R>::Binary;
 
        operator std::string() const
        {
@@ -84,51 +88,40 @@ struct Equal
        }
 };
 
-} // namespace join
-
-template<typename L, typename R>
-join::Equal<L, R> operator==(Expression<L> l, Expression<R> r)
-{
-       return {l.value, r.value};
-}
-
 template<typename L, typename R>
-struct Greater : public condition::Binary<L, R>
-{
-       using condition::Binary<L, R>::Binary;
+struct And : public Binary<L, R> {
+       using Binary<L, R>::Binary;
 
        operator std::string() const
        {
-               return ">";
+               return "AND";
        }
 };
 
 template<typename L, typename R>
-Greater<L, R> operator>(Expression<L> expr, R r)
-{
-       return {expr.value, r};
-}
-
-template<bool B, typename T = void>
-using enable_if_t = typename std::enable_if<B, T>::type;
+struct Or  : public Binary<L, R> {
+       using Binary<L, R>::Binary;
 
-template<typename T>
-using is_condition = typename std::is_base_of<condition::Base, T>;
+       operator std::string() const
+       {
+               return "OR";
+       }
+};
 
 template<typename L,
                 typename R,
-                typename = typename tsqb::enable_if_t<is_condition<L>::value
-                                                        && tsqb::is_condition<R>::value>>
-condition::And<L, R> operator&&(const L& l, const R& r)
+                typename = typename std::enable_if_t<is_expression<L>::value &&
+                                                                                         is_expression<R>::value>>
+And<L, R> operator&&(const L& l, const R& r)
 {
        return {l, r};
 }
 
 template<typename L,
                 typename R,
-                typename = typename tsqb::enable_if_t<is_condition<L>::value
-                                                        && tsqb::is_condition<R>::value>>
-condition::Or<L, R> operator||(const L& l, const R& r)
+                typename = typename std::enable_if_t<is_expression<L>::value &&
+                                                                                         is_expression<R>::value>>
+Or<L, R> operator||(const L& l, const R& r)
 {
        return {l, r};
 }
diff --git a/src/vist/query-builder/tests/expression.cpp b/src/vist/query-builder/tests/expression.cpp
new file mode 100644 (file)
index 0000000..558c657
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include <gtest/gtest.h>
+
+#include "schema.hpp"
+
+using namespace vist::tsqb;
+using namespace vist::test;
+
+TEST(QueryBuilderExpressionTests, equal)
+{
+       std::string dump = (Table1::Column1 == 3);
+       EXPECT_EQ(dump, "=");
+}
+
+TEST(QueryBuilderExpressionTests, greater)
+{
+       std::string dump = (Table1::Column1 > 3);
+       EXPECT_EQ(dump, ">");
+}
+
+TEST(QueryBuilderExpressionTests, lesser)
+{
+       std::string dump = (Table1::Column1 < 3);
+       EXPECT_EQ(dump, "<");
+}
index 9fccaae..7f4da4b 100644 (file)
@@ -108,12 +108,12 @@ TEST(QueryBuilderTsqbTests, SELECT_ALL)
 TEST(QueryBuilderTsqbTests, SELECT_WHERE)
 {
        std::string select1 = AdminTable.select(Admin::Uid, Admin::Key)
-                                                                       .where(expr(&Admin::id) > 3);
-       std::string select2 = admin.selectAll().where(expr(&Admin::uid) > 3);
-       std::string select3 = admin.selectAll().where(expr(&Admin::uid) > 3 &&
-                                                                                                 expr(&Admin::pkg) == "dpm");
-       std::string select4 = admin.selectAll().where(expr(&Admin::uid) > 3 ||
-                                                                                                 expr(&Admin::pkg) == "dpm");
+                                                                       .where(Admin::Id > 3);
+       std::string select2 = admin.selectAll().where(Admin::Uid > 3);
+       std::string select3 = admin.selectAll().where(Admin::Uid > 3 &&
+                                                                                                 Admin::Pkg == "dpm");
+       std::string select4 = admin.selectAll().where(Admin::Uid > 3 ||
+                                                                                                 Admin::Pkg == "dpm");
 
        EXPECT_EQ(select1, "SELECT uid, key FROM admin WHERE id > ?");
        EXPECT_EQ(select2, "SELECT * FROM admin WHERE uid > ?");
@@ -125,10 +125,10 @@ TEST(QueryBuilderTsqbTests, UPDATE)
 {
        int uid = 0, id = 1;
        std::string update1 = admin.update(Admin::Id, Admin::Pkg, Admin::Uid, Admin::Key);
-       std::string update2 = admin.update(Admin::Key).where(expr(&Admin::uid) == uid &&
-                                                                                                                 expr(&Admin::id) == id);
+       std::string update2 = admin.update(Admin::Key).where((Admin::Uid == uid) &&
+                                                                                                                (Admin::Id == id));
        std::string update3 = admin.update(Admin::Key, Admin::Pkg)
-                                                          .where(expr(&Admin::uid) == 0 && expr(&Admin::id) == 1);
+                                                          .where((Admin::Uid == 0) && (Admin::Id == 1));
 
        EXPECT_EQ(update1, "UPDATE admin SET id = ?, pkg = ?, uid = ?, key = ?");
        EXPECT_EQ(update2, "UPDATE admin SET key = ? WHERE uid = ? AND id = ?");
@@ -138,8 +138,8 @@ TEST(QueryBuilderTsqbTests, UPDATE)
 TEST(QueryBuilderTsqbTests, DELETE)
 {
        std::string delete1 = admin.remove();
-       std::string delete2 = admin.remove().where(expr(&Admin::pkg) == "dpm" &&
-                                                                                          expr(&Admin::uid) == 3);
+       std::string delete2 = admin.remove().where((Admin::Pkg == "dpm") &&
+                                                                                          (Admin::Uid == 3));
 
        EXPECT_EQ(delete1, "DELETE FROM admin");
        EXPECT_EQ(delete2, "DELETE FROM admin WHERE pkg = ? AND uid = ?");
@@ -159,13 +159,13 @@ TEST(QueryBuilderTsqbTests, TYPE_SAFE)
 /*
  * Below cause complie error since expression types are dismatch.
 
-       std::string type_unsafe1 = admin.selectAll().where(expr(&Admin::uid) > "dpm");
-       std::string type_unsafe2 = admin.selectAll().where(expr(&Admin::uid) == "dpm");
-       std::string type_unsafe3 = admin.selectAll().where(expr(&Admin::pkg) == 3);
+       std::string type_unsafe1 = admin.selectAll().where(Admin::Uid > "dpm");
+       std::string type_unsafe2 = admin.selectAll().where(Admin::Uid == "dpm");
+       std::string type_unsafe3 = admin.selectAll().where(Admin::Pkg == 3);
        int pkg = 3;
-       std::string type_unsafe4 = admin.selectAll().where(expr(&Admin::pkg) < pkg);
-       std::string type_unsafe5 = admin.remove().where(expr(&Admin::pkg) == "dpm" &&
-                                                                                                       expr(&Admin::uid) == "dpm");
+       std::string type_unsafe4 = admin.selectAll().where(Admin::Pkg) < pkg);
+       std::string type_unsafe5 = admin.remove().where(Admin::Pkg) == "dpm" &&
+                                                                                                       Admin::Uid) == "dpm");
 */
 }
 
@@ -175,7 +175,7 @@ TEST(QueryBuilderTsqbTests, MULTI_SELECT)
                                                                                 ManagedPolicy::Id, ManagedPolicy::Value);
        std::string multiSelect2 = db.select(Admin::Uid, Admin::Key,
                                                                                 ManagedPolicy::Id, ManagedPolicy::Value)
-                                                                .where(expr(&Admin::uid) > 0 && expr(&ManagedPolicy::id) == 3);
+                                                                .where((Admin::Uid > 0) && (ManagedPolicy::Id == 3));
 
        EXPECT_EQ(multiSelect1, "SELECT admin.uid, admin.key, managed_policy.id, "
                                                        "managed_policy.value FROM admin, managed_policy");
@@ -193,10 +193,10 @@ TEST(QueryBuilderTsqbTests, JOIN)
                                                  .join<ManagedPolicy>(condition::Join::CROSS);
        std::string join3 = db.select(ManagedPolicy::Value)
                                                  .join<PolicyDefinition>()
-                                                 .on(expr(&ManagedPolicy::pid) == expr(&PolicyDefinition::id))
+                                                 .on(ManagedPolicy::Pid) == PolicyDefinition::Id))
                                                  .join<Admin>()
-                                                 .on(expr(&ManagedPolicy::aid) == expr(&Admin::id))
-                                                 .where(expr(&ManagedPolicy::pid) == 99);
+                                                 .on(ManagedPolicy::Aid) == Admin::Id))
+                                                 .where(ManagedPolicy::Pid) == 99);
 
        EXPECT_EQ(join1, "SELECT admin.uid, admin.key FROM admin "
                                         "LEFT OUTER JOIN policy_definition");