From 50cadf3dac0d56ef8181d1800cc30f8dcb749141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Jun 2017 10:38:39 +0200 Subject: Implement our own database ORM, and update the whole code to use it Entirely replace LiteSQL fix #3271 --- src/database/insert_query.hpp | 128 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/database/insert_query.hpp (limited to 'src/database/insert_query.hpp') diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp new file mode 100644 index 0000000..00b77c5 --- /dev/null +++ b/src/database/insert_query.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include + +template +typename std::enable_if, Id>::value, void>::type +actual_bind(sqlite3_stmt* statement, std::vector& params, const std::tuple&) +{ + const auto value = params.front(); + params.erase(params.begin()); + if (sqlite3_bind_text(statement, N + 1, value.data(), static_cast(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 +typename std::enable_if, Id>::value, void>::type +actual_bind(sqlite3_stmt* statement, std::vector&, const std::tuple& columns) +{ + auto&& column = std::get(columns); + if (column.value != 0) + { + if (sqlite3_bind_int64(statement, N + 1, column.value) != SQLITE_OK) + log_error("Failed to bind ", column.value, " to id."); + } + else if (sqlite3_bind_null(statement, 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 + void execute(const std::tuple& columns, sqlite3* db) + { + auto statement = this->prepare(db); + { + this->bind_param<0>(columns, statement); + if (sqlite3_step(statement) != SQLITE_DONE) + log_error("Failed to execute query: ", sqlite3_errmsg(db)); + } + } + + template + typename std::enable_if::type + bind_param(const std::tuple& columns, sqlite3_stmt* statement) + { + using ColumnType = typename std::remove_reference(columns))>::type; + + actual_bind(statement, this->params, columns); + this->bind_param(columns, statement); + } + + template + typename std::enable_if::type + bind_param(const std::tuple&, sqlite3_stmt*) + {} + + template + void insert_values(const std::tuple& columns) + { + this->body += "VALUES ("; + this->insert_value<0>(columns); + this->body += ")"; + } + + template + typename std::enable_if::type + insert_value(const std::tuple& columns) + { + this->body += "?"; + if (N != sizeof...(T) - 1) + this->body += ","; + this->body += " "; + add_param(*this, std::get(columns)); + this->insert_value(columns); + } + template + typename std::enable_if::type + insert_value(const std::tuple&) + { } + + template + void insert_col_names(const std::tuple& columns) + { + this->body += " ("; + this->insert_col_name<0>(columns); + this->body += ")\n"; + } + + template + typename std::enable_if::type + insert_col_name(const std::tuple& columns) + { + auto value = std::get(columns); + + this->body += value.name; + + if (N < (sizeof...(T) - 1)) + this->body += ", "; + + this->insert_col_name(columns); + } + template + typename std::enable_if::type + insert_col_name(const std::tuple&) + {} + + + private: +}; -- cgit v1.2.3 From 9defd0ccb75b1905c308ed0437e5ccd479e3a7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 00:04:00 +0200 Subject: Add a Statement class to manage the sqlite3_stmt objects and avoid leaks --- src/database/insert_query.hpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/database/insert_query.hpp') diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 00b77c5..1712916 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,11 +14,11 @@ template typename std::enable_if, Id>::value, void>::type -actual_bind(sqlite3_stmt* statement, std::vector& params, const std::tuple&) +actual_bind(Statement& statement, std::vector& params, const std::tuple&) { const auto value = params.front(); params.erase(params.begin()); - if (sqlite3_bind_text(statement, N + 1, value.data(), static_cast(value.size()), SQLITE_TRANSIENT) != SQLITE_OK) + if (sqlite3_bind_text(statement.get(), N + 1, value.data(), static_cast(value.size()), SQLITE_TRANSIENT) != SQLITE_OK) log_error("Failed to bind ", value, " to param ", N); else log_debug("Bound (not id) [", value, "] to ", N); @@ -25,15 +26,15 @@ actual_bind(sqlite3_stmt* statement, std::vector& params, const std template typename std::enable_if, Id>::value, void>::type -actual_bind(sqlite3_stmt* statement, std::vector&, const std::tuple& columns) +actual_bind(Statement& statement, std::vector&, const std::tuple& columns) { auto&& column = std::get(columns); if (column.value != 0) { - if (sqlite3_bind_int64(statement, N + 1, column.value) != SQLITE_OK) + 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, N + 1) != SQLITE_OK) + 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); @@ -53,14 +54,14 @@ struct InsertQuery: public Query auto statement = this->prepare(db); { this->bind_param<0>(columns, statement); - if (sqlite3_step(statement) != SQLITE_DONE) + if (sqlite3_step(statement.get()) != SQLITE_DONE) log_error("Failed to execute query: ", sqlite3_errmsg(db)); } } template typename std::enable_if::type - bind_param(const std::tuple& columns, sqlite3_stmt* statement) + bind_param(const std::tuple& columns, Statement& statement) { using ColumnType = typename std::remove_reference(columns))>::type; @@ -70,7 +71,7 @@ struct InsertQuery: public Query template typename std::enable_if::type - bind_param(const std::tuple&, sqlite3_stmt*) + bind_param(const std::tuple&, Statement&) {} template -- cgit v1.2.3 From 2677ac42e8d2e1cf162fec773a9acb453bef8b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 10:31:45 +0200 Subject: Fix compilation (many warnings, and a linkage error) with clang++ --- src/database/insert_query.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/database/insert_query.hpp') diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 1712916..4965fc0 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -31,7 +31,7 @@ actual_bind(Statement& statement, std::vector&, const std::tuple(columns); if (column.value != 0) { - if (sqlite3_bind_int64(statement.get(), N + 1, column.value) != SQLITE_OK) + if (sqlite3_bind_int64(statement.get(), N + 1, static_cast(column.value)) != SQLITE_OK) log_error("Failed to bind ", column.value, " to id."); } else if (sqlite3_bind_null(statement.get(), N + 1) != SQLITE_OK) @@ -110,9 +110,9 @@ struct InsertQuery: public Query typename std::enable_if::type insert_col_name(const std::tuple& columns) { - auto value = std::get(columns); + using ColumnType = typename std::remove_reference(columns))>::type; - this->body += value.name; + this->body += ColumnType::name; if (N < (sizeof...(T) - 1)) this->body += ", "; -- cgit v1.2.3