database.cpp

Download
cpp 208 lines 5.3 KB
  1#include "database.h"
  2#include <algorithm>
  3#include <numeric>
  4#include <fstream>
  5#include <iostream>
  6#include <iomanip>
  7
  8/**
  9 * @brief Add a new student to the database
 10 */
 11void StudentDatabase::addStudent(std::shared_ptr<Student> student) {
 12    // Check for duplicate ID
 13    auto it = std::find_if(students.begin(), students.end(),
 14        [&student](const std::shared_ptr<Student>& s) {
 15            return s->getId() == student->getId();
 16        });
 17
 18    if (it != students.end()) {
 19        throw std::invalid_argument("Student with ID " + std::to_string(student->getId()) + " already exists");
 20    }
 21
 22    students.push_back(student);
 23}
 24
 25/**
 26 * @brief Remove a student by ID
 27 */
 28void StudentDatabase::removeStudent(int id) {
 29    auto it = std::find_if(students.begin(), students.end(),
 30        [id](const std::shared_ptr<Student>& s) {
 31            return s->getId() == id;
 32        });
 33
 34    if (it == students.end()) {
 35        throw StudentNotFoundException(id);
 36    }
 37
 38    students.erase(it);
 39}
 40
 41/**
 42 * @brief Find a student by ID
 43 * @return Shared pointer to student
 44 * @throws StudentNotFoundException if not found
 45 */
 46std::shared_ptr<Student> StudentDatabase::findById(int id) const {
 47    auto it = std::find_if(students.begin(), students.end(),
 48        [id](const std::shared_ptr<Student>& s) {
 49            return s->getId() == id;
 50        });
 51
 52    if (it == students.end()) {
 53        throw StudentNotFoundException(id);
 54    }
 55
 56    return *it;
 57}
 58
 59/**
 60 * @brief Find all students with matching name (case-sensitive substring)
 61 */
 62std::vector<std::shared_ptr<Student>> StudentDatabase::findByName(const std::string& name) const {
 63    std::vector<std::shared_ptr<Student>> results;
 64
 65    std::copy_if(students.begin(), students.end(), std::back_inserter(results),
 66        [&name](const std::shared_ptr<Student>& s) {
 67            return s->getName().find(name) != std::string::npos;
 68        });
 69
 70    return results;
 71}
 72
 73/**
 74 * @brief Display all students
 75 */
 76void StudentDatabase::listAll() const {
 77    if (students.empty()) {
 78        std::cout << "No students in database.\n";
 79        return;
 80    }
 81
 82    std::cout << "\n" << std::string(80, '=') << "\n";
 83    std::cout << "STUDENT DATABASE (" << students.size() << " students)\n";
 84    std::cout << std::string(80, '=') << "\n";
 85
 86    for (const auto& student : students) {
 87        std::cout << *student << "\n";
 88    }
 89
 90    std::cout << std::string(80, '=') << "\n\n";
 91}
 92
 93/**
 94 * @brief Sort students by ID (ascending)
 95 */
 96void StudentDatabase::sortById() {
 97    std::sort(students.begin(), students.end(),
 98        [](const std::shared_ptr<Student>& a, const std::shared_ptr<Student>& b) {
 99            return a->getId() < b->getId();
100        });
101}
102
103/**
104 * @brief Sort students by name (alphabetical)
105 */
106void StudentDatabase::sortByName() {
107    std::sort(students.begin(), students.end(),
108        [](const std::shared_ptr<Student>& a, const std::shared_ptr<Student>& b) {
109            return a->getName() < b->getName();
110        });
111}
112
113/**
114 * @brief Sort students by GPA (descending - highest first)
115 */
116void StudentDatabase::sortByGpa() {
117    std::sort(students.begin(), students.end(),
118        [](const std::shared_ptr<Student>& a, const std::shared_ptr<Student>& b) {
119            return a->getGpa() > b->getGpa();
120        });
121}
122
123/**
124 * @brief Calculate average GPA of all students
125 */
126double StudentDatabase::calculateAverageGpa() const {
127    if (students.empty()) {
128        return 0.0;
129    }
130
131    double sum = std::accumulate(students.begin(), students.end(), 0.0,
132        [](double total, const std::shared_ptr<Student>& s) {
133            return total + s->getGpa();
134        });
135
136    return sum / students.size();
137}
138
139/**
140 * @brief Count students by major
141 * @return Map of major -> student count
142 */
143std::map<std::string, int> StudentDatabase::countByMajor() const {
144    std::map<std::string, int> majorCount;
145
146    for (const auto& student : students) {
147        majorCount[student->getMajor()]++;
148    }
149
150    return majorCount;
151}
152
153/**
154 * @brief Save database to CSV file
155 */
156void StudentDatabase::saveToFile(const std::string& filename) const {
157    std::ofstream file(filename);
158
159    if (!file.is_open()) {
160        throw std::runtime_error("Failed to open file for writing: " + filename);
161    }
162
163    // Write header
164    file << "id,name,major,gpa\n";
165
166    // Write student data
167    for (const auto& student : students) {
168        file << student->toCSV() << "\n";
169    }
170
171    file.close();
172    std::cout << "Database saved to " << filename << " (" << students.size() << " students)\n";
173}
174
175/**
176 * @brief Load database from CSV file
177 */
178void StudentDatabase::loadFromFile(const std::string& filename) {
179    std::ifstream file(filename);
180
181    if (!file.is_open()) {
182        throw std::runtime_error("Failed to open file for reading: " + filename);
183    }
184
185    students.clear();
186    std::string line;
187
188    // Skip header
189    std::getline(file, line);
190
191    // Read student data
192    int count = 0;
193    while (std::getline(file, line)) {
194        if (line.empty()) continue;
195
196        try {
197            auto student = std::make_shared<Student>(Student::fromCSV(line));
198            students.push_back(student);
199            count++;
200        } catch (const std::exception& e) {
201            std::cerr << "Warning: Failed to parse line: " << line << " (" << e.what() << ")\n";
202        }
203    }
204
205    file.close();
206    std::cout << "Database loaded from " << filename << " (" << count << " students)\n";
207}