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 AcademicTerm entities in the database.
009 * Demonstrates JDBC operations with date fields: CREATE, READ, UPDATE, DELETE.
010 */
011public class AcademicTermDAOImpl implements AcademicTermDAO {
012
013  private final Connection connection;
014
015  /**
016   * Creates a new AcademicTermDAOImpl with the specified database connection.
017   *
018   * @param connection the database connection to use
019   */
020  public AcademicTermDAOImpl(Connection connection) {
021    this.connection = connection;
022  }
023
024  /**
025   * Drops the academic_terms 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 academic_terms");
033    }
034  }
035
036  /**
037   * Creates the academic_terms table in the database if it does not already exist.
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 IF NOT EXISTS academic_terms (" +
046        "  id IDENTITY PRIMARY KEY," +
047        "  name VARCHAR(255) NOT NULL," +
048        "  start_date DATE NOT NULL," +
049        "  end_date DATE NOT NULL" +
050        ")"
051      );
052    }
053  }
054
055  /**
056   * Saves an academic term to the database.
057   * The term's ID will be automatically generated by the database and set on the object.
058   *
059   * @param term the academic term to save
060   * @throws SQLException if a database error occurs
061   */
062  @Override
063  public void save(AcademicTerm term) throws SQLException {
064    String sql = "INSERT INTO academic_terms (name, start_date, end_date) VALUES (?, ?, ?)";
065
066    try (PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
067      statement.setString(1, term.getName());
068      statement.setDate(2, Date.valueOf(term.getStartDate()));
069      statement.setDate(3, Date.valueOf(term.getEndDate()));
070      statement.executeUpdate();
071
072      // Retrieve the auto-generated ID and set it on the term object
073      try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
074        if (generatedKeys.next()) {
075          int generatedId = generatedKeys.getInt(1);
076          term.setId(generatedId);
077        } else {
078          throw new SQLException("Creating academic term failed, no ID obtained.");
079        }
080      }
081    }
082  }
083
084  /**
085   * Finds an academic term by its ID.
086   *
087   * @param id the ID to search for
088   * @return the academic term with the given ID, or null if not found
089   * @throws SQLException if a database error occurs
090   */
091  @Override
092  public AcademicTerm findById(int id) throws SQLException {
093    String sql = "SELECT id, name, start_date, end_date FROM academic_terms WHERE id = ?";
094
095    try (PreparedStatement statement = connection.prepareStatement(sql)) {
096      statement.setInt(1, id);
097
098      try (ResultSet resultSet = statement.executeQuery()) {
099        if (resultSet.next()) {
100          return extractAcademicTermFromResultSet(resultSet);
101        }
102      }
103    }
104
105    return null;
106  }
107
108  /**
109   * Finds an academic term by its name.
110   *
111   * @param name the name to search for
112   * @return the academic term with the given name, or null if not found
113   * @throws SQLException if a database error occurs
114   */
115  @Override
116  public AcademicTerm findByName(String name) throws SQLException {
117    String sql = "SELECT id, name, start_date, end_date FROM academic_terms WHERE name = ?";
118
119    try (PreparedStatement statement = connection.prepareStatement(sql)) {
120      statement.setString(1, name);
121
122      try (ResultSet resultSet = statement.executeQuery()) {
123        if (resultSet.next()) {
124          return extractAcademicTermFromResultSet(resultSet);
125        }
126      }
127    }
128
129    return null;
130  }
131
132  /**
133   * Finds all academic terms in the database.
134   *
135   * @return a list of all academic terms
136   * @throws SQLException if a database error occurs
137   */
138  @Override
139  public List<AcademicTerm> findAll() throws SQLException {
140    List<AcademicTerm> terms = new ArrayList<>();
141    String sql = "SELECT id, name, start_date, end_date FROM academic_terms ORDER BY start_date";
142
143    try (Statement statement = connection.createStatement();
144         ResultSet resultSet = statement.executeQuery(sql)) {
145      while (resultSet.next()) {
146        terms.add(extractAcademicTermFromResultSet(resultSet));
147      }
148    }
149
150    return terms;
151  }
152
153  /**
154   * Updates an existing academic term in the database.
155   * Uses the term's ID to identify which record to update.
156   *
157   * @param term the academic term to update
158   * @throws SQLException if a database error occurs
159   */
160  @Override
161  public void update(AcademicTerm term) throws SQLException {
162    String sql = "UPDATE academic_terms SET name = ?, start_date = ?, end_date = ? WHERE id = ?";
163
164    try (PreparedStatement statement = connection.prepareStatement(sql)) {
165      statement.setString(1, term.getName());
166      statement.setDate(2, Date.valueOf(term.getStartDate()));
167      statement.setDate(3, Date.valueOf(term.getEndDate()));
168      statement.setInt(4, term.getId());
169
170      int rowsAffected = statement.executeUpdate();
171      if (rowsAffected == 0) {
172        throw new SQLException("Update failed, no academic term found with ID: " + term.getId());
173      }
174    }
175  }
176
177  /**
178   * Deletes an academic term from the database by ID.
179   *
180   * @param id the ID of the academic term to delete
181   * @throws SQLException if a database error occurs
182   */
183  @Override
184  public void delete(int id) throws SQLException {
185    String sql = "DELETE FROM academic_terms WHERE id = ?";
186
187    try (PreparedStatement statement = connection.prepareStatement(sql)) {
188      statement.setInt(1, id);
189      int rowsAffected = statement.executeUpdate();
190
191      if (rowsAffected == 0) {
192        throw new SQLException("Delete failed, no academic term found with ID: " + id);
193      }
194    }
195  }
196
197  /**
198   * Extracts an AcademicTerm object from the current row of a ResultSet.
199   *
200   * @param resultSet the result set positioned at an academic term row
201   * @return an AcademicTerm object with data from the result set
202   * @throws SQLException if a database error occurs
203   */
204  private AcademicTerm extractAcademicTermFromResultSet(ResultSet resultSet) throws SQLException {
205    int id = resultSet.getInt("id");
206    String name = resultSet.getString("name");
207    Date startDate = resultSet.getDate("start_date");
208    Date endDate = resultSet.getDate("end_date");
209
210    AcademicTerm term = new AcademicTerm(name, startDate.toLocalDate(), endDate.toLocalDate());
211    term.setId(id);
212    return term;
213  }
214}
215
216