001package edu.pdx.cs.joy.jdbc;
002
003import java.sql.*;
004import java.util.ArrayList;
005import java.util.List;
006
007/**
008 * Data Access Object implementation for managing Course entities in the database.
009 * Demonstrates basic JDBC operations: CREATE, READ, UPDATE.
010 */
011public class CourseDAOImpl implements CourseDAO {
012
013  private final Connection connection;
014
015  /**
016   * Creates a new CourseDAOImpl with the specified database connection.
017   *
018   * @param connection the database connection to use
019   */
020  public CourseDAOImpl(Connection connection) {
021    this.connection = connection;
022  }
023
024  /**
025   * Drops the courses table from the database if it exists.
026   *
027   * @param connection the database connection to use
028   * @throws SQLException if a database error occurs
029   */
030  public static void dropTable(Connection connection) throws SQLException {
031    try (Statement statement = connection.createStatement()) {
032      statement.execute("DROP TABLE IF EXISTS courses");
033    }
034  }
035
036  /**
037   * Creates the courses table in the database.
038   *
039   * @param connection the database connection to use
040   * @throws SQLException if a database error occurs
041   */
042  public static void createTable(Connection connection) throws SQLException {
043    try (Statement statement = connection.createStatement()) {
044      statement.execute(
045        "CREATE TABLE courses (" +
046        "  id IDENTITY PRIMARY KEY," +
047        "  title VARCHAR(255) NOT NULL," +
048        "  department_id INTEGER NOT NULL," +
049        "  credits INTEGER NOT NULL," +
050        "  FOREIGN KEY (department_id) REFERENCES departments(id)" +
051        ")"
052      );
053    }
054  }
055
056  /**
057   * Saves a course to the database.
058   * The course's ID will be automatically generated by the database and set on the object.
059   *
060   * @param course the course to save
061   * @throws SQLException if a database error occurs
062   */
063  @Override
064  public void save(Course course) throws SQLException {
065    String sql = "INSERT INTO courses (title, department_id, credits) VALUES (?, ?, ?)";
066
067    try (PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
068      statement.setString(1, course.getTitle());
069      statement.setInt(2, course.getDepartmentId());
070      statement.setInt(3, course.getCredits());
071      statement.executeUpdate();
072
073      // Retrieve the auto-generated ID and set it on the course object
074      try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
075        if (generatedKeys.next()) {
076          int generatedId = generatedKeys.getInt(1);
077          course.setId(generatedId);
078        } else {
079          throw new SQLException("Creating course failed, no ID obtained.");
080        }
081      }
082    }
083  }
084
085  /**
086   * Finds a course by its title.
087   *
088   * @param title the title to search for
089   * @return the course with the given title, or null if not found
090   * @throws SQLException if a database error occurs
091   */
092  @Override
093  public Course findByTitle(String title) throws SQLException {
094    String sql = "SELECT id, title, department_id, credits FROM courses WHERE title = ?";
095
096    try (PreparedStatement statement = connection.prepareStatement(sql)) {
097      statement.setString(1, title);
098
099      try (ResultSet resultSet = statement.executeQuery()) {
100        if (resultSet.next()) {
101          return extractCourseFromResultSet(resultSet);
102        }
103      }
104    }
105
106    return null;
107  }
108
109  /**
110   * Finds all courses associated with a specific department.
111   *
112   * @param departmentId the department ID to search for
113   * @return a list of courses in the department
114   * @throws SQLException if a database error occurs
115   */
116  @Override
117  public List<Course> findByDepartmentId(int departmentId) throws SQLException {
118    List<Course> courses = new ArrayList<>();
119    String sql = "SELECT id, title, department_id, credits FROM courses WHERE department_id = ?";
120
121    try (PreparedStatement statement = connection.prepareStatement(sql)) {
122      statement.setInt(1, departmentId);
123
124      try (ResultSet resultSet = statement.executeQuery()) {
125        while (resultSet.next()) {
126          courses.add(extractCourseFromResultSet(resultSet));
127        }
128      }
129    }
130
131    return courses;
132  }
133
134  /**
135   * Extracts a Course object from the current row of a ResultSet.
136   *
137   * @param resultSet the result set positioned at a course row
138   * @return a Course object with data from the result set
139   * @throws SQLException if a database error occurs
140   */
141  private Course extractCourseFromResultSet(ResultSet resultSet) throws SQLException {
142    int id = resultSet.getInt("id");
143    String title = resultSet.getString("title");
144    int departmentId = resultSet.getInt("department_id");
145    int credits = resultSet.getInt("credits");
146
147    Course course = new Course(title, departmentId, credits);
148    course.setId(id);
149    return course;
150  }
151
152  /**
153   * Updates an existing course in the database.
154   * Uses the course's ID to identify which record to update.
155   *
156   * @param course the course to update
157   * @throws SQLException if a database error occurs
158   */
159  @Override
160  public void update(Course course) throws SQLException {
161    String sql = "UPDATE courses SET title = ?, department_id = ?, credits = ? WHERE id = ?";
162
163    try (PreparedStatement statement = connection.prepareStatement(sql)) {
164      statement.setString(1, course.getTitle());
165      statement.setInt(2, course.getDepartmentId());
166      statement.setInt(3, course.getCredits());
167      statement.setInt(4, course.getId());
168
169      int rowsAffected = statement.executeUpdate();
170      if (rowsAffected == 0) {
171        throw new SQLException("Update failed, no course found with ID: " + course.getId());
172      }
173    }
174  }
175}
176
177