TransactionRepositoryAdapter.java
package com.github.jenkaby.bikerental.finance.infrastructure.persistence.adapter;
import com.github.jenkaby.bikerental.finance.domain.model.Transaction;
import com.github.jenkaby.bikerental.finance.domain.model.TransactionHistoryFilter;
import com.github.jenkaby.bikerental.finance.domain.model.TransactionSourceType;
import com.github.jenkaby.bikerental.finance.domain.model.TransactionType;
import com.github.jenkaby.bikerental.finance.domain.repository.TransactionRepository;
import com.github.jenkaby.bikerental.finance.infrastructure.persistence.mapper.TransactionJpaMapper;
import com.github.jenkaby.bikerental.finance.infrastructure.persistence.repository.TransactionJpaRepository;
import com.github.jenkaby.bikerental.finance.infrastructure.persistence.specification.CustomerTransactionsSpec;
import com.github.jenkaby.bikerental.finance.infrastructure.persistence.specification.SpecConstant;
import com.github.jenkaby.bikerental.shared.domain.CustomerRef;
import com.github.jenkaby.bikerental.shared.domain.IdempotencyKey;
import com.github.jenkaby.bikerental.shared.domain.RentalRef;
import com.github.jenkaby.bikerental.shared.domain.model.vo.Page;
import com.github.jenkaby.bikerental.shared.domain.model.vo.PageRequest;
import lombok.extern.slf4j.Slf4j;
import net.kaczmarzyk.spring.data.jpa.utils.SpecificationBuilder;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Slf4j
@Repository
class TransactionRepositoryAdapter implements TransactionRepository {
private final TransactionJpaRepository jpaRepository;
private final TransactionJpaMapper mapper;
TransactionRepositoryAdapter(TransactionJpaRepository jpaRepository, TransactionJpaMapper mapper) {
this.jpaRepository = jpaRepository;
this.mapper = mapper;
}
@Override
@Transactional(propagation = Propagation.MANDATORY)
public Transaction save(Transaction transaction) {
var entity = mapper.toEntity(transaction);
var saved = jpaRepository.save(entity);
return mapper.toDomain(saved);
}
@Override
public Optional<Transaction> findByIdempotencyKeyAndCustomerId(IdempotencyKey idempotencyKey, CustomerRef customerId) {
return jpaRepository.findByIdempotencyKeyAndCustomerId(idempotencyKey.id(), customerId.id())
.map(mapper::toDomain);
}
@Override
public Optional<Transaction> findByRentalRefAndType(RentalRef rentalRef, TransactionType type) {
return findAllByRentalRefAndType(rentalRef, type).stream()
.findFirst();
}
@Override
public List<Transaction> findAllByRentalRefAndType(RentalRef rentalRef, TransactionType type) {
return jpaRepository.findAllBySourceTypeAndSourceIdAndTransactionType(
TransactionSourceType.RENTAL,
String.valueOf(rentalRef.id()),
type)
.stream()
.map(mapper::toDomain)
.toList();
}
@Override
public boolean existsByRentalRefAndType(RentalRef rentalRef, TransactionType type) {
return jpaRepository.existsBySourceTypeAndSourceIdAndTransactionType(
TransactionSourceType.RENTAL,
String.valueOf(rentalRef.id()),
type);
}
@Override
@Transactional(readOnly = true)
public Page<Transaction> findTransactionHistory(CustomerRef customerId, TransactionHistoryFilter filter, PageRequest pageRequest) {
var pageable = org.springframework.data.domain.PageRequest.of(pageRequest.page(), pageRequest.size(),
Sort.by(Sort.Direction.DESC, SpecConstant.TransactionField.RECORDED_AT));
var txnSpec = SpecificationBuilder.specification(CustomerTransactionsSpec.class)
.withParam(SpecConstant.TransactionField.CUSTOMER_ID, customerId.id().toString());
filter.toMap().forEach(txnSpec::withParam);
var spec = txnSpec.build();
var springPage = jpaRepository.findAll(spec, pageable);
var items = springPage.getContent().stream()
.map(mapper::toDomain)
.toList();
return new Page<>(items, springPage.getTotalElements(), pageRequest);
}
}