~singpolyma/biboumi

ref: ba61d2034058818fe76cef6b23f311259d37b3fe biboumi/src/database/insert_query.hpp -rw-r--r-- 3.9 KiB
ba61d203 — louiz’ Empty the <command/> nodes before reusing them in our responses 5 years ago
                                                                                
50cadf3d louiz’
9defd0cc louiz’
4bd7b698 louiz’
50cadf3d louiz’
4bd7b698 louiz’
50cadf3d louiz’
4bd7b698 louiz’
50cadf3d louiz’
0168b96b louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
0168b96b louiz’
50cadf3d louiz’
7e64a2e3 louiz’
0168b96b louiz’
50cadf3d louiz’
5834dd53 louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
0168b96b louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
50cadf3d louiz’
61de6b1d louiz’
5834dd53 louiz’
50cadf3d louiz’
5834dd53 louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
0168b96b louiz’
d0e3c71b louiz’
0168b96b louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
50cadf3d louiz’
5834dd53 louiz’
0168b96b louiz’
50cadf3d louiz’
5834dd53 louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
50cadf3d louiz’
d0e3c71b louiz’
0168b96b louiz’
d0e3c71b louiz’
d62ca9f8 louiz’
d0e3c71b louiz’
d62ca9f8 louiz’
d0e3c71b louiz’
50cadf3d louiz’
4bd7b698 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#pragma once

#include <database/statement.hpp>
#include <database/database.hpp>
#include <database/column.hpp>
#include <database/query.hpp>
#include <database/row.hpp>

#include <logger/logger.hpp>

#include <utils/is_one_of.hpp>

#include <type_traits>
#include <vector>
#include <string>
#include <tuple>

template <std::size_t N=0, typename... T>
typename std::enable_if<N < sizeof...(T), void>::type
update_autoincrement_id(std::tuple<T...>& columns, Statement& statement)
{
  using ColumnType = typename std::decay<decltype(std::get<N>(columns))>::type;
  if (std::is_same<ColumnType, Id>::value)
    auto&& column = std::get<Id>(columns);
  update_autoincrement_id<N+1>(columns, statement);
}

template <std::size_t N=0, typename... T>
typename std::enable_if<N == sizeof...(T), void>::type
update_autoincrement_id(std::tuple<T...>&, Statement&)
{}

struct InsertQuery: public Query
{
  template <typename... T>
  InsertQuery(const std::string& name, const std::tuple<T...>& columns):
      Query("INSERT INTO ")
  {
    this->body += name;
    this->insert_col_names(columns);
    this->insert_values(columns);
  }

  template <typename... T>
  void execute(DatabaseEngine& db, std::tuple<T...>& columns)
  {
#ifdef DEBUG_SQL_QUERIES
    const auto timer = this->log_and_time();
#endif

    auto statement = db.prepare(this->body);
    this->bind_param(columns, *statement);

    if (statement->step() != StepResult::Error)
      db.extract_last_insert_rowid(*statement);
    else
      log_error("Failed to extract the rowid from the last INSERT");
  }

  template <int N=0, typename... T>
  typename std::enable_if<N < sizeof...(T), void>::type
  bind_param(const std::tuple<T...>& columns, Statement& statement, int index=1)
  {
    auto&& column = std::get<N>(columns);
    using ColumnType = std::decay_t<decltype(column)>;

    if (!std::is_same<ColumnType, Id>::value)
      actual_bind(statement, column.value, index++);

    this->bind_param<N+1>(columns, statement, index);
  }

  template <int N=0, typename... T>
  typename std::enable_if<N == sizeof...(T), void>::type
  bind_param(const std::tuple<T...>&, Statement&, int)
  {}

  template <typename... T>
  void insert_values(const std::tuple<T...>& columns)
  {
    this->body += "VALUES (";
    this->insert_value(columns);
    this->body += ")";
  }

  template <int N=0, typename... T>
  typename std::enable_if<N < sizeof...(T), void>::type
  insert_value(const std::tuple<T...>& columns, int index=1)
  {
    using ColumnType = std::decay_t<decltype(std::get<N>(columns))>;

    if (!std::is_same<ColumnType, Id>::value)
      {
        this->body += "$" + std::to_string(index++);
        if (N != sizeof...(T) - 1)
          this->body += ", ";
      }
    this->insert_value<N+1>(columns, index);
  }
  template <int N=0, typename... T>
  typename std::enable_if<N == sizeof...(T), void>::type
  insert_value(const std::tuple<T...>&, const int)
  { }

  template <typename... T>
  void insert_col_names(const std::tuple<T...>& columns)
  {
    this->body += " (";
    this->insert_col_name(columns);
    this->body += ")";
  }

  template <int N=0, typename... T>
  typename std::enable_if<N < sizeof...(T), void>::type
  insert_col_name(const std::tuple<T...>& columns)
  {
    using ColumnType = std::decay_t<decltype(std::get<N>(columns))>;

    if (!std::is_same<ColumnType, Id>::value)
      {
        this->body += ColumnType::name;

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

    this->insert_col_name<N+1>(columns);
  }

  template <int N=0, typename... T>
  typename std::enable_if<N == sizeof...(T), void>::type
  insert_col_name(const std::tuple<T...>&)
  {}
};

template <typename... T>
void insert(Row<T...>& row, DatabaseEngine& db)
{
  InsertQuery query(row.table_name, row.columns);
  // Ugly workaround for non portable stuff
  if (is_one_of<Id, T...>)
    query.body += db.get_returning_id_sql_string(Id::name);
  query.execute(db, row.columns);
}