6de1be0647d74933b4d96d5dca42d1a6c7291702
[platform/core/security/vist.git] / src / vist / query-builder / database.hpp
1 /*
2  *  Copyright (c) 2017-present Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16
17 #pragma once
18
19 #include "column.hpp"
20 #include "condition.hpp"
21 #include "crud.hpp"
22 #include "expression.hpp"
23 #include "util.hpp"
24
25 #include <algorithm>
26 #include <set>
27 #include <sstream>
28 #include <string>
29 #include <tuple>
30 #include <vector>
31
32 namespace vist {
33 namespace tsqb {
34
35 template<typename... Tables>
36 class Database : public Crud<Database<Tables...>> {
37 public:
38         using Self = Database<Tables...>;
39
40         explicit Database(const std::string& name, Tables ...tables) :
41                 name(name), tables(tables...) {}
42
43         template<typename Table>
44         Self& join(condition::Join type = condition::Join::INNER);
45
46         template<typename Expr>
47         Self& on(Expr expr);
48
49         std::size_t size() const noexcept;
50
51         operator std::string();
52
53         std::string name;
54
55 public: // CRTP(Curiously Recurring Template Pattern) for CRUD
56         template<typename... Cs>
57         std::vector<std::string> getTableNames(Cs&& ...columns) const noexcept;
58         template<typename Table>
59         std::string getTableName(Table&& table) const noexcept;
60         template<typename... Cs> 
61         std::vector<std::string> getColumnNames(Cs&& ...columns) const noexcept;
62         template<typename Column>
63         std::string getColumnName(Column&& column) const noexcept;
64
65         std::vector<std::string> cache;
66
67 private:
68         std::tuple<Tables...> tables;
69 };
70
71 template<typename... Tables>
72 template<typename Table>
73 Database<Tables...>& Database<Tables...>::join(condition::Join type)
74 {
75         std::stringstream ss;
76         ss << condition::to_string(type) << " ";
77         ss << "JOIN ";
78         ss << this->getTableName(Table());
79
80         this->cache.emplace_back(ss.str());
81         return *this;
82 }
83
84 template<typename... Tables>
85 template<typename Expr>
86 Database<Tables...>& Database<Tables...>::on(Expr expr)
87 {
88         std::stringstream ss;
89         ss << "ON ";
90
91         auto lname = this->getColumnName(std::move(expr.l.type));
92         ss << lname << " ";
93
94         ss << std::string(expr) << " ";
95
96         auto rname = this->getColumnName(std::move(expr.r.type));
97         ss << rname;
98
99         this->cache.emplace_back(ss.str());
100         return *this;
101 }
102
103 template<typename... Tables>
104 Database<Tables...>::operator std::string()
105 {
106         std::stringstream ss;
107         for (const auto& c : cache)
108                 ss << c << " ";
109
110         this->cache.clear();
111         return util::rtrim(ss.str());
112 }
113
114 template<typename... Tables>
115 template<typename... Cs>
116 std::vector<std::string> Database<Tables...>::getTableNames(Cs&& ...columns) const noexcept
117 {
118         std::set<std::string> names;
119
120         auto predicate = [this, &names](const auto& column) {
121                 using ColumnType = std::remove_reference_t<decltype(column)>;
122                 using TableType = typename ColumnType::Table;
123                 auto name = this->getTableName(TableType());
124                 if (!name.empty())
125                                 names.emplace(name);
126         };
127
128         auto closure = [&predicate](const auto&... iter) {
129                 (predicate(iter), ...);
130         };
131
132         std::apply(closure, std::tuple(columns...));
133
134         return std::vector<std::string>(names.begin(), names.end());
135 }
136
137 template<typename... Tables>
138 template<typename... Cs>
139 std::vector<std::string> Database<Tables...>::getColumnNames(Cs&& ...columns) const noexcept
140 {
141         std::vector<std::string> names;
142         auto predicate = [this, &names](const auto& column) {
143                 auto name = this->getColumnName(column);
144                 if (!name.empty())
145                         names.emplace_back(name);
146         };
147
148         auto closure = [&predicate](const auto&... iter) {
149                 (predicate(iter), ...);
150         };
151
152         std::apply(closure, std::tuple(columns...));
153
154         return names;
155 }
156
157 template<typename... Tables>
158 template<typename Table>
159 std::string Database<Tables...>::getTableName(Table&& table) const noexcept
160 {
161         std::string name;
162         auto predicate = [&name, &table](const auto& type) {
163                 if (type.compare(table))
164                         name = type.name;
165         };
166
167         auto closure = [&predicate](const auto&... iter) {
168                 (predicate(iter), ...);
169         };
170
171         std::apply(closure, this->tables);
172
173         return name;
174 }
175
176 template<typename... Tables>
177 template<typename Column>
178 std::string Database<Tables...>::getColumnName(Column&& column) const noexcept
179 {
180         using ColumnType = std::remove_reference_t<decltype(column)>;
181         using TableType = typename ColumnType::Table;
182         TableType table;
183
184         std::string name;
185         auto predicate = [&name, &table, &column](const auto& iter) {
186                 if (iter.compare(table)) {
187                         auto cname = iter.getColumnName(column);
188                         name = iter.name + "." + cname;
189                 }
190         };
191
192         auto closure = [&predicate](const auto&... iter) {
193                 (predicate(iter), ...);
194         };
195
196         std::apply(closure, this->tables);
197
198         return name;
199 }
200
201 template<typename... Tables>
202 std::size_t Database<Tables...>::size() const noexcept
203 {
204         using TupleType = std::tuple<Tables...>;
205         return std::tuple_size<TupleType>::value;
206 }
207
208 } // namespace tsqb
209 } // namespace vist