Skip to content

Commit

Permalink
EventManager: move most db interaction logic in repository
Browse files Browse the repository at this point in the history
  • Loading branch information
syjer committed Jan 17, 2019
1 parent 2b30567 commit 6512924
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 53 deletions.
14 changes: 4 additions & 10 deletions src/main/java/alfio/manager/AdminReservationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
import org.springframework.context.MessageSource;
import org.springframework.dao.DataIntegrityViolationException;
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 Down Expand Up @@ -88,7 +87,6 @@ public class AdminReservationManager {
private final TicketReservationManager ticketReservationManager;
private final TicketCategoryRepository ticketCategoryRepository;
private final TicketRepository ticketRepository;
private final NamedParameterJdbcTemplate jdbc;
private final SpecialPriceRepository specialPriceRepository;
private final TicketReservationRepository ticketReservationRepository;
private final EventRepository eventRepository;
Expand Down Expand Up @@ -552,7 +550,7 @@ private Result<TicketCategory> checkExistingCategory(TicketsInfo ti, Event event

private void createMissingTickets(Event event, int tickets) {
final MapSqlParameterSource[] params = generateEmptyTickets(event, Date.from(ZonedDateTime.now(event.getZoneId()).toInstant()), tickets, Ticket.TicketStatus.FREE).toArray(MapSqlParameterSource[]::new);
jdbc.batchUpdate(ticketRepository.bulkTicketInitialization(), params);
ticketRepository.bulkTicketInitialization(params);
}

@Transactional
Expand Down Expand Up @@ -696,15 +694,11 @@ private void removeTicketsFromReservation(TicketReservation reservation, Event e

ticketRepository.resetCategoryIdForUnboundedCategoriesWithTicketIds(ticketIds);
ticketFieldRepository.deleteAllValuesForTicketIds(ticketIds);
MapSqlParameterSource[] args = ticketIds.stream().map(id -> new MapSqlParameterSource("ticketId", id)
.addValue("reservationId", reservationId)
.addValue("eventId", event.getId())
.addValue("newUuid", UUID.randomUUID().toString())
).toArray(MapSqlParameterSource[]::new);

List<String> reservationIds = ticketRepository.findReservationIds(ticketIds);
List<String> ticketUUIDs = ticketRepository.findUUIDs(ticketIds);
int[] results = jdbc.batchUpdate(ticketRepository.batchReleaseTickets(), args);
Validate.isTrue(Arrays.stream(results).sum() == args.length, "Failed to update tickets");
int[] results = ticketRepository.batchReleaseTickets(reservationId, ticketIds, event);
Validate.isTrue(Arrays.stream(results).sum() == ticketIds.size(), "Failed to update tickets");
if(!removeReservation) {
if(forceInvoiceReceiptUpdate) {
auditingRepository.insert(reservationId, userId, event.getId(), FORCED_UPDATE_INVOICE, date, RESERVATION, reservationId);
Expand Down
14 changes: 5 additions & 9 deletions src/main/java/alfio/manager/EventManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -91,7 +90,6 @@ public class EventManager {
private final TicketRepository ticketRepository;
private final SpecialPriceRepository specialPriceRepository;
private final PromoCodeDiscountRepository promoCodeRepository;
private final NamedParameterJdbcTemplate jdbc;
private final ConfigurationManager configurationManager;
private final TicketFieldRepository ticketFieldRepository;
private final EventDeleterRepository eventDeleterRepository;
Expand Down Expand Up @@ -339,7 +337,7 @@ public void updateEventPrices(EventAndOrganizationId original, EventModification
Event modified = eventRepository.findById(eventId);
if(seatsDifference > 0) {
final MapSqlParameterSource[] params = generateEmptyTickets(modified, Date.from(ZonedDateTime.now(modified.getZoneId()).toInstant()), seatsDifference, TicketStatus.RELEASED).toArray(MapSqlParameterSource[]::new);
jdbc.batchUpdate(ticketRepository.bulkTicketInitialization(), params);
ticketRepository.bulkTicketInitialization(params);
} else {
List<Integer> ids = ticketRepository.selectNotAllocatedTicketsForUpdate(eventId, Math.abs(seatsDifference), singletonList(TicketStatus.FREE.name()));
Validate.isTrue(ids.size() == Math.abs(seatsDifference), "cannot lock enough tickets for deletion.");
Expand Down Expand Up @@ -570,7 +568,7 @@ private Integer insertCategory(TicketCategoryModification tc, Event event) {
TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(category.getKey(), eventId);
if(tc.isBounded()) {
List<Integer> lockedTickets = ticketRepository.selectNotAllocatedTicketsForUpdate(eventId, ticketCategory.getMaxTickets(), asList(TicketStatus.FREE.name(), TicketStatus.RELEASED.name()));
jdbc.batchUpdate(ticketRepository.bulkTicketUpdate(), lockedTickets.stream().map(id -> new MapSqlParameterSource("id", id).addValue("categoryId", ticketCategory.getId()).addValue("srcPriceCts", ticketCategory.getSrcPriceCts())).toArray(MapSqlParameterSource[]::new));
ticketRepository.bulkTicketUpdate(lockedTickets, ticketCategory);
if(tc.isTokenGenerationRequested()) {
insertTokens(ticketCategory);
ticketRepository.revertToFree(eventId, ticketCategory.getId(), lockedTickets);
Expand Down Expand Up @@ -699,9 +697,7 @@ void handleTicketNumberModification(Event event, TicketCategory original, Ticket
//the updated category contains more tickets than the older one
List<Integer> lockedTickets = ticketRepository.selectNotAllocatedTicketsForUpdate(event.getId(), addedTickets, asList(TicketStatus.FREE.name(), TicketStatus.RELEASED.name()));
Validate.isTrue(addedTickets == lockedTickets.size(), "Cannot add %d tickets. There are only %d free tickets.", addedTickets, lockedTickets.size());
jdbc.batchUpdate(ticketRepository.bulkTicketUpdate(), lockedTickets.stream()
.map(id -> new MapSqlParameterSource("id", id).addValue("categoryId", updated.getId()).addValue("srcPriceCts", updated.getSrcPriceCts()))
.toArray(MapSqlParameterSource[]::new));
ticketRepository.bulkTicketUpdate(lockedTickets, updated);
if(updated.isAccessRestricted()) {
//since the updated category is not public, the tickets shouldn't be distributed to waiting people.
ticketRepository.revertToFree(event.getId(), updated.getId(), lockedTickets);
Expand All @@ -718,14 +714,14 @@ void handleTicketNumberModification(Event event, TicketCategory original, Ticket
}
ticketRepository.invalidateTickets(ids);
final MapSqlParameterSource[] params = generateEmptyTickets(event, Date.from(ZonedDateTime.now(event.getZoneId()).toInstant()), absDifference, TicketStatus.RELEASED).toArray(MapSqlParameterSource[]::new);
jdbc.batchUpdate(ticketRepository.bulkTicketInitialization(), params);
ticketRepository.bulkTicketInitialization(params);
}
}

private void createAllTicketsForEvent(Event event, EventModification em) {
Validate.notNull(em.getAvailableSeats());
final MapSqlParameterSource[] params = prepareTicketsBulkInsertParameters(ZonedDateTime.now(event.getZoneId()), event, em.getAvailableSeats(), TicketStatus.FREE);
jdbc.batchUpdate(ticketRepository.bulkTicketInitialization(), params);
ticketRepository.bulkTicketInitialization(params);
}

private int insertEvent(EventModification em) {
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/alfio/manager/WaitingQueueManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static alfio.model.system.ConfigurationKeys.*;
Expand Down Expand Up @@ -190,11 +191,11 @@ private void preReserveTickets(Event event, int ticketsNeeded, int eventId, int
.sorted(Comparator.comparing(t -> t.getExpiration(event.getZoneId())))
.map(tc -> Pair.of(determineAvailableSeats(ticketCategoriesStats.get(tc.getId()), eventStatisticView), ticketCategoriesStats.get(tc.getId())))
.collect(new PreReservedTicketDistributor(toBeGenerated));
MapSqlParameterSource[] candidates = collectedTickets.stream()
List<Integer> ids = collectedTickets.stream()
.flatMap(p -> selectTicketsForPreReservation(eventId, p).stream())
.map(id -> new MapSqlParameterSource().addValue("id", id))
.toArray(MapSqlParameterSource[]::new);
jdbc.batchUpdate(ticketRepository.preReserveTicket(), candidates);
.collect(Collectors.toList());

ticketRepository.preReserveTicket(ids);
}

private List<Integer> selectTicketsForPreReservation(int eventId, Pair<Integer, TicketCategoryStatisticView> p) {
Expand Down
40 changes: 27 additions & 13 deletions src/main/java/alfio/repository/TicketRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@
*/
package alfio.repository;

import alfio.model.FullTicketInfo;
import alfio.model.Ticket;
import alfio.model.TicketInfo;
import alfio.model.TicketWithReservationAndTransaction;
import alfio.model.*;
import ch.digitalfondue.npjt.Bind;
import ch.digitalfondue.npjt.Query;
import ch.digitalfondue.npjt.QueryRepository;
Expand All @@ -39,12 +36,19 @@ public interface TicketRepository {
String REVERT_TO_FREE = "update ticket set status = 'FREE' where status = 'RELEASED' and event_id = :eventId";


@Query(type = QueryType.TEMPLATE, value = "insert into ticket (uuid, creation, category_id, event_id, status, original_price_cts, paid_price_cts, src_price_cts)"
+ "values(:uuid, :creation, :categoryId, :eventId, :status, 0, 0, :srcPriceCts)")
String bulkTicketInitialization();
//TODO: refactor, try to move the MapSqlParameterSource inside the default method!
default void bulkTicketInitialization(MapSqlParameterSource[] args) {
getNamedParameterJdbcTemplate().batchUpdate("insert into ticket (uuid, creation, category_id, event_id, status, original_price_cts, paid_price_cts, src_price_cts)"
+ "values(:uuid, :creation, :categoryId, :eventId, :status, 0, 0, :srcPriceCts)", args);
}

@Query(type = QueryType.TEMPLATE, value = "update ticket set category_id = :categoryId, src_price_cts = :srcPriceCts where id = :id")
String bulkTicketUpdate();
default void bulkTicketUpdate(List<Integer> ids, TicketCategory ticketCategory) {
MapSqlParameterSource[] params = ids.stream().map(id -> new MapSqlParameterSource("id", id)
.addValue("categoryId", ticketCategory.getId())
.addValue("srcPriceCts", ticketCategory.getSrcPriceCts()))
.toArray(MapSqlParameterSource[]::new);
getNamedParameterJdbcTemplate().batchUpdate("update ticket set category_id = :categoryId, src_price_cts = :srcPriceCts where id = :id", params);
}

@Query("select id from ticket where status in (:requiredStatuses) and category_id = :categoryId and event_id = :eventId and tickets_reservation_id is null order by id limit :amount for update")
List<Integer> selectTicketInCategoryForUpdate(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId, @Bind("amount") int amount, @Bind("requiredStatuses") List<String> requiredStatus);
Expand Down Expand Up @@ -247,8 +251,14 @@ default Set<String> findAllReservationsConfirmedButNotAssignedForUpdate(int even
@Query(RELEASE_TICKET_QUERY)
int releaseTicket(@Bind("reservationId") String reservationId, @Bind("newUuid") String newUuid, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId);

@Query(value = RELEASE_TICKET_QUERY, type = QueryType.TEMPLATE)
String batchReleaseTickets();
default int[] batchReleaseTickets(String reservationId, List<Integer> ticketIds, Event event) {
MapSqlParameterSource[] args = ticketIds.stream().map(id -> new MapSqlParameterSource("ticketId", id)
.addValue("reservationId", reservationId)
.addValue("eventId", event.getId())
.addValue("newUuid", UUID.randomUUID().toString())
).toArray(MapSqlParameterSource[]::new);
return getNamedParameterJdbcTemplate().batchUpdate(RELEASE_TICKET_QUERY, args);
}

@Query("update ticket set status = 'RELEASED', uuid = :newUuid, " + RESET_TICKET + " where id = :ticketId and status = 'PENDING' and tickets_reservation_id = :reservationId and event_id = :eventId")
int releaseExpiredTicket(@Bind("reservationId") String reservationId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId, @Bind("newUuid") String newUuid);
Expand Down Expand Up @@ -289,8 +299,12 @@ default void resetTickets(List<Integer> ticketIds) {
@Query("select count(*) from ticket where status = 'PRE_RESERVED'")
Integer countPreReservedTickets(@Bind("eventId") int eventId);

@Query(type = QueryType.TEMPLATE, value = "update ticket set status = 'PRE_RESERVED' where id = :id")
String preReserveTicket();
default void preReserveTicket(List<Integer> ids) {
MapSqlParameterSource[] params = ids.stream()
.map(id -> new MapSqlParameterSource().addValue("id", id))
.toArray(MapSqlParameterSource[]::new);
getNamedParameterJdbcTemplate().batchUpdate("update ticket set status = 'PRE_RESERVED' where id = :id", params);
}

@Query("select * from ticket where status = 'FREE' and event_id = :eventId")
List<Ticket> findFreeByEventId(@Bind("eventId") int eventId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void init() {
EventRepository eventRepository = mock(EventRepository.class);
event = mock(Event.class);
when(event.getId()).thenReturn(eventId);
eventManager = new EventManager(null, eventRepository, null, ticketCategoryRepository, ticketCategoryDescriptionRepository, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
eventManager = new EventManager(null, eventRepository, null, ticketCategoryRepository, ticketCategoryDescriptionRepository, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
when(eventRepository.countExistingTickets(0)).thenReturn(availableSeats);
when(event.getZoneId()).thenReturn(ZoneId.systemDefault());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,16 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

import java.time.ZoneId;
import java.util.Arrays;
import java.util.List;

import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;

Expand All @@ -47,7 +42,6 @@ public class EventManagerHandleTicketModificationTest {
private TicketCategory original;
private TicketCategory updated;
private TicketRepository ticketRepository;
private NamedParameterJdbcTemplate jdbc;
private EventManager eventManager;
private final int eventId = 10;
private int originalCategoryId = 20;
Expand All @@ -60,9 +54,9 @@ void init() {
original = mock(TicketCategory.class);
updated = mock(TicketCategory.class);
ticketRepository = mock(TicketRepository.class);
jdbc = mock(NamedParameterJdbcTemplate.class);

when(event.getId()).thenReturn(eventId);
eventManager = new EventManager(null, null, null, null, null, ticketRepository, null, null, jdbc, null, null, null, null, null, null, null, null, null, null, null);
eventManager = new EventManager(null, null, null, null, null, ticketRepository, null, null, null, null, null, null, null, null, null, null, null, null, null);
when(original.getId()).thenReturn(originalCategoryId);
when(updated.getId()).thenReturn(updatedCategoryId);
when(original.getSrcPriceCts()).thenReturn(1000);
Expand All @@ -71,7 +65,6 @@ void init() {
when(updated.getMaxTickets()).thenReturn(11);
when(original.isBounded()).thenReturn(true);
when(event.getZoneId()).thenReturn(ZoneId.systemDefault());
when(ticketRepository.bulkTicketUpdate()).thenReturn("bulk");
}

@DisplayName("throw exception if there are tickets already sold")
Expand All @@ -96,7 +89,7 @@ void invalidateExceedingTickets() {
void doNothingIfZero() {
eventManager.handleTicketNumberModification(event, original, updated, 0, false);
verify(ticketRepository, never()).invalidateTickets(anyList());
verify(jdbc, never()).batchUpdate(anyString(), any(SqlParameterSource[].class));
verify(ticketRepository, never()).bulkTicketUpdate(any(), any());
}

@Test
Expand All @@ -105,9 +98,7 @@ void insertTicketIfDifference1() {
when(ticketRepository.selectNotAllocatedTicketsForUpdate(eq(eventId), eq(1), eq(Arrays.asList(Ticket.TicketStatus.FREE.name(), Ticket.TicketStatus.RELEASED.name())))).thenReturn(singletonList(1));
eventManager.handleTicketNumberModification(event, original, updated, 1, false);
verify(ticketRepository, never()).invalidateTickets(anyList());
ArgumentCaptor<SqlParameterSource[]> captor = ArgumentCaptor.forClass(SqlParameterSource[].class);
verify(jdbc, times(1)).batchUpdate(anyString(), captor.capture());
assertEquals(1, captor.getValue().length);
verify(ticketRepository, times(1)).bulkTicketUpdate(any(), any());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void init() {
TicketRepository ticketRepository = mock(TicketRepository.class);
when(event.getId()).thenReturn(eventId);
eventManager = new EventManager(null, null, null, null,
null, ticketRepository, specialPriceRepository, null, null, null, null, null, null, null, null, null, null, null, null, null);
null, ticketRepository, specialPriceRepository, null, null, null, null, null, null, null, null, null, null, null, null);
when(original.getId()).thenReturn(20);
when(updated.getId()).thenReturn(30);
when(original.getSrcPriceCts()).thenReturn(1000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void setUp() {
eventDescriptionRepository, ticketCategoryRepository, ticketCategoryDescriptionRepository,
ticketRepository, specialPriceRepository, null, null, null,
null, null, null,
null, null, null, organizationRepository,
null, null, organizationRepository,
null, null, null);
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/java/alfio/manager/WaitingQueueManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void processPreReservations() {
verify(ticketRepository).countWaiting(eq(eventId));
verify(ticketRepository, never()).revertToFree(eq(eventId));
verify(ticketRepository).countPreReservedTickets(eq(eventId));
verify(ticketRepository).preReserveTicket();
verify(ticketRepository).preReserveTicket(anyList());
verify(ticketRepository).selectWaitingTicketsForUpdate(eq(eventId), anyString(), anyInt());
}
}

0 comments on commit 6512924

Please sign in to comment.