diff options
Diffstat (limited to 'src/database/database.cpp')
-rw-r--r-- | src/database/database.cpp | 160 |
1 files changed, 124 insertions, 36 deletions
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 |