From 9c6b194b3a88f2cf12a80ddb3c2e253ff773ad6b Mon Sep 17 00:00:00 2001 From: Wessel Tip Date: Thu, 25 Sep 2025 11:51:46 +0200 Subject: [PATCH] feat(database): Missing queries, rename `lecture` -> `course` --- .../src/config/ConfigManager.hpp | 1 + .../src/database/DatabaseManager.cpp | 37 +++++++++++++--- .../src/database/DatabaseManager.hpp | 3 +- .../src/database/SQLQueries.hpp | 43 +++++++++++-------- .../src/database/StudentCourse.hpp | 4 +- .../nodes/ExamResultGenerator.cpp | 12 +++--- src/g2_2025_interfaces/action/Retake.action | 2 +- src/g2_2025_interfaces/msg/Exam.msg | 2 +- src/g2_2025_interfaces/msg/Student.msg | 2 +- src/g2_2025_interfaces/srv/Exams.srv | 2 +- 10 files changed, 73 insertions(+), 35 deletions(-) diff --git a/src/g2_2025_grade_calculator_pkg/src/config/ConfigManager.hpp b/src/g2_2025_grade_calculator_pkg/src/config/ConfigManager.hpp index 4bf8214..cd585b9 100644 --- a/src/g2_2025_grade_calculator_pkg/src/config/ConfigManager.hpp +++ b/src/g2_2025_grade_calculator_pkg/src/config/ConfigManager.hpp @@ -37,6 +37,7 @@ private: bool loaded_ { false }; std::vector default_config_paths_ = { "config.toml", + "./src/config.toml", "../config.toml", "../../config.toml", "../../../config.toml", diff --git a/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.cpp b/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.cpp index 13eee4f..706e24c 100644 --- a/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.cpp +++ b/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.cpp @@ -75,7 +75,7 @@ std::vector DatabaseManager::queue_pending_combinations() { for (const auto& row : result) { StudentCourse sc; sc.student_name = row[0].as(); - sc.lecture_name = row[1].as(); + sc.course_name = row[1].as(); combinations.push_back(sc); } @@ -96,7 +96,7 @@ bool DatabaseManager::enroll_student_into_course(const StudentCourse& sc) { try { pqxx::work txn(*conn_); - txn.exec_params(SQL_INSERT_STUDENT_ENROLLMENT, sc.student_name, sc.lecture_name); + txn.exec_params(SQL_INSERT_STUDENT_ENROLLMENT, sc.student_name, sc.course_name); txn.commit(); return true; @@ -110,7 +110,7 @@ bool DatabaseManager::enroll_student_into_course(const StudentCourse& sc) { } } -bool DatabaseManager::store_exam_result(const std::string& student_name, const std::string& lecture_name, int grade) { +bool DatabaseManager::store_exam_result(const std::string& student_name, const std::string& course_name, int grade) { if (!is_connected()) return false; try { @@ -118,7 +118,7 @@ bool DatabaseManager::store_exam_result(const std::string& student_name, const s txn.exec_params( SQL_INSERT_EXAM_RESULT, - student_name, lecture_name, grade + student_name, course_name, grade ); txn.commit(); @@ -133,6 +133,33 @@ bool DatabaseManager::store_exam_result(const std::string& student_name, const s } } +bool DatabaseManager::store_final_course_result( + const StudentCourse& sc, + int exam_count, + int final_grade +) { + if (!is_connected()) return false; + + try { + pqxx::work txn(*conn_); + + txn.exec_params( + SQL_INSERT_FINAL_COURSE_RESULT, + sc.student_name, sc.course_name, exam_count, final_grade + ); + + txn.commit(); + return true; + + } catch (const pqxx::sql_error &e) { + RCLCPP_ERROR(logger_, "[DBS] store final course result failed: %s", e.what()); + return false; + } catch (const std::exception &e) { + RCLCPP_ERROR(logger_, "[DBS] database error: %s", e.what()); + return false; + } +} + void DatabaseManager::create_tables() { if (!conn_ || !conn_->is_open()) return; @@ -141,7 +168,7 @@ void DatabaseManager::create_tables() { txn.exec(SQL_CREATE_ENROLLMENTS_TABLE); txn.exec(SQL_CREATE_EXAM_RESULTS); - txn.exec(SQL_CREATE_LECTURE_RESULTS); + txn.exec(SQL_CREATE_COURSE_RESULTS); txn.commit(); diff --git a/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.hpp b/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.hpp index 3bb1869..ba2dc40 100644 --- a/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.hpp +++ b/src/g2_2025_grade_calculator_pkg/src/database/DatabaseManager.hpp @@ -33,8 +33,9 @@ public: // Data operations std::vector queue_pending_combinations(); - bool store_exam_result(const std::string& student_name, const std::string& lecture_name, int grade); + bool store_exam_result(const std::string& student_name, const std::string& course_name, int grade); bool enroll_student_into_course(const StudentCourse& sc); + bool store_final_course_result(const StudentCourse& sc, int exam_count, int final_grade); private: rclcpp::Logger logger_; diff --git a/src/g2_2025_grade_calculator_pkg/src/database/SQLQueries.hpp b/src/g2_2025_grade_calculator_pkg/src/database/SQLQueries.hpp index 4e8af88..1848728 100644 --- a/src/g2_2025_grade_calculator_pkg/src/database/SQLQueries.hpp +++ b/src/g2_2025_grade_calculator_pkg/src/database/SQLQueries.hpp @@ -11,53 +11,55 @@ static const std::string SQL_CREATE_ENROLLMENTS_TABLE = R"( CREATE TABLE IF NOT EXISTS student_enrollments ( id SERIAL PRIMARY KEY, student_name VARCHAR(100) NOT NULL, - lecture_name VARCHAR(100) NOT NULL, - enrolled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE(student_name, lecture_name) + course_name VARCHAR(100) NOT NULL, + is_retake BOOLEAN DEFAULT FALSE, + enrolled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); )"; +// UNIQUE(student_name, course_name) static const std::string SQL_CREATE_EXAM_RESULTS = R"( CREATE TABLE IF NOT EXISTS exam_results ( id SERIAL PRIMARY KEY, student_name VARCHAR(100) NOT NULL, - lecture_name VARCHAR(100) NOT NULL, - exam_grade FLOAT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE(student_name, lecture_name) + course_name VARCHAR(100) NOT NULL, + exam_grade INTEGER NOT NULL, + is_retake BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); )"; +// UNIQUE(student_name, course_name) - -static const std::string SQL_CREATE_LECTURE_RESULTS = R"( +static const std::string SQL_CREATE_COURSE_RESULTS = R"( CREATE TABLE IF NOT EXISTS final_course_results ( id SERIAL PRIMARY KEY, student_name VARCHAR(100) NOT NULL, - lecture_name VARCHAR(100) NOT NULL, - final_grade FLOAT NOT NULL, + course_name VARCHAR(100) NOT NULL, + exam_count INTEGER NOT NULL, + final_grade INTEGER NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE(student_name, lecture_name) + UNIQUE(student_name, course_name) ); )"; static const std::string SQL_SELECT_MISSING_RESULTS = R"( - SELECT se.student_name, se.lecture_name + SELECT se.student_name, se.course_name FROM student_enrollments se LEFT JOIN final_course_results fcr ON se.student_name = fcr.student_name - AND se.lecture_name = fcr.lecture_name + AND se.course_name = fcr.course_name WHERE fcr.id IS NULL )"; static const std::string SQL_INSERT_EXAM_RESULT = R"( - INSERT INTO exam_results (student_name, lecture_name, exam_grade) + INSERT INTO exam_results (student_name, course_name, exam_grade) VALUES ($1, $2, $3) )"; -// ON CONFLICT (student_name, lecture_name) +// ON CONFLICT (student_name, course_name) // DO UPDATE SET exam_grade = EXCLUDED.exam_grade, created_at = CURRENT_TIMESTAMP static const std::string SQL_INSERT_STUDENT_ENROLLMENT = R"( - INSERT INTO student_enrollments (student_name, lecture_name) + INSERT INTO student_enrollments (student_name, course_name) VALUES ($1, $2) ON CONFLICT DO NOTHING )"; @@ -65,3 +67,10 @@ static const std::string SQL_INSERT_STUDENT_ENROLLMENT = R"( static const std::string SQL_SELECT_STUDENT_LIST = R"( SELECT COUNT(*) FROM student_enrollments )"; + +static const std::string SQL_INSERT_FINAL_COURSE_RESULT = R"( + INSERT INTO final_course_results (student_name, course_name, exam_count, final_grade) + VALUES ($1, $2, $3, $4) +)"; +// ON CONFLICT (student_name, course_name) +// DO UPDATE SET exam_count = EXCLUDED.exam_count, final_grade = EXCLUDED.final_grade, created_at = CURRENT_TIMESTAMP diff --git a/src/g2_2025_grade_calculator_pkg/src/database/StudentCourse.hpp b/src/g2_2025_grade_calculator_pkg/src/database/StudentCourse.hpp index a1fd46b..009dd58 100644 --- a/src/g2_2025_grade_calculator_pkg/src/database/StudentCourse.hpp +++ b/src/g2_2025_grade_calculator_pkg/src/database/StudentCourse.hpp @@ -13,10 +13,10 @@ namespace assignments::one::exam_result_generator { struct StudentCourse { std::string student_name; - std::string lecture_name; + std::string course_name; bool operator==(const StudentCourse& other) const { - return student_name == other.student_name && lecture_name == other.lecture_name; + return student_name == other.student_name && course_name == other.course_name; } }; diff --git a/src/g2_2025_grade_calculator_pkg/src/exam_result_generator/nodes/ExamResultGenerator.cpp b/src/g2_2025_grade_calculator_pkg/src/exam_result_generator/nodes/ExamResultGenerator.cpp index 2962602..3ba346f 100644 --- a/src/g2_2025_grade_calculator_pkg/src/exam_result_generator/nodes/ExamResultGenerator.cpp +++ b/src/g2_2025_grade_calculator_pkg/src/exam_result_generator/nodes/ExamResultGenerator.cpp @@ -61,37 +61,37 @@ void ExamResultGenerator::generate_random_result() { int grade = grade_dist_(gen_); - db_manager_->store_exam_result(selected.student_name, selected.lecture_name, grade); + db_manager_->store_exam_result(selected.student_name, selected.course_name, grade); // Publish exam result auto exam_msg = g2_2025_interfaces::msg::Exam(); - exam_msg.lecture_name = selected.lecture_name; + exam_msg.course_name = selected.course_name; exam_msg.result = grade; exam_publisher_->publish(exam_msg); RCLCPP_INFO(this->get_logger(), "generated grade: (%d) %s in %s", - grade, selected.student_name.c_str(), selected.lecture_name.c_str() + grade, selected.student_name.c_str(), selected.course_name.c_str() ); } void ExamResultGenerator::student_management_callback(const g2_2025_interfaces::msg::Student::SharedPtr msg) { StudentCourse sc; sc.student_name = msg->student_name; - sc.lecture_name = msg->lecture_name; + sc.course_name = msg->course_name; auto it = std::find(operations_queue_.begin(), operations_queue_.end(), sc); if (it != operations_queue_.end()) { operations_queue_.erase(it); RCLCPP_INFO(this->get_logger(), "removed from queue: %s - %s", - sc.student_name.c_str(), sc.lecture_name.c_str() + sc.student_name.c_str(), sc.course_name.c_str() ); } else { add_student_course_combination(sc); RCLCPP_INFO(this->get_logger(), "added to queue: %s - %s", - sc.student_name.c_str(), sc.lecture_name.c_str() + sc.student_name.c_str(), sc.course_name.c_str() ); } } diff --git a/src/g2_2025_interfaces/action/Retake.action b/src/g2_2025_interfaces/action/Retake.action index 66ebe9a..bc8d36b 100644 --- a/src/g2_2025_interfaces/action/Retake.action +++ b/src/g2_2025_interfaces/action/Retake.action @@ -1,5 +1,5 @@ string student_name -string lecture_name +string course_name --- --- float32 result diff --git a/src/g2_2025_interfaces/msg/Exam.msg b/src/g2_2025_interfaces/msg/Exam.msg index 8d1beb9..a37853e 100644 --- a/src/g2_2025_interfaces/msg/Exam.msg +++ b/src/g2_2025_interfaces/msg/Exam.msg @@ -1,3 +1,3 @@ -string lecture_name +string course_name int32 result builtin_interfaces/Time timestamp diff --git a/src/g2_2025_interfaces/msg/Student.msg b/src/g2_2025_interfaces/msg/Student.msg index fa576b2..ddbc0b0 100644 --- a/src/g2_2025_interfaces/msg/Student.msg +++ b/src/g2_2025_interfaces/msg/Student.msg @@ -1,3 +1,3 @@ string student_name -string lecture_name +string course_name builtin_interfaces/Time timestamp diff --git a/src/g2_2025_interfaces/srv/Exams.srv b/src/g2_2025_interfaces/srv/Exams.srv index d5f62f3..87dc142 100644 --- a/src/g2_2025_interfaces/srv/Exams.srv +++ b/src/g2_2025_interfaces/srv/Exams.srv @@ -1,6 +1,6 @@ # Request string student_name -string lecture_name +string course_name int32[] exam_grades --- # Response