All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.hammelion.mappedjpa.MappedRepository Maven / Gradle / Ivy

package com.github.hammelion.mappedjpa;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import io.vavr.control.Try;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * A repository which actually creates an abstraction layer between domain objects and persistence layer entity objects.
 *
 * @param   Wrapped JpaRepository
 * @param   Entity object
 * @param   Domain object (DTO)
 * @param  Id of an entity
 */
@SuppressWarnings({"unchecked", "OptionalUsedAsFieldOrParameterType", "unused"})
public class MappedRepository, D, E, ID> implements JpaRepository {
    protected final J repository;
    protected final DtoMapper mapper;

    public MappedRepository(
        J repository,
        DtoMapper mapper
    ) {
        this.repository = repository;
        this.mapper = mapper;
    }

    private static RuntimeException runtimeException(Throwable t) {
        if (t instanceof RuntimeException) {
            return (RuntimeException) t;
        }
        return new RuntimeException(t);
    }

    @Override
    public Optional findById(ID id) {
        return callOpt(() -> repository.findById(id));
    }

    @Override
    public boolean existsById(ID id) {
        return repository.existsById(id);
    }

    @Override
    public List findAll() {
        return callList(repository::findAll);
    }

    @Override
    public List findAll(Sort sort) {
        return callList(() -> repository.findAll(sort));
    }

    @Override
    public Page findAll(Pageable pageable) {
        return callPage(() -> repository.findAll(pageable));
    }

    @Override
    public List findAllById(Iterable ids) {
        return callList(() -> repository.findAllById(ids));
    }

    @Override
    public long count() {
        return repository.count();
    }

    @Override
    public void deleteById(ID id) {
        repository.deleteById(id);
    }

    @Override
    public void delete(D entity) {
        repository.delete(fromDto(entity));
    }

    @Override
    public void deleteAll(Iterable entities) {
        repository.deleteAll(fromDtoList(entities));
    }

    @Override
    public void deleteAll() {
        repository.deleteAll();
    }

    @Override
    public  S save(S entity) {
        return call(() -> repository.save(fromDto(entity)));
    }

    @Override
    public  List saveAll(Iterable entities) {
        return callList(() -> repository.saveAll(fromDtoList(entities)));
    }

    @Override
    public void flush() {
        repository.flush();
    }

    @Override
    public  S saveAndFlush(S entity) {
        return call(() -> repository.saveAndFlush(fromDto(entity)));
    }

    @Override
    public void deleteInBatch(Iterable entities) {
        repository.deleteInBatch(fromDtoList(entities));
    }

    @Override
    public void deleteAllInBatch() {
        repository.deleteAllInBatch();
    }

    @Override
    public D getOne(ID id) {
        return call(() -> repository.getOne(id));
    }

    @Override
    public  Optional findOne(Example example) {
        return callOpt(() -> repository.findOne(fromDto(example)));
    }

    @Override
    public  List findAll(Example example) {
        return this.callList(() -> repository.findAll(fromDto(example)));
    }

    @Override
    public  List findAll(
        Example example,
        Sort sort
    ) {
        return this.callList(() -> repository.findAll(fromDto(example), sort));
    }

    @Override
    public  Page findAll(
        Example example,
        Pageable pageable
    ) {
        return callPage(() -> repository.findAll(fromDto(example), pageable));
    }

    @Override
    public  long count(Example example) {
        return repository.count(fromDto(example));
    }

    @Override
    public  boolean exists(Example example) {
        return repository.exists(fromDto(example));
    }

    private  List callList(
        Callable> f
    ) {
        return Try.of(() -> f.call().stream().map(e -> (S) mapper.toDto(e)).collect(Collectors.toList()))
                  .getOrElseThrow(MappedRepository::runtimeException);
    }

    private  Optional callOpt(
        Callable> f
    ) {
        return Try.of(f::call)
                  .map(o -> o.map(e -> (S) mapper.toDto(e)))
                  .getOrElseThrow(MappedRepository::runtimeException);
    }

    private  S call(Callable f) {
        return Try.of(f::call)
                  .map(e -> (S) mapper.toDto(e))
                  .getOrElseThrow(MappedRepository::runtimeException);
    }

    private  Page callPage(Callable> f) {
        return Try.of(f::call)
                  .map(p -> p.map(e -> (S) mapper.toDto(e)))
                  .getOrElseThrow(MappedRepository::runtimeException);
    }

    public Optional toDto(Optional o) {
        return o.map(mapper::toDto);
    }

    public List toDto(Iterable entities) {
        return StreamSupport.stream(entities.spliterator(), false)
                            .map(mapper::toDto)
                            .collect(Collectors.toList());
    }

    public List fromDtoList(Iterable dtos) {
        return StreamSupport.stream(dtos.spliterator(), false)
                            .map(this::fromDto)
                            .collect(Collectors.toList());
    }

    public E fromDto(D dto) {
        return mapper.fromDto(dto);
    }

    public  Example fromDto(Example example) {
        return Example.of(fromDto(example.getProbe()));
    }
}