#include "Database.h" #include "Core/Logger.h" #include #include namespace Older { bool Database::open(const std::string &path) { if (sqlite3_open(path.c_str(), &m_sqlite)) { LOG(error) << "Can't open database: " << sqlite3_errmsg(m_sqlite); return false; } initialize(); return true; } void Database::upsertVisitRecord(const std::string &url, const std::string &visitorUuid, const std::string &userAgent, int64_t viewTime) { sqlite3_stmt *statement = nullptr; const char *query = "INSERT INTO visit_analysis (url, visitor_uuid, last_user_agent, last_view_time, page_view_count) " "VALUES (?, ?, ?, ?, 1) " "ON CONFLICT(url, visitor_uuid) DO UPDATE SET " "last_user_agent = excluded.last_user_agent, " "last_view_time = excluded.last_view_time, " "page_view_count = page_view_count + 1;"; if (sqlite3_prepare_v2(m_sqlite, query, -1, &statement, nullptr) == SQLITE_OK) { sqlite3_bind_text(statement, 1, url.c_str(), -1, SQLITE_STATIC); sqlite3_bind_text(statement, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); sqlite3_bind_text(statement, 3, userAgent.c_str(), -1, SQLITE_STATIC); sqlite3_bind_int(statement, 4, viewTime); if (sqlite3_step(statement) != SQLITE_DONE) { LOG(error) << "Error inserting/updating record: " << sqlite3_errmsg(m_sqlite); } } sqlite3_finalize(statement); } VisitorStats Database::visitorStats(const std::string &url) { VisitorStats ret; ret.url = url; sqlite3_stmt *statement = nullptr; const char *query = "SELECT COUNT(DISTINCT visitor_uuid) AS visitor_count, SUM(page_view_count) AS total_views " "FROM visit_analysis WHERE url = ?;"; if (sqlite3_prepare_v2(m_sqlite, query, -1, &statement, nullptr) == SQLITE_OK) { sqlite3_bind_text(statement, 1, url.c_str(), -1, SQLITE_STATIC); if (sqlite3_step(statement) == SQLITE_ROW) { ret.visitorCount = sqlite3_column_int(statement, 0); ret.totalViews = sqlite3_column_int(statement, 1); } } sqlite3_finalize(statement); return ret; } std::list Database::mostViewedUrls(int n) { std::list ret; sqlite3_stmt *statement = nullptr; const char *query = "SELECT url, SUM(page_view_count) AS total_page_views " "FROM visit_analysis " "GROUP BY url " "ORDER BY total_page_views DESC " "LIMIT ?;"; if (sqlite3_prepare_v2(m_sqlite, query, -1, &statement, nullptr) == SQLITE_OK) { sqlite3_bind_int(statement, 1, n); while (sqlite3_step(statement) == SQLITE_ROW) { VisitorStats item; item.url = reinterpret_cast(sqlite3_column_text(statement, 0)); item.totalViews = sqlite3_column_int(statement, 1); ret.push_back(item); } } sqlite3_finalize(statement); return ret; } std::list Database::latestViewedUrls(int n) { std::list ret; sqlite3_stmt *statement = nullptr; const char *query = "SELECT url, last_view_time " "FROM visit_analysis " "ORDER BY last_view_time DESC " "LIMIT ?;"; if (sqlite3_prepare_v2(m_sqlite, query, -1, &statement, nullptr) == SQLITE_OK) { sqlite3_bind_int(statement, 1, n); while (sqlite3_step(statement) == SQLITE_ROW) { VisitorStats item; item.url = reinterpret_cast(sqlite3_column_text(statement, 0)); item.lastViewTime = sqlite3_column_int64(statement, 1); ret.push_back(item); } } sqlite3_finalize(statement); return ret; } SiteStats Database::siteStats() { SiteStats ret; sqlite3_stmt *statement; const char *query = "SELECT COUNT(DISTINCT visitor_uuid) AS total_visitors, SUM(page_view_count) AS total_page_views " "FROM visit_analysis;"; if (sqlite3_prepare_v2(m_sqlite, query, -1, &statement, nullptr) == SQLITE_OK) { if (sqlite3_step(statement) == SQLITE_ROW) { ret.totalVisitors = sqlite3_column_int(statement, 0); ret.totalViews = sqlite3_column_int(statement, 1); } } sqlite3_finalize(statement); return ret; } void Database::initialize() { createVisitAnalysisTable(); } void Database::createVisitAnalysisTable() { const char *createTableQuery = R"( CREATE TABLE IF NOT EXISTS visit_analysis ( id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL, visitor_uuid TEXT NOT NULL, last_user_agent TEXT NOT NULL, last_view_time INTEGER NOT NULL, page_view_count INTEGER NOT NULL, UNIQUE(url, visitor_uuid) ); )"; char *message = nullptr; int rc = sqlite3_exec(m_sqlite, createTableQuery, nullptr, nullptr, &message); if (rc != SQLITE_OK) { LOG(error) << "Error creating table: " << message; sqlite3_free(message); } } }