Skip to content

Commit

Permalink
fix&test[model]: fix the repositories not only adding new rows
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucy Ciara Herud-Thomassen authored and Lucy Ciara Herud-Thomassen committed Mar 20, 2026
1 parent ab5ab06 commit 4444322
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 64 deletions.
24 changes: 13 additions & 11 deletions src/main/java/edu/group5/app/model/DBRepository.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package edu.group5.app.model;

import java.util.HashMap;
import java.util.Map;
import java.util.List;

/**
* Abstract base class for repositories that store their data
* in a database-related structure.
*
* <p>
* Extends {@link Repository} and specifies that the content
* is stored as a {@link Map}.
* Extends {@link Repository} and specifies that the content
* is stored as a {@link Map}.
* </p>
*/
public abstract class DBRepository<K, V> extends Repository<K, V> {
protected final Map<K, V> contentLock;

/**
* Constructs a DBRepository with the given content.
*
Expand All @@ -23,19 +26,18 @@ protected DBRepository(Map<K, V> content) {
this.contentLock = new HashMap<>();
}

protected void updateContentLock() {
synchronized (contentLock) {
contentLock.clear();
contentLock.putAll(this.content);
}
}
protected abstract void updateContentLock();

public abstract boolean addContent(V value);

/**
* Exports the repository content as a list of Object arrays, where each array represents a row of data.
* This method is intended for converting the repository content into a format suitable for database storage or export.
* @return a List of Object arrays representing the repository content for database export
* Exports the repository content as a list of Object arrays, where each array
* represents a row of data.
* This method is intended for converting the repository content into a format
* suitable for database storage or export.
*
* @return a List of Object arrays representing the repository content for
* database export
*/
public abstract List<Object[]> export();
}
87 changes: 53 additions & 34 deletions src/main/java/edu/group5/app/model/donation/DonationRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@
* Repository class for Donation.
*
* <p>
* Extends {@link DBRepository} and manages Donation entities.
* Extends {@link DBRepository} and manages Donation entities.
* </p>
*/
public class DonationRepository extends DBRepository<Integer, Donation> {
private final HashMap<Integer, Donation> content;

/**
* Constructs DonationRepository from a list of Object[] rows from the database.
* @param rows List of Object[] representing donations from the DB.
* Each row must have 6 elements:
* [donationId, userId, organizationId, amount, date, paymentMethod]
* @throws IllegalArgumentException if the input list is null or any row is invalid
*
* @param rows List of Object[] representing donations from the DB.
* Each row must have 6 elements:
* [donationId, userId, organizationId, amount, date, paymentMethod]
* @throws IllegalArgumentException if the input list is null or any row is
* invalid
*/
public DonationRepository(List<Object[]> rows) {
super(new HashMap<>());
Expand All @@ -35,36 +37,52 @@ public DonationRepository(List<Object[]> rows) {
}
this.content = new HashMap<>();
for (Object[] row : rows) {
if (row == null || row.length != 6 ) {
if (row == null || row.length != 6) {
throw new IllegalArgumentException("Each row must contain exactly 6 elements");
}
int donationId = (int) row[0];
int customerId = (int) row[1];
int organizationId = (int) row[2];
int organizationId = (int) row[2];
BigDecimal amount = (BigDecimal) row[3];
Timestamp date = (Timestamp) row[4];
String paymentMethod = (String) row[5];

Donation donation = new Donation(donationId, customerId, organizationId, amount, date, paymentMethod);
this.content.put(donationId, donation);
}
super.updateContentLock();
this.updateContentLock();
}

@Override
protected void updateContentLock() {
synchronized (contentLock) {
this.contentLock.clear();
this.contentLock.putAll(this.content);
}
}

@Override
public List<Object[]> export() {
return content.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> { Donation donation = entry.getValue();
return new Object[] {
donation.donationId(), donation.userId(),
donation.organizationId(), donation.amount(),
donation.date(), donation.paymentMethod()};})
.toList();
Map<Integer, Donation> output = new HashMap<>(this.content);
for (int i : super.contentLock.keySet()) {
output.remove(i);
}
this.updateContentLock();
return output.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> {
Donation donation = entry.getValue();
return new Object[] {
donation.donationId(), donation.userId(),
donation.organizationId(), donation.amount(),
donation.date(), donation.paymentMethod() };
})
.toList();
}

/**
* Retrieves a donation by its ID.
*
* @param donationId the ID of the donation to retrieve
* @return the Donation object with the specified ID, or null if not found
* @throws IllegalArgumentException if the donationId is not positive
Expand All @@ -77,10 +95,12 @@ public Donation getDonationById(int donationId) {
}

/**
* Generates the next donation ID based on the current maximum ID in the repository.
* Generates the next donation ID based on the current maximum ID in the
* repository.
*
* @return the next donation ID to be used for a new donation
*/
public int getNextDonationId() {
public int getNextDonationId() {
return content.keySet().stream().max(Integer::compareTo).orElse(0) + 1;
} /* TODO change this when data database is introduced */

Expand All @@ -91,22 +111,22 @@ public Map<Integer, Donation> getAllDonations() {
/**
* Adds a new donation to the repository
* <p>
* The donation is stored using its {@code donationId} as the key.
* If a donation with the same ID already exists, the donation
* will not be added.
* The donation is stored using its {@code donationId} as the key.
* If a donation with the same ID already exists, the donation
* will not be added.
* </p>
*
* @param donation the donation to add
* @return {@code true} if the donation was successfully added, and
* {@code false} if a donation with the same ID already exists
* {@code false} if a donation with the same ID already exists
*/
@Override
public boolean addContent(Donation donation) {
if (donation == null) {
throw new IllegalArgumentException("Donation cannot be null");
}
if (content.containsKey(donation.donationId())){
return false;
if (content.containsKey(donation.donationId())) {
return false;
}
this.content.put(donation.donationId(), donation);
return true;
Expand All @@ -116,12 +136,12 @@ public boolean addContent(Donation donation) {
* Returns all donations sorted by date (ascending).
*
* <p>
* The returned map preserves the sorted order.
* The returned map preserves the sorted order.
* </p>
*
* @return a new {@link HashMap} containing the donations sorted by date
*/
public HashMap<Integer, Donation> sortByDate(){
public HashMap<Integer, Donation> sortByDate() {
return content.entrySet().stream()
.sorted(Map.Entry.comparingByValue(
Comparator.comparing(Donation::date)))
Expand All @@ -136,7 +156,7 @@ public HashMap<Integer, Donation> sortByDate(){
* Returns all donations sorted by amount (ascending).
*
* <p>
* The returned map preserves the sorted order from lowest to highest amount.
* The returned map preserves the sorted order from lowest to highest amount.
* </p>
*
* @return a new {@link HashMap} containing the donations sorted by amount.
Expand All @@ -149,12 +169,12 @@ public HashMap<Integer, Donation> sortByAmount() {
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
LinkedHashMap::new));
}

/**
* Returns all donations associated with a specific organization.
*
* @param orgNumber the organization ID to filter by
* @return a map containing all donations that belong to the given organization
* @throws IllegalArgumentException if the orgNumber is not positive
Expand All @@ -165,17 +185,17 @@ public HashMap<Integer, Donation> filterByOrganization(int orgNumber) {
}
return content.entrySet()
.stream()
.filter(entry -> entry.getValue().organizationId() == orgNumber)
.filter(entry -> entry.getValue().organizationId() == orgNumber)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
LinkedHashMap::new));
}

/**
* Returns all donations made by a specific user.
*
* @param userId the user ID to filter by
* @return a map containing all donations that belong to the given user
* @throws IllegalArgumentException if the userId is not positive
Expand All @@ -190,7 +210,6 @@ public HashMap<Integer, Donation> filterByUser(int userId) {
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
LinkedHashMap::new));
}
}
61 changes: 42 additions & 19 deletions src/main/java/edu/group5/app/model/user/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

import edu.group5.app.model.DBRepository;

public class UserRepository extends DBRepository<Integer, User>{
public class UserRepository extends DBRepository<Integer, User> {
public final static String ROLE_CUSTOMER = "Customer";

/**
* Constructs UserRepository using Hashmap,
* and extends the content from DBRepository.
*
* @param content the underlying map used to store users,
* where the key represents the user ID
*/
Expand All @@ -20,7 +22,7 @@ public UserRepository(List<Object[]> rows) {
throw new IllegalArgumentException("The list of rows cannot be null");
}
for (Object[] row : rows) {
if (row == null || row.length != 6 ) {
if (row == null || row.length != 6) {
throw new IllegalArgumentException("Each row must contain exactly 6 elements");
}
int userId = (int) row[0];
Expand All @@ -38,28 +40,46 @@ public UserRepository(List<Object[]> rows) {
}
this.content.put(userId, user);
}
super.updateContentLock();
this.updateContentLock();
}

@Override
protected void updateContentLock() {
synchronized (contentLock) {
this.contentLock.clear();
this.contentLock.putAll(this.content);
}
}

@Override
public List<Object[]> export() {
return content.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> { User user = entry.getValue();
return new Object[]{user.getUserId(), user.getRole(),
user.getFirstName(), user.getLastName(),
user.getEmail(), user.getPasswordHash()};})
Map<Integer, User> output = new HashMap<>(this.content);
for (int i : contentLock.keySet()) {
output.remove(i);
}
this.updateContentLock();
return output.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> {
User user = entry.getValue();
return new Object[] { user.getUserId(), user.getRole(),
user.getFirstName(), user.getLastName(),
user.getEmail(), user.getPasswordHash() };
})
.toList();

}

public HashMap<Integer, User> getUsers() {
return new HashMap<>(content);
}

/**
* Retrieves a user by their unique identifier.
*
* @param userId the unique identifier of the user to retrieve
* @return the user with the specified ID, or {@code null} if no such user exists
* @return the user with the specified ID, or {@code null} if no such user
* exists
* @throws IllegalArgumentException if the userId is not positive
*/
public User getUserById(int userId) {
Expand All @@ -72,12 +92,13 @@ public User getUserById(int userId) {
/**
* Generates the next user ID based on repository size.
* Uses size+1 and then moves forward if that ID is already taken.
*
* @return the next available user ID
* @throws IllegalStateException if no available user ID can be found
*/
public int getNextUserId() {
public int getNextUserId() {
if (content.isEmpty()) {
return 1;
return 1;
}
int maxKey = content.keySet().stream().max(Integer::compareTo).orElseThrow(
() -> new IllegalStateException("No keys found"));
Expand All @@ -88,21 +109,21 @@ public int getNextUserId() {
/**
* Adds a new user to the repository
* <p>
* The user is stored using its {@code userId} as the key.
* If a user with the same ID already exists, the user
* will not be added.
* The user is stored using its {@code userId} as the key.
* If a user with the same ID already exists, the user
* will not be added.
* </p>
*
* @param user the user to add
* @return {@code true} if the user was successfully added, and
* {@code false} if a user with the same ID already exists
* {@code false} if a user with the same ID already exists
*/
@Override
public boolean addContent(User user) {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
if (content.containsKey(user.getUserId())){
if (content.containsKey(user.getUserId())) {
return false;
}
this.content.put(user.getUserId(), user);
Expand All @@ -111,8 +132,10 @@ public boolean addContent(User user) {

/**
* Finds a user by their email address.
*
* @param email the email address of the user to find
* @return the user with the specified email address, or {@code null} if no such user exists
* @return the user with the specified email address, or {@code null} if no such
* user exists
*/
public User findUserByEmail(String email) {
if (email == null || email.trim().isEmpty()) {
Expand All @@ -122,5 +145,5 @@ public User findUserByEmail(String email) {
.filter(user -> user.getEmail().equals(email))
.findFirst()
.orElse(null);
}
}
}
Loading

0 comments on commit 4444322

Please sign in to comment.