From: sangwan.kwon Date: Thu, 11 Jan 2018 10:50:48 +0000 (+0900) Subject: Draft query-builder X-Git-Tag: submit/tizen_4.0/20180119.042851^2~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a58781ea23db796463641c15e573127738ce3fc2;p=platform%2Fcore%2Fsecurity%2Fklay.git Draft query-builder - Capture member pointer of struct. (column.hxx) - Bind columns as table structure. (table.hxx) - Generate select query by using Table::select(), Table::selectAll(). - Generate single where expression. Change-Id: I929cf5d0d98f97fcb78e88162bafe9e3b955e1bb Signed-off-by: sangwan.kwon --- diff --git a/include/klay/db/query-builder/column.hxx b/include/klay/db/query-builder/column.hxx new file mode 100644 index 0000000..d24ae73 --- /dev/null +++ b/include/klay/db/query-builder/column.hxx @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace qxx { + +template +struct Column { + typedef Field Object::*Type; + + std::string name; + Type type; +}; + +template +Column make_column(const std::string& name, F O::*field) { + return {name, field}; +} + +} // namespace qxx diff --git a/include/klay/db/query-builder/expression.hxx b/include/klay/db/query-builder/expression.hxx new file mode 100644 index 0000000..adc6c27 --- /dev/null +++ b/include/klay/db/query-builder/expression.hxx @@ -0,0 +1,68 @@ +#pragma once + +namespace qxx { +namespace condition { + +template +struct Binary { + L l; + R r; + + Binary(L l, R r) : l(l), r(r) {} +}; + +} // namespace condition + +template +struct Expression { + Type value; +}; + +template +Expression expr(Type value) { + return {value}; +} + +template +struct Lesser : public condition::Binary { + using condition::Binary::Binary; + + operator std::string() const { + return "<"; + } +}; + +template +Lesser operator<(Expression expr, R r) { + return {expr.value, r}; +} + +template +struct Equal : public condition::Binary { + using condition::Binary::Binary; + + operator std::string() const { + return "="; + } +}; + +template +Equal operator==(Expression expr, R r) { + return {expr.value, r}; +} + +template +struct Greater : public condition::Binary { + using condition::Binary::Binary; + + operator std::string() const { + return ">"; + } +}; + +template +Equal operator>(Expression expr, R r) { + return {expr.value, r}; +} + +} // namespace qxx diff --git a/include/klay/db/query-builder/table-impl.hxx b/include/klay/db/query-builder/table-impl.hxx new file mode 100644 index 0000000..db4b174 --- /dev/null +++ b/include/klay/db/query-builder/table-impl.hxx @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +namespace qxx { +namespace internal { + +template +class TableImpl { +public: + std::vector getColumnNames() const noexcept { return {}; } + + template + std::string getColumnName(Type type) const noexcept { return std::string(); } + + int size() const noexcept { return 0; } +}; + +template +class TableImpl : public TableImpl { +public: + using Column = Front; + + explicit TableImpl(Front front, Rest ...rest) : Base(rest...), column(front) {} + + int size() const noexcept { return Base::size() + 1; } + + std::vector getColumnNames(void) const noexcept { + auto names = Base::getColumnNames(); + names.emplace_back(this->column.name); + return names; + } + + template + std::string getColumnName(ColumnType type) const noexcept { + // [TO-DO] Do Not Cast. + // [ALTER] std::is_same{} + // [PROBLEM] Cannot multi-table select.. + // [CRITICAL] (&Data::int == &Data2::int) is same + if (reinterpret_cast(column.type) == type) + return column.name; + + return Base::template getColumnName(type); + } + +private: + using Base = TableImpl; + + Column column; +}; + +} // namespace internal +} // namespace qxx diff --git a/include/klay/db/query-builder/table.hxx b/include/klay/db/query-builder/table.hxx new file mode 100644 index 0000000..d236eda --- /dev/null +++ b/include/klay/db/query-builder/table.hxx @@ -0,0 +1,167 @@ +#pragma once + +#include "column.hxx" +#include "table-impl.hxx" +#include "tuple-helper.hxx" + +#include +#include +#include +#include + +namespace qxx { + +template +class Table { +public: + using Self = Table; + + template + Self select(ColumnTypes&&... cts); + + Self selectAll(void); + + template + Self where(Expr expr); + + operator std::string(); + +private: + using ImplType = internal::TableImpl; + + explicit Table(const std::string& name, ImplType impl); + + template + friend Table make_table(const std::string& name, Cs&& ...columns); + + template + std::vector getColumnNames(Cs&& tuple); + + int size() const noexcept; + + std::vector getColumnNames(void) const noexcept; + + template + std::string getColumnName(ColumnType&& type) const noexcept; + + struct GetColumnNames { + ImplType impl; + std::vector names; + + GetColumnNames(const ImplType &impl) : impl(impl) {} + + template + void operator()(T&& type) { + auto name = this->impl.getColumnName(std::forward(type)); + if (!name.empty()) + names.emplace_back(name); + } + }; + + std::string name; + ImplType impl; + + std::vector cache; +}; + +template +Table make_table(const std::string& name, Columns&& ...cs) +{ + auto impl = internal::TableImpl(std::forward(cs)...); + return Table(name, std::move(impl)); +} + +template +Table::Table(const std::string& name, ImplType impl) + : name(name), impl(impl) {} + +template +template +Table Table::select(ColumnTypes&&... cts) +{ + this->cache.clear(); + + auto columnTuple = std::make_tuple(std::forward(cts)...); + auto columnNames = this->getColumnNames(std::move(columnTuple)); + + std::stringstream ss; + ss << "SELECT "; + + for(const auto& c : columnNames) + ss << c << " "; + + ss << "FROM " << this->name; + + cache.emplace_back(ss.str()); + + return *this; +} + +template +Table Table::selectAll(void) +{ + this->cache.clear(); + + std::stringstream ss; + ss << "SELECT * FROM " << this->name; + + cache.emplace_back(ss.str()); + + return *this; +} + +template +template +Table Table::where(Expr expr) +{ + auto name = this->impl.getColumnName(expr.l); + + std::stringstream ss; + ss << "WHERE " << name << " " << std::string(expr) << " ?"; + + this->cache.emplace_back(ss.str()); + + return *this; +} + +template +Table::operator std::string() +{ + std::stringstream ss; + for (const auto& c : cache) + ss << c << " "; + + this->cache.clear(); + return ss.str(); +} + +template +template +std::vector Table::getColumnNames(Cs&& tuple) +{ + GetColumnNames closure(this->impl); + tuple_helper::for_each(std::forward(tuple), closure); + + return closure.names; +} + +template +int Table::size() const noexcept +{ + return this->impl.size(); +} + +template +std::vector Table::getColumnNames(void) const noexcept +{ + return this->impl.getColumnNames(); +} + +template +template +std::string Table::getColumnName(ColumnType&& type) const noexcept +{ + return this->impl.getColumnName(std::forward(type)); +} + +} // namespace qxx diff --git a/include/klay/db/query-builder/test-main.cpp b/include/klay/db/query-builder/test-main.cpp new file mode 100644 index 0000000..30dd09b --- /dev/null +++ b/include/klay/db/query-builder/test-main.cpp @@ -0,0 +1,35 @@ +#include "table.hxx" +#include "column.hxx" +#include "expression.hxx" + +#include + +using namespace qxx; + +struct Admin { + int id; + std::string pkg; + int uid; + std::string key; + int removable; +}; + +int main() { + auto admin = make_table("admin", make_column("id", &Admin::id), + make_column("pkg", &Admin::pkg), + make_column("uid", &Admin::uid), + make_column("key", &Admin::key), + make_column("removable", &Admin::removable)); + + std::string select1 = admin.select(&Admin::id, &Admin::pkg, &Admin::uid, &Admin::key); + std::string select2 = admin.select(&Admin::id, &Admin::uid, &Admin::key); + std::string select3 = admin.select(&Admin::uid, &Admin::key).where(expr(&Admin::id) > 3); + std::string select4 = admin.selectAll().where(expr(&Admin::uid) > 3); + + std::cout << select1 << '\n'; // SELECT id pkg uid key FROM admin + std::cout << select2 << '\n'; // SELECT id uid key FROM admin + std::cout << select3 << '\n'; // SELECT uid key FROM admin WHERE id = ? + std::cout << select4 << '\n'; // SELECT * FROM admin WHERE uid = ? + + return 0; +} diff --git a/include/klay/db/query-builder/tuple-helper.hxx b/include/klay/db/query-builder/tuple-helper.hxx new file mode 100644 index 0000000..0979973 --- /dev/null +++ b/include/klay/db/query-builder/tuple-helper.hxx @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace qxx { +namespace tuple_helper { +namespace internal { + +template +class Iterator { +public: + Iterator(const T& tuple, C&& closure) { + Iterator iter(tuple, std::forward(closure)); + closure(std::get(tuple)); + } +}; + +template +class Iterator<0, T, C> { +public: + Iterator(const T&, C&&) {} +}; + +} // namespace internal + +template +void for_each(const T& tuple, C&& closure) +{ + using Iter = internal::Iterator::value, T, C>; + Iter iter(tuple, std::forward(closure)); +} + +} // namspace tuple-hepler +} // namspace qxx