find overdue reservations

This commit is contained in:
Wojtek Krzywiec
2020-05-30 21:30:56 +02:00
parent 943693bd1d
commit 62c683fb63
9 changed files with 96 additions and 47 deletions

View File

@@ -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()));
}

View File

@@ -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());
}
}

View File

@@ -0,0 +1,9 @@
package io.wkrzywiec.hexagonal.library.borrowing.infrastructure;
import lombok.Data;
@Data
public class OverdueReservationEntity {
private Long reservationId;
private Long bookIdentification;
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}