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/select_query.hpp | 153 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/database/select_query.hpp (limited to 'src/database/select_query.hpp') diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp new file mode 100644 index 0000000..b41632e --- /dev/null +++ b/src/database/select_query.hpp @@ -0,0 +1,153 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include + +using namespace std::string_literals; + +template +typename std::enable_if::value, sqlite3_int64>::type +extract_row_value(sqlite3_stmt* statement, const int i) +{ + return sqlite3_column_int64(statement, i); +} + +template +typename std::enable_if::value, std::string>::type +extract_row_value(sqlite3_stmt* statement, const int i) +{ + const auto size = sqlite3_column_bytes(statement, i); + const unsigned char* str = sqlite3_column_text(statement, i); + std::string result(reinterpret_cast(str), size); + return result; +} + +template +typename std::enable_if::type +extract_row_values(Row& row, sqlite3_stmt* statement) +{ + using ColumnType = typename std::remove_reference(row.columns))>::type; + + auto&& column = std::get(row.columns); + column.value = static_cast(extract_row_value(statement, N)); + + extract_row_values(row, statement); +} + +template +typename std::enable_if::type +extract_row_values(Row&, sqlite3_stmt*) +{} + +template +struct SelectQuery: public Query +{ + SelectQuery(std::string table_name): + Query("SELECT"), + table_name(table_name) + { + this->insert_col_name<0>(); + this->body += " from " + this->table_name; + } + + template + typename std::enable_if::type + insert_col_name() + { + using ColumnsType = std::tuple; + ColumnsType tuple{}; + auto value = std::get(tuple); + + this->body += " "s + value.name; + + if (N < (sizeof...(T) - 1)) + this->body += ", "; + + this->insert_col_name(); + } + template + typename std::enable_if::type + insert_col_name() + {} + + SelectQuery& where() + { + this->body += " WHERE "; + return *this; + }; + + SelectQuery& order_by() + { + this->body += " ORDER BY "; + return *this; + } + + SelectQuery& limit() + { + this->body += " LIMIT "; + return *this; + } + + auto execute(sqlite3* db) + { + auto statement = this->prepare(db); + int i = 1; + for (const std::string& param: this->params) + { + if (sqlite3_bind_text(statement, i, param.data(), static_cast(param.size()), SQLITE_TRANSIENT) != SQLITE_OK) + log_debug("Failed to bind ", param, " to param ", i); + else + log_debug("Bound ", param, " to ", i); + + i++; + } + std::vector> rows; + while (sqlite3_step(statement) == SQLITE_ROW) + { + Row row(this->table_name); + extract_row_values(row, statement); + rows.push_back(row); + } + return rows; + } + + const std::string table_name; +}; + +template +typename std::enable_if::value, SelectQuery&>::type +operator<<(SelectQuery& query, const T&) +{ + query.body += T::name; + return query; +} + +template +SelectQuery& operator<<(SelectQuery& query, const char* str) +{ + query.body += str; + return query; +} + +template +SelectQuery& operator<<(SelectQuery& query, const std::string& str) +{ + query.body += "?"; + actual_add_param(query, str); + return query; +} + +template +typename std::enable_if::value, SelectQuery&>::type +operator<<(SelectQuery& query, const Integer& i) +{ + query.body += "?"; + actual_add_param(query, i); + return query; +} -- 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/select_query.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/database/select_query.hpp') diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index b41632e..80d1424 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,24 +14,24 @@ using namespace std::string_literals; template typename std::enable_if::value, sqlite3_int64>::type -extract_row_value(sqlite3_stmt* statement, const int i) +extract_row_value(Statement& statement, const int i) { - return sqlite3_column_int64(statement, i); + return sqlite3_column_int64(statement.get(), i); } template typename std::enable_if::value, std::string>::type -extract_row_value(sqlite3_stmt* statement, const int i) +extract_row_value(Statement& statement, const int i) { - const auto size = sqlite3_column_bytes(statement, i); - const unsigned char* str = sqlite3_column_text(statement, i); + const auto size = sqlite3_column_bytes(statement.get(), i); + const unsigned char* str = sqlite3_column_text(statement.get(), i); std::string result(reinterpret_cast(str), size); return result; } template typename std::enable_if::type -extract_row_values(Row& row, sqlite3_stmt* statement) +extract_row_values(Row& row, Statement& statement) { using ColumnType = typename std::remove_reference(row.columns))>::type; @@ -42,7 +43,7 @@ extract_row_values(Row& row, sqlite3_stmt* statement) template typename std::enable_if::type -extract_row_values(Row&, sqlite3_stmt*) +extract_row_values(Row&, Statement&) {} template @@ -100,7 +101,7 @@ struct SelectQuery: public Query int i = 1; for (const std::string& param: this->params) { - if (sqlite3_bind_text(statement, i, param.data(), static_cast(param.size()), SQLITE_TRANSIENT) != SQLITE_OK) + if (sqlite3_bind_text(statement.get(), i, param.data(), static_cast(param.size()), SQLITE_TRANSIENT) != SQLITE_OK) log_debug("Failed to bind ", param, " to param ", i); else log_debug("Bound ", param, " to ", i); @@ -108,7 +109,7 @@ struct SelectQuery: public Query i++; } std::vector> rows; - while (sqlite3_step(statement) == SQLITE_ROW) + while (sqlite3_step(statement.get()) == SQLITE_ROW) { Row row(this->table_name); extract_row_values(row, statement); -- 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/select_query.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/database/select_query.hpp') diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 80d1424..d0c1d59 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -25,7 +25,7 @@ extract_row_value(Statement& statement, const int i) { const auto size = sqlite3_column_bytes(statement.get(), i); const unsigned char* str = sqlite3_column_text(statement.get(), i); - std::string result(reinterpret_cast(str), size); + std::string result(reinterpret_cast(str), static_cast(size)); return result; } @@ -62,10 +62,9 @@ struct SelectQuery: public Query insert_col_name() { using ColumnsType = std::tuple; - ColumnsType tuple{}; - auto value = std::get(tuple); + using ColumnType = typename std::remove_reference(std::declval()))>::type; - this->body += " "s + value.name; + this->body += " "s + ColumnType::name; if (N < (sizeof...(T) - 1)) this->body += ", "; -- cgit v1.2.3