diff --git a/Server/Database/Database.cpp b/Server/Database/Database.cpp index e9831e9..be856ee 100644 --- a/Server/Database/Database.cpp +++ b/Server/Database/Database.cpp @@ -106,6 +106,50 @@ void Database::setTaskFinished(int id, bool finished, uint64_t finishedTime) { } } +void Database::updateTodayVisitCount(const std::string &url, const std::string &visitorUuid) { + sqlite3_stmt *stmt = nullptr; + const char *sql_select = "SELECT page_view_count FROM today_visit_count WHERE url = ? AND visitor_uuid = ?"; + if (sqlite3_prepare_v2(m_sqlite3, sql_select, -1, &stmt, 0) != SQLITE_OK) { + LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); + return; + } + sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); + int rc = sqlite3_step(stmt); + if (rc == SQLITE_ROW) { // 记录存在,执行UPDATE语句 + sqlite3_finalize(stmt); // 释放SELECT语句的资源 + const char *sql_update = + "UPDATE today_visit_count SET page_view_count = page_view_count + 1 WHERE url = ? AND visitor_uuid = ?"; + if (sqlite3_prepare_v2(m_sqlite3, sql_update, -1, &stmt, 0) != SQLITE_OK) { + LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); + return; + } + sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); + if (sqlite3_step(stmt) != SQLITE_DONE) { + LOG(error) << "Failed to execute statement: " << sqlite3_errmsg(m_sqlite3); + sqlite3_finalize(stmt); + return; + } + } else { // 记录不存在,执行INSERT语句 + sqlite3_finalize(stmt); // 释放SELECT语句的资源 + const char *sql_insert = "INSERT INTO today_visit_count (url, visitor_uuid, page_view_count) VALUES (?, ?, 1)"; + if (sqlite3_prepare_v2(m_sqlite3, sql_insert, -1, &stmt, 0) != SQLITE_OK) { + LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); + return; + } + sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); + if (sqlite3_step(stmt) != SQLITE_DONE) { // 执行INSERT语句 + LOG(error) << "Failed to execute statement: " << sqlite3_errmsg(m_sqlite3); + sqlite3_finalize(stmt); + return; + } + } + // 释放语句资源 + sqlite3_finalize(stmt); +} + bool Database::addHomeBoxItem(const std::string &name, const std::string &location, int cost) { bool ret = true; std::ostringstream oss; @@ -129,7 +173,7 @@ static int selectHomeBoxItemCallback(void *data, int argc, char **argv, char **c if (argv[i] == nullptr) continue; if (strcmp(columnName[i], "id") == 0) { item.id = std::atol(argv[i]); - } else if (strcmp(columnName[i], "name") == 0) { + } else if (strcmp(columnName[i], "name") == 0) { item.name = argv[i]; } else if (strcmp(columnName[i], "location") == 0) { item.location = argv[i]; @@ -169,6 +213,37 @@ void Database::initialize() { LOG(error) << "Failed to create table: " << sqlite3_errmsg(m_sqlite3); return; } + + const char *sql_create_visit_count = R"( + CREATE TABLE IF NOT EXISTS visit_count ( + id INTEGER NOT NULL PRIMARY KEY, + url TEXT NOT NULL, + page_view_count INTEGER NOT NULL, + unique_visitor_count INTEGER NOT NULL + ); + )"; + + char *message = nullptr; + result = sqlite3_exec(m_sqlite3, sql_create_visit_count, 0, 0, &message); + if (result != SQLITE_OK) { + LOG(error) << "Failed to create table: " << message << std::endl; + sqlite3_free(message); + } + + const char *sql_create_today_visit_count = R"( + CREATE TABLE IF NOT EXISTS today_visit_count ( + id INTEGER NOT NULL, + url TEXT NOT NULL, + visitor_uuid TEXT NOT NULL, + page_view_count INTEGER NOT NULL, + PRIMARY KEY (id) + ); + )"; + result = sqlite3_exec(m_sqlite3, sql_create_today_visit_count, 0, 0, &message); + if (result != SQLITE_OK) { + LOG(error) << "Failed to create table: " << message << std::endl; + sqlite3_free(message); + } } Database::~Database() { diff --git a/Server/Database/Database.h b/Server/Database/Database.h index 048d904..3c91683 100644 --- a/Server/Database/Database.h +++ b/Server/Database/Database.h @@ -20,6 +20,8 @@ public: bool removeTask(int id); void setTaskFinished(int id, bool finished, uint64_t finishedTime); + void updateTodayVisitCount(const std::string &url, const std::string &visitorUuid); + HomeBox::Items homeBoxItems(); bool addHomeBoxItem(const std::string &name, const std::string &location, int cost); diff --git a/UnitTest/DatabaseTest.cpp b/UnitTest/DatabaseTest.cpp index f798b84..73e791f 100644 --- a/UnitTest/DatabaseTest.cpp +++ b/UnitTest/DatabaseTest.cpp @@ -23,4 +23,8 @@ BOOST_AUTO_TEST_CASE(DatabaseTest) { auto now = duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); database.setTaskFinished(1, true, now); + + database.updateTodayVisitCount("/note", "uuid_123"); + database.updateTodayVisitCount("/note/1", "uuid_1232"); + database.updateTodayVisitCount("/note", "uuid_123"); } \ No newline at end of file