001package edu.pdx.cs.joy.family; 002 003import java.sql.*; 004import java.util.ArrayList; 005import java.util.List; 006import java.util.Map; 007 008/** 009 * Data Access Object implementation for managing Marriage entities in the database. 010 */ 011public class MarriageDAOImpl implements MarriageDAO { 012 013 private final Connection connection; 014 private final Map<Integer, Person> personCache; 015 016 /** 017 * Creates a new MarriageDAOImpl with the specified database connection. 018 * 019 * @param connection the database connection to use 020 * @param personCache a cache of persons to resolve marriage partners 021 */ 022 public MarriageDAOImpl(Connection connection, Map<Integer, Person> personCache) { 023 this.connection = connection; 024 this.personCache = personCache; 025 } 026 027 /** 028 * Drops the marriages table from the database if it exists. 029 * 030 * @param connection the database connection to use 031 * @throws SQLException if a database error occurs 032 */ 033 public static void dropTable(Connection connection) throws SQLException { 034 try (Statement statement = connection.createStatement()) { 035 statement.execute("DROP TABLE IF EXISTS marriages"); 036 } 037 } 038 039 /** 040 * Creates the marriages table in the database. 041 * 042 * @param connection the database connection to use 043 * @throws SQLException if a database error occurs 044 */ 045 public static void createTable(Connection connection) throws SQLException { 046 try (Statement statement = connection.createStatement()) { 047 statement.execute( 048 "CREATE TABLE IF NOT EXISTS marriages (" + 049 " husband_id INTEGER NOT NULL," + 050 " wife_id INTEGER NOT NULL," + 051 " marriage_date TIMESTAMP," + 052 " location VARCHAR(255)," + 053 " PRIMARY KEY (husband_id, wife_id)," + 054 " FOREIGN KEY (husband_id) REFERENCES persons(id)," + 055 " FOREIGN KEY (wife_id) REFERENCES persons(id)" + 056 ")" 057 ); 058 } 059 } 060 061 /** 062 * Saves a marriage to the database. 063 * 064 * @param marriage the marriage to save 065 * @throws SQLException if a database error occurs 066 */ 067 @Override 068 public void save(Marriage marriage) throws SQLException { 069 String sql = "INSERT INTO marriages (husband_id, wife_id, marriage_date, location) " + 070 "VALUES (?, ?, ?, ?)"; 071 072 try (PreparedStatement statement = connection.prepareStatement(sql)) { 073 statement.setInt(1, marriage.getHusband().getId()); 074 statement.setInt(2, marriage.getWife().getId()); 075 076 if (marriage.getDate() == null) { 077 statement.setNull(3, Types.TIMESTAMP); 078 } else { 079 statement.setTimestamp(3, new Timestamp(marriage.getDate().getTime())); 080 } 081 082 statement.setString(4, marriage.getLocation()); 083 084 statement.executeUpdate(); 085 } 086 } 087 088 /** 089 * Finds all marriages for a specific person ID. 090 * 091 * @param personId the person ID 092 * @return a list of marriages involving the person 093 * @throws SQLException if a database error occurs 094 */ 095 @Override 096 public List<Marriage> findByPersonId(int personId) throws SQLException { 097 List<Marriage> marriages = new ArrayList<>(); 098 String sql = "SELECT husband_id, wife_id, marriage_date, location " + 099 "FROM marriages WHERE husband_id = ? OR wife_id = ?"; 100 101 try (PreparedStatement statement = connection.prepareStatement(sql)) { 102 statement.setInt(1, personId); 103 statement.setInt(2, personId); 104 105 try (ResultSet resultSet = statement.executeQuery()) { 106 while (resultSet.next()) { 107 marriages.add(extractMarriageFromResultSet(resultSet)); 108 } 109 } 110 } 111 112 return marriages; 113 } 114 115 /** 116 * Finds all marriages in the database. 117 * 118 * @return a list of all marriages 119 * @throws SQLException if a database error occurs 120 */ 121 @Override 122 public List<Marriage> findAll() throws SQLException { 123 List<Marriage> marriages = new ArrayList<>(); 124 String sql = "SELECT husband_id, wife_id, marriage_date, location FROM marriages"; 125 126 try (Statement statement = connection.createStatement(); 127 ResultSet resultSet = statement.executeQuery(sql)) { 128 while (resultSet.next()) { 129 marriages.add(extractMarriageFromResultSet(resultSet)); 130 } 131 } 132 133 return marriages; 134 } 135 136 /** 137 * Deletes a marriage from the database. 138 * 139 * @param husbandId the husband's ID 140 * @param wifeId the wife's ID 141 * @throws SQLException if a database error occurs 142 */ 143 @Override 144 public void delete(int husbandId, int wifeId) throws SQLException { 145 String sql = "DELETE FROM marriages WHERE husband_id = ? AND wife_id = ?"; 146 147 try (PreparedStatement statement = connection.prepareStatement(sql)) { 148 statement.setInt(1, husbandId); 149 statement.setInt(2, wifeId); 150 int rowsAffected = statement.executeUpdate(); 151 152 if (rowsAffected == 0) { 153 throw new SQLException("Delete failed, no marriage found for husband ID: " + 154 husbandId + " and wife ID: " + wifeId); 155 } 156 } 157 } 158 159 /** 160 * Extracts a Marriage object from the current row of a ResultSet. 161 * 162 * @param resultSet the result set positioned at a marriage row 163 * @return a Marriage object with data from the result set 164 * @throws SQLException if a database error occurs 165 */ 166 private Marriage extractMarriageFromResultSet(ResultSet resultSet) throws SQLException { 167 int husbandId = resultSet.getInt("husband_id"); 168 int wifeId = resultSet.getInt("wife_id"); 169 170 Person husband = personCache.get(husbandId); 171 Person wife = personCache.get(wifeId); 172 173 if (husband == null || wife == null) { 174 throw new SQLException("Cannot create marriage: Person not found in cache. " + 175 "Husband ID: " + husbandId + ", Wife ID: " + wifeId); 176 } 177 178 Marriage marriage = new Marriage(husband, wife); 179 180 Timestamp marriageDate = resultSet.getTimestamp("marriage_date"); 181 if (marriageDate != null) { 182 marriage.setDate(new java.util.Date(marriageDate.getTime())); 183 } 184 185 marriage.setLocation(resultSet.getString("location")); 186 187 return marriage; 188 } 189} 190