Skip to content

Commit d99b228

Browse files
committed
A test and example of another type of custom cache
1 parent dfdc813 commit d99b228

File tree

3 files changed

+164
-18
lines changed

3 files changed

+164
-18
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ task myJavadocs(type: Javadoc) {
5757
dependencies {
5858
testCompile "junit:junit:$junitVersion"
5959
testCompile 'org.awaitility:awaitility:2.0.0'
60+
testCompile 'com.github.ben-manes.caffeine:caffeine:2.7.0'
6061
}
6162

6263
task wrapper(type: Wrapper) {

gradle/publishing.gradle

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,24 +74,24 @@ publishing {
7474
}
7575
}
7676

77-
bintray {
78-
user = System.getenv('BINTRAY_USER')
79-
key = System.getenv('BINTRAY_KEY')
80-
publications = ['maven']
81-
publish = true
82-
pkg {
83-
userOrg = 'graphql-java'
84-
repo = 'graphql-java'
85-
name = "java-dataloader"
86-
desc = projectDescription
87-
licenses = ['Apache-2.0']
88-
vcsUrl = 'https://github.com/graphql-java/java-dataloader.git'
89-
version {
90-
released = new Date()
91-
vcsTag = project.version
92-
gpg {
93-
sign = true
77+
bintray {
78+
user = System.getenv('BINTRAY_USER')
79+
key = System.getenv('BINTRAY_KEY')
80+
publications = ['maven']
81+
publish = true
82+
pkg {
83+
userOrg = 'graphql-java'
84+
repo = 'graphql-java'
85+
name = "java-dataloader"
86+
desc = projectDescription
87+
licenses = ['Apache-2.0']
88+
vcsUrl = 'https://github.com/graphql-java/java-dataloader.git'
89+
version {
90+
released = new Date()
91+
vcsTag = project.version
92+
gpg {
93+
sign = true
94+
}
9495
}
9596
}
9697
}
97-
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package org.dataloader.caching;
2+
3+
import com.github.benmanes.caffeine.cache.Cache;
4+
import com.github.benmanes.caffeine.cache.Caffeine;
5+
import org.checkerframework.checker.nullness.qual.NonNull;
6+
import org.dataloader.CacheMap;
7+
import org.dataloader.DataLoader;
8+
import org.dataloader.DataLoaderOptions;
9+
import org.junit.Test;
10+
11+
import java.util.ArrayList;
12+
import java.util.Collection;
13+
import java.util.List;
14+
import java.util.Set;
15+
import java.util.TreeSet;
16+
import java.util.concurrent.CompletableFuture;
17+
import java.util.concurrent.ConcurrentMap;
18+
import java.util.concurrent.ExecutionException;
19+
import java.util.concurrent.TimeUnit;
20+
import java.util.stream.Collectors;
21+
22+
import static java.util.Arrays.asList;
23+
import static java.util.Collections.emptyList;
24+
import static java.util.Collections.singletonList;
25+
import static org.awaitility.Awaitility.await;
26+
import static org.dataloader.DataLoaderOptions.newOptions;
27+
import static org.hamcrest.Matchers.equalTo;
28+
import static org.junit.Assert.assertArrayEquals;
29+
import static org.junit.Assert.assertThat;
30+
31+
public class CaffieneCacheTest {
32+
33+
static class CaffieneCache implements CacheMap<String, CompletableFuture<String>> {
34+
35+
Cache<String, CompletableFuture<String>> caffeineCache = Caffeine.newBuilder()
36+
.maximumSize(10_000)
37+
.expireAfterWrite(5, TimeUnit.MINUTES)
38+
//.refreshAfterWrite(1, TimeUnit.MINUTES)
39+
.build();
40+
41+
@NonNull
42+
private String buildValue(@NonNull String key) {
43+
return key;
44+
}
45+
46+
@Override
47+
public boolean containsKey(String key) {
48+
return caffeineCache.getIfPresent(key) != null;
49+
}
50+
51+
@Override
52+
public CompletableFuture<String> get(String key) {
53+
return caffeineCache.getIfPresent(key);
54+
}
55+
56+
@Override
57+
public CacheMap<String, CompletableFuture<String>> set(String key, CompletableFuture<String> value) {
58+
caffeineCache.put(key, value);
59+
return this;
60+
}
61+
62+
@Override
63+
public CacheMap<String, CompletableFuture<String>> delete(String key) {
64+
caffeineCache.invalidate(key);
65+
return this;
66+
}
67+
68+
@Override
69+
public CacheMap<String, CompletableFuture<String>> clear() {
70+
caffeineCache.invalidateAll();
71+
return this;
72+
}
73+
74+
public Set<String> keySet() {
75+
ConcurrentMap<String, CompletableFuture<String>> map = caffeineCache.asMap();
76+
return new TreeSet<>(map.keySet());
77+
}
78+
}
79+
80+
81+
private static <K, V> DataLoader<K, V> idLoader(DataLoaderOptions options, List<Collection<K>> loadCalls) {
82+
return DataLoader.newDataLoader(keys -> {
83+
loadCalls.add(new ArrayList<>(keys));
84+
@SuppressWarnings("unchecked")
85+
List<V> values = keys.stream()
86+
.map(k -> (V) k)
87+
.collect(Collectors.toList());
88+
return CompletableFuture.completedFuture(values);
89+
}, options);
90+
}
91+
92+
@Test
93+
public void can_run_truly_custom_cache() throws ExecutionException, InterruptedException {
94+
CaffieneCache customMap = new CaffieneCache();
95+
List<Collection<String>> loadCalls = new ArrayList<>();
96+
DataLoaderOptions options = newOptions().setCacheMap(customMap);
97+
DataLoader<String, String> identityLoader = idLoader(options, loadCalls);
98+
99+
// Fetches as expected
100+
101+
CompletableFuture future1 = identityLoader.load("a");
102+
CompletableFuture future2 = identityLoader.load("b");
103+
CompletableFuture<List<String>> composite = identityLoader.dispatch();
104+
105+
await().until(composite::isDone);
106+
assertThat(future1.get(), equalTo("a"));
107+
assertThat(future2.get(), equalTo("b"));
108+
109+
assertThat(loadCalls, equalTo(singletonList(asList("a", "b"))));
110+
assertArrayEquals(customMap.keySet().toArray(), asList("a", "b").toArray());
111+
112+
CompletableFuture future3 = identityLoader.load("c");
113+
CompletableFuture future2a = identityLoader.load("b");
114+
composite = identityLoader.dispatch();
115+
116+
await().until(composite::isDone);
117+
assertThat(future3.get(), equalTo("c"));
118+
assertThat(future2a.get(), equalTo("b"));
119+
120+
assertThat(loadCalls, equalTo(asList(asList("a", "b"), singletonList("c"))));
121+
assertArrayEquals(customMap.keySet().toArray(), asList("a", "b", "c").toArray());
122+
123+
// Supports clear
124+
125+
identityLoader.clear("b");
126+
assertArrayEquals(customMap.keySet().toArray(), asList("a", "c").toArray());
127+
128+
CompletableFuture future2b = identityLoader.load("b");
129+
composite = identityLoader.dispatch();
130+
131+
await().until(composite::isDone);
132+
assertThat(future2b.get(), equalTo("b"));
133+
assertThat(loadCalls, equalTo(asList(asList("a", "b"),
134+
singletonList("c"), singletonList("b"))));
135+
136+
assertArrayEquals(customMap.keySet().toArray(), asList("a", "b", "c").toArray());
137+
138+
// Supports clear all
139+
140+
identityLoader.clearAll();
141+
142+
assertArrayEquals(customMap.keySet().toArray(), emptyList().toArray());
143+
144+
}
145+
}

0 commit comments

Comments
 (0)