Skip to content

getIfPresent and getIfCompleted support #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 25, 2019
Merged
Show file tree
Hide file tree
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
63 changes: 33 additions & 30 deletions src/main/java/org/dataloader/DataLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

import static org.dataloader.impl.Assertions.nonNull;
Expand Down Expand Up @@ -50,7 +51,6 @@
*
* @param <K> type parameter indicating the type of the data load keys
* @param <V> type parameter indicating the type of the data that is returned
*
* @author <a href="https://github.com/aschrijver/">Arnold Schrijver</a>
* @author <a href="https://github.com/bbakerman/">Brad Baker</a>
*/
Expand All @@ -68,7 +68,6 @@ public class DataLoader<K, V> {
* @param batchLoadFunction the batch load function to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newDataLoader(BatchLoader<K, V> batchLoadFunction) {
Expand All @@ -82,7 +81,6 @@ public static <K, V> DataLoader<K, V> newDataLoader(BatchLoader<K, V> batchLoadF
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newDataLoader(BatchLoader<K, V> batchLoadFunction, DataLoaderOptions options) {
Expand All @@ -103,7 +101,6 @@ public static <K, V> DataLoader<K, V> newDataLoader(BatchLoader<K, V> batchLoadF
* @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newDataLoaderWithTry(BatchLoader<K, Try<V>> batchLoadFunction) {
Expand All @@ -119,9 +116,7 @@ public static <K, V> DataLoader<K, V> newDataLoaderWithTry(BatchLoader<K, Try<V>
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*
* @see #newDataLoaderWithTry(BatchLoader)
*/
@SuppressWarnings("unchecked")
Expand All @@ -136,7 +131,6 @@ public static <K, V> DataLoader<K, V> newDataLoaderWithTry(BatchLoader<K, Try<V>
* @param batchLoadFunction the batch load function to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newDataLoader(BatchLoaderWithContext<K, V> batchLoadFunction) {
Expand All @@ -150,7 +144,6 @@ public static <K, V> DataLoader<K, V> newDataLoader(BatchLoaderWithContext<K, V>
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newDataLoader(BatchLoaderWithContext<K, V> batchLoadFunction, DataLoaderOptions options) {
Expand All @@ -171,7 +164,6 @@ public static <K, V> DataLoader<K, V> newDataLoader(BatchLoaderWithContext<K, V>
* @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newDataLoaderWithTry(BatchLoaderWithContext<K, Try<V>> batchLoadFunction) {
Expand All @@ -187,9 +179,7 @@ public static <K, V> DataLoader<K, V> newDataLoaderWithTry(BatchLoaderWithContex
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*
* @see #newDataLoaderWithTry(BatchLoader)
*/
public static <K, V> DataLoader<K, V> newDataLoaderWithTry(BatchLoaderWithContext<K, Try<V>> batchLoadFunction, DataLoaderOptions options) {
Expand All @@ -203,7 +193,6 @@ public static <K, V> DataLoader<K, V> newDataLoaderWithTry(BatchLoaderWithContex
* @param batchLoadFunction the batch load function to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoader<K, V> batchLoadFunction) {
Expand All @@ -217,7 +206,6 @@ public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoader<K, V
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoader<K, V> batchLoadFunction, DataLoaderOptions options) {
Expand All @@ -231,15 +219,14 @@ public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoader<K, V
* <p>
* If its important you to know the exact status of each item in a batch call and whether it threw exceptions then
* you can use this form to create the data loader.
*
* <p>
* Using Try objects allows you to capture a value returned or an exception that might
* have occurred trying to get a value. .
* <p>
*
* @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newMappedDataLoaderWithTry(MappedBatchLoader<K, Try<V>> batchLoadFunction) {
Expand All @@ -255,9 +242,7 @@ public static <K, V> DataLoader<K, V> newMappedDataLoaderWithTry(MappedBatchLoad
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*
* @see #newDataLoaderWithTry(BatchLoader)
*/
@SuppressWarnings("unchecked")
Expand All @@ -272,7 +257,6 @@ public static <K, V> DataLoader<K, V> newMappedDataLoaderWithTry(MappedBatchLoad
* @param batchLoadFunction the batch load function to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoaderWithContext<K, V> batchLoadFunction) {
Expand All @@ -286,7 +270,6 @@ public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoaderWithC
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoaderWithContext<K, V> batchLoadFunction, DataLoaderOptions options) {
Expand All @@ -307,7 +290,6 @@ public static <K, V> DataLoader<K, V> newMappedDataLoader(MappedBatchLoaderWithC
* @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*/
public static <K, V> DataLoader<K, V> newMappedDataLoaderWithTry(MappedBatchLoaderWithContext<K, Try<V>> batchLoadFunction) {
Expand All @@ -323,9 +305,7 @@ public static <K, V> DataLoader<K, V> newMappedDataLoaderWithTry(MappedBatchLoad
* @param options the options to use
* @param <K> the key type
* @param <V> the value type
*
* @return a new DataLoader
*
* @see #newDataLoaderWithTry(BatchLoader)
*/
@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -374,13 +354,43 @@ private CacheMap<Object, CompletableFuture<V>> determineCacheMap(DataLoaderOptio
* and returned from cache).
*
* @param key the key to load
*
* @return the future of the value
*/
public CompletableFuture<V> load(K key) {
return load(key, null);
}

/**
* This will return an optional promise to a value previously loaded via {@link #load(Object)} call or empty if not call has been made for that key.
* <p>
* If you do get a present CompletableFuture it does not mean it has been dispatched and completed yet. It just means
* its at least pending and in cache. Of course if caching is disabled there will never be a present Optional returned.
* <p>
* NOTE : This will NOT cause a data load to happen. You must called {@link #load(Object)} for that.
*
* @param key the key to check
* @return an Optional to the future of the value
*/
public Optional<CompletableFuture<V>> getIfPresent(K key) {
return helper.getIfPresent(key);
}

/**
* This will return an optional promise to a value previously loaded via {@link #load(Object)} call that has in fact been completed or empty
* if no call has been made for that key or the promise has not completed yet.
* <p>
* If you do get a present CompletableFuture it means it has been dispatched and completed.
* <p>
* NOTE : This will NOT cause a data load to happen. You must called {@link #load(Object)} for that.
*
* @param key the key to check
* @return an Optional to the future of the value
*/
public Optional<CompletableFuture<V>> getIfCompleted(K key) {
return helper.getIfCompleted(key);
}


/**
* Requests to load the data with the specified key asynchronously, and returns a future of the resulting value.
* <p>
Expand All @@ -393,7 +403,6 @@ public CompletableFuture<V> load(K key) {
*
* @param key the key to load
* @param keyContext a context object that is specific to this key
*
* @return the future of the value
*/
public CompletableFuture<V> load(K key, Object keyContext) {
Expand All @@ -409,7 +418,6 @@ public CompletableFuture<V> load(K key, Object keyContext) {
* and returned from cache).
*
* @param keys the list of keys to load
*
* @return the composite future of the list of values
*/
public CompletableFuture<List<V>> loadMany(List<K> keys) {
Expand All @@ -429,7 +437,6 @@ public CompletableFuture<List<V>> loadMany(List<K> keys) {
*
* @param keys the list of keys to load
* @param keyContexts the list of key calling context objects
*
* @return the composite future of the list of values
*/
public CompletableFuture<List<V>> loadMany(List<K> keys, List<Object> keyContexts) {
Expand Down Expand Up @@ -495,7 +502,6 @@ public int dispatchDepth() {
* on the next load request.
*
* @param key the key to remove
*
* @return the data loader for fluent coding
*/
public DataLoader<K, V> clear(K key) {
Expand Down Expand Up @@ -523,7 +529,6 @@ public DataLoader<K, V> clearAll() {
*
* @param key the key
* @param value the value
*
* @return the data loader for fluent coding
*/
public DataLoader<K, V> prime(K key, V value) {
Expand All @@ -541,7 +546,6 @@ public DataLoader<K, V> prime(K key, V value) {
*
* @param key the key
* @param error the exception to prime instead of a value
*
* @return the data loader for fluent coding
*/
public DataLoader<K, V> prime(K key, Exception error) {
Expand All @@ -559,7 +563,6 @@ public DataLoader<K, V> prime(K key, Exception error) {
* If no cache key function is present in {@link DataLoaderOptions}, then the returned value equals the input key.
*
* @param key the input key
*
* @return the cache key after the input is transformed with the cache key function
*/
public Object getCacheKey(K key) {
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/org/dataloader/DataLoaderHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
Expand All @@ -27,6 +28,7 @@
*/
class DataLoaderHelper<K, V> {


class LoaderQueueEntry<K, V> {

final K key;
Expand Down Expand Up @@ -68,6 +70,34 @@ Object getCallContext() {
this.stats = stats;
}

Optional<CompletableFuture<V>> getIfPresent(K key) {
synchronized (dataLoader) {
Object cacheKey = getCacheKey(nonNull(key));
boolean cachingEnabled = loaderOptions.cachingEnabled();
if (cachingEnabled) {
if (futureCache.containsKey(cacheKey)) {
stats.incrementCacheHitCount();
return Optional.of(futureCache.get(cacheKey));
}
}
}
return Optional.empty();
}

Optional<CompletableFuture<V>> getIfCompleted(K key) {
synchronized (dataLoader) {
Optional<CompletableFuture<V>> cachedPromise = getIfPresent(key);
if (cachedPromise.isPresent()) {
CompletableFuture<V> promise = cachedPromise.get();
if (promise.isDone()) {
return cachedPromise;
}
}
}
return Optional.empty();
}


CompletableFuture<V> load(K key, Object loadContext) {
synchronized (dataLoader) {
Object cacheKey = getCacheKey(nonNull(key));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static boolean failed(CompletableFuture future) {
}

public static <T> CompletableFuture<List<T>> allOf(List<CompletableFuture<T>> cfs) {
return CompletableFuture.allOf(cfs.toArray(new CompletableFuture[cfs.size()]))
return CompletableFuture.allOf(cfs.toArray(new CompletableFuture[0]))
.thenApply(v -> cfs.stream()
.map(CompletableFuture::join)
.collect(toList())
Expand Down
Loading