select_query.hpp 3.35 KB
Newer Older
1 2
#pragma once

louiz’'s avatar
louiz’ committed
3 4
#include <database/engine.hpp>

5 6
#include <database/table.hpp>
#include <database/database.hpp>
7
#include <database/statement.hpp>
8
#include <database/query.hpp>
9
#include <logger/logger.hpp>
10 11
#include <database/row.hpp>

12 13
#include <utils/optional_bool.hpp>

14 15 16 17 18 19
#include <vector>
#include <string>

using namespace std::string_literals;

template <typename T>
20 21
typename std::enable_if<std::is_integral<T>::value, std::int64_t>::type
extract_row_value(Statement& statement, const int i)
22
{
23 24 25 26 27 28 29 30 31 32 33
  return statement.get_column_int64(i);
}

template <typename T>
typename std::enable_if<std::is_same<std::string, T>::value, T>::type
extract_row_value(Statement& statement, const int i)
{
  return statement.get_column_text(i);
}

template <typename T>
34
typename std::enable_if<std::is_same<OptionalBool, T>::value, T>::type
35 36 37
extract_row_value(Statement& statement, const int i)
{
  const auto integer = statement.get_column_int(i);
38
  OptionalBool result;
39
  if (integer > 0)
40
    result.set_value(true);
41
  else if (integer < 0)
42 43
    result.set_value(false);
  return result;
44 45
}

46
template <std::size_t N=0, typename... T>
47 48
typename std::enable_if<N < sizeof...(T), void>::type
extract_row_values(Row<T...>& row, Statement& statement)
49
{
50
  using ColumnType = typename std::remove_reference<decltype(std::get<N>(row.columns))>::type;
51

52 53
  auto&& column = std::get<N>(row.columns);
  column.value = static_cast<decltype(column.value)>(extract_row_value<typename ColumnType::real_type>(statement, N));
54

55
  extract_row_values<N+1>(row, statement);
56 57
}

58 59 60 61 62
template <std::size_t N=0, typename... T>
typename std::enable_if<N == sizeof...(T), void>::type
extract_row_values(Row<T...>&, Statement&)
{}

63 64 65 66 67 68 69
template <typename... T>
struct SelectQuery: public Query
{
    SelectQuery(std::string table_name):
        Query("SELECT"),
        table_name(table_name)
    {
70
      this->insert_col_name();
71 72 73
      this->body += " from " + this->table_name;
    }

74
    template <std::size_t N=0>
75 76
    typename std::enable_if<N < sizeof...(T), void>::type
    insert_col_name()
77
    {
78 79
      using ColumnsType = std::tuple<T...>;
      using ColumnType = typename std::remove_reference<decltype(std::get<N>(std::declval<ColumnsType>()))>::type;
80

81
      this->body += " " + std::string{ColumnType::name};
82

83 84
      if (N < (sizeof...(T) - 1))
        this->body += ", ";
85

86
      this->insert_col_name<N+1>();
87
    }
88 89 90 91
    template <std::size_t N=0>
    typename std::enable_if<N == sizeof...(T), void>::type
    insert_col_name()
    {}
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

  SelectQuery& where()
    {
      this->body += " WHERE ";
      return *this;
    };

    SelectQuery& order_by()
    {
      this->body += " ORDER BY ";
      return *this;
    }

    SelectQuery& limit()
    {
      this->body += " LIMIT ";
      return *this;
    }

louiz’'s avatar
louiz’ committed
111
    auto execute(DatabaseEngine& db)
112 113
    {
      std::vector<Row<T...>> rows;
louiz’'s avatar
louiz’ committed
114

115 116 117 118
#ifdef DEBUG_SQL_QUERIES
      const auto timer = this->log_and_time();
#endif

louiz’'s avatar
louiz’ committed
119
      auto statement = db.prepare(this->body);
120 121
      if (!statement)
        return rows;
louiz’'s avatar
louiz’ committed
122 123 124
      statement->bind(std::move(this->params));

      while (statement->step() == StepResult::Row)
125 126
        {
          Row<T...> row(this->table_name);
louiz’'s avatar
louiz’ committed
127
          extract_row_values(row, *statement);
128 129
          rows.push_back(row);
        }
louiz’'s avatar
louiz’ committed
130

131 132 133 134 135 136
      return rows;
    }

    const std::string table_name;
};

137 138 139 140 141 142
template <typename... T>
auto select(const Table<T...> table)
{
  SelectQuery<T...> query(table.name);
  return query;
}