#include "backup.hpp"
#include <chrono>
#include <filesystem>
#include <format>
#include <string>
#include <mw/database.hpp>
#include <mw/error.hpp>
#include <mw/utils.hpp>
#include <spdlog/spdlog.h>
namespace overseer::db
{
namespace
{
std::string nowStamp()
{
auto now = std::chrono::system_clock::now();
return std::format("{:%Y%m%d-%H%M%S}",
std::chrono::floor<std::chrono::seconds>(now));
}
// Single-quote escape for inline SQL string literals.
std::string sqlQuote(const std::string& s)
{
std::string out;
out.reserve(s.size() + 2);
out.push_back('\'');
for(char c : s)
{
if(c == '\'')
{
out.push_back('\'');
out.push_back('\'');
}
else
{
out.push_back(c);
}
}
out.push_back('\'');
return out;
}
} // namespace
mw::E<std::filesystem::path>
backupDatabaseFile(mw::SQLite& db, const std::string& db_path)
{
std::filesystem::path src = db_path;
auto abs = std::filesystem::absolute(src);
auto dest = abs;
dest += ".bak-" + nowStamp();
// VACUUM INTO is the documented online-backup-equivalent SQL form
// and it is safe with WAL active. See
// https://www.sqlite.org/lang_vacuum.html#vacuuminto
std::string sql = "VACUUM INTO " + sqlQuote(dest.string()) + ";";
if(auto rt = db.execute(sql.c_str()); !rt.has_value())
{
return std::unexpected(mw::runtimeError(std::format(
"Failed to back up database: {}", mw::errorMsg(rt.error()))));
}
spdlog::info("Database backed up to {}", dest.string());
return dest;
}
} // namespace overseer::db