summaryrefslogtreecommitdiff
path: root/src/database/update_query.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/database/update_query.hpp')
-rw-r--r--src/database/update_query.hpp100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/database/update_query.hpp b/src/database/update_query.hpp
new file mode 100644
index 0000000..32befc0
--- /dev/null
+++ b/src/database/update_query.hpp
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <database/query.hpp>
+#include <database/engine.hpp>
+
+using namespace std::string_literals;
+
+template <class T, class... Tuple>
+struct Index;
+
+template <class T, class... Types>
+struct Index<T, std::tuple<T, Types...>>
+{
+ static const std::size_t value = 0;
+};
+
+template <class T, class U, class... Types>
+struct Index<T, std::tuple<U, Types...>>
+{
+ static const std::size_t value = Index<T, std::tuple<Types...>>::value + 1;
+};
+
+struct UpdateQuery: public Query
+{
+ template <typename... T>
+ UpdateQuery(const std::string& name, const std::tuple<T...>& columns):
+ Query("UPDATE ")
+ {
+ this->body += name;
+ this->insert_col_names_and_values(columns);
+ }
+
+ template <typename... T>
+ void insert_col_names_and_values(const std::tuple<T...>& columns)
+ {
+ this->body += " SET ";
+ this->insert_col_name_and_value(columns);
+ this->body += " WHERE "s + Id::name + "=$" + std::to_string(this->current_param);
+ }
+
+ template <int N=0, typename... T>
+ typename std::enable_if<N < sizeof...(T), void>::type
+ insert_col_name_and_value(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 + "=$"s + std::to_string(this->current_param);
+ this->current_param++;
+
+ if (N < (sizeof...(T) - 1))
+ this->body += ", ";
+ }
+
+ this->insert_col_name_and_value<N+1>(columns);
+ }
+ template <int N=0, typename... T>
+ typename std::enable_if<N == sizeof...(T), void>::type
+ insert_col_name_and_value(const std::tuple<T...>&)
+ {}
+
+
+ template <typename... T>
+ void execute(DatabaseEngine& db, const std::tuple<T...>& columns)
+ {
+ auto statement = db.prepare(this->body);
+ this->bind_param(columns, *statement);
+ this->bind_id(columns, *statement);
+
+ statement->step();
+ }
+
+ 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 bind_id(const std::tuple<T...>& columns, Statement& statement)
+ {
+ static constexpr auto index = Index<Id, std::tuple<T...>>::value;
+ auto&& value = std::get<index>(columns);
+
+ actual_bind(statement, value.value, sizeof...(T));
+ }
+};