c++17: Refactor table with class type deduction
authorSangwan Kwon <sangwan.kwon@samsung.com>
Thu, 23 Jan 2020 06:26:09 +0000 (15:26 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Thu, 30 Jan 2020 04:14:41 +0000 (13:14 +0900)
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/vist/CMakeLists.txt
src/vist/query-builder/CMakeLists.txt
src/vist/query-builder/column-pack.hpp
src/vist/query-builder/column.hpp
src/vist/query-builder/crud.hpp
src/vist/query-builder/table.hpp
src/vist/query-builder/tests/columns.cpp [new file with mode: 0644]

index 4208e76..dcecc0d 100644 (file)
@@ -49,6 +49,7 @@ ADD_SUBDIRECTORY(database)
 ADD_SUBDIRECTORY(event)
 ADD_SUBDIRECTORY(klass)
 ADD_SUBDIRECTORY(logger)
+ADD_SUBDIRECTORY(query-builder)
 ADD_SUBDIRECTORY(sdk)
 
 # rmi
index 3965ab0..7220d8f 100644 (file)
@@ -14,6 +14,6 @@
 
 ADD_VIST_COMMON_LIBRARY(vist_query_builder query-builder.cpp)
 
-/// TSQB: Type Safe Query Builder
+# TSQB: Type Safe Query Builder
 FILE(GLOB TSQB_TESTS "tests/*.cpp")
 ADD_VIST_TEST(${TSQB_TESTS})
index 6f4e66f..7c759f3 100644 (file)
 
 #pragma once
 
+#include "tuple-helper.hpp"
 #include "type.hpp"
 
 #include <string>
+#include <tuple>
 #include <vector>
 
 namespace vist {
 namespace tsqb {
 namespace internal {
 
-template<typename... Base>
-class ColumnPack {
+template<typename... Columns>
+class ColumnPack final {
 public:
-       virtual ~ColumnPack() = default;
+       using TableType = typename std::tuple_element<0, std::tuple<Columns...>>::type::TableType;
+       using TupleType = std::tuple<Columns...>;
 
-       template<typename ColumnType>
-       std::string getName(ColumnType&&) const noexcept { return std::string(); }
-       std::vector<std::string> getNames(void) const noexcept { return {}; }
+       explicit ColumnPack(Columns&& ...columns) : columns(columns...)
+       {
+       }
 
-       int size() const noexcept { return 0; }
-};
+       template<typename Column>
+       std::string getName(const Column& column) const noexcept
+       {
+               std::string name;
+               auto predicate = [&name, &column](const auto& iter) {
+                       if (type::cast_compare(column, iter.type)) 
+                               name = iter.name;
+               };
 
-template<typename Front, typename... Rest>
-class ColumnPack<Front, Rest...> : public ColumnPack<Rest...> {
-public:
-       using Column = Front;
-       using TableType = typename Column::TableType;
+               tuple_helper::for_each(this->columns, predicate);
 
-       explicit ColumnPack(Front&& front, Rest&& ...rest);
-       virtual ~ColumnPack() = default;
+               return name;
+       }
 
-       ColumnPack(const ColumnPack&) = delete;
-       ColumnPack& operator=(const ColumnPack&) = delete;
+       std::vector<std::string> getNames(void) const noexcept
+       {
+               std::vector<std::string> names;
+               auto closure = [&names](const auto& iter) {
+                       names.push_back(iter.name);
+               };
 
-       ColumnPack(ColumnPack&&) = default;
-       ColumnPack& operator=(ColumnPack&&) = default;
+               tuple_helper::for_each(this->columns, closure);
 
-       template<typename ColumnType>
-       std::string getName(ColumnType&& type) const noexcept;
-       std::vector<std::string> getNames(void) const noexcept;
+               return names;
+       }
 
-       int size() const noexcept { return Base::size() + 1; }
+       std::size_t size() const noexcept
+       {
+               return std::tuple_size<TupleType>::value;
+       }
 
 private:
-       using Base = ColumnPack<Rest...>;
-
-       Column column;
+       std::tuple<Columns...> columns;
 };
 
-template<typename Front, typename... Rest>
-ColumnPack<Front, Rest...>::ColumnPack(Front&& front, Rest&& ...rest) :
-       Base(std::forward<Rest>(rest)...), column(front)
-{
-}
-
-template<typename Front, typename... Rest>
-std::vector<std::string> ColumnPack<Front, Rest...>::getNames(void) const noexcept
-{
-       auto names = Base::getNames();
-       names.push_back(this->column.name);
-
-       return std::move(names);
-}
-
-template<typename Front, typename... Rest>
-template<typename ColumnType>
-std::string ColumnPack<Front, Rest...>::getName(ColumnType&& type) const noexcept
-{
-       if (type::cast_compare(column.type, std::forward<ColumnType>(type)))
-               return column.name;
-
-       return Base::template getName<ColumnType>(std::forward<ColumnType>(type));
-}
-
 } // namespace internal
 } // namespace tsqb
 } // namespace vist
index 5ec7aba..70b1c75 100644 (file)
@@ -23,11 +23,15 @@ namespace vist {
 namespace tsqb {
 
 template<typename Object, typename Field>
-struct Column {
+struct Column final {
        using Type = Field Object::*;
        using FieldType = Field;
        using TableType = Object;
 
+       Column(const std::string& name, Field Object::*field) : name(name), type(field)
+       {
+       }
+
        std::string name;
        Type type;
 };
index bfba587..ded5080 100644 (file)
@@ -124,7 +124,7 @@ T& Crud<T>::selectInternal(ColumnTuple&& ct, bool distinct)
        if (distinct)
                ss << "DISTINCT ";
 
-       int i = 0;
+       std::size_t i = 0;
        for (const auto& c : columnNames) {
                ss << c;
 
index 9bdafad..fe7e208 100644 (file)
@@ -102,7 +102,7 @@ Table<Columns...>::Table(const std::string& name, ColumnPackType&& columnPack)
 
 template<typename... Columns>
 template<typename Cs>
-std::set<std::string> Table<Columns...>::getTableNames(Cs&& tuple) const noexcept
+std::set<std::string> Table<Columns...>::getTableNames(Cs&&) const noexcept
 {
        return {this->name};
 }
diff --git a/src/vist/query-builder/tests/columns.cpp b/src/vist/query-builder/tests/columns.cpp
new file mode 100644 (file)
index 0000000..23ddc4e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *  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 <vist/query-builder/column-pack.hpp>
+#include <vist/query-builder/column.hpp>
+
+using namespace vist::tsqb;
+using namespace vist::tsqb::internal;
+
+namespace {
+
+struct Sample {
+       int int1;
+       int int2;
+       std::string str1;
+       std::string str2;
+       bool bool1;
+       bool bool2;
+};
+
+ColumnPack columns { Column("int1", &Sample::int1),
+                                        Column("int2", &Sample::int2),
+                                        Column("str1", &Sample::str1),
+                                        Column("str2", &Sample::str2),
+                                        Column("bool1", &Sample::bool1),
+                                        Column("bool2", &Sample::bool2) };
+}
+
+TEST(ColumnTests, size)
+{
+       EXPECT_EQ(columns.size(), 6);
+}
+
+TEST(ColumnTests, get_name)
+{
+       EXPECT_EQ(columns.getName(&Sample::int1), "int1");
+       EXPECT_EQ(columns.getName(&Sample::int2), "int2");
+       EXPECT_EQ(columns.getName(&Sample::str1), "str1");
+       EXPECT_EQ(columns.getName(&Sample::str2), "str2");
+       EXPECT_EQ(columns.getName(&Sample::bool1), "bool1");
+       EXPECT_EQ(columns.getName(&Sample::bool2), "bool2");
+}
+
+TEST(ColumnTests, get_names)
+{
+       EXPECT_EQ(columns.getNames().size(), 6);
+}