Javers ~ Запрос текущего состояния репозитория - PullRequest
0 голосов
/ 19 июня 2020

Это звучит как-то так c должно быть легко, но почему-то я не могу понять, как это сделать.

Используя Javers, как я могу получить текущее состояние репозитория?

Пример: у меня есть три символа, один из которых обновляется. Теперь я хочу запросить список всех символов в том виде, в каком они есть в настоящее время:

public class JaversMemoryRepositoryTest {
    private static final String AUTHOR_NAME = "Luther Lansfeld";
    private static Javers javersRepository;
    GameCharacter sylvia;
    GameCharacter bokay;
    GameCharacter cyrus;
    
    @BeforeEach
    public void setUpJaversRepository() {
        javersRepository = JaversBuilder.javers().build();
        sylvia = GameCharacters.sylvia();
        javersRepository.commit(AUTHOR_NAME, sylvia);
        sylvia.name = "Sylvia the Atomic";
        javersRepository.commit(AUTHOR_NAME, sylvia);
        bokay= GameCharacters.bokay();
        javersRepository.commit(AUTHOR_NAME, bokay);
        cyrus= GameCharacters.cyrus();
        javersRepository.commit(AUTHOR_NAME, cyrus);
    }

    @Test
    public void queryShouldFindLatestVersionOfEachCharacter() {
        JqlQuery entryQuery = QueryBuilder.byClass(GameCharacter.class).build();
        List<Shadow<GameCharacter>> gameCharacterShadowList
            = javersRepository.findShadows(entryQuery);
        assertEquals(3, gameCharacterShadowList.size());
    }
}

Однако этот тест не проходит (получил 4, ожидалось 3), потому что я получаю две тени для Сильвии.

Я знаю, что, вероятно, я мог бы решить эту проблему с помощью функции, которая выполняет итерацию по тени, разделяет их по идентификатору и оставляет только ту, которая имеет самую последнюю версию, но почему-то это кажется излишним для чего-то настолько базового c, что я уверен что у Джавера это должно быть где-то.

Может быть, что-то вроде:

JqlQuery entryQuery = QueryBuilder.byClass(GameCharacter.class).withLatestVersion().build();

... кроме того, что этого не существует. Но речь идет о том, что я здесь пытаюсь сделать.

Или противоположность:

JqlQuery entryQuery = QueryBuilder.byClass(GameCharacter.class).withVersion(1).build();

... который получает самую старую версию каждого GameCharacter. Я уже пробовал withVersion(-1) для этого, но, очевидно, Javers не считает версии с конца.

Мы будем очень благодарны за любые отзывы по этому поводу.

EDIT : Вот тестовый пример, который в настоящее время дает сбой, поскольку предполагаемое поведение не реализовано, но хорошо воспроизводит вариант использования:

import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.*;

import java.util.*;

import org.javers.core.*;
import org.javers.core.metamodel.annotation.Id;
import org.javers.repository.jql.*;
import org.javers.shadow.Shadow;
import org.junit.jupiter.api.*;

public class GetLatestVersionTest {
    private static final String FIRST_STRING = "This string should be in the end result";
    private static final String SECOND_STRING = "This string will get overwritten with a newer version";
    private static final String THIRD_STRING = "This string should also be in the end result";
    private static final String FOURTH_STRING = "This string should be in the end result as well";
    private static final String AUTHOR_NAME = "Test Author";

    @Test
    public void shouldRetrieveOnlyLatestVersionsOfAllObjects() {
        Javers javers = JaversBuilder.javers().build();
        StringContainer firstObject = new StringContainer(FIRST_STRING);
        javers.commit(AUTHOR_NAME, firstObject);
        StringContainer secondObject = new StringContainer(SECOND_STRING);
        javers.commit(AUTHOR_NAME, secondObject);
        StringContainer thirdObject = new StringContainer(THIRD_STRING);
        javers.commit(AUTHOR_NAME, thirdObject);
        secondObject.string = FOURTH_STRING;
        javers.commit(AUTHOR_NAME, secondObject);
        
        //At this point, some logic is needed that will only query the latest version
        JqlQuery entryQuery = QueryBuilder.byClass(StringContainer.class).withVersion(-1).build();
        List<Shadow<StringContainer>> mostRecentShadows = javers.findShadows(entryQuery);
        
        assertEquals(3, mostRecentShadows.size());
        List<String> mostRecentStrings = new ArrayList<>();
        for(Shadow<StringContainer> shadow : mostRecentShadows) {
            mostRecentStrings.add(shadow.get().string);
        }
        assertTrue(mostRecentStrings.contains(FIRST_STRING));
        assertFalse(mostRecentStrings.contains(SECOND_STRING));
        assertTrue(mostRecentStrings.contains(THIRD_STRING));
        assertTrue(mostRecentStrings.contains(FOURTH_STRING));
    }
}

class StringContainer {
    @Id
    public String string;
    
    public StringContainer(String string) {
        this.string = string;
    }
}

Зависимости Gradle для этого:

plugins {
    id 'java-library-distribution'
}

repositories {
    jcenter()
}

dependencies {
    // Use JUnit test framework
    testCompile("org.junit.jupiter:junit-jupiter:5.6.0")
    testCompile("org.junit.platform:junit-platform-runner:1.6.0")
    
    //Logging
    compile 'commons-logging:commons-logging:1.2'
    compile 'log4j:log4j:1.2.17'
    compile 'org.slf4j:slf4j-log4j12:1.7.25'
    compile 'commons-logging:commons-logging:1.2'
    
    //JaVers
    compile 'org.javers:javers-core:5.10.0'
    compile 'org.javers:javers-persistence-mongo:5.10.0'
}

1 Ответ

0 голосов
/ 19 июня 2020

Я написал служебный класс, который использует тот факт, что тени сортируются по возрастанию, чтобы решить эту проблему с минимальными усилиями:

    public static List<Shadow<GameCharacter>> getLatestShadowsFrom(
        List<Shadow<GameCharacter>> gameCharacterShadowList
    ) {
        List<Shadow<GameCharacter>> latestGameCharacterShadows
            = new ArrayList<>();
        List<String> registeredGameCharacterShadowIds
            = new ArrayList<>(); 
        for(Shadow<GameCharacter> gameCharacterShadow : gameCharacterShadowList) {
            String gameCharacterId
                = gameCharacterShadow.get()._id;
            if(!registeredGameCharacterShadowIds.contains(gameCharacterId)) {
                registeredGameCharacterShadowIds.add(gameCharacterId);
                latestGameCharacterShadows.add(gameCharacterShadow);
            }
        }
        return latestGameCharacterShadows;
    }

Применяется следующим образом:

    @Test
    public void queryShouldFindLatestVersionOfEachCharacter() {
        JqlQuery entryQuery = QueryBuilder.byClass(GameCharacter.class).build();
        List<Shadow<GameCharacter>> allGameCharacterShadows
            = javersRepository.findShadows(entryQuery);
        List<Shadow<GameCharacter>> latestGameCharacterShadows
            = JaversUtilities.getLatestShadowsFrom(allGameCharacterShadows);
        assertEquals(3, latestGameCharacterShadows.size());
    }

Однако основным недостатком этого подхода является то, что, поскольку эта функция полагается на поле _id в GameCharacter, я должен создать копию этой функции для каждого объекта с расходящейся переменной идентификатора (все эти которые имеют поле _id, в конце концов, могут быть сгруппированы в абстрактный класс), поэтому это не кажется мне оптимальным.

Итак, если у кого-то есть лучшее решение, не стесняйтесь размещать его здесь. Я по-прежнему сохраню здесь этот обходной путь, поскольку он выполняет свою работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...