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

tech.ydb.yoj.repository.db.projection.RwProjectionCache Maven / Gradle / Ivy

Go to download

Core YOJ (YDB ORM for Java) abstractions and APIs for domain entities, repositories, transactions etc.

The newest version!
package tech.ydb.yoj.repository.db.projection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.ydb.yoj.repository.db.Entity;
import tech.ydb.yoj.repository.db.RepositoryTransaction;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toMap;

public class RwProjectionCache implements ProjectionCache {
    private static final Logger log = LoggerFactory.getLogger(RwProjectionCache.class);

    private final Map, Row> rows = new LinkedHashMap<>();

    @Override
    public void load(Entity entity) {
        row(entity.getId()).load(entity);
    }

    @Override
    public void save(Entity entity) {
        row(entity.getId()).save(entity);
    }

    @Override
    public void delete(Entity.Id id) {
        row(id).delete();
    }

    private Row row(Entity.Id id) {
        return rows.computeIfAbsent(id, __ -> new Row());
    }

    @Override
    public void applyProjectionChanges(RepositoryTransaction transaction) {
        Map, Entity> oldProjections = rows.values().stream()
                .flatMap(Row::projectionsBefore)
                .collect(toMap(Entity::getId, e -> e, this::mergeOldProjections));
        Map, Entity> newProjections = rows.values().stream()
                .flatMap(Row::projectionsAfter)
                .collect(toMap(Entity::getId, e -> e, this::mergeNewProjections));

        for (Row row : rows.values()) {
            row.flush();
        }

        oldProjections.values().stream()
                .filter(e -> !newProjections.containsKey(e.getId()))
                .forEach(e -> deleteEntity(transaction, e.getId()));
        newProjections.values().stream()
                .filter(e -> !e.equals(oldProjections.get(e.getId())))
                .forEach(e -> saveEntity(transaction, e));
    }

    private > void deleteEntity(RepositoryTransaction transaction, Entity.Id entityId) {
        transaction.table(entityId.getType()).delete(entityId);
    }

    private > void saveEntity(RepositoryTransaction transaction, Entity entity) {
        @SuppressWarnings("unchecked")
        T castedEntity = (T) entity;

        transaction.table(entity.getId().getType()).save(castedEntity);
    }

    private Entity mergeOldProjections(Entity p1, Entity p2) {
        if (p1 == p2 || p1.equals(p2)) {
            log.error("FIX THIS ASAP! Got two equal projections with the same ID: {}. NO exception is thrown so that "
                    + "you can just fix and migrate the entities to fix the projections", p1);
            return p1;
        }
        throw new IllegalStateException("Got two unequal projections with the same ID: p1=" + p1 + "; p2=" + p2);
    }

    private Entity mergeNewProjections(Entity p1, Entity p2) {
        throw new IllegalStateException("Got two projections with the same ID: p1=" + p1 + "; p2=" + p2);
    }

    private static class Row {
        Entity loaded;
        Entity saved;
        boolean writable;

        void load(Entity entity) {
            if (loaded == null) {
                loaded = entity;
            }
        }

        void save(Entity entity) {
            saved = entity;
            writable = true;
        }

        void delete() {
            saved = null;
            writable = true;
        }

        Stream> projectionsBefore() {
            return writable && loaded != null ? loaded.createProjections().stream() : Stream.empty();
        }

        Stream> projectionsAfter() {
            return writable && saved != null ? saved.createProjections().stream() : Stream.empty();
        }

        void flush() {
            if (writable) {
                loaded = saved;
            }
            saved = null;
            writable = false;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy