~singpolyma/biboumi

ref: 3cd649023680bd49f9865fd62474d4db6a9d7c68 biboumi/src/database/table.hpp -rw-r--r-- 3.2 KiB
3cd64902 — louiz’ Remove all the ugly database debug 5 years ago
                                                                                
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
4a963cc4 louiz’
0168b96b louiz’
4a963cc4 louiz’
0168b96b louiz’
4a963cc4 louiz’
0168b96b louiz’
4a963cc4 louiz’
50cadf3d louiz’
cf56b60f louiz’
3974371e louiz’
cf56b60f louiz’
50cadf3d louiz’
0168b96b louiz’
4a963cc4 louiz’
0168b96b louiz’
4a963cc4 louiz’
0168b96b louiz’
50cadf3d louiz’
0168b96b louiz’
3cd64902 louiz’
0168b96b louiz’
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
4a963cc4 louiz’
0168b96b louiz’
4a963cc4 louiz’
0168b96b louiz’
4a963cc4 louiz’
0168b96b louiz’
4a963cc4 louiz’
5834dd53 louiz’
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
3cd64902 louiz’
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
5834dd53 louiz’
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#pragma once

#include <database/engine.hpp>

#include <database/select_query.hpp>
#include <database/row.hpp>

#include <algorithm>
#include <string>
#include <set>

using namespace std::string_literals;

template <typename T>
std::string ToSQLType(DatabaseEngine& db)
{
  if (std::is_same<T, Id>::value)
    return db.id_column_type();
  else if (std::is_same<typename T::real_type, std::string>::value)
    return "TEXT";
  else
    return "INTEGER";
}

template <typename ColumnType>
void add_column_to_table(DatabaseEngine& db, const std::string& table_name)
{
  const std::string name = ColumnType::name;
  std::string query{"ALTER TABLE " + table_name + " ADD " + ColumnType::name + " " + ToSQLType<ColumnType>(db)};
  auto res = db.raw_exec(query);
  if (std::get<0>(res) == false)
    log_error("Error adding column ", name, " to table ", table_name, ": ",  std::get<1>(res));
}

template <typename ColumnType, decltype(ColumnType::options) = nullptr>
void append_option(std::string& s)
{
  s += " "s + ColumnType::options;
}

template <typename, typename... Args>
void append_option(Args&& ...)
{ }

template <typename... T>
class Table
{
  static_assert(sizeof...(T) > 0, "Table cannot be empty");
  using ColumnTypes = std::tuple<T...>;

 public:
  using RowType = Row<T...>;

  Table(std::string name):
      name(std::move(name))
  {}

  void upgrade(DatabaseEngine& db)
  {
    const auto existing_columns = db.get_all_columns_from_table(this->name);
    add_column_if_not_exists(db, existing_columns);
  }

  void create(DatabaseEngine& db)
  {
    std::string query{"CREATE TABLE IF NOT EXISTS "};
    query += this->name;
    query += " (";
    this->add_column_create(db, query);
    query += ")";

    auto result = db.raw_exec(query);
    if (std::get<0>(result) == false)
      log_error("Error executing query: ", std::get<1>(result));
  }

  RowType row()
  {
    return {this->name};
  }

  auto select()
  {
    SelectQuery<T...> select(this->name);
    return select;
  }

  const std::string& get_name() const
  {
    return this->name;
  }

 private:

  template <std::size_t N=0>
  typename std::enable_if<N < sizeof...(T), void>::type
  add_column_if_not_exists(DatabaseEngine& db, const std::set<std::string>& existing_columns)
  {
    using ColumnType = typename std::remove_reference<decltype(std::get<N>(std::declval<ColumnTypes>()))>::type;
    if (existing_columns.count(ColumnType::name) == 0)
      add_column_to_table<ColumnType>(db, this->name);
    add_column_if_not_exists<N+1>(db, existing_columns);
  }
  template <std::size_t N=0>
  typename std::enable_if<N == sizeof...(T), void>::type
  add_column_if_not_exists(DatabaseEngine&, const std::set<std::string>&)
  {}

  template <std::size_t N=0>
  typename std::enable_if<N < sizeof...(T), void>::type
  add_column_create(DatabaseEngine& db, std::string& str)
  {
    using ColumnType = typename std::remove_reference<decltype(std::get<N>(std::declval<ColumnTypes>()))>::type;
    str += ColumnType::name;
    str += " ";
    str += ToSQLType<ColumnType>(db);
    if (N != sizeof...(T) - 1)
      str += ",";

    add_column_create<N+1>(db, str);
  }
  template <std::size_t N=0>
  typename std::enable_if<N == sizeof...(T), void>::type
  add_column_create(DatabaseEngine&, std::string&)
  { }

  const std::string name;
};