~singpolyma/biboumi

ref: 9defd0ccb75b1905c308ed0437e5ccd479e3a7b8 biboumi/src/database/insert_query.hpp -rw-r--r-- 3.6 KiB
9defd0cc — louiz’ Add a Statement class to manage the sqlite3_stmt objects and avoid leaks 5 years ago
                                                                                
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc louiz’
50cadf3d louiz’
9defd0cc 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
129
#pragma once

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

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

#include <sqlite3.h>

template <int N, typename ColumnType, typename... T>
typename std::enable_if<!std::is_same<std::decay_t<ColumnType>, Id>::value, void>::type
actual_bind(Statement& statement, std::vector<std::string>& params, const std::tuple<T...>&)
{
  const auto value = params.front();
  params.erase(params.begin());
  if (sqlite3_bind_text(statement.get(), N + 1, value.data(), static_cast<int>(value.size()), SQLITE_TRANSIENT) != SQLITE_OK)
    log_error("Failed to bind ", value, " to param ", N);
  else
    log_debug("Bound (not id) [", value, "] to ", N);
}

template <int N, typename ColumnType, typename... T>
typename std::enable_if<std::is_same<std::decay_t<ColumnType>, Id>::value, void>::type
actual_bind(Statement& statement, std::vector<std::string>&, const std::tuple<T...>& columns)
{
  auto&& column = std::get<Id>(columns);
  if (column.value != 0)
    {
      if (sqlite3_bind_int64(statement.get(), N + 1, column.value) != SQLITE_OK)
        log_error("Failed to bind ", column.value, " to id.");
    }
  else if (sqlite3_bind_null(statement.get(), N + 1) != SQLITE_OK)
    log_error("Failed to bind NULL to param ", N);
  else
    log_debug("Bound NULL to ", N);
}

struct InsertQuery: public Query
{
  InsertQuery(const std::string& name):
      Query("INSERT OR REPLACE INTO ")
  {
    this->body += name;
  }

  template <typename... T>
  void execute(const std::tuple<T...>& columns, sqlite3* db)
  {
    auto statement = this->prepare(db);
    {
      this->bind_param<0>(columns, statement);
      if (sqlite3_step(statement.get()) != SQLITE_DONE)
        log_error("Failed to execute query: ", sqlite3_errmsg(db));
    }
  }

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

    actual_bind<N, ColumnType>(statement, this->params, columns);
    this->bind_param<N+1>(columns, statement);
  }

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

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

  template <int N, typename... T>
  typename std::enable_if<N < sizeof...(T), void>::type
  insert_value(const std::tuple<T...>& columns)
  {
    this->body += "?";
    if (N != sizeof...(T) - 1)
      this->body += ",";
    this->body += " ";
    add_param(*this, std::get<N>(columns));
    this->insert_value<N+1>(columns);
  }
  template <int N, typename... T>
  typename std::enable_if<N == sizeof...(T), void>::type
  insert_value(const std::tuple<T...>&)
  { }

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

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

    this->body += value.name;

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

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


 private:
};