Skip to content

Commit 007013a

Browse files
Antoine Boyerbbakerman
Antoine Boyer
authored andcommitted
Ability to atomically compute a data loader if absent
1 parent 885fcd2 commit 007013a

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

src/main/java/org/dataloader/DataLoaderRegistry.java

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package org.dataloader;
22

3-
import org.dataloader.stats.Statistics;
4-
53
import java.util.ArrayList;
64
import java.util.HashSet;
75
import java.util.List;
86
import java.util.Map;
97
import java.util.Set;
108
import java.util.concurrent.ConcurrentHashMap;
9+
import java.util.function.Function;
10+
import org.dataloader.stats.Statistics;
1111

1212
/**
1313
* This allows data loaders to be registered together into a single place so
@@ -30,6 +30,26 @@ public DataLoaderRegistry register(String key, DataLoader<?, ?> dataLoader) {
3030
return this;
3131
}
3232

33+
/**
34+
* Computes a data loader if absent or return it if it was
35+
* already registered at that key.
36+
*
37+
* Note: The entire method invocation is performed atomically,
38+
* so the function is applied at most once per key.
39+
*
40+
* @param key the key of the data loader
41+
* @param mappingFunction the function to compute a data loader
42+
* @param <K> the type of keys
43+
* @param <V> the type of values
44+
*
45+
* @return a data loader
46+
*/
47+
@SuppressWarnings("unchecked")
48+
public <K, V> DataLoader<K, V> computeIfAbsent(final String key,
49+
final Function<String, DataLoader<?, ?>> mappingFunction) {
50+
return (DataLoader<K, V>) dataLoaders.computeIfAbsent(key, mappingFunction);
51+
}
52+
3353
/**
3454
* This will combine all the current data loaders in this registry and all the data loaders from the specified registry
3555
* and return a new combined registry

src/test/java/org/dataloader/DataLoaderRegistryTest.java

+33-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package org.dataloader;
22

3+
import java.util.concurrent.CompletableFuture;
34
import org.dataloader.stats.Statistics;
45
import org.junit.Test;
56

6-
import java.util.concurrent.CompletableFuture;
7-
87
import static java.util.Arrays.asList;
98
import static org.hamcrest.Matchers.equalTo;
109
import static org.hamcrest.Matchers.hasItems;
@@ -101,4 +100,35 @@ public void stats_can_be_collected() throws Exception {
101100
assertThat(statistics.getLoadErrorCount(), equalTo(0L));
102101
assertThat(statistics.getBatchLoadExceptionCount(), equalTo(0L));
103102
}
104-
}
103+
104+
@Test
105+
public void computeIfAbsent_creates_a_data_loader_if_there_was_no_value_at_key() {
106+
107+
DataLoaderRegistry registry = new DataLoaderRegistry();
108+
109+
DataLoader<Object, Object> dlA = new DataLoader<>(identityBatchLoader);
110+
DataLoader<Object, Object> registered = registry.computeIfAbsent("a", (key) -> dlA);
111+
112+
assertThat(registered, equalTo(dlA));
113+
assertThat(registry.getKeys(), hasItems("a"));
114+
assertThat(registry.getDataLoaders(), hasItems(dlA));
115+
}
116+
117+
@Test
118+
public void computeIfAbsent_returns_an_existing_data_loader_if_there_was_a_value_at_key() {
119+
120+
DataLoaderRegistry registry = new DataLoaderRegistry();
121+
122+
DataLoader<Object, Object> dlA = new DataLoader<>(identityBatchLoader);
123+
registry.computeIfAbsent("a", (key) -> dlA);
124+
125+
// register again at same key
126+
DataLoader<Object, Object> dlA2 = new DataLoader<>(identityBatchLoader);
127+
DataLoader<Object, Object> registered = registry.computeIfAbsent("a", (key) -> dlA2);
128+
129+
assertThat(registered, equalTo(dlA));
130+
assertThat(registry.getKeys(), hasItems("a"));
131+
assertThat(registry.getDataLoaders(), hasItems(dlA));
132+
}
133+
134+
}

0 commit comments

Comments
 (0)