--- /dev/null
+#pragma once
+
+#include <string>
+#include <tuple>
+
+namespace qxx {
+
+template<typename Object, typename Field>
+struct Column {
+ typedef Field Object::*Type;
+
+ std::string name;
+ Type type;
+};
+
+template<typename O, typename F>
+Column<O, F> make_column(const std::string& name, F O::*field) {
+ return {name, field};
+}
+
+} // namespace qxx
--- /dev/null
+#pragma once
+
+namespace qxx {
+namespace condition {
+
+template<class L, class R>
+struct Binary {
+ L l;
+ R r;
+
+ Binary(L l, R r) : l(l), r(r) {}
+};
+
+} // namespace condition
+
+template<class Type>
+struct Expression {
+ Type value;
+};
+
+template<class Type>
+Expression<Type> expr(Type value) {
+ return {value};
+}
+
+template<class L, class R>
+struct Lesser : public condition::Binary<L, R> {
+ using condition::Binary<L, R>::Binary;
+
+ operator std::string() const {
+ return "<";
+ }
+};
+
+template<class L, class R>
+Lesser<L, R> operator<(Expression<L> expr, R r) {
+ return {expr.value, r};
+}
+
+template<class L, class R>
+struct Equal : public condition::Binary<L, R> {
+ using condition::Binary<L, R>::Binary;
+
+ operator std::string() const {
+ return "=";
+ }
+};
+
+template<class L, class R>
+Equal<L, R> operator==(Expression<L> expr, R r) {
+ return {expr.value, r};
+}
+
+template<class L, class R>
+struct Greater : public condition::Binary<L, R> {
+ using condition::Binary<L, R>::Binary;
+
+ operator std::string() const {
+ return ">";
+ }
+};
+
+template<class L, class R>
+Equal<L, R> operator>(Expression<L> expr, R r) {
+ return {expr.value, r};
+}
+
+} // namespace qxx
--- /dev/null
+#pragma once
+
+#include <string>
+#include <vector>
+
+namespace qxx {
+namespace internal {
+
+template<typename... Base>
+class TableImpl {
+public:
+ std::vector<std::string> getColumnNames() const noexcept { return {}; }
+
+ template<class Type>
+ std::string getColumnName(Type type) const noexcept { return std::string(); }
+
+ int size() const noexcept { return 0; }
+};
+
+template<typename Front, typename... Rest>
+class TableImpl<Front, Rest...> : public TableImpl<Rest...> {
+public:
+ using Column = Front;
+
+ explicit TableImpl(Front front, Rest ...rest) : Base(rest...), column(front) {}
+
+ int size() const noexcept { return Base::size() + 1; }
+
+ std::vector<std::string> getColumnNames(void) const noexcept {
+ auto names = Base::getColumnNames();
+ names.emplace_back(this->column.name);
+ return names;
+ }
+
+ template<typename ColumnType>
+ std::string getColumnName(ColumnType type) const noexcept {
+ // [TO-DO] Do Not Cast.
+ // [ALTER] std::is_same<F, typename T::field_type>{}
+ // [PROBLEM] Cannot multi-table select..
+ // [CRITICAL] (&Data::int == &Data2::int) is same
+ if (reinterpret_cast<ColumnType>(column.type) == type)
+ return column.name;
+
+ return Base::template getColumnName<ColumnType>(type);
+ }
+
+private:
+ using Base = TableImpl<Rest...>;
+
+ Column column;
+};
+
+} // namespace internal
+} // namespace qxx
--- /dev/null
+#pragma once
+
+#include "column.hxx"
+#include "table-impl.hxx"
+#include "tuple-helper.hxx"
+
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <sstream>
+
+namespace qxx {
+
+template<typename... Columns>
+class Table {
+public:
+ using Self = Table<Columns...>;
+
+ template<typename... ColumnTypes>
+ Self select(ColumnTypes&&... cts);
+
+ Self selectAll(void);
+
+ template<typename Expr>
+ Self where(Expr expr);
+
+ operator std::string();
+
+private:
+ using ImplType = internal::TableImpl<Columns...>;
+
+ explicit Table(const std::string& name, ImplType impl);
+
+ template<typename ...Cs>
+ friend Table<Cs...> make_table(const std::string& name, Cs&& ...columns);
+
+ template<typename Cs>
+ std::vector<std::string> getColumnNames(Cs&& tuple);
+
+ int size() const noexcept;
+
+ std::vector<std::string> getColumnNames(void) const noexcept;
+
+ template<typename ColumnType>
+ std::string getColumnName(ColumnType&& type) const noexcept;
+
+ struct GetColumnNames {
+ ImplType impl;
+ std::vector<std::string> names;
+
+ GetColumnNames(const ImplType &impl) : impl(impl) {}
+
+ template <typename T>
+ void operator()(T&& type) {
+ auto name = this->impl.getColumnName(std::forward<T>(type));
+ if (!name.empty())
+ names.emplace_back(name);
+ }
+ };
+
+ std::string name;
+ ImplType impl;
+
+ std::vector<std::string> cache;
+};
+
+template<typename ...Columns>
+Table<Columns...> make_table(const std::string& name, Columns&& ...cs)
+{
+ auto impl = internal::TableImpl<Columns...>(std::forward<Columns>(cs)...);
+ return Table<Columns...>(name, std::move(impl));
+}
+
+template<typename... Columns>
+Table<Columns...>::Table(const std::string& name, ImplType impl)
+ : name(name), impl(impl) {}
+
+template<typename... Columns>
+template<typename... ColumnTypes>
+Table<Columns...> Table<Columns...>::select(ColumnTypes&&... cts)
+{
+ this->cache.clear();
+
+ auto columnTuple = std::make_tuple(std::forward<ColumnTypes>(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<typename ...Columns>
+Table<Columns...> Table<Columns...>::selectAll(void)
+{
+ this->cache.clear();
+
+ std::stringstream ss;
+ ss << "SELECT * FROM " << this->name;
+
+ cache.emplace_back(ss.str());
+
+ return *this;
+}
+
+template<typename... Columns>
+template<typename Expr>
+Table<Columns...> Table<Columns...>::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<typename... Columns>
+Table<Columns...>::operator std::string()
+{
+ std::stringstream ss;
+ for (const auto& c : cache)
+ ss << c << " ";
+
+ this->cache.clear();
+ return ss.str();
+}
+
+template<typename... Columns>
+template<typename Cs>
+std::vector<std::string> Table<Columns...>::getColumnNames(Cs&& tuple)
+{
+ GetColumnNames closure(this->impl);
+ tuple_helper::for_each(std::forward<Cs>(tuple), closure);
+
+ return closure.names;
+}
+
+template<typename... Columns>
+int Table<Columns...>::size() const noexcept
+{
+ return this->impl.size();
+}
+
+template<typename... Columns>
+std::vector<std::string> Table<Columns...>::getColumnNames(void) const noexcept
+{
+ return this->impl.getColumnNames();
+}
+
+template<typename... Columns>
+template<typename ColumnType>
+std::string Table<Columns...>::getColumnName(ColumnType&& type) const noexcept
+{
+ return this->impl.getColumnName(std::forward<ColumnType>(type));
+}
+
+} // namespace qxx
--- /dev/null
+#include "table.hxx"
+#include "column.hxx"
+#include "expression.hxx"
+
+#include <iostream>
+
+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;
+}
--- /dev/null
+#pragma once
+
+#include <tuple>
+
+namespace qxx {
+namespace tuple_helper {
+namespace internal {
+
+template<int n, typename T, typename C>
+class Iterator {
+public:
+ Iterator(const T& tuple, C&& closure) {
+ Iterator<n - 1, T, C> iter(tuple, std::forward<C>(closure));
+ closure(std::get<n-1>(tuple));
+ }
+};
+
+template<typename T, typename C>
+class Iterator<0, T, C> {
+public:
+ Iterator(const T&, C&&) {}
+};
+
+} // namespace internal
+
+template<typename T, typename C>
+void for_each(const T& tuple, C&& closure)
+{
+ using Iter = internal::Iterator<std::tuple_size<T>::value, T, C>;
+ Iter iter(tuple, std::forward<C>(closure));
+}
+
+} // namspace tuple-hepler
+} // namspace qxx