diff options
Diffstat (limited to 'src/database')
-rw-r--r-- | src/database/column.hpp | 6 | ||||
-rw-r--r-- | src/database/database.cpp | 160 | ||||
-rw-r--r-- | src/database/database.hpp | 37 | ||||
-rw-r--r-- | src/database/delete_query.hpp | 33 | ||||
-rw-r--r-- | src/database/insert_query.hpp | 17 | ||||
-rw-r--r-- | src/database/postgresql_engine.cpp | 13 | ||||
-rw-r--r-- | src/database/postgresql_engine.hpp | 3 | ||||
-rw-r--r-- | src/database/postgresql_statement.hpp | 20 | ||||
-rw-r--r-- | src/database/query.cpp | 3 | ||||
-rw-r--r-- | src/database/query.hpp | 7 | ||||
-rw-r--r-- | src/database/row.hpp | 40 | ||||
-rw-r--r-- | src/database/save.hpp | 31 | ||||
-rw-r--r-- | src/database/select_query.hpp | 10 | ||||
-rw-r--r-- | src/database/sqlite3_engine.cpp | 1 | ||||
-rw-r--r-- | src/database/sqlite3_engine.hpp | 3 | ||||
-rw-r--r-- | src/database/sqlite3_statement.hpp | 1 | ||||
-rw-r--r-- | src/database/table.hpp | 11 | ||||
-rw-r--r-- | src/database/update_query.hpp | 11 |
18 files changed, 312 insertions, 95 deletions
diff --git a/src/database/column.hpp b/src/database/column.hpp index 1f16bcf..50c9c14 100644 --- a/src/database/column.hpp +++ b/src/database/column.hpp @@ -13,10 +13,14 @@ struct Column T value{}; }; +struct ForeignKey: Column<std::size_t> { + static constexpr auto name = "fk_"; +}; + struct Id: Column<std::size_t> { static constexpr std::size_t unset_value = static_cast<std::size_t>(-1); static constexpr auto name = "id_"; static constexpr auto options = "PRIMARY KEY"; - Id(): Column<std::size_t>(-1) {} + Id(): Column<std::size_t>(unset_value) {} }; diff --git a/src/database/database.cpp b/src/database/database.cpp index 3622963..3b3e890 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -1,10 +1,12 @@ #include "biboumi.h" #ifdef USE_DATABASE +#include <database/select_query.hpp> +#include <database/save.hpp> #include <database/database.hpp> -#include <uuid/uuid.h> #include <utils/get_first_non_empty.hpp> #include <utils/time.hpp> +#include <utils/uuid.hpp> #include <config/config.hpp> #include <database/sqlite3_engine.hpp> @@ -21,6 +23,7 @@ Database::GlobalOptionsTable Database::global_options("globaloptions_"); Database::IrcServerOptionsTable Database::irc_server_options("ircserveroptions_"); Database::IrcChannelOptionsTable Database::irc_channel_options("ircchanneloptions_"); Database::RosterTable Database::roster("roster"); +Database::AfterConnectionCommandsTable Database::after_connection_commands("after_connection_commands_"); std::map<Database::CacheKey, Database::EncodingIn::real_type> Database::encoding_in_cache{}; Database::GlobalPersistent::GlobalPersistent(): @@ -53,57 +56,80 @@ void Database::open(const std::string& filename) Database::irc_channel_options.upgrade(*Database::db); Database::roster.create(*Database::db); Database::roster.upgrade(*Database::db); + Database::after_connection_commands.create(*Database::db); + Database::after_connection_commands.upgrade(*Database::db); create_index<Database::Owner, Database::IrcChanName, Database::IrcServerName>(*Database::db, "archive_index", Database::muc_log_lines.get_name()); } Database::GlobalOptions Database::get_global_options(const std::string& owner) { - auto request = Database::global_options.select(); + auto request = select(Database::global_options); request.where() << Owner{} << "=" << owner; - Database::GlobalOptions options{Database::global_options.get_name()}; auto result = request.execute(*Database::db); if (result.size() == 1) - options = result.front(); - else - options.col<Owner>() = owner; + return result.front(); + Database::GlobalOptions options{Database::global_options.get_name()}; + options.col<Owner>() = owner; return options; } Database::IrcServerOptions Database::get_irc_server_options(const std::string& owner, const std::string& server) { - auto request = Database::irc_server_options.select(); + auto request = select(Database::irc_server_options); request.where() << Owner{} << "=" << owner << " and " << Server{} << "=" << server; - Database::IrcServerOptions options{Database::irc_server_options.get_name()}; auto result = request.execute(*Database::db); if (result.size() == 1) - options = result.front(); - else + return result.front(); + Database::IrcServerOptions options{Database::irc_server_options.get_name()}; + options.col<Owner>() = owner; + options.col<Server>() = server; + return options; +} + +Database::AfterConnectionCommands Database::get_after_connection_commands(const IrcServerOptions& server_options) +{ + const auto id = server_options.col<Id>(); + if (id == Id::unset_value) + return {}; + auto request = select(Database::after_connection_commands); + request.where() << ForeignKey{} << "=" << id; + return request.execute(*Database::db); +} + +void Database::set_after_connection_commands(const Database::IrcServerOptions& server_options, Database::AfterConnectionCommands& commands) +{ + const auto id = server_options.col<Id>(); + if (id == Id::unset_value) + return ; + + Transaction transaction; + auto query = Database::after_connection_commands.del(); + query.where() << ForeignKey{} << "=" << id; + query.execute(*Database::db); + + for (auto& command: commands) { - options.col<Owner>() = owner; - options.col<Server>() = server; + command.col<ForeignKey>() = server_options.col<Id>(); + save(command, *Database::db); } - return options; } Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel) { - auto request = Database::irc_channel_options.select(); + auto request = select(Database::irc_channel_options); request.where() << Owner{} << "=" << owner <<\ " and " << Server{} << "=" << server <<\ " and " << Channel{} << "=" << channel; - Database::IrcChannelOptions options{Database::irc_channel_options.get_name()}; auto result = request.execute(*Database::db); if (result.size() == 1) - options = result.front(); - else - { - options.col<Owner>() = owner; - options.col<Server>() = server; - options.col<Channel>() = channel; - } + return result.front(); + Database::IrcChannelOptions options{Database::irc_channel_options.get_name()}; + options.col<Owner>() = owner; + options.col<Server>() = server; + options.col<Channel>() = channel; return options; } @@ -159,15 +185,18 @@ std::string Database::store_muc_message(const std::string& owner, const std::str line.col<Body>() = body; line.col<Nick>() = nick; - line.save(Database::db); + save(line, *Database::db); return uuid; } std::vector<Database::MucLogLine> Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start, const std::string& end) + int limit, const std::string& start, const std::string& end, const Id::real_type reference_record_id, Database::Paging paging) { - auto request = Database::muc_log_lines.select(); + if (limit == 0) + return {}; + + auto request = select(Database::muc_log_lines); request.where() << Database::Owner{} << "=" << owner << \ " and " << Database::IrcChanName{} << "=" << chan_name << \ " and " << Database::IrcServerName{} << "=" << server; @@ -184,15 +213,59 @@ std::vector<Database::MucLogLine> Database::get_muc_logs(const std::string& owne if (end_time != -1) request << " and " << Database::Date{} << "<=" << end_time; } + if (reference_record_id != Id::unset_value) + { + request << " and " << Id{}; + if (paging == Database::Paging::first) + request << ">"; + else + request << "<"; + request << reference_record_id; + } - request.order_by() << Id{} << " DESC "; + if (paging == Database::Paging::first) + request.order_by() << Id{} << " ASC "; + else + request.order_by() << Id{} << " DESC "; if (limit >= 0) request.limit() << limit; auto result = request.execute(*Database::db); - return {result.crbegin(), result.crend()}; + if (paging == Database::Paging::first) + return result; + else + return {result.crbegin(), result.crend()}; +} + +Database::MucLogLine Database::get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, + const std::string& uuid, const std::string& start, const std::string& end) +{ + auto request = select(Database::muc_log_lines); + request.where() << Database::Owner{} << "=" << owner << \ + " and " << Database::IrcChanName{} << "=" << chan_name << \ + " and " << Database::IrcServerName{} << "=" << server << \ + " and " << Database::Uuid{} << "=" << uuid; + + if (!start.empty()) + { + const auto start_time = utils::parse_datetime(start); + if (start_time != -1) + request << " and " << Database::Date{} << ">=" << start_time; + } + if (!end.empty()) + { + const auto end_time = utils::parse_datetime(end); + if (end_time != -1) + request << " and " << Database::Date{} << "<=" << end_time; + } + + auto result = request.execute(*Database::db); + + if (result.empty()) + throw Database::RecordNotFound{}; + return result.front(); } void Database::add_roster_item(const std::string& local, const std::string& remote) @@ -202,7 +275,7 @@ void Database::add_roster_item(const std::string& local, const std::string& remo roster_item.col<Database::LocalJid>() = local; roster_item.col<Database::RemoteJid>() = remote; - roster_item.save(Database::db); + save(roster_item, *Database::db); } void Database::delete_roster_item(const std::string& local, const std::string& remote) @@ -216,7 +289,7 @@ void Database::delete_roster_item(const std::string& local, const std::string& r bool Database::has_roster_item(const std::string& local, const std::string& remote) { - auto query = Database::roster.select(); + auto query = select(Database::roster); query.where() << Database::LocalJid{} << "=" << local << \ " and " << Database::RemoteJid{} << "=" << remote; @@ -227,7 +300,7 @@ bool Database::has_roster_item(const std::string& local, const std::string& remo std::vector<Database::RosterItem> Database::get_contact_list(const std::string& local) { - auto query = Database::roster.select(); + auto query = select(Database::roster); query.where() << Database::LocalJid{} << "=" << local; return query.execute(*Database::db); @@ -235,7 +308,7 @@ std::vector<Database::RosterItem> Database::get_contact_list(const std::string& std::vector<Database::RosterItem> Database::get_full_roster() { - auto query = Database::roster.select(); + auto query = select(Database::roster); return query.execute(*Database::db); } @@ -247,11 +320,26 @@ void Database::close() std::string Database::gen_uuid() { - char uuid_str[37]; - uuid_t uuid; - uuid_generate(uuid); - uuid_unparse(uuid, uuid_str); - return uuid_str; + return utils::gen_uuid(); +} + +Transaction::Transaction() +{ + const auto result = Database::raw_exec("BEGIN"); + if (std::get<bool>(result) == false) + log_error("Failed to create SQL transaction: ", std::get<std::string>(result)); + else + this->success = true; + } +Transaction::~Transaction() +{ + if (this->success) + { + const auto result = Database::raw_exec("END"); + if (std::get<bool>(result) == false) + log_error("Failed to end SQL transaction: ", std::get<std::string>(result)); + } +} #endif diff --git a/src/database/database.hpp b/src/database/database.hpp index ec44543..d986ecc 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -22,6 +22,8 @@ class Database { public: using time_point = std::chrono::system_clock::time_point; + struct RecordNotFound: public std::exception {}; + enum class Paging { first, last }; struct Uuid: Column<std::string> { static constexpr auto name = "uuid_"; }; @@ -82,6 +84,7 @@ class Database struct RemoteJid: Column<std::string> { static constexpr auto name = "remote"; }; + struct Address: Column<std::string> { static constexpr auto name = "address_"; }; using MucLogLineTable = Table<Id, Uuid, Owner, IrcChanName, IrcServerName, Date, Body, Nick>; using MucLogLine = MucLogLineTable::RowType; @@ -89,7 +92,7 @@ class Database using GlobalOptionsTable = Table<Id, Owner, MaxHistoryLength, RecordHistory, GlobalPersistent>; using GlobalOptions = GlobalOptionsTable::RowType; - using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, AfterConnectionCommand, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength>; + using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength, Address, Nick>; using IrcServerOptions = IrcServerOptionsTable::RowType; using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>; @@ -98,6 +101,9 @@ class Database using RosterTable = Table<LocalJid, RemoteJid>; using RosterItem = RosterTable::RowType; + using AfterConnectionCommandsTable = Table<Id, ForeignKey, AfterConnectionCommand>; + using AfterConnectionCommands = std::vector<AfterConnectionCommandsTable::RowType>; + Database() = default; ~Database() = default; @@ -118,8 +124,22 @@ class Database static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner, const std::string& server, const std::string& channel); + static AfterConnectionCommands get_after_connection_commands(const IrcServerOptions& server_options); + static void set_after_connection_commands(const IrcServerOptions& server_options, AfterConnectionCommands& commands); + + /** + * Get all the lines between (optional) start and end dates, with a (optional) limit. + * If after_id is set, only the records after it will be returned. + */ static std::vector<MucLogLine> get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit=-1, const std::string& start="", const std::string& end=""); + int limit=-1, const std::string& start="", const std::string& end="", + const Id::real_type reference_record_id=Id::unset_value, Paging=Paging::first); + + /** + * Get just one single record matching the given uuid, between (optional) end and start. + * If it does not exist (or is not between end and start), throw a RecordNotFound exception. + */ + static MucLogLine get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, const std::string& uuid, const std::string& start="", const std::string& end=""); static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, time_point date, const std::string& body, const std::string& nick); @@ -144,6 +164,8 @@ class Database static IrcServerOptionsTable irc_server_options; static IrcChannelOptionsTable irc_channel_options; static RosterTable roster; + static AfterConnectionCommandsTable after_connection_commands; + static std::unique_ptr<DatabaseEngine> db; /** @@ -181,11 +203,20 @@ class Database static auto raw_exec(const std::string& query) { - Database::db->raw_exec(query); + return Database::db->raw_exec(query); } private: static std::string gen_uuid(); static std::map<CacheKey, EncodingIn::real_type> encoding_in_cache; }; + +class Transaction +{ +public: + Transaction(); + ~Transaction(); + bool success{false}; +}; + #endif /* USE_DATABASE */ diff --git a/src/database/delete_query.hpp b/src/database/delete_query.hpp new file mode 100644 index 0000000..dce705b --- /dev/null +++ b/src/database/delete_query.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <database/query.hpp> +#include <database/engine.hpp> + +class DeleteQuery: public Query +{ +public: + DeleteQuery(const std::string& name): + Query("DELETE") + { + this->body += " from " + name; + } + + DeleteQuery& where() + { + this->body += " WHERE "; + return *this; + }; + + void execute(DatabaseEngine& db) + { + auto statement = db.prepare(this->body); + if (!statement) + return; +#ifdef DEBUG_SQL_QUERIES + const auto timer = this->log_and_time(); +#endif + statement->bind(std::move(this->params)); + if (statement->step() != StepResult::Done) + log_error("Failed to execute DELETE command"); + } +}; diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 9726424..230e873 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -1,10 +1,15 @@ #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> @@ -22,7 +27,7 @@ update_autoincrement_id(std::tuple<T...>& columns, Statement& 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& statement) +update_autoincrement_id(std::tuple<T...>&, Statement&) {} struct InsertQuery: public Query @@ -127,3 +132,13 @@ struct InsertQuery: public Query 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); +} diff --git a/src/database/postgresql_engine.cpp b/src/database/postgresql_engine.cpp index 984a959..59bc885 100644 --- a/src/database/postgresql_engine.cpp +++ b/src/database/postgresql_engine.cpp @@ -11,6 +11,8 @@ #include <logger/logger.hpp> +#include <cstring> + PostgresqlEngine::PostgresqlEngine(PGconn*const conn): conn(conn) {} @@ -20,6 +22,15 @@ PostgresqlEngine::~PostgresqlEngine() PQfinish(this->conn); } +static void logging_notice_processor(void*, const char* original) +{ + if (original && std::strlen(original) > 0) + { + std::string message{original, std::strlen(original) - 1}; + log_warning("PostgreSQL: ", message); + } +} + std::unique_ptr<DatabaseEngine> PostgresqlEngine::open(const std::string& conninfo) { PGconn* con = PQconnectdb(conninfo.data()); @@ -34,8 +45,10 @@ std::unique_ptr<DatabaseEngine> PostgresqlEngine::open(const std::string& connin { const char* errmsg = PQerrorMessage(con); log_error("Postgresql connection failed: ", errmsg); + PQfinish(con); throw std::runtime_error("failed to open connection."); } + PQsetNoticeProcessor(con, &logging_notice_processor, nullptr); return std::make_unique<PostgresqlEngine>(con); } diff --git a/src/database/postgresql_engine.hpp b/src/database/postgresql_engine.hpp index fe4fb53..1a9c249 100644 --- a/src/database/postgresql_engine.hpp +++ b/src/database/postgresql_engine.hpp @@ -36,12 +36,15 @@ private: #else +using namespace std::string_literals; + class PostgresqlEngine { public: static std::unique_ptr<DatabaseEngine> open(const std::string& string) { throw std::runtime_error("Cannot open postgresql database "s + string + ": biboumi is not compiled with libpq."); + return {}; } }; diff --git a/src/database/postgresql_statement.hpp b/src/database/postgresql_statement.hpp index 571c8f1..37e8ea0 100644 --- a/src/database/postgresql_statement.hpp +++ b/src/database/postgresql_statement.hpp @@ -6,6 +6,8 @@ #include <libpq-fe.h> +#include <cstring> + class PostgresqlStatement: public Statement { public: @@ -90,7 +92,7 @@ class PostgresqlStatement: public Statement private: private: - bool execute() + bool execute(const bool second_attempt=false) { std::vector<const char*> params; params.reserve(this->params.size()); @@ -108,8 +110,20 @@ private: const auto status = PQresultStatus(this->result); if (status != PGRES_TUPLES_OK && status != PGRES_COMMAND_OK) { - log_error("Failed to execute command: ", PQresultErrorMessage(this->result)); - return false; + const char* original = PQerrorMessage(this->conn); + if (original && std::strlen(original) > 0) + log_error("Failed to execute command: ", std::string{original, std::strlen(original) - 1}); + if (PQstatus(this->conn) != CONNECTION_OK && !second_attempt) + { + log_info("Trying to reconnect to PostgreSQL server and execute the query again."); + PQreset(this->conn); + return this->execute(true); + } + else + { + log_error("Givin up."); + return false; + } } return true; } diff --git a/src/database/query.cpp b/src/database/query.cpp index 4054007..d72066e 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -6,7 +6,7 @@ void actual_bind(Statement& statement, const std::string& value, int index) statement.bind_text(index, value); } -void actual_bind(Statement& statement, const std::size_t value, int index) +void actual_bind(Statement& statement, const std::int64_t& value, int index) { statement.bind_int64(index, value); } @@ -21,7 +21,6 @@ void actual_bind(Statement& statement, const OptionalBool& value, int index) statement.bind_int64(index, -1); } - void actual_add_param(Query& query, const std::string& val) { query.params.push_back(val); diff --git a/src/database/query.hpp b/src/database/query.hpp index 547138f..ba28b1a 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -12,7 +12,12 @@ #include <string> void actual_bind(Statement& statement, const std::string& value, int index); -void actual_bind(Statement& statement, const std::size_t value, int index); +void actual_bind(Statement& statement, const std::int64_t& value, int index); +template <typename T, typename std::enable_if_t<std::is_integral<T>::value>* = 0> +void actual_bind(Statement& statement, const T& value, int index) +{ + actual_bind(statement, static_cast<std::int64_t>(value), index); +} void actual_bind(Statement& statement, const OptionalBool& value, int index); #ifdef DEBUG_SQL_QUERIES diff --git a/src/database/row.hpp b/src/database/row.hpp index 2d55897..27caf43 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -1,9 +1,5 @@ #pragma once -#include <database/insert_query.hpp> -#include <database/update_query.hpp> -#include <logger/logger.hpp> - #include <utils/is_one_of.hpp> #include <type_traits> @@ -29,43 +25,7 @@ struct Row return col.value; } - template <bool Coucou=true> - void save(std::unique_ptr<DatabaseEngine>& db, typename std::enable_if<!is_one_of<Id, T...>::value && Coucou>::type* = nullptr) - { - this->insert(*db); - } - - template <bool Coucou=true> - void save(std::unique_ptr<DatabaseEngine>& db, typename std::enable_if<is_one_of<Id, T...>::value && Coucou>::type* = nullptr) - { - const Id& id = std::get<Id>(this->columns); - if (id.value == Id::unset_value) - { - this->insert(*db); - std::get<Id>(this->columns).value = db->last_inserted_rowid; - } - else - this->update(*db); - } - - private: - void insert(DatabaseEngine& db) - { - InsertQuery query(this->table_name, this->columns); - // Ugly workaround for non portable stuff - query.body += db.get_returning_id_sql_string(Id::name); - query.execute(db, this->columns); - } - - void update(DatabaseEngine& db) - { - UpdateQuery query(this->table_name, this->columns); - - query.execute(db, this->columns); - } - public: std::tuple<T...> columns; std::string table_name; - }; diff --git a/src/database/save.hpp b/src/database/save.hpp new file mode 100644 index 0000000..4362110 --- /dev/null +++ b/src/database/save.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <database/update_query.hpp> +#include <database/insert_query.hpp> + +#include <database/engine.hpp> + +#include <database/row.hpp> + +#include <utils/is_one_of.hpp> + +template <typename... T, bool Coucou=true> +void save(Row<T...>& row, DatabaseEngine& db, typename std::enable_if<!is_one_of<Id, T...> && Coucou>::type* = nullptr) +{ + insert(row, db); +} + +template <typename... T, bool Coucou=true> +void save(Row<T...>& row, DatabaseEngine& db, typename std::enable_if<is_one_of<Id, T...> && Coucou>::type* = nullptr) +{ + const Id& id = std::get<Id>(row.columns); + if (id.value == Id::unset_value) + { + insert(row, db); + if (db.last_inserted_rowid >= 0) + std::get<Id>(row.columns).value = static_cast<Id::real_type>(db.last_inserted_rowid); + } + else + update(row, db); +} + diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 5a17f38..b9fdc06 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -2,6 +2,8 @@ #include <database/engine.hpp> +#include <database/table.hpp> +#include <database/database.hpp> #include <database/statement.hpp> #include <database/query.hpp> #include <logger/logger.hpp> @@ -115,6 +117,8 @@ struct SelectQuery: public Query #endif auto statement = db.prepare(this->body); + if (!statement) + return rows; statement->bind(std::move(this->params)); while (statement->step() == StepResult::Row) @@ -130,3 +134,9 @@ struct SelectQuery: public Query const std::string table_name; }; +template <typename... T> +auto select(const Table<T...> table) +{ + SelectQuery<T...> query(table.name); + return query; +} diff --git a/src/database/sqlite3_engine.cpp b/src/database/sqlite3_engine.cpp index ae4a146..5e3bba1 100644 --- a/src/database/sqlite3_engine.cpp +++ b/src/database/sqlite3_engine.cpp @@ -3,7 +3,6 @@ #ifdef SQLITE3_FOUND #include <database/sqlite3_engine.hpp> - #include <database/sqlite3_statement.hpp> #include <database/query.hpp> diff --git a/src/database/sqlite3_engine.hpp b/src/database/sqlite3_engine.hpp index 5b8176c..a7bfcdb 100644 --- a/src/database/sqlite3_engine.hpp +++ b/src/database/sqlite3_engine.hpp @@ -35,12 +35,15 @@ private: #else +using namespace std::string_literals; + class Sqlite3Engine { public: static std::unique_ptr<DatabaseEngine> open(const std::string& string) { throw std::runtime_error("Cannot open sqlite3 database "s + string + ": biboumi is not compiled with sqlite3 lib."); + return {}; } }; diff --git a/src/database/sqlite3_statement.hpp b/src/database/sqlite3_statement.hpp index 7738fa6..3ed60c0 100644 --- a/src/database/sqlite3_statement.hpp +++ b/src/database/sqlite3_statement.hpp @@ -88,5 +88,4 @@ class Sqlite3Statement: public Statement private: sqlite3_stmt* stmt; - int last_step_result{SQLITE_OK}; }; diff --git a/src/database/table.hpp b/src/database/table.hpp index 680e7cc..0b8bfc0 100644 --- a/src/database/table.hpp +++ b/src/database/table.hpp @@ -2,7 +2,7 @@ #include <database/engine.hpp> -#include <database/select_query.hpp> +#include <database/delete_query.hpp> #include <database/row.hpp> #include <algorithm> @@ -79,10 +79,10 @@ class Table return {this->name}; } - auto select() + auto del() { - SelectQuery<T...> select(this->name); - return select; + DeleteQuery query(this->name); + return query; } const std::string& get_name() const @@ -90,6 +90,8 @@ class Table return this->name; } + const std::string name; + private: template <std::size_t N=0> @@ -124,5 +126,4 @@ class Table add_column_create(DatabaseEngine&, std::string&) { } - const std::string name; }; diff --git a/src/database/update_query.hpp b/src/database/update_query.hpp index a29ac3f..c2b819d 100644 --- a/src/database/update_query.hpp +++ b/src/database/update_query.hpp @@ -1,7 +1,8 @@ #pragma once -#include <database/query.hpp> #include <database/engine.hpp> +#include <database/query.hpp> +#include <database/row.hpp> using namespace std::string_literals; @@ -102,3 +103,11 @@ struct UpdateQuery: public Query actual_bind(statement, value.value, sizeof...(T)); } }; + +template <typename... T> +void update(Row<T...>& row, DatabaseEngine& db) +{ + UpdateQuery query(row.table_name, row.columns); + + query.execute(db, row.columns); +} |