-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ticket-booking code review #1
base: review
Are you sure you want to change the base?
Changes from all commits
725d5f6
6aa823d
35f8d74
1397527
b0513c9
5217170
1230b38
3e7931f
1428ad9
1f69fb7
fea484d
9d2e815
61a73bb
56b4831
850caac
40be48e
0a1d75e
9fa7966
b034c09
3d5dd15
ffacc60
f38fd0b
ab6b679
0918df0
fc861b1
3c076c0
2c9c3c7
9723963
5c9e668
0c7dfd1
bb90c87
aaf2ea4
b92b053
321b6ce
247faaa
181db35
2317f98
8383712
3c14dbf
5571b80
e41c034
0d688a4
3508cb6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# ticket-booking | ||
|
||
|
||
### Additional assumptions | ||
- Requested time interval for point 1. of the scenario can be at max 1 week. | ||
- Search for movie screenings for point 1. of the scenario can apply only to future screenings. | ||
- Each row has the same number of seats | ||
- Reservation expiration date is set to 5 minutes after booking the seats | ||
- All tickets for single reservation must have the same currency | ||
|
||
--- | ||
|
||
### How to build and run | ||
|
||
To build and run the app you can use provided bash script | ||
``` | ||
./buildAndRun.sh | ||
``` | ||
Or you can use mvnw directly | ||
``` | ||
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev | ||
``` | ||
|
||
System uses in-memory database with initialized dummy data. | ||
|
||
--- | ||
You can use useCase.sh bash script to execute required use case. | ||
It performs 3 REST calls and prints responses to the console. | ||
``` | ||
./useCase.sh | ||
``` | ||
|
||
Example output: | ||
```agsl | ||
1. Fetch movie screenings that start between 15:20 and 18:00 on 05.04.2023: | ||
[{"movieTitle":"Django","screeningTimes":[{"screeningId":"4941fe3f-611b-48a2-b31d-ed2fc551069f","start":"2023-04-05T16:30:00","end":"2023-04-05T18:00:00"}]},{"movieTitle":"Hateful 8","screeningTimes":[{"screeningId":"cd174523-4630-4f36-9611-5a78d663e15a","start":"2023-04-05T15:30:00","end":"2023-04-05T17:00:00"},{"screeningId":"fd612a91-db41-4bc3-a794-f8c1a3d8e1d2","start":"2023-04-05T17:30:00","end":"2023-04-05T19:00:00"}]},{"movieTitle":"Pulp Fiction","screeningTimes":[{"screeningId":"a80be8de-0c61-4e0a-a3e5-95b055845c18","start":"2023-04-05T16:00:00","end":"2023-04-05T17:30:00"}]}] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fajnie byłoby to przepuścić przez jakiś formater (jq?). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rzeczywiście byłoby czytelniej, sorka :) |
||
|
||
2. Fetch Django screening details with an id of 4941fe3f-611b-48a2-b31d-ed2fc551069f: | ||
{"roomName":"Room C","rowsNumber":5,"seatsInRowNumber":5,"availableSeats":[{"rowNumber":1,"seatNumber":4},{"rowNumber":1,"seatNumber":5},{"rowNumber":2,"seatNumber":1},{"rowNumber":2,"seatNumber":2},{"rowNumber":2,"seatNumber":3},{"rowNumber":2,"seatNumber":4},{"rowNumber":2,"seatNumber":5},{"rowNumber":3,"seatNumber":1},{"rowNumber":3,"seatNumber":2},{"rowNumber":3,"seatNumber":3},{"rowNumber":3,"seatNumber":4},{"rowNumber":3,"seatNumber":5},{"rowNumber":4,"seatNumber":1},{"rowNumber":4,"seatNumber":2},{"rowNumber":4,"seatNumber":3},{"rowNumber":4,"seatNumber":4},{"rowNumber":4,"seatNumber":5},{"rowNumber":5,"seatNumber":1},{"rowNumber":5,"seatNumber":2},{"rowNumber":5,"seatNumber":3},{"rowNumber":5,"seatNumber":4},{"rowNumber":5,"seatNumber":5}]} | ||
|
||
3. Book 3 seats for the screening. One adult, one child and one student: | ||
{"reservationId":"9011fe1c-9e19-4dd8-a2e2-9f26277a83fd","priceDto":{"currency":"PLN","amount":55.50},"expirationTime":"2023-03-05T20:10:26.054379365"} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
./mvnw clean spring-boot:run -Dspring-boot.run.profiles=dev |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,13 +15,23 @@ | |
<description>Ticket booking app</description> | ||
<properties> | ||
<java.version>17</java.version> | ||
<mapstruct.version>1.5.3.Final</mapstruct.version> | ||
<guava.version>31.1-jre</guava.version> | ||
</properties> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-data-jpa</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.h2database</groupId> | ||
<artifactId>h2</artifactId> | ||
<scope>runtime</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
|
@@ -32,6 +42,27 @@ | |
<artifactId>spring-boot-starter-test</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-validation</artifactId> | ||
<version>RELEASE</version> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To jeszcze działa? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ups, miało być bez wersji, powinna być z parenta. |
||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.assertj</groupId> | ||
<artifactId>assertj-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.mapstruct</groupId> | ||
<artifactId>mapstruct</artifactId> | ||
<version>${mapstruct.version}</version> | ||
</dependency> | ||
<!-- https://mvnrepository.com/artifact/com.google.guava/guava --> | ||
<dependency> | ||
<groupId>com.google.guava</groupId> | ||
<artifactId>guava</artifactId> | ||
<version>${guava.version}</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
|
@@ -48,6 +79,26 @@ | |
</excludes> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<configuration> | ||
<source>17</source> | ||
<target>17</target> | ||
<annotationProcessorPaths> | ||
<path> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<version>${lombok.version}</version> | ||
</path> | ||
<path> | ||
<groupId>org.mapstruct</groupId> | ||
<artifactId>mapstruct-processor</artifactId> | ||
<version>${mapstruct.version}</version> | ||
</path> | ||
</annotationProcessorPaths> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.elmc.booking.adapters.configuration; | ||
|
||
import com.elmc.booking.domain.ports.incoming.ReservationService; | ||
import com.elmc.booking.domain.ports.incoming.ScreeningService; | ||
import com.elmc.booking.domain.ports.outgoing.ReservationRepository; | ||
import com.elmc.booking.domain.ports.outgoing.ScreeningRepository; | ||
import com.elmc.booking.domain.ports.outgoing.TicketTypeRepository; | ||
import com.elmc.booking.domain.reservation.ReservationManagement; | ||
import com.elmc.booking.domain.screening.ScreeningManagement; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class ServicesConfiguration { | ||
|
||
@Bean | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Czemu tworzymy tak, a nie przez adnotację nad serwisem? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oczywiście można dodać adnotację na poziomie serwisu domenowego, ale chciałem, żeby domena nie zawierała springowych adnotacji. |
||
public ScreeningService getScreeningService(ScreeningRepository screeningRepository) { | ||
return new ScreeningManagement(screeningRepository); | ||
} | ||
|
||
@Bean | ||
public ReservationService getReservationService(ReservationRepository reservationRepository, | ||
TicketTypeRepository ticketTypeRepository, | ||
ScreeningRepository screeningRepository) { | ||
return new ReservationManagement(reservationRepository, ticketTypeRepository, screeningRepository); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package com.elmc.booking.adapters.incoming.rest; | ||
|
||
import com.elmc.booking.domain.reservation.exceptions.*; | ||
import com.elmc.booking.domain.screening.exceptions.*; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.ControllerAdvice; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
|
||
@Slf4j | ||
@ControllerAdvice | ||
public class ControllerExceptionHandler { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fajnie, że dużo tych wyjątków i obsłużone z głową! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dzięki :) |
||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> invalidScreeningTimeIntervalExceptionHandler(InvalidScreeningTimeIntervalException exception) { | ||
log.error("Exception thrown InvalidScreeningTimeIntervalException: {}", exception.getMessage(), exception); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kiedy dobrze jest logować na error a kiedy na warn? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error do błędów, które uniemożliwiają poprawne funkcjonowanie aplikacji, natomiast warn gdy coś jest nie tak, ale aplikacja działa prawidłowo. Tutaj można by to pozmieniać na warny. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dla mnie fajną regułą kciuka jest czy człowiek (administrator?) musi reagować - jak tak to error, jak nie to warn. |
||
ErrorMessage errorMessage = new ErrorMessage("startTime has to be before endTime [startTime: %s], [endTime: %s]" | ||
.formatted(exception.getStartTime(), exception.getStartTime())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> tooLongIntervalExceptionHandler(TooLongIntervalException exception) { | ||
log.error("Exception thrown TooLongIntervalException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("Time interval between two dates can be at max 1 week [startTime: %s], [endTime: %s]" | ||
.formatted(exception.getStartTime(), exception.getStartTime())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> searchForPastScreeningsExceptionHandler(SearchForPastScreeningsException exception) { | ||
log.error("Exception thrown SearchForPastScreeningsException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("Screenings search can only apply to future screenings [startTime: %s], [endTime: %s]" | ||
.formatted(exception.getStartTime(), exception.getStartTime())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> noSuchScreeningExceptionHandler(NoSuchScreeningException exception) { | ||
log.error("Exception thrown NoSuchScreeningException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("No screening was found for provided id: [screeningId: %s]" | ||
.formatted(exception.getScreeningId())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.NOT_FOUND); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> seatAlreadyBookedExceptionHandler(SeatAlreadyBookedException exception) { | ||
log.error("Exception thrown SeatAlreadyBookedException: Provided seats are already booked: [seatIds: {}]", | ||
exception.getSeatsToBook(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("Provided seats have been already booked by another client"); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> singleSeatLeftOutAfterBookingExceptionHandler(SingleSeatLeftOutAfterBookingException exception) { | ||
log.error("Exception thrown SingleSeatLeftOutAfterBookingException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage( | ||
"Cannot book provided seats as one seat would be left out between two booked seats"); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> invalidFirstnameExceptionHandler(InvalidFirstnameException exception) { | ||
log.error("Exception thrown InvalidFirstnameException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage( | ||
"Invalid firstname provided. Firstname must be at least 3 characters long [firstname: %s]" | ||
.formatted(exception.getFirstname())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> invalidSurnameExceptionHandler(InvalidSurnameException exception) { | ||
log.error("Exception thrown InvalidSurnameException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage( | ||
"Invalid surname provided. Surname must be at least 3 characters long [firstname: %s]" | ||
.formatted(exception.getSurname())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> noTicketsForReservationExceptionHandler(NoTicketsForReservationException exception) { | ||
log.error("Exception thrown NoTicketsForReservationException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("Reservation must apply to at least one seat"); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> sameSeatChosenMultipleTimesExceptionHandler(SameSeatChosenMultipleTimesException exception) { | ||
log.error("Exception thrown SameSeatChosenMultipleTimesException: Same seat was chosen multiple times [seatIds: {}]", | ||
exception.getSeatsToBook(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("You cannot chose the same seat more than once during booking"); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> bookingToLateExceptionHandler(BookingToLateException exception) { | ||
log.error("Exception thrown BookingToLateException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("Seats can be booked at least %d minutes before screening starts" | ||
.formatted(exception.getMinutesToBookBeforeScreening())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> seatsNotExistExceptionHandler(SeatsNotExistException exception) { | ||
log.error("Exception thrown SeatsNotExistException: Some provided seats do not exist for screening {}", | ||
exception.getSeatsToBook(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("Provided seats do not exist for given screening"); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> invalidTicketTypesExceptionHandler(InvalidTicketTypesException exception) { | ||
log.error("Exception thrown InvalidTicketTypesException: Some provided ticket types do not exist {}", | ||
exception.getProvidedTicketTypeNames(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage("Provided ticket types do not exist in the system"); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
@ExceptionHandler | ||
public ResponseEntity<ErrorMessage> differentCurrenciesExceptionHandler(DifferentCurrenciesException exception) { | ||
log.error("Exception thrown DifferentCurrenciesException: {}", exception.getMessage(), exception); | ||
ErrorMessage errorMessage = new ErrorMessage( | ||
"Only one currency can be used for single reservation [number of provided currencies: %d]" | ||
.formatted(exception.getNumberOfCurrencies())); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.UNPROCESSABLE_ENTITY); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.elmc.booking.adapters.incoming.rest; | ||
|
||
import lombok.Value; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
@Value | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Skoro to Java 17 to czy nie fajniej byłoby użyć recordów? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rekordy nie mogą mieć dodatkowych pól poza tymi z konstruktora. ErrorMessage był początkowo rekordem ale podawanie za każdym razem daty przy tworzeniu obiektu jakoś średnio mi wyglądało, więc zmieniłem to na klasę z ustawioną datą. |
||
public class ErrorMessage { | ||
LocalDateTime dateTime = LocalDateTime.now(); | ||
String description; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.elmc.booking.adapters.incoming.rest; | ||
|
||
import com.elmc.booking.domain.ports.dto.outgoing.CreatedReservationDto; | ||
import com.elmc.booking.adapters.incoming.rest.request.ReservationRequest; | ||
import com.elmc.booking.domain.ports.incoming.ReservationService; | ||
import jakarta.validation.Valid; | ||
import lombok.AllArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RequestMapping("/api/reservation") | ||
@RestController | ||
@Slf4j | ||
@AllArgsConstructor | ||
public class ReservationController { | ||
|
||
private ReservationService reservationService; | ||
|
||
@PostMapping | ||
@ResponseStatus(HttpStatus.CREATED) | ||
public CreatedReservationDto bookSeats(@RequestBody @Valid ReservationRequest reservationRequest) { | ||
log.debug("New reservation request received {}", reservationRequest); | ||
return reservationService.bookSeats(reservationRequest.toDto()); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.elmc.booking.adapters.incoming.rest; | ||
|
||
import com.elmc.booking.domain.ports.dto.outgoing.MovieScreeningsDto; | ||
import com.elmc.booking.domain.ports.dto.outgoing.ScreeningDetailsDto; | ||
import com.elmc.booking.domain.ports.incoming.ScreeningService; | ||
import lombok.AllArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.format.annotation.DateTimeFormat; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.UUID; | ||
|
||
@RequestMapping("/api/screening") | ||
@RestController | ||
@Slf4j | ||
@AllArgsConstructor | ||
public class ScreeningController { | ||
|
||
private final ScreeningService screeningService; | ||
|
||
@GetMapping | ||
@ResponseStatus(HttpStatus.OK) | ||
public List<MovieScreeningsDto> searchForScreenings(@RequestParam("start") | ||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) | ||
LocalDateTime start, | ||
@RequestParam("end") | ||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) | ||
LocalDateTime end) { | ||
log.debug("Search for movie screenings received [startTime: {}], [endTime: {}]", start, end); | ||
return screeningService.searchForMovieScreenings(start, end); | ||
} | ||
|
||
@GetMapping("/{screeningId}") | ||
@ResponseStatus(HttpStatus.OK) | ||
public ScreeningDetailsDto getScreeningDetails(@PathVariable UUID screeningId) { | ||
log.debug("Request for screening details received [screeningId: {}]", screeningId); | ||
return screeningService.getScreeningDetails(screeningId); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.elmc.booking.adapters.incoming.rest.request; | ||
|
||
import com.elmc.booking.domain.ports.dto.incoming.RequestedReservationDto; | ||
import jakarta.validation.constraints.NotNull; | ||
|
||
import java.util.List; | ||
import java.util.UUID; | ||
|
||
public record ReservationRequest(@NotNull UUID screeningId, | ||
@NotNull String firstname, | ||
@NotNull String surname, | ||
@NotNull List<TicketData> tickets) { | ||
|
||
public RequestedReservationDto toDto() { | ||
return new RequestedReservationDto(screeningId, | ||
firstname, | ||
surname, | ||
tickets.stream() | ||
.map(TicketData::toDto) | ||
.toList()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skąd takie założenie?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Żeby ograniczyć liczbę jednorazowo pobieranych rekordów. Bez tego użytkownik mógłby pobrać seanse od teraz na kilka miesięcy w przód. Ograniczenie wyszukiwania do jednego tygodnia może być w pewnym sensie paginacją. Dodatkowo uznałem, że użytkownik szukając seansu rzadko potrzebowały dłuższego przedziału.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super, cieszę się, że to zauważyłeś!