-
Notifications
You must be signed in to change notification settings - Fork 2
Implement History APIs Client #213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2670088
7c0c60c
f69cd48
6edb436
b06cbd6
ec3abd8
938d44e
a5cb0b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package io.lionweb.repoclient; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import io.lionweb.lioncore.java.LionWebVersion; | ||
import io.lionweb.lioncore.java.model.ClassifierInstanceUtils; | ||
import io.lionweb.lioncore.java.model.Node; | ||
import io.lionweb.lioncore.java.model.impl.DynamicNode; | ||
import io.lionweb.repoclient.api.HistorySupport; | ||
import io.lionweb.repoclient.api.RepositoryConfiguration; | ||
import io.lionweb.repoclient.api.RepositoryVersionToken; | ||
import io.lionweb.repoclient.languages.PropertiesLanguage; | ||
import io.lionweb.repoclient.testing.AbstractRepoClientFunctionalTest; | ||
import java.io.IOException; | ||
import java.util.*; | ||
import org.junit.jupiter.api.Test; | ||
import org.testcontainers.junit.jupiter.Testcontainers; | ||
|
||
@Testcontainers | ||
public class LionWebRepoClientHistoryApiFunctionalTest extends AbstractRepoClientFunctionalTest { | ||
|
||
public LionWebRepoClientHistoryApiFunctionalTest() { | ||
super(LionWebVersion.v2023_1, false); | ||
} | ||
|
||
@Test | ||
public void partitionsCRUD() throws IOException { | ||
String repoName = "myHistoryDB1"; | ||
LionWebRepoClient client = | ||
new LionWebRepoClient(LionWebVersion.v2023_1, "localhost", getModelRepoPort(), repoName); | ||
client.createRepository( | ||
new RepositoryConfiguration(repoName, LionWebVersion.v2023_1, HistorySupport.ENABLED)); | ||
client.getJsonSerialization().registerLanguage(PropertiesLanguage.propertiesLanguage); | ||
|
||
// Create partition | ||
DynamicNode f1 = new DynamicNode("f1", PropertiesLanguage.propertiesPartition); | ||
DynamicNode f2 = new DynamicNode("f2", PropertiesLanguage.propertiesPartition); | ||
RepositoryVersionToken v1 = | ||
client.createPartitions(client.getJsonSerialization().serializeNodesToJsonString(f1, f2)); | ||
|
||
// Delete partitions | ||
RepositoryVersionToken v2 = client.deletePartitions(Arrays.asList("f1")); | ||
|
||
// Check list | ||
RepositoryVersionToken v0 = new RepositoryVersionToken("0"); | ||
List<Node> partitionsAt0 = client.listPartitions(v0); | ||
assertEquals(0, partitionsAt0.size()); | ||
|
||
List<Node> partitionsAt1 = client.listPartitions(v1); | ||
assertEquals(2, partitionsAt1.size()); | ||
assertTrue(partitionsAt1.stream().anyMatch(p -> p.getID().equals("f1"))); | ||
assertTrue(partitionsAt1.stream().anyMatch(p -> p.getID().equals("f2"))); | ||
|
||
List<Node> partitionsAt2 = client.listPartitions(v2); | ||
assertEquals(1, partitionsAt2.size()); | ||
assertEquals("f2", partitionsAt2.get(0).getID()); | ||
} | ||
|
||
@Test | ||
public void partitionHistory() throws IOException { | ||
String repoName = "myHistoryDB2"; | ||
LionWebRepoClient client = | ||
new LionWebRepoClient(LionWebVersion.v2023_1, "localhost", getModelRepoPort(), repoName); | ||
client.createRepository( | ||
new RepositoryConfiguration(repoName, LionWebVersion.v2023_1, HistorySupport.ENABLED)); | ||
client.getJsonSerialization().registerLanguage(PropertiesLanguage.propertiesLanguage); | ||
|
||
// Create partition, initially empty | ||
DynamicNode p1 = new DynamicNode("p1", PropertiesLanguage.propertiesPartition); | ||
RepositoryVersionToken v0 = | ||
client.createPartitions(client.getJsonSerialization().serializeNodesToJsonString(p1)); | ||
|
||
// Populate partition | ||
DynamicNode f1 = new DynamicNode("f1", PropertiesLanguage.propertiesFile); | ||
ClassifierInstanceUtils.setPropertyValueByName(f1, "path", "a/b/c"); | ||
ClassifierInstanceUtils.addChild(p1, "files", f1); | ||
RepositoryVersionToken v1 = client.store(p1); | ||
|
||
// Modify property | ||
ClassifierInstanceUtils.setPropertyValueByName(f1, "path", "a/b/foo"); | ||
RepositoryVersionToken v2 = client.store(p1); | ||
|
||
// Add child | ||
DynamicNode f2 = new DynamicNode("f2", PropertiesLanguage.propertiesFile); | ||
ClassifierInstanceUtils.setPropertyValueByName(f2, "path", "a/b/c2"); | ||
ClassifierInstanceUtils.addChild(p1, "files", f2); | ||
RepositoryVersionToken v3 = client.store(p1); | ||
|
||
// Delete child | ||
p1.removeChild(f1); | ||
RepositoryVersionToken v4 = client.store(p1); | ||
|
||
// Check data | ||
Node p1_v0 = client.retrieve(v0, p1.getID()); | ||
assertEquals(0, ClassifierInstanceUtils.getChildrenByContainmentName(p1_v0, "files").size()); | ||
|
||
Node p1_v1 = client.retrieve(v1, p1.getID()); | ||
assertEquals(1, ClassifierInstanceUtils.getChildrenByContainmentName(p1_v1, "files").size()); | ||
Node f1_v1 = ClassifierInstanceUtils.getChildrenByContainmentName(p1_v1, "files").get(0); | ||
assertEquals("a/b/c", ClassifierInstanceUtils.getPropertyValueByName(f1_v1, "path")); | ||
|
||
Node p1_v2 = client.retrieve(v2, p1.getID()); | ||
assertEquals(1, ClassifierInstanceUtils.getChildrenByContainmentName(p1_v2, "files").size()); | ||
Node f1_v2 = ClassifierInstanceUtils.getChildrenByContainmentName(p1_v2, "files").get(0); | ||
assertEquals("a/b/foo", ClassifierInstanceUtils.getPropertyValueByName(f1_v2, "path")); | ||
|
||
Node p1_v3 = client.retrieve(v3, p1.getID()); | ||
assertEquals(2, ClassifierInstanceUtils.getChildrenByContainmentName(p1_v3, "files").size()); | ||
Node f1_v3 = ClassifierInstanceUtils.getChildrenByContainmentName(p1_v3, "files").get(0); | ||
assertEquals("a/b/foo", ClassifierInstanceUtils.getPropertyValueByName(f1_v3, "path")); | ||
Node f2_v3 = ClassifierInstanceUtils.getChildrenByContainmentName(p1_v3, "files").get(1); | ||
assertEquals("a/b/c2", ClassifierInstanceUtils.getPropertyValueByName(f2_v3, "path")); | ||
|
||
Node p1_v4 = client.retrieve(v4, p1.getID()); | ||
assertEquals(1, ClassifierInstanceUtils.getChildrenByContainmentName(p1_v4, "files").size()); | ||
Node f2_v4 = ClassifierInstanceUtils.getChildrenByContainmentName(p1_v4, "files").get(0); | ||
assertEquals("a/b/c2", ClassifierInstanceUtils.getPropertyValueByName(f2_v4, "path")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,17 +3,21 @@ | |
import io.lionweb.lioncore.java.model.Node; | ||
import java.io.IOException; | ||
import java.util.List; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
public interface BulkAPIClient { | ||
void createPartitions(List<Node> partitions) throws IOException; | ||
@Nullable | ||
RepositoryVersionToken createPartitions(List<Node> partitions) throws IOException; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we separate regular client from history client, do we want to introduce history stuff ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have separate interfaces: one for each module of the repository. We do that for two reasons:
For the implementation currently in this codebase I think it makes sense to support all the interfaces because most methods work both for repository with or without history. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking whether we want to have anything history-related in the non-history Interface. We still can implement all interfaces on one class. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The non-history interface is extended by the history one. We could duplicate the methods such as listPartitions and createPartitions, but then one would need to call different methods depending on the fact they are operating on a repo with history or without. It seems to be over complicated. I thought about that for one week but I could not find a proper solution, so I would lean toward merging this as-is |
||
|
||
void deletePartitions(List<String> ids) throws IOException; | ||
@Nullable | ||
RepositoryVersionToken deletePartitions(List<String> ids) throws IOException; | ||
|
||
List<Node> listPartitions() throws IOException; | ||
|
||
List<String> ids(int count) throws IOException; | ||
|
||
void store(List<Node> nodes) throws IOException; | ||
@Nullable | ||
RepositoryVersionToken store(List<Node> nodes) throws IOException; | ||
|
||
List<Node> retrieve(List<String> nodeIds, int limit) throws IOException; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package io.lionweb.repoclient.api; | ||
|
||
import io.lionweb.lioncore.java.model.Node; | ||
import java.io.IOException; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public interface HistoryAPIClient { | ||
@NotNull | ||
List<Node> listPartitions(RepositoryVersionToken repoVersion) throws IOException; | ||
|
||
@NotNull | ||
List<Node> retrieve(RepositoryVersionToken repoVersion, @NotNull List<String> nodeIds, int limit) | ||
throws IOException; | ||
|
||
default Node retrieve(RepositoryVersionToken repoVersion, @NotNull String nodeId, int limit) | ||
throws IOException { | ||
List<Node> res = retrieve(repoVersion, Arrays.asList(nodeId), limit); | ||
Node node = res.stream().filter(n -> n.getID().equals(nodeId)).findFirst().get(); | ||
return node; | ||
} | ||
|
||
default Node retrieve(RepositoryVersionToken repoVersion, @NotNull String nodeId) | ||
throws IOException { | ||
return retrieve(repoVersion, nodeId, Integer.MAX_VALUE); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package io.lionweb.repoclient.api; | ||
|
||
import java.util.Objects; | ||
|
||
/** Value distinguishing a version of a particular repository. */ | ||
public class RepositoryVersionToken { | ||
private final String token; | ||
|
||
public RepositoryVersionToken(String token) { | ||
this.token = token; | ||
} | ||
|
||
public String getToken() { | ||
return token; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (!(o instanceof RepositoryVersionToken)) return false; | ||
RepositoryVersionToken that = (RepositoryVersionToken) o; | ||
return Objects.equals(token, that.token); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hashCode(token); | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.