diff --git a/performanceDb/src/main/java/org/lucares/performance/db/Group.java b/performanceDb/src/main/java/org/lucares/performance/db/Group.java new file mode 100644 index 0000000..93ae896 --- /dev/null +++ b/performanceDb/src/main/java/org/lucares/performance/db/Group.java @@ -0,0 +1,23 @@ +package org.lucares.performance.db; + +import java.util.List; + +class Group { + private final Tags tags; + + private final List files; + + public Group(final Tags tags, final List files) { + super(); + this.tags = tags; + this.files = files; + } + + public Tags getTags() { + return tags; + } + + public List getFiles() { + return files; + } +} diff --git a/performanceDb/src/main/java/org/lucares/performance/db/GroupResult.java b/performanceDb/src/main/java/org/lucares/performance/db/GroupResult.java index ead49d1..8247dc3 100644 --- a/performanceDb/src/main/java/org/lucares/performance/db/GroupResult.java +++ b/performanceDb/src/main/java/org/lucares/performance/db/GroupResult.java @@ -15,6 +15,9 @@ public class GroupResult { this.groupedBy = groupedBy; } + /** + * @return {@link Stream} unbound, unordered and non-parallel + */ public Stream asStream() { return entries; } diff --git a/performanceDb/src/main/java/org/lucares/performance/db/Grouping.java b/performanceDb/src/main/java/org/lucares/performance/db/Grouping.java new file mode 100644 index 0000000..c741d93 --- /dev/null +++ b/performanceDb/src/main/java/org/lucares/performance/db/Grouping.java @@ -0,0 +1,59 @@ +package org.lucares.performance.db; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Grouping { + + public static final String NO_GROUPING = null; + private final List groups = new ArrayList<>(); + + private Grouping(final Group group) { + this.groups.add(group); + } + + private Grouping(final Collection groups) { + this.groups.addAll(groups); + } + + public static Grouping groupBy(final List pdbFiles, final String groupByField) { + + final Grouping result; + if (groupByField == NO_GROUPING) { + final Group group = new Group(null, pdbFiles); + + result = new Grouping(group); + } else { + final Map grouping = new HashMap<>(); + + for (final PdbFile pdbFile : pdbFiles) { + final Tags tags = pdbFile.getTags(); + final String value = tags.getValue(groupByField); + + if (value != null) { + addIfNotExists(grouping, groupByField, value); + grouping.get(value).getFiles().add(pdbFile); + } + } + result = new Grouping(grouping.values()); + } + return result; + } + + private static void addIfNotExists(final Map grouping, final String groupByField, + final String value) { + if (!grouping.containsKey(value)) { + final Tags tags = Tags.create(groupByField, value); + final List files = new ArrayList<>(); + + grouping.put(value, new Group(tags, files)); + } + } + + public Collection getGroups() { + return groups; + } +} diff --git a/performanceDb/src/main/java/org/lucares/performance/db/PerformanceDb.java b/performanceDb/src/main/java/org/lucares/performance/db/PerformanceDb.java index eae78c3..931e58a 100644 --- a/performanceDb/src/main/java/org/lucares/performance/db/PerformanceDb.java +++ b/performanceDb/src/main/java/org/lucares/performance/db/PerformanceDb.java @@ -3,6 +3,7 @@ package org.lucares.performance.db; import java.io.IOException; import java.nio.file.Path; import java.time.OffsetDateTime; +import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -112,17 +113,43 @@ public class PerformanceDb implements AutoCloseable { } } + /** + * + * @param query + * @return + */ + public Result get(final String query) { + return get(query, Grouping.NO_GROUPING); + } + /** * Return the entries as an unbound, ordered and non-parallel stream. * * @param query - * @return {@link Stream} unbound, ordered and non-parallel + * @param groupBy + * the tag to group by + * @return {@link Result} */ - public Result get(final String query) { + public Result get(final String query, final String groupBy) { final List pdbFiles = tagsToFile.getFilesForQuery(query); - final Stream stream = toStream(pdbFiles); - return new Result(new GroupResult(stream, Tags.EMPTY)); + + final Grouping grouping = Grouping.groupBy(pdbFiles, groupBy); + + final Result result = toResult(grouping); + + return result; + } + + private Result toResult(final Grouping grouping) { + final List groupResults = new ArrayList<>(); + for (final Group group : grouping.getGroups()) { + final Stream stream = toStream(group.getFiles()); + final GroupResult groupResult = new GroupResult(stream, group.getTags()); + groupResults.add(groupResult); + } + final Result result = new Result(groupResults); + return result; } private Stream toStream(final List pdbFiles) { diff --git a/performanceDb/src/main/java/org/lucares/performance/db/Query.java b/performanceDb/src/main/java/org/lucares/performance/db/Query.java index c715cb5..8114d47 100644 --- a/performanceDb/src/main/java/org/lucares/performance/db/Query.java +++ b/performanceDb/src/main/java/org/lucares/performance/db/Query.java @@ -5,12 +5,12 @@ final class Query { final StringBuilder result = new StringBuilder(); for (final String key : tags.getKeys()) { - tags.getValue(key).ifPresent(value -> { - result.append(key); - result.append("="); - result.append(value); - result.append(" "); - }); + final String value = tags.getValue(key); + + result.append(key); + result.append("="); + result.append(value); + result.append(" "); } return result.toString().trim(); diff --git a/performanceDb/src/main/java/org/lucares/performance/db/Result.java b/performanceDb/src/main/java/org/lucares/performance/db/Result.java index a61e95c..02b7ede 100644 --- a/performanceDb/src/main/java/org/lucares/performance/db/Result.java +++ b/performanceDb/src/main/java/org/lucares/performance/db/Result.java @@ -1,6 +1,8 @@ package org.lucares.performance.db; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; public class Result { @@ -8,7 +10,11 @@ public class Result { private final List groupResults; public Result(final GroupResult... groupResults) { - this.groupResults = Arrays.asList(groupResults); + this(Arrays.asList(groupResults)); + } + + public Result(final Collection groupResults) { + this.groupResults = new ArrayList<>(groupResults); } public GroupResult singleGroup() { @@ -17,4 +23,8 @@ public class Result { } return groupResults.get(0); } + + public List getGroups() { + return new ArrayList<>(groupResults); + } } diff --git a/performanceDb/src/main/java/org/lucares/performance/db/Tag.java b/performanceDb/src/main/java/org/lucares/performance/db/Tag.java new file mode 100644 index 0000000..7f28c8d --- /dev/null +++ b/performanceDb/src/main/java/org/lucares/performance/db/Tag.java @@ -0,0 +1,57 @@ +package org.lucares.performance.db; + +public class Tag { + private final String key; + + private final String value; + + public Tag(final String key, final String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return key + "=" + value; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final Tag other = (Tag) obj; + if (key == null) { + if (other.key != null) + return false; + } else if (!key.equals(other.key)) + return false; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } + +} diff --git a/performanceDb/src/main/java/org/lucares/performance/db/Tags.java b/performanceDb/src/main/java/org/lucares/performance/db/Tags.java index 40b733a..d249304 100644 --- a/performanceDb/src/main/java/org/lucares/performance/db/Tags.java +++ b/performanceDb/src/main/java/org/lucares/performance/db/Tags.java @@ -4,7 +4,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -13,14 +12,14 @@ import java.util.function.BiConsumer; public class Tags { static final Tags EMPTY = new Tags(); - private final Map tags; + private final Map tags; private Tags() { super(); tags = Collections.emptyMap(); } - private Tags(final Map tags) { + private Tags(final Map tags) { this.tags = tags; ensureNoInternalFields(); } @@ -38,15 +37,15 @@ public class Tags { } public static Tags create(final String key1, final String value1, final String key2, final String value2) { - final Map tags = new HashMap<>(2); - tags.put(key1, value1); - tags.put(key2, value2); + final Map tags = new HashMap<>(2); + tags.put(key1, new Tag(key1, value1)); + tags.put(key2, new Tag(key2, value2)); return new Tags(tags); } - public static Tags create(final String key1, final String value1) { - final Map tags = new HashMap<>(1); - tags.put(key1, value1); + public static Tags create(final String key, final String value) { + final Map tags = new HashMap<>(1); + tags.put(key, new Tag(key, value)); return new Tags(tags); } @@ -54,8 +53,9 @@ public class Tags { Objects.requireNonNull(key, "key must not be null"); Objects.requireNonNull(value, "value must not be null"); - final Map newTags = new HashMap<>(tags); - newTags.put(key.intern(), value.intern()); + final Map newTags = new HashMap<>(tags); + + newTags.put(key, new Tag(key, value)); return new Tags(newTags); } @@ -71,9 +71,10 @@ public class Tags { return result; } - public Optional getValue(final String key) { - final String value = tags.get(key); - return Optional.ofNullable(value); + public String getValue(final String key) { + final Tag tag = tags.get(key); + final String value = tag != null ? tag.getValue() : null; + return value; } public Set getKeys() { @@ -81,8 +82,8 @@ public class Tags { } public void forEach(final BiConsumer keyValueConsumer) { - for (final Map.Entry e : tags.entrySet()) { - keyValueConsumer.accept(e.getKey(), e.getValue()); + for (final Map.Entry e : tags.entrySet()) { + keyValueConsumer.accept(e.getKey(), e.getValue().getValue()); } } @@ -126,9 +127,11 @@ public class Tags { for (final String key : keys) { + final String value = tags.get(key).getValue(); + result.append(substr(key, cutAt)); result.append("-"); - result.append(substr(tags.get(key), cutAt)); + result.append(substr(value, cutAt)); result.append("_"); } diff --git a/performanceDb/src/test/java/org/lucares/performance/db/PerformanceDbTest.java b/performanceDb/src/test/java/org/lucares/performance/db/PerformanceDbTest.java index e89db1e..22ed0b6 100644 --- a/performanceDb/src/test/java/org/lucares/performance/db/PerformanceDbTest.java +++ b/performanceDb/src/test/java/org/lucares/performance/db/PerformanceDbTest.java @@ -163,14 +163,39 @@ public class PerformanceDbTest { final TimeRange timeRange = new TimeRange(from, to); final long numberOfEntries = timeRange.duration().toHours(); - final Tags tagsOne = Tags.create("myKey", "one", "commonKey", "commonValue"); - final Tags tagsTwo = Tags.create("myKey", "two", "commonKey", "commonValue"); - final Tags tagsThree = Tags.create("myKey", "three", "commonKey", "commonValue"); - storeEntries(db, timeRange, numberOfEntries, tagsOne, 1); - storeEntries(db, timeRange, numberOfEntries, tagsTwo, 2); - storeEntries(db, timeRange, numberOfEntries, tagsThree, 3); + final String key = "myKey"; + final Tags tagsOne = Tags.create(key, "one", "commonKey", "commonValue"); + final Tags tagsTwo = Tags.create(key, "two", "commonKey", "commonValue"); + final Tags tagsThree = Tags.create(key, "three", "commonKey", "commonValue"); + final List entriesOne = storeEntries(db, timeRange, numberOfEntries, tagsOne, 1); + final List entriesTwo = storeEntries(db, timeRange, numberOfEntries, tagsTwo, 2); + final List entriesThree = storeEntries(db, timeRange, numberOfEntries, tagsThree, 3); - final Result result = db.get("commonKey=commonValue | groupBy myKey"); + final Result result = db.get("commonKey=commonValue", key); + + final List groups = result.getGroups(); + + final List actualGroup = new ArrayList<>(); + for (final GroupResult groupResult : groups) { + final String groupedByValue = groupResult.getGroupedBy().getValue(key); + actualGroup.add(groupedByValue); + + switch (groupedByValue) { + case "one": + Assert.assertEquals(groupResult.asList(), entriesOne); + break; + case "two": + Assert.assertEquals(groupResult.asList(), entriesTwo); + break; + case "three": + Assert.assertEquals(groupResult.asList(), entriesThree); + break; + + default: + break; + } + } + Assert.assertEquals(actualGroup, Arrays.asList("one", "two", "three")); } }