Skip to content

Commit

Permalink
Feat: DAO data acsess object(s) will help SETTING new data to database
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianBalunan committed Mar 11, 2026
1 parent 609ca49 commit 3f55f66
Show file tree
Hide file tree
Showing 2 changed files with 277 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
package ntnu.sytemutvikling.team6.DAO;

import ntnu.sytemutvikling.team6.scraper.APICharityData;

import java.sql.*;
import java.util.List;

/**
* Manages the charity
* <p>
* This class is responsible for establishing connections using environment variables
* and maintaining the {@code charities} table based on data retrieved from the IK API.
* </p>
*/

public class CharityDAO {

import APICharityData;

import java.sql.*;
import java.util.List;



public class DatabaseManager {
private final String databaseURL;
private final String username;
private final String password;

/**
Constructs a new {@code DatabaseManager} using database credentials
* retrieved from system environment variables.
* <p>
* Required environment variables:
* <ul>
* <li>{@code HMH_DB_URL}</li>
* <li>{@code HMH_DB_USERNAME}</li>
* <li>{@code HMH_DB_PASSWORD}</li>
* </ul>
* </p>
*
* @throws IllegalStateException if either databaseURL, username, or password is {@code null} or blank
*/

// Values stored in system environment variables for security (using ntnu's phpmyadmin for this project)
public DatabaseManager() {
this.databaseURL = System.getenv("HMH_DB_URL");
this.username = System.getenv("HMH_DB_USERNAME");
this.password = System.getenv("HMH_DB_PASSWORD");

if (this.databaseURL == null || this.databaseURL.isBlank()) {
throw new IllegalStateException("Database environment variable URL has not been set");
}

if (this.username == null || this.username.isBlank()) {
throw new IllegalStateException("Username environment variable has not been set");
}

if (this.password == null || this.password.isBlank()) {
throw new IllegalStateException("Password environment variable has not been set");
}
}

/**
* Constructs a new {@code DatabaseManager} using database credentials
* <p>
* Used primarily for JUnit tests. Production should use the constructor
* using environment variables.
* </p>
*
* @param databaseURL the url to the database
* @param username the username used to log in to the database
* @param password the password used to log in to the database
* @throws IllegalArgumentException if databaseURL, username, or password is
* {@code null} or blank
*/

public DatabaseManager(String databaseURL, String username, String password) {
this.databaseURL = databaseURL;
this.username = username;
this.password = password;

if (this.databaseURL == null || this.databaseURL.isBlank()) {
throw new IllegalArgumentException("Database environment variable URL has not been set");
}

if (this.username == null || this.username.isBlank()) {
throw new IllegalArgumentException("Username environment variable has not been set");
}

if (this.password == null || this.password.isBlank()) {
throw new IllegalArgumentException("Password environment variable has not been set");
}
}

/**
* Creates the {@code charities} table if it does not already exist.
* <p>
* The table structure is based on fields from {@link APICharityData}.
* </p>
* @throws RuntimeException if a {@link SQLException} occurs while creating the table
*/

public void createTables() {
String sql_query = """
-- MySQL Workbench Forward Engineering
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
-- -----------------------------------------------------
-- Schema HelpMeHelp
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema HelpMeHelp
-- -----------------------------------------------------
--CREATE SCHEMA IF NOT EXISTS `HelpMeHelp` DEFAULT CHARACTER SET utf8 ;
--USE `HelpMeHelp` ;
USE apbaluna;
-- -----------------------------------------------------
-- Table `HelpMeHelp`.`Charities`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `HelpMeHelp`.`Charities` (
`UUID` CHAR(36) NOT NULL,
`charity_name` VARCHAR(255) NOT NULL,
`charity_description` VARCHAR(255) NOT NULL,
`isVerified` TINYINT NOT NULL,
`category` VARCHAR(45) NOT NULL,
PRIMARY KEY (`UUID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `HelpMeHelp`.`Donations`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `HelpMeHelp`.`Donations` (
`UUID` CHAR(36) NOT NULL,
`amount` DECIMAL NOT NULL,
`date` DATE NOT NULL,
`Charities_UUID` CHAR(36) NOT NULL,
PRIMARY KEY (`UUID`),
INDEX `fk_Donations_Charities_idx` (`Charities_UUID` ASC) VISIBLE,
CONSTRAINT `fk_Donations_Charities`
FOREIGN KEY (`Charities_UUID`)
REFERENCES `HelpMeHelp`.`Charities` (`UUID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
""";

try (Connection conn = DriverManager.getConnection(databaseURL, username, password);
Statement s = conn.createStatement()) {

s.execute(sql_query);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("Error creating table.");
}
}

/**
* Synchronizes the {@code charities} table with the provided list of APICharityData.
* <p>
* Summary of function:
* <ul>
* <li>Inserts new records</li>
* <li>Updates existing records using {@code ON DUPLICATE KEY UPDATE}</li>
* <li>Removes database records that are not present in the provided list</li>
* </ul>
* A temporary table is used to determine which records should be deleted.
* </p>
*
* @param charities a list of ApiCharityDaya objects
* @throws RuntimeException if a {@link SQLException} occurs during database synchronization
*/

public void updateCharities(List<APICharityData> charities) {
Connection conn = null;
try {
conn = DriverManager.getConnection(databaseURL, username, password);
conn.setAutoCommit(false);
// Inserts objects values into charities
String sql_query = """
INSERT INTO charities (org_number, name, status, url, is_pre_approved)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
status = VALUES(status),
url = VALUES(url),
is_pre_approved = VALUES(is_pre_approved)
""";

try (PreparedStatement s = conn.prepareStatement(sql_query)) {
for (APICharityData charity : charities) {
s.setString(1, charity.getOrg_number().replaceAll("\\s", ""));
s.setString(2, charity.getName());
s.setString(3, charity.getStatus());
s.setString(4, charity.getUrl());
s.setBoolean(5, charity.getIs_pre_approved());

s.addBatch();
}
s.executeBatch();
}


// Temporary table for parity check
sql_query = "CREATE TEMPORARY TABLE temp (org_number VARCHAR(100) PRIMARY KEY)";
try (PreparedStatement temp_create = conn.prepareStatement(sql_query)) {
temp_create.execute();
}

String sql_update_temp_table = "INSERT INTO temp (org_number) VALUES (?)";
try (PreparedStatement temp_update = conn.prepareStatement(sql_update_temp_table)) {
for (APICharityData charity : charities) {
temp_update.setString(1, charity.getOrg_number().replaceAll("\\s", ""));
temp_update.addBatch();
}
temp_update.executeBatch();
}



// Removes records not found in the list from charities table
sql_query = """
DELETE FROM charities c
WHERE NOT EXISTS (
SELECT 1
FROM temp t
WHERE c.org_number = t.org_number
)
""";

try (PreparedStatement delete_old_records = conn.prepareStatement(sql_query)){
delete_old_records.execute();
}

conn.commit();
} catch (SQLException e) {

if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}

e.printStackTrace();
throw new RuntimeException("ERROR: Something went wrong during updating charities table.");
} finally {
if (conn != null) {
try {
conn.setAutoCommit(true);
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package ntnu.sytemutvikling.team6.DAO;

public class DonationDAO {
}

0 comments on commit 3f55f66

Please sign in to comment.