Skip to content

Commit 1658732

Browse files
committed
Started work on getIfPresent
1 parent 27a5b6b commit 1658732

File tree

4 files changed

+161
-16
lines changed

4 files changed

+161
-16
lines changed

src/main/java/org/dataloader/DataLoader.java

+25-15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.ArrayList;
2424
import java.util.Collections;
2525
import java.util.List;
26+
import java.util.Optional;
2627
import java.util.concurrent.CompletableFuture;
2728

2829
import static org.dataloader.impl.Assertions.nonNull;
@@ -381,21 +382,30 @@ public CompletableFuture<V> load(K key) {
381382
return load(key, null);
382383
}
383384

384-
/**
385-
* Requests to load the data with the specified key asynchronously, and returns a future of the resulting value.
386-
* <p>
387-
* If batching is enabled (the default), you'll have to call {@link DataLoader#dispatch()} at a later stage to
388-
* start batch execution. If you forget this call the future will never be completed (unless already completed,
389-
* and returned from cache).
390-
* <p>
391-
* The key context object may be useful in the batch loader interfaces such as {@link org.dataloader.BatchLoaderWithContext} or
392-
* {@link org.dataloader.MappedBatchLoaderWithContext} to help retrieve data.
393-
*
394-
* @param key the key to load
395-
* @param keyContext a context object that is specific to this key
396-
*
397-
* @return the future of the value
398-
*/
385+
public Optional<CompletableFuture<V>> getIfPresent(K key) {
386+
return helper.getIfPresent(key);
387+
}
388+
389+
public Optional<CompletableFuture<V>> getIfCompleted(K key) {
390+
return helper.getIfCompleted(key);
391+
}
392+
393+
394+
/**
395+
* Requests to load the data with the specified key asynchronously, and returns a future of the resulting value.
396+
* <p>
397+
* If batching is enabled (the default), you'll have to call {@link DataLoader#dispatch()} at a later stage to
398+
* start batch execution. If you forget this call the future will never be completed (unless already completed,
399+
* and returned from cache).
400+
* <p>
401+
* The key context object may be useful in the batch loader interfaces such as {@link org.dataloader.BatchLoaderWithContext} or
402+
* {@link org.dataloader.MappedBatchLoaderWithContext} to help retrieve data.
403+
*
404+
* @param key the key to load
405+
* @param keyContext a context object that is specific to this key
406+
*
407+
* @return the future of the value
408+
*/
399409
public CompletableFuture<V> load(K key, Object keyContext) {
400410
return helper.load(key, keyContext);
401411
}

src/main/java/org/dataloader/DataLoaderHelper.java

+30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.LinkedHashSet;
99
import java.util.List;
1010
import java.util.Map;
11+
import java.util.Optional;
1112
import java.util.Set;
1213
import java.util.concurrent.CompletableFuture;
1314
import java.util.concurrent.CompletionStage;
@@ -27,6 +28,7 @@
2728
*/
2829
class DataLoaderHelper<K, V> {
2930

31+
3032
class LoaderQueueEntry<K, V> {
3133

3234
final K key;
@@ -68,6 +70,34 @@ Object getCallContext() {
6870
this.stats = stats;
6971
}
7072

73+
Optional<CompletableFuture<V>> getIfPresent(K key) {
74+
synchronized (dataLoader) {
75+
Object cacheKey = getCacheKey(nonNull(key));
76+
boolean cachingEnabled = loaderOptions.cachingEnabled();
77+
if (cachingEnabled) {
78+
if (futureCache.containsKey(cacheKey)) {
79+
stats.incrementCacheHitCount();
80+
return Optional.of(futureCache.get(cacheKey));
81+
}
82+
}
83+
}
84+
return Optional.empty();
85+
}
86+
87+
Optional<CompletableFuture<V>> getIfCompleted(K key) {
88+
synchronized (dataLoader) {
89+
Optional<CompletableFuture<V>> cachedPromise = getIfPresent(key);
90+
if (cachedPromise.isPresent()) {
91+
CompletableFuture<V> promise = cachedPromise.get();
92+
if (promise.isDone()) {
93+
return cachedPromise;
94+
}
95+
}
96+
}
97+
return Optional.empty();
98+
}
99+
100+
71101
CompletableFuture<V> load(K key, Object loadContext) {
72102
synchronized (dataLoader) {
73103
Object cacheKey = getCacheKey(nonNull(key));

src/main/java/org/dataloader/impl/CompletableFutureKit.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static boolean failed(CompletableFuture future) {
4444
}
4545

4646
public static <T> CompletableFuture<List<T>> allOf(List<CompletableFuture<T>> cfs) {
47-
return CompletableFuture.allOf(cfs.toArray(new CompletableFuture[cfs.size()]))
47+
return CompletableFuture.allOf(cfs.toArray(new CompletableFuture[0]))
4848
.thenApply(v -> cfs.stream()
4949
.map(CompletableFuture::join)
5050
.collect(toList())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package org.dataloader;
2+
3+
import org.junit.Test;
4+
5+
import java.util.Optional;
6+
import java.util.concurrent.CompletableFuture;
7+
import java.util.concurrent.CompletionStage;
8+
9+
import static org.hamcrest.Matchers.equalTo;
10+
import static org.hamcrest.Matchers.sameInstance;
11+
import static org.junit.Assert.assertThat;
12+
13+
14+
/**
15+
* Tests for IfPresent and IfCompleted functionality.
16+
*/
17+
@SuppressWarnings("OptionalGetWithoutIsPresent")
18+
public class DataLoaderIfPresentTest {
19+
20+
private <T> BatchLoader<T, T> keysAsValues() {
21+
return CompletableFuture::completedFuture;
22+
}
23+
24+
@Test
25+
public void should_detect_if_present_cf() {
26+
DataLoader<Integer, Integer> dataLoader = new DataLoader<>(keysAsValues());
27+
28+
Optional<CompletableFuture<Integer>> cachedPromise = dataLoader.getIfPresent(1);
29+
assertThat(cachedPromise.isPresent(), equalTo(false));
30+
31+
CompletionStage<Integer> future1 = dataLoader.load(1);
32+
33+
cachedPromise = dataLoader.getIfPresent(1);
34+
assertThat(cachedPromise.isPresent(), equalTo(true));
35+
36+
assertThat(cachedPromise.get(), sameInstance(future1));
37+
38+
// but its not done!
39+
assertThat(cachedPromise.get().isDone(), equalTo(false));
40+
//
41+
// and hence it cant be loaded as complete
42+
cachedPromise = dataLoader.getIfCompleted(1);
43+
assertThat(cachedPromise.isPresent(), equalTo(false));
44+
}
45+
46+
@Test
47+
public void should_not_be_present_if_cleared() {
48+
DataLoader<Integer, Integer> dataLoader = new DataLoader<>(keysAsValues());
49+
50+
Optional<CompletableFuture<Integer>> cachedPromise = dataLoader.getIfPresent(1);
51+
dataLoader.load(1);
52+
53+
cachedPromise = dataLoader.getIfPresent(1);
54+
assertThat(cachedPromise.isPresent(), equalTo(true));
55+
56+
dataLoader.clear(1);
57+
58+
cachedPromise = dataLoader.getIfPresent(1);
59+
assertThat(cachedPromise.isPresent(), equalTo(false));
60+
61+
// and hence is not completed as well
62+
cachedPromise = dataLoader.getIfCompleted(1);
63+
assertThat(cachedPromise.isPresent(), equalTo(false));
64+
}
65+
66+
@Test
67+
public void should_allow_completed_cfs_to_be_found() {
68+
DataLoader<Integer, Integer> dataLoader = new DataLoader<>(keysAsValues());
69+
70+
Optional<CompletableFuture<Integer>> cachedPromise = dataLoader.getIfPresent(1);
71+
dataLoader.load(1);
72+
73+
cachedPromise = dataLoader.getIfPresent(1);
74+
assertThat(cachedPromise.isPresent(), equalTo(true));
75+
76+
cachedPromise = dataLoader.getIfCompleted(1);
77+
assertThat(cachedPromise.isPresent(), equalTo(false));
78+
79+
dataLoader.dispatch();
80+
81+
cachedPromise = dataLoader.getIfPresent(1);
82+
assertThat(cachedPromise.isPresent(), equalTo(true));
83+
84+
cachedPromise = dataLoader.getIfCompleted(1);
85+
assertThat(cachedPromise.isPresent(), equalTo(true));
86+
assertThat(cachedPromise.get().isDone(), equalTo(true));
87+
}
88+
89+
@Test
90+
public void should_work_with_primed_caches() {
91+
DataLoader<Integer, Integer> dataLoader = new DataLoader<>(keysAsValues());
92+
dataLoader.prime(1, 666);
93+
94+
Optional<CompletableFuture<Integer>> cachedPromise = dataLoader.getIfPresent(1);
95+
assertThat(cachedPromise.isPresent(), equalTo(true));
96+
97+
cachedPromise = dataLoader.getIfCompleted(1);
98+
assertThat(cachedPromise.isPresent(), equalTo(true));
99+
assertThat(cachedPromise.get().isDone(), equalTo(true));
100+
101+
// and its value is what we expect
102+
assertThat(cachedPromise.get().join(), equalTo(666));
103+
}
104+
105+
}

0 commit comments

Comments
 (0)