package de.rwth.idsg.bikeman.repository;
import de.rwth.idsg.bikeman.domain.Booking;
import de.rwth.idsg.bikeman.domain.Booking_;
import de.rwth.idsg.bikeman.domain.Reservation;
import de.rwth.idsg.bikeman.domain.Reservation_;
import de.rwth.idsg.bikeman.ixsi.IXSIConstants;
import de.rwth.idsg.bikeman.ixsi.dto.BookingDTO;
import de.rwth.idsg.bikeman.web.rest.exception.DatabaseException;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.LocalDateTime;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Root;
import java.util.List;
/**
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
* @since 08.01.2015
*/
@Repository
@Slf4j
public class BookingRepositoryImpl implements BookingRepository {
@PersistenceContext
private EntityManager em;
@Override
public Booking save(Booking b) {
em.persist(b);
final String ixsiBookingId = IXSIConstants.Provider.id + IXSIConstants.BOOKING_ID_DELIMITER + b.getBookingId();
b.setIxsiBookingId(ixsiBookingId);
em.merge(b);
return b;
}
@Override
@Transactional
public void cancel(Booking booking) {
// TODO: Really delete from DB or some other logic (setting a flag)?
em.remove(booking);
}
@Override
@Transactional(readOnly = true)
public boolean isNotUsedAndExpired(String ixsiBookingId) {
final String query = "SELECT COUNT(b) FROM Booking b " +
"WHERE b.ixsiBookingId = :ixsiBookingId " +
"AND b.transaction IS NULL " +
"AND (:now > b.reservation.endDateTime)";
Long count = em.createQuery(query, Long.class)
.setParameter("ixsiBookingId", ixsiBookingId)
.setParameter("now", new LocalDateTime())
.getSingleResult();
return count == 1;
}
@Override
@Transactional(readOnly = true)
public List<BookingDTO> findNotUsedAndExpiredBookings(List<String> ixsiBookingIdList) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<BookingDTO> criteria = builder.createQuery(BookingDTO.class);
Root<Booking> booking = criteria.from(Booking.class);
Join<Booking, Reservation> reservation = booking.join(Booking_.reservation, JoinType.INNER);
criteria.select(
builder.construct(
BookingDTO.class,
booking.get(Booking_.ixsiBookingId),
reservation.get(Reservation_.startDateTime)
)
);
criteria.where(
builder.and(
booking.get(Booking_.ixsiBookingId).in(ixsiBookingIdList),
booking.get(Booking_.transaction).isNull(),
builder.lessThan(reservation.get(Reservation_.endDateTime), new LocalDateTime())
));
return em.createQuery(criteria).getResultList();
}
@Override
@Transactional(readOnly = true)
public List<Booking> findClosedBookings(List<String> ixsiBookingIdList) {
final String query = "SELECT b FROM Booking b WHERE b.ixsiBookingId IN (:ixsiBookingIdList) " +
"AND b.transaction.endDateTime IS NOT NULL " +
"AND b.transaction.toSlot IS NOT NULL";
return em.createQuery(query, Booking.class)
.setParameter("ixsiBookingIdList", ixsiBookingIdList)
.getResultList();
}
@Override
public Booking findByIxsiBookingIdForUser(String ixsiBookingId, String userId) {
final String query = "SELECT b FROM Booking b " +
"WHERE b.ixsiBookingId = :ixsiBookingId " +
"AND b.reservation.cardAccount.cardId = :userId";
try {
return em.createQuery(query, Booking.class)
.setParameter("ixsiBookingId", ixsiBookingId)
.setParameter("userId", userId)
.getSingleResult();
} catch (NoResultException e) {
throw new DatabaseException(
"Could not find booking for the given id " + ixsiBookingId + " and user " + userId, e);
}
}
}