Skip to content

Commit

Permalink
Added to combine as map methods to value with failures (#2635)
Browse files Browse the repository at this point in the history
Co-authored-by: James White <[email protected]>
  • Loading branch information
James-OpenGamma and James-OpenGamma authored Feb 9, 2024
1 parent 07d7fbf commit 720b231
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.collect.ArgChecker;

Expand Down Expand Up @@ -232,6 +233,44 @@ public static <T> BinaryOperator<ValueWithFailures<T>> combiningValues(BinaryOpe
StreamBuilder::build);
}

/**
* Returns a collector that can be used to create a combined {@code ValueWithFailure}
* from a stream of entries where the values contain {@code Result} instances.
* <p>
* This collects a {@code Stream<Map.Entry<K, Result<V>>>} to a {@code ValueWithFailures<Map<K, V>>}.
*
* @param <K> the type of the map key
* @param <V> the type of the success map values
* @throws IllegalArgumentException if duplicate keys are collected
* @return a {@link Collector}
*/
public static <K, V> Collector<? super Map.Entry<K, Result<V>>, ? , ValueWithFailures<Map<K, V>>> toCombinedResultsAsMap() {
return Collector.of(
() -> new MapStreamBuilder<>(ImmutableMap.<K, V>builder()),
MapStreamBuilder::addResult,
MapStreamBuilder::combine,
MapStreamBuilder::build);
}

/**
* Returns a collector that creates a combined {@code ValueWithFailure} from a stream
* of entries where the values contain {@code ValueWithFailure} instances.
* <p>
* This collects a {@code Stream<Map.Entry<K, ValueWithFailures<V>>} to a {@code ValueWithFailures<Map<K, V>>}.
*
* @param <K> the type of the map key
* @param <V> the type of the entry success values in the {@link ValueWithFailures}
* @throws IllegalArgumentException if duplicate keys are collected
* @return a {@link Collector}
*/
public static <K, V> Collector<? super Map.Entry<K, ValueWithFailures<V>>, ? , ValueWithFailures<Map<K, V>>> toCombinedValuesAsMap() {
return Collector.of(
() -> new MapStreamBuilder<>(ImmutableMap.<K, V>builder()),
MapStreamBuilder::add,
MapStreamBuilder::combine,
MapStreamBuilder::build);
}

/**
* Combines separate instances of {@code ValueWithFailure} into a single instance,
* using a list to collect the values.
Expand Down Expand Up @@ -315,6 +354,39 @@ private <C extends Collection<T>> ValueWithFailures<C> build() {
}
}

private static final class MapStreamBuilder<K, V, B extends ImmutableMap.Builder<K, V>> {

private final B values;
private final ImmutableList.Builder<FailureItem> failures = ImmutableList.builder();

private MapStreamBuilder(B values) {
this.values = values;
}

private void add(Map.Entry<K, ValueWithFailures<V>> item) {
values.put(item.getKey(), item.getValue().getValue());
failures.addAll(item.getValue().getFailures());
}

private void addResult(Map.Entry<K, Result<V>> item) {
Result<V> itemValue = item.getValue();
itemValue.ifSuccess(value -> values.put(item.getKey(), value));
itemValue.ifFailure(failure -> failures.addAll(failure.getItems()));
}

private MapStreamBuilder<K, V, B> combine(MapStreamBuilder<K, V, B> builder) {
values.putAll(builder.values.build());
failures.addAll(builder.failures.build());
return this;
}

// cast to the right collection type, can assume the methods in this class are using the correct types
@SuppressWarnings("unchecked")
private <C extends Map<K, V>> ValueWithFailures<C> build() {
return (ValueWithFailures<C>) ValueWithFailures.of(values.buildOrThrow(), failures.build());
}
}

//-------------------------------------------------------------------------
/**
* Checks if there are any failures.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.collect.Guavate;
import com.opengamma.strata.collect.MapStream;
import com.opengamma.strata.collect.Messages;

/**
Expand Down Expand Up @@ -259,6 +262,49 @@ public void test_toCombinedResultsAsList() {
assertThat(failures.get(0).getMessage()).isEqualTo("Uh oh");
}

@Test
public void test_toCombinedResultAsMap() {
Map<String, Result<String>> resultsMap = ImmutableMap.of(
"key 1", Result.success("success 1"),
"key 2", Result.failure(FAILURE1),
"key 3", Result.success("success 2"));

ValueWithFailures<Map<String, String>> valuesWithFailures = MapStream.of(resultsMap)
.collect(ValueWithFailures.toCombinedResultsAsMap());

Map<String, String> expectedResult = ImmutableMap.of(
"key 1", "success 1",
"key 3", "success 2");

assertThat(valuesWithFailures.getValue()).isEqualTo(expectedResult);

assertThat(valuesWithFailures.getFailures())
.singleElement()
.isEqualTo(FAILURE1);
}

@Test
public void test_toCombinedValuesAsMap() {
Map<String, ValueWithFailures<String>> resultsMap = ImmutableMap.of(
"key 1", ValueWithFailures.of("success 1", FAILURE1),
"key 2", ValueWithFailures.of("success 2", FAILURE2),
"key 3", ValueWithFailures.of("success 3"));

ValueWithFailures<Map<String, String>> valuesWithFailures = MapStream.of(resultsMap)
.collect(ValueWithFailures.toCombinedValuesAsMap());

Map<String, String> expectedResult = ImmutableMap.of(
"key 1", "success 1",
"key 2", "success 2",
"key 3", "success 3");

assertThat(valuesWithFailures.getValue()).isEqualTo(expectedResult);

assertThat(valuesWithFailures.getFailures())
.hasSize(2)
.containsExactly(FAILURE1, FAILURE2);
}

@Test
public void test_combineAsList() {
ImmutableList<ValueWithFailures<Double>> listOfValueWithFailures = Stream.of(5d, 6d, 7d)
Expand Down

0 comments on commit 720b231

Please sign in to comment.