generated from wessel/boilerplate
feat(database): Missing queries, rename lecture -> course
This commit is contained in:
@@ -37,6 +37,7 @@ private:
|
||||
bool loaded_ { false };
|
||||
std::vector<std::string> default_config_paths_ = {
|
||||
"config.toml",
|
||||
"./src/config.toml",
|
||||
"../config.toml",
|
||||
"../../config.toml",
|
||||
"../../../config.toml",
|
||||
|
||||
@@ -75,7 +75,7 @@ std::vector<StudentCourse> DatabaseManager::queue_pending_combinations() {
|
||||
for (const auto& row : result) {
|
||||
StudentCourse sc;
|
||||
sc.student_name = row[0].as<std::string>();
|
||||
sc.lecture_name = row[1].as<std::string>();
|
||||
sc.course_name = row[1].as<std::string>();
|
||||
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();
|
||||
|
||||
|
||||
@@ -33,8 +33,9 @@ public:
|
||||
|
||||
// Data operations
|
||||
std::vector<StudentCourse> 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_;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
string student_name
|
||||
string lecture_name
|
||||
string course_name
|
||||
---
|
||||
---
|
||||
float32 result
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
string lecture_name
|
||||
string course_name
|
||||
int32 result
|
||||
builtin_interfaces/Time timestamp
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
string student_name
|
||||
string lecture_name
|
||||
string course_name
|
||||
builtin_interfaces/Time timestamp
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Request
|
||||
string student_name
|
||||
string lecture_name
|
||||
string course_name
|
||||
int32[] exam_grades
|
||||
---
|
||||
# Response
|
||||
|
||||
Reference in New Issue
Block a user