summaryrefslogtreecommitdiff
path: root/src/database/database.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/database/database.cpp')
-rw-r--r--src/database/database.cpp177
1 files changed, 134 insertions, 43 deletions
diff --git a/src/database/database.cpp b/src/database/database.cpp
index 3622963..9037ce1 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;
}
@@ -136,10 +162,6 @@ Database::IrcChannelOptions Database::get_irc_channel_options_with_server_and_gl
coptions.col<EncodingOut>() = get_first_non_empty(coptions.col<EncodingOut>(),
soptions.col<EncodingOut>());
- coptions.col<MaxHistoryLength>() = get_first_non_empty(coptions.col<MaxHistoryLength>(),
- soptions.col<MaxHistoryLength>(),
- goptions.col<MaxHistoryLength>());
-
return coptions;
}
@@ -159,15 +181,15 @@ 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)
+std::tuple<bool, std::vector<Database::MucLogLine>> Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server,
+ std::size_t 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();
+ auto request = select(Database::muc_log_lines);
request.where() << Database::Owner{} << "=" << owner << \
" and " << Database::IrcChanName{} << "=" << chan_name << \
" and " << Database::IrcServerName{} << "=" << server;
@@ -184,15 +206,70 @@ 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;
+ // Just a simple trick: to know whether we got the totality of the
+ // possible results matching this query (except for the limit), we just
+ // ask one more element. If we get that additional element, this means
+ // we don’t have everything. And then we just discard it. If we don’t
+ // have more, this means we have everything.
+ request.limit() << limit + 1;
auto result = request.execute(*Database::db);
+ bool complete = true;
- return {result.crbegin(), result.crend()};
+ if (result.size() == limit + 1)
+ {
+ complete = false;
+ result.erase(std::prev(result.end()));
+ }
+
+ if (paging == Database::Paging::first)
+ return std::make_tuple(complete, result);
+ else
+ return std::make_tuple(complete, std::vector<Database::MucLogLine>(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 +279,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 +293,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 +304,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 +312,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 +324,25 @@ 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