Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

feat: added SpringValueCache for easy creation of data loader ValueCache objects that utilize Spring Caches under the hood #964

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package graphql.kickstart.spring.cache;

import static java.util.concurrent.CompletableFuture.runAsync;
import static java.util.concurrent.CompletableFuture.supplyAsync;

import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import lombok.RequiredArgsConstructor;
import org.dataloader.ValueCache;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;

/**
* A {@link ValueCache} which uses a Spring {@link Cache} for caching.
*
* @see <a
* href="https://www.graphql-java.com/documentation/batching/#per-request-data-loaders">GraphQL Java
* docs</a>
*/
@RequiredArgsConstructor
public class SpringValueCache<K, V> implements ValueCache<K, V> {

private final Cache cache;
private Function<K, ?> keyTransformer;

@Override
public CompletableFuture<V> get(K key) {
return supplyAsync(() -> {
Object finalKey = this.getKey(key);
ValueWrapper valueWrapper = this.cache.get(finalKey);

if (valueWrapper == null) {
throw new CacheEntryNotFoundException(this.cache.getName(), finalKey);
}

return (V) valueWrapper.get();
});
}

@Override
public CompletableFuture<V> set(K key, V value) {
return supplyAsync(() -> {
this.cache.put(this.getKey(key), value);
return value;
});
}

@Override
public CompletableFuture<Void> delete(K key) {
return runAsync(() -> this.cache.evictIfPresent(this.getKey(key)));
}

@Override
public CompletableFuture<Void> clear() {
return runAsync(this.cache::invalidate);
}

public <KFinal> SpringValueCache<K, V> setKeyTransformer(Function<K, KFinal> transformer) {
this.keyTransformer = transformer;
return this;
}

private Object getKey(K key) {
return (
this.keyTransformer == null
? key
: this.keyTransformer.apply(key)
);
}

public static class CacheEntryNotFoundException extends RuntimeException {
public CacheEntryNotFoundException(String cacheName, Object key) {
super("Entry could not be found in cache named \"" + cacheName + "\" for key: " + key);
}
}
}
Loading