find overdue reservations
This commit is contained in:
@@ -3,7 +3,7 @@ package io.wkrzywiec.hexagonal.library.borrowing;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ActiveUser;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.BookReservedEvent;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.Days;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.MaxReservationInterval;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.DueDate;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.MakeBookAvailableCommand;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.OverdueReservation;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservationDetails;
|
||||
@@ -18,6 +18,8 @@ import io.wkrzywiec.hexagonal.library.borrowing.ports.incoming.ReserveBook;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.ports.outgoing.BorrowingDatabase;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.ports.outgoing.BorrowingEventPublisher;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
public class BorrowingFacade implements MakeBookAvailable, ReserveBook, CancelOverdueReservations {
|
||||
@@ -53,8 +55,8 @@ public class BorrowingFacade implements MakeBookAvailable, ReserveBook, CancelOv
|
||||
|
||||
@Override
|
||||
public void cancelOverdueReservations() {
|
||||
MaxReservationInterval maxReservationInterval = new MaxReservationInterval(new Days(3L));
|
||||
List<OverdueReservation> overdueReservationList = database.findReservationsAfter(maxReservationInterval);
|
||||
DueDate dueDate = new DueDate(Instant.now().plus(3L, ChronoUnit.DAYS));
|
||||
List<OverdueReservation> overdueReservationList = database.findReservationsAfter(dueDate);
|
||||
overdueReservationList.forEach(
|
||||
overdue -> database.setBookAvailable(overdue.getBookIdentificationAsLong()));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.wkrzywiec.hexagonal.library.borrowing.infrastructure;
|
||||
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ActiveUser;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.AvailableBook;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.MaxReservationInterval;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.DueDate;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.OverdueReservation;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservationDetails;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservationId;
|
||||
@@ -10,11 +10,14 @@ import io.wkrzywiec.hexagonal.library.borrowing.model.ReservedBook;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.ports.outgoing.BorrowingDatabase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BorrowingDatabaseAdapter implements BorrowingDatabase {
|
||||
@@ -96,7 +99,13 @@ public class BorrowingDatabaseAdapter implements BorrowingDatabase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OverdueReservation> findReservationsAfter(MaxReservationInterval maxReservationInterval) {
|
||||
return null;
|
||||
public List<OverdueReservation> findReservationsAfter(DueDate dueDate) {
|
||||
List<OverdueReservationEntity> entities = jdbcTemplate.query(
|
||||
"SELECT id AS reservationId, book_id AS bookIdentification FROM reserved WHERE reserved_date > ?",
|
||||
new BeanPropertyRowMapper<OverdueReservationEntity>(OverdueReservationEntity.class),
|
||||
Timestamp.from(dueDate.asInstant()));
|
||||
return entities.stream()
|
||||
.map(entity -> new OverdueReservation(entity.getReservationId(), entity.getBookIdentification()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.wkrzywiec.hexagonal.library.borrowing.infrastructure;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class OverdueReservationEntity {
|
||||
private Long reservationId;
|
||||
private Long bookIdentification;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.wkrzywiec.hexagonal.library.borrowing.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class DueDate {
|
||||
private final Instant timeStamp;
|
||||
|
||||
public Instant asInstant(){
|
||||
return timeStamp;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package io.wkrzywiec.hexagonal.library.borrowing.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class MaxReservationInterval {
|
||||
public Days days;
|
||||
}
|
||||
@@ -4,10 +4,10 @@ import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class OverdueReservation {
|
||||
private final ReservationId reservationId;
|
||||
private final BookIdentification bookIdentification;
|
||||
private Long reservationId;
|
||||
private Long bookIdentification;
|
||||
|
||||
public Long getBookIdentificationAsLong() {
|
||||
return bookIdentification.getValueAsLong();
|
||||
return bookIdentification;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.wkrzywiec.hexagonal.library.borrowing.ports.outgoing;
|
||||
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ActiveUser;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.AvailableBook;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.MaxReservationInterval;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.DueDate;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.OverdueReservation;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservationDetails;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservedBook;
|
||||
@@ -15,5 +15,5 @@ public interface BorrowingDatabase {
|
||||
Optional<AvailableBook> getAvailableBook(Long bookId);
|
||||
Optional<ActiveUser> getActiveUser(Long userId);
|
||||
ReservationDetails save(ReservedBook reservedBook);
|
||||
List<OverdueReservation> findReservationsAfter(MaxReservationInterval maxReservationInterval);
|
||||
List<OverdueReservation> findReservationsAfter(DueDate dueDate);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.wkrzywiec.hexagonal.library.borrowing;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ActiveUser;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.AvailableBook;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.BookIdentification;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.MaxReservationInterval;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.DueDate;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.OverdueReservation;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservationDetails;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservationId;
|
||||
@@ -12,7 +12,6 @@ import io.wkrzywiec.hexagonal.library.borrowing.ports.outgoing.BorrowingDatabase
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
@@ -58,15 +57,15 @@ public class InMemoryBorrowingDatabase implements BorrowingDatabase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OverdueReservation> findReservationsAfter(MaxReservationInterval maxReservationInterval) {
|
||||
public List<OverdueReservation> findReservationsAfter(DueDate dueDate) {
|
||||
return reservedBooks.values().stream()
|
||||
.filter(reservedBook ->
|
||||
reservedBook.getReservedDateAsInstant()
|
||||
.isAfter(Instant.now().plus(maxReservationInterval.getDays().getCount(), ChronoUnit.DAYS)))
|
||||
.isAfter(dueDate.asInstant()))
|
||||
.map(reservedBook ->
|
||||
new OverdueReservation(
|
||||
new ReservationId(1L),
|
||||
new BookIdentification(reservedBook.getIdAsLong())))
|
||||
1L,
|
||||
reservedBook.getIdAsLong()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import io.wkrzywiec.hexagonal.library.BookTestData;
|
||||
import io.wkrzywiec.hexagonal.library.UserTestData;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ActiveUser;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.AvailableBook;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.DueDate;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.OverdueReservation;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservationDetails;
|
||||
import io.wkrzywiec.hexagonal.library.borrowing.model.ReservedBook;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -14,6 +16,9 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -39,10 +44,7 @@ public class BorrowingDatabaseAdapterITCase {
|
||||
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
|
||||
public void shouldSaveAvailableBook(){
|
||||
//given
|
||||
Long bookId = jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM book WHERE title = ?",
|
||||
Long.class,
|
||||
BookTestData.homoDeusBookTitle());
|
||||
Long bookId = getHomoDeusBookId();
|
||||
|
||||
//when
|
||||
database.setBookAvailable(bookId);
|
||||
@@ -61,10 +63,7 @@ public class BorrowingDatabaseAdapterITCase {
|
||||
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
|
||||
public void shouldGetAvailableBook(){
|
||||
//given
|
||||
Long bookId = jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM book WHERE title = ?",
|
||||
Long.class,
|
||||
BookTestData.homoDeusBookTitle());
|
||||
Long bookId = getHomoDeusBookId();
|
||||
|
||||
//when
|
||||
Optional<AvailableBook> availableBookOptional = database.getAvailableBook(bookId);
|
||||
@@ -80,10 +79,7 @@ public class BorrowingDatabaseAdapterITCase {
|
||||
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
|
||||
public void shouldGetActiveUser() {
|
||||
//given
|
||||
Long activeUserId = jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM user WHERE email = ?",
|
||||
Long.class,
|
||||
UserTestData.johnDoeEmail());
|
||||
Long activeUserId = getJohnDoeUserId();
|
||||
|
||||
//when
|
||||
Optional<ActiveUser> activeUserOptional = database.getActiveUser(activeUserId);
|
||||
@@ -99,15 +95,9 @@ public class BorrowingDatabaseAdapterITCase {
|
||||
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
|
||||
public void shouldSaveReservedBook(){
|
||||
//given
|
||||
Long bookId = jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM book WHERE title = ?",
|
||||
Long.class,
|
||||
BookTestData.homoDeusBookTitle());
|
||||
Long bookId = getHomoDeusBookId();
|
||||
|
||||
Long activeUserId = jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM user WHERE email = ?",
|
||||
Long.class,
|
||||
UserTestData.johnDoeEmail());
|
||||
Long activeUserId = getJohnDoeUserId();
|
||||
|
||||
ReservedBook reservedBook = new ReservedBook(bookId, activeUserId);
|
||||
|
||||
@@ -119,4 +109,40 @@ public class BorrowingDatabaseAdapterITCase {
|
||||
assertEquals(activeUserId, reservationDetails.getReservedBook().getAssignedUserIdAsLong());
|
||||
assertTrue(reservationDetails.getReservationId().getIdAsLong() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Find book after 3 days of reservation")
|
||||
@Sql({"/book-and-user.sql"})
|
||||
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
|
||||
public void shouldFindOverdueReservations(){
|
||||
//given
|
||||
DueDate thirdDayAfterReservation = new DueDate(Instant.now().plus(3, ChronoUnit.DAYS));
|
||||
Long overdueBookId = getHomoDeusBookId();
|
||||
Long johnDoeUserId = getJohnDoeUserId();
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO public.reserved (book_id, user_id, reserved_date) VALUES (?, ?, ?)",
|
||||
overdueBookId,
|
||||
johnDoeUserId,
|
||||
Instant.now().plus(3, ChronoUnit.DAYS));
|
||||
|
||||
//when
|
||||
OverdueReservation overdueReservation = database.findReservationsAfter(thirdDayAfterReservation).get(0);
|
||||
|
||||
//then
|
||||
assertEquals(overdueBookId, overdueReservation.getBookIdentificationAsLong());
|
||||
}
|
||||
|
||||
private Long getHomoDeusBookId(){
|
||||
return jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM book WHERE title = ?",
|
||||
Long.class,
|
||||
BookTestData.homoDeusBookTitle());
|
||||
}
|
||||
|
||||
private Long getJohnDoeUserId(){
|
||||
return jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM user WHERE email = ?",
|
||||
Long.class,
|
||||
UserTestData.johnDoeEmail());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user