database stuff done

This commit is contained in:
2025-10-25 18:45:36 -05:00
parent 138ab70eff
commit 0c6889dcff
4 changed files with 148 additions and 7 deletions

View File

@@ -0,0 +1,116 @@
#include "database-utils.hpp"
#include <stdexcept>
namespace database_utils {
TrackerDb::TrackerDb(std::shared_ptr<duckdb::Connection> connection)
: conn_(std::move(connection)) {}
void TrackerDb::initialize_schema() {
conn_->Query(R"(
CREATE TABLE IF NOT EXISTS trackers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tracker_id VARCHAR UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
)");
conn_->Query(R"(
CREATE TABLE IF NOT EXISTS access_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tracker_fk INTEGER REFERENCES trackers(id) ON DELETE CASCADE,
accessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR
);
)");
}
bool TrackerDb::tracker_exists(const std::string& tracker_id) {
auto stmt = conn_->Prepare("SELECT COUNT(*) FROM trackers WHERE tracker_id = $1;");
auto res = stmt->Execute(tracker_id);
if (res->HasError()) throw std::runtime_error(res->GetError());
int64_t count = res->GetValue<int64_t>(0, 0);
return count > 0;
}
void TrackerDb::add_tracker(const std::string& tracker_id) {
if (tracker_exists(tracker_id)) return;
auto stmt = conn_->Prepare("INSERT INTO trackers (tracker_id) VALUES ($1);");
auto res = stmt->Execute(tracker_id);
if (res->HasError()) throw std::runtime_error(res->GetError());
}
void TrackerDb::log_access(const std::string& tracker_id, const std::string& ip_address) {
if (!tracker_exists(tracker_id)) add_tracker(tracker_id);
auto stmt = conn_->Prepare(R"(
INSERT INTO access_logs (tracker_fk, ip_address)
SELECT id, $2 FROM trackers WHERE tracker_id = $1;
)");
auto res = stmt->Execute(tracker_id, ip_address);
if (res->HasError()) throw std::runtime_error(res->GetError());
}
std::vector<std::tuple<std::string, std::string, std::string>> TrackerDb::get_all_accesses() {
auto res = conn_->Query(R"(
SELECT t.tracker_id, l.accessed_at, l.ip_address
FROM access_logs l
JOIN trackers t ON t.id = l.tracker_fk
ORDER BY l.accessed_at DESC;
)");
if (res->HasError()) throw std::runtime_error(res->GetError());
std::vector<std::tuple<std::string, std::string, std::string>> out;
out.reserve(res->RowCount());
for (std::size_t i = 0; i < res->RowCount(); ++i) {
out.emplace_back(
res->GetValue<std::string>(0, i),
res->GetValue<std::string>(1, i),
res->GetValue<std::string>(2, i)
);
}
return out;
}
std::vector<std::tuple<std::string, std::string>> TrackerDb::get_accesses_for(const std::string& tracker_id) {
auto stmt = conn_->Prepare(R"(
SELECT accessed_at, ip_address
FROM access_logs l
JOIN trackers t ON t.id = l.tracker_fk
WHERE t.tracker_id = $1
ORDER BY accessed_at DESC;
)");
auto res = stmt->Execute(tracker_id);
if (res->HasError()) throw std::runtime_error(res->GetError());
std::vector<std::tuple<std::string, std::string>> out;
out.reserve(res->RowCount());
for (std::size_t i = 0; i < res->RowCount(); ++i) {
out.emplace_back(
res->GetValue<std::string>(0, i),
res->GetValue<std::string>(1, i)
);
}
return out;
}
std::size_t TrackerDb::get_access_count(const std::string& tracker_id) {
auto stmt = conn_->Prepare(R"(
SELECT COUNT(*)
FROM access_logs l
JOIN trackers t ON t.id = l.tracker_fk
WHERE t.tracker_id = $1;
)");
auto res = stmt->Execute(tracker_id);
if (res->HasError()) throw std::runtime_error(res->GetError());
return static_cast<std::size_t>(res->GetValue<int64_t>(0, 0));
}
void TrackerDb::remove_tracker(const std::string& tracker_id) {
auto stmt = conn_->Prepare("DELETE FROM trackers WHERE tracker_id = $1;");
auto res = stmt->Execute(tracker_id);
if (res->HasError()) throw std::runtime_error(res->GetError());
}
} // namespace database_utils

View File

@@ -0,0 +1,31 @@
#pragma once
#include <duckdb.hpp>
#include <memory>
#include <string>
#include <vector>
#include <tuple>
namespace database_utils {
class TrackerDb {
public:
explicit TrackerDb(std::shared_ptr<duckdb::Connection> connection);
~TrackerDb() = default;
void initialize_schema();
bool tracker_exists(const std::string& tracker_id);
void add_tracker(const std::string& tracker_id);
void log_access(const std::string& tracker_id, const std::string& ip_address);
std::vector<std::tuple<std::string, std::string, std::string>> get_all_accesses();
std::vector<std::tuple<std::string, std::string>> get_accesses_for(const std::string& tracker_id);
std::size_t get_access_count(const std::string& tracker_id);
void remove_tracker(const std::string& tracker_id);
private:
std::shared_ptr<duckdb::Connection> conn_;
};
} // namespace database_utils

View File

@@ -83,8 +83,4 @@ void start_http_server(std::uint16_t port, std::shared_ptr<duckdb::Connection> c
}
}
namespace database_utils {
void initialize_db(std::shared_ptr<duckdb::Connection> connection){
}
}

View File

@@ -10,6 +10,4 @@ namespace socket_manager {
void start_http_server(std::uint16_t port, std::shared_ptr<duckdb::Connection> connection );
}
namespace database_utils {
void initialize_db(std::shared_ptr<duckdb::Connection> connection);
}