Skip to content

Commit

Permalink
admin reservation request manager: move part of the db logic to repos…
Browse files Browse the repository at this point in the history
…itory
  • Loading branch information
syjer committed Jan 17, 2019
1 parent 7f5e3f3 commit 2b30567
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 24 deletions.
25 changes: 7 additions & 18 deletions src/main/java/alfio/manager/AdminReservationRequestManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@
import alfio.repository.AdminReservationRequestRepository;
import alfio.repository.EventRepository;
import alfio.repository.user.UserRepository;
import alfio.util.Json;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
Expand All @@ -47,7 +45,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static alfio.util.OptionalWrapper.optionally;
import static java.util.Collections.singletonList;
import static java.util.Optional.ofNullable;

Expand All @@ -59,7 +56,6 @@ public class AdminReservationRequestManager {

private final AdminReservationManager adminReservationManager;
private final EventManager eventManager;
private final NamedParameterJdbcTemplate jdbc;
private final UserRepository userRepository;
private final AdminReservationRequestRepository adminReservationRequestRepository;
private final EventRepository eventRepository;
Expand Down Expand Up @@ -90,6 +86,7 @@ public Result<String> scheduleReservations(String eventName,
.orElseGet(() -> Result.error(ErrorCode.ReservationError.UPDATE_FAILED));
}

//TODO: rewrite, and add test!
public Pair<Integer, Integer> processPendingReservations() {
Map<Boolean, List<MapSqlParameterSource>> result = adminReservationRequestRepository.findPendingForUpdate(1000)
.stream()
Expand All @@ -98,13 +95,13 @@ public Pair<Integer, Integer> processPendingReservations() {

Result<Triple<TicketReservation, List<Ticket>, Event>> reservationResult = Result.fromNullable(eventRepository.findOptionalById((int) request.getEventId()).orElse(null), ErrorCode.EventError.NOT_FOUND)
.flatMap(e -> Result.fromNullable(userRepository.findOptionalById((int) request.getUserId()).map(u -> Pair.of(e, u)).orElse(null), ErrorCode.EventError.ACCESS_DENIED))
.flatMap(p -> processReservation(request, p));
.flatMap(p -> processReservation(request, p.getLeft(), p.getRight()));
return buildParameterSource(id, reservationResult);
}).collect(Collectors.partitioningBy(ps -> AdminReservationRequest.Status.SUCCESS.name().equals(ps.getValue("status"))));

result.values().forEach(list -> {
try {
jdbc.batchUpdate(adminReservationRequestRepository.updateStatus(), list.toArray(new MapSqlParameterSource[0]));
adminReservationRequestRepository.updateStatus(list);
} catch(Exception e) {
log.fatal("cannot update the status of "+list.size()+" reservations", e);
}
Expand All @@ -114,14 +111,14 @@ public Pair<Integer, Integer> processPendingReservations() {

}

private Result<Triple<TicketReservation, List<Ticket>, Event>> processReservation(AdminReservationRequest request, Pair<Event, User> p) {
private Result<Triple<TicketReservation, List<Ticket>, Event>> processReservation(AdminReservationRequest request, Event event, User user) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_NESTED);
TransactionTemplate template = new TransactionTemplate(transactionManager, definition);
return template.execute(status -> {
var savepoint = status.createSavepoint();
try {
String eventName = p.getLeft().getShortName();
String username = p.getRight().getUsername();
String eventName = event.getShortName();
String username = user.getUsername();
Result<Triple<TicketReservation, List<Ticket>, Event>> result = adminReservationManager.createReservation(request.getBody(), eventName, username)
.flatMap(r -> adminReservationManager.confirmReservation(eventName, r.getLeft().getId(), username));
if(!result.isSuccess()) {
Expand All @@ -147,15 +144,7 @@ private Result<String> insertRequest(AdminReservationModification body, EventAnd
try {
String requestId = UUID.randomUUID().toString();
long userId = userRepository.findIdByUserName(username).orElseThrow(IllegalArgumentException::new);
MapSqlParameterSource[] requests = spread(body, singleReservation)
.map(res -> new MapSqlParameterSource("userId", userId)
.addValue("requestId", requestId)
.addValue("requestType", AdminReservationRequest.RequestType.IMPORT.name())
.addValue("status", AdminReservationRequest.Status.PENDING.name())
.addValue("eventId", event.getId())
.addValue("body", Json.toJson(res)))
.toArray(MapSqlParameterSource[]::new);
jdbc.batchUpdate(adminReservationRequestRepository.insertRequest(), requests);
adminReservationRequestRepository.insertRequest(requestId, userId, event, spread(body, singleReservation));
return Result.success(requestId);
} catch (Exception e) {
log.error("can't insert reservation request", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,50 @@

import alfio.model.AdminReservationRequest;
import alfio.model.AdminReservationRequestStats;
import alfio.model.EventAndOrganizationId;
import alfio.model.modification.AdminReservationModification;
import alfio.util.Json;
import ch.digitalfondue.npjt.Bind;
import ch.digitalfondue.npjt.Query;
import ch.digitalfondue.npjt.QueryRepository;
import ch.digitalfondue.npjt.QueryType;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

@QueryRepository
public interface AdminReservationRequestRepository {

@Query(value = "insert into admin_reservation_request(user_id, request_id, event_id, request_type, status, body) values(:userId, :requestId, :eventId, :requestType, :status, :body)",
type = QueryType.TEMPLATE)
String insertRequest();
default void insertRequest(String requestId, long userId, EventAndOrganizationId event, Stream<AdminReservationModification> requestModifications) {
MapSqlParameterSource[] requests = requestModifications.map(res -> new MapSqlParameterSource("userId", userId)
.addValue("requestId", requestId)
.addValue("requestType", AdminReservationRequest.RequestType.IMPORT.name())
.addValue("status", AdminReservationRequest.Status.PENDING.name())
.addValue("eventId", event.getId())
.addValue("body", Json.toJson(res)))
.toArray(MapSqlParameterSource[]::new);

getNamedParameterJdbcTemplate().batchUpdate("insert into admin_reservation_request(user_id, request_id, event_id, request_type, status, body) values(:userId, :requestId, :eventId, :requestType, :status, :body)", requests);
}

@Query("select id from admin_reservation_request where status = 'PENDING' order by request_id limit :limit for update skip locked")
List<Long> findPendingForUpdate(@Bind("limit") int limit);

@Query("select * from admin_reservation_request where id = :id")
AdminReservationRequest fetchCompleteById(@Bind("id") long id);

@Query(value = "update admin_reservation_request set status = :status, reservation_id = :reservationId, failure_code = :failureCode where id = :id", type = QueryType.TEMPLATE)
String updateStatus();
//todo, would be better to have more sane parameters, we are leaking the details here
default void updateStatus(List<MapSqlParameterSource> params) {
getNamedParameterJdbcTemplate().batchUpdate("update admin_reservation_request set status = :status, reservation_id = :reservationId, failure_code = :failureCode where id = :id", params.toArray(new MapSqlParameterSource[0]));
}


@Query("select * from admin_reservation_request_stats where request_id = :requestId and event_id = :eventId")
Optional<AdminReservationRequestStats> findStatsByRequestIdAndEventId(@Bind("requestId") String requestId, @Bind("eventId") long eventId);


NamedParameterJdbcTemplate getNamedParameterJdbcTemplate();

}

0 comments on commit 2b30567

Please sign in to comment.