AbstractFileRepository.java

package io.extact.rms.application.persistence.file;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import jakarta.validation.Valid;

import io.extact.rms.application.domain.IdAccessable;
import io.extact.rms.application.domain.Transformable;
import io.extact.rms.application.domain.constraint.ValidationGroups.Add;
import io.extact.rms.application.domain.constraint.ValidationGroups.Update;
import io.extact.rms.application.persistence.GenericRepository;
import io.extact.rms.application.persistence.file.converter.EntityArrayConverter;
import io.extact.rms.application.persistence.file.io.FileAccessor;
import io.extact.rms.platform.validate.ValidateGroup;
import io.extact.rms.platform.validate.ValidateParam;

public class AbstractFileRepository<T extends Transformable & IdAccessable> implements GenericRepository<T>, FileRepository {

    private FileAccessor fileAccessor;
    private EntityArrayConverter<T> entityConverter;


    // ----------------------------------------------------- constructor methods

    public AbstractFileRepository(FileAccessor fileAccessor, EntityArrayConverter<T> entityConverter) {
        this.fileAccessor = fileAccessor;
        this.entityConverter = entityConverter;
    }


    // ----------------------------------------------------- implement methods

    @Override
    public T get(int id) {
        return load().stream()
                .filter(items -> Integer.parseInt(items[0]) == id) // numberはpos:0は共通
                .map(entityConverter::toEntity)
                .findFirst()
                .orElse(null);
    }

    @Override
    public List<T> findAll() {
        return load().stream()
                .map(entityConverter::toEntity)
                .toList();
    }

    @ValidateParam
    @ValidateGroup(groups = Add.class)
    @Override
    public void add(@Valid T entity) {
        var nextSeq = this.getNextSequence();
        entity.setId(nextSeq);
        save(entity.transform(entityConverter::toArray));
    }

    @ValidateParam
    @ValidateGroup(groups = Update.class)
    public T update(@Valid T entity) {
        var replaced = new AtomicBoolean(false);
        var lines = load().stream()
                .map(items -> {
                    if (items[0].equals(String.valueOf(entity.getId()))) {
                        replaced.set(true);
                        return getConverter().toArray(entity);
                    }
                    return items;
                })
                .toList();
        if (!replaced.get()) {
            return null;
        }
        this.saveAll(lines);
        return entity;
    }

    public void delete(T entity) {
        this.delete(entity.getId());
    }

    @Override
    public Path getStoragePath() {
        return fileAccessor.getFilePath();
    }


    // ----------------------------------------------------- specific methods

    public int getNextSequence() {
        return load().stream()
                .map(items -> Integer.parseInt(items[0]))
                .collect(Collectors.maxBy(Integer::compareTo))
                .orElse(0)
                + 1;
    }

    public void delete(Integer id) {
        var excludedData = load().stream()
                .filter(items -> Integer.parseInt(items[0])  != id) // numberはpos:0は共通
                .toList();
        saveAll(excludedData);
    }


    // ----------------------------------------------------- package private methods

    EntityArrayConverter<T> getConverter() {
        return entityConverter;
    }

    List<String[]> load() {
        try {
            List<String[]> dataList = new ArrayList<>();
            fileAccessor.load(dataList);
            return dataList;
        } catch (IOException e) {
            throw new IoSystemException(e);
        }
    }

    void save(String[] arrayData) {
        try {
            fileAccessor.save(arrayData);
        } catch (IOException e) {
            throw new IoSystemException(e);
        }
    }

    void saveAll(List<String[]> allData) {
        try {
            fileAccessor.saveAll(allData);
        } catch (IOException e) {
            throw new IoSystemException(e);
        }
    }
}