diff --git a/README.md b/README.md index ecfc4c6..73351ad 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ and Nicholas Schrock (@schrockn) from [Facebook](https://www.facebook.com/), the - Deals with partial errors when a batch future fails - Can disable batching and/or caching in configuration - Can supply your own [`CacheMap`](https://github.com/graphql-java/java-dataloader/blob/master/src/main/java/io/engagingspaces/vertx/dataloader/CacheMap.java) implementations -- Has very high test coverage (see [Acknowledgements](#acknowlegdements)) +- Has very high test coverage ## Examples @@ -70,7 +70,7 @@ a list of keys } }; - DataLoader userLoader = DataLoader.newDataLoader(userBatchLoader); + DataLoader userLoader = DataLoaderFactory.newDataLoader(userBatchLoader); ``` @@ -188,7 +188,7 @@ for the context object. } }; - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = DataLoaderFactory.newDataLoader(batchLoader, options); ``` The batch loading code will now receive this environment object and it can be used to get context perhaps allowing it @@ -219,7 +219,7 @@ You can gain access to them as a map by key or as the original list of context o } }; - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = DataLoaderFactory.newDataLoader(batchLoader, options); loader.load("keyA", "contextForA"); loader.load("keyB", "contextForB"); ``` @@ -255,7 +255,7 @@ For example, let's assume you want to load users from a database, you could prob } }; - DataLoader userLoader = DataLoader.newMappedDataLoader(mapBatchLoader); + DataLoader userLoader = DataLoaderFactory.newMappedDataLoader(mapBatchLoader); // ... ``` @@ -295,7 +295,7 @@ DataLoader supports this type and you can use this form to create a batch loader and some of which may have failed. From that data loader can infer the right behavior in terms of the `load(x)` promise. ```java - DataLoader dataLoader = DataLoader.newDataLoaderWithTry(new BatchLoader>() { + DataLoader dataLoader = DataLoaderFactory.newDataLoaderWithTry(new BatchLoader>() { @Override public CompletionStage>> load(List keys) { return CompletableFuture.supplyAsync(() -> { @@ -320,7 +320,7 @@ react to that, in a type safe manner. In certain uncommon cases, a DataLoader which does not cache may be desirable. ```java - DataLoader.newDataLoader(userBatchLoader, DataLoaderOptions.newOptions().setCachingEnabled(false)); + DataLoaderFactory.newDataLoader(userBatchLoader, DataLoaderOptions.newOptions().setCachingEnabled(false)); ``` Calling the above will ensure that every call to `.load()` will produce a new promise, and requested keys will not be saved in memory. @@ -387,7 +387,7 @@ You can configure the statistics collector used when you build the data loader ```java DataLoaderOptions options = DataLoaderOptions.newOptions().setStatisticsCollector(() -> new ThreadLocalStatisticsCollector()); - DataLoader userDataLoader = DataLoader.newDataLoader(userBatchLoader,options); + DataLoader userDataLoader = DataLoaderFactory.newDataLoader(userBatchLoader,options); ``` @@ -399,22 +399,24 @@ and `NoOpStatisticsCollector`. If you are serving web requests then the data can be specific to the user requesting it. If you have user specific data then you will not want to cache data meant for user A to then later give it user B in a subsequent request. -The scope of your `DataLoader` instances is important. You might want to create them per web request to ensure data is only cached within that +The scope of your `DataLoader` instances is important. You will want to create them per web request to ensure data is only cached within that web request and no more. -If your data can be shared across web requests then you might want to scope your data loaders so they survive longer than the web request say. +If your data can be shared across web requests then use a custom cache to keep values in a common place. + +Data loaders are stateful components that contain promises (with context) that are likely share the same affinity as the request. ## Custom caches -The default cache behind `DataLoader` is an in memory `HashMap`. There is no expiry on this and it lives for as long as the data loader +The default cache behind `DataLoader` is an in memory `HashMap`. There is no expiry on this, and it lives for as long as the data loader lives. -However you can create your own custom cache and supply it to the data loader on construction via the `org.dataloader.CacheMap` interface. +However, you can create your own custom cache and supply it to the data loader on construction via the `org.dataloader.CacheMap` interface. ```java MyCustomCache customCache = new MyCustomCache(); DataLoaderOptions options = DataLoaderOptions.newOptions().setCacheMap(customCache); - DataLoader.newDataLoader(userBatchLoader, options); + DataLoaderFactory.newDataLoader(userBatchLoader, options); ``` You could choose to use one of the fancy cache implementations from Guava or Kaffeine and wrap it in a `CacheMap` wrapper ready diff --git a/src/main/java/org/dataloader/DataLoader.java b/src/main/java/org/dataloader/DataLoader.java index f59d0a1..8c4779f 100644 --- a/src/main/java/org/dataloader/DataLoader.java +++ b/src/main/java/org/dataloader/DataLoader.java @@ -75,7 +75,10 @@ public class DataLoader { * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newDataLoader(BatchLoader batchLoadFunction) { return newDataLoader(batchLoadFunction, null); } @@ -89,9 +92,12 @@ public static DataLoader newDataLoader(BatchLoader batchLoadF * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newDataLoader(BatchLoader batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>(batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** @@ -110,7 +116,10 @@ public static DataLoader newDataLoader(BatchLoader batchLoadF * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newDataLoaderWithTry(BatchLoader> batchLoadFunction) { return newDataLoaderWithTry(batchLoadFunction, null); } @@ -127,11 +136,12 @@ public static DataLoader newDataLoaderWithTry(BatchLoader * * @return a new DataLoader * - * @see #newDataLoaderWithTry(BatchLoader) + * @see DataLoaderFactory#newDataLoaderWithTry(BatchLoader) + * @deprecated use {@link DataLoaderFactory} instead */ - @SuppressWarnings("unchecked") + @Deprecated public static DataLoader newDataLoaderWithTry(BatchLoader> batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>((BatchLoader) batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** @@ -143,7 +153,10 @@ public static DataLoader newDataLoaderWithTry(BatchLoader * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newDataLoader(BatchLoaderWithContext batchLoadFunction) { return newDataLoader(batchLoadFunction, null); } @@ -157,9 +170,12 @@ public static DataLoader newDataLoader(BatchLoaderWithContext * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newDataLoader(BatchLoaderWithContext batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>(batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** @@ -178,7 +194,10 @@ public static DataLoader newDataLoader(BatchLoaderWithContext * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newDataLoaderWithTry(BatchLoaderWithContext> batchLoadFunction) { return newDataLoaderWithTry(batchLoadFunction, null); } @@ -195,10 +214,12 @@ public static DataLoader newDataLoaderWithTry(BatchLoaderWithContex * * @return a new DataLoader * - * @see #newDataLoaderWithTry(BatchLoader) + * @see DataLoaderFactory#newDataLoaderWithTry(BatchLoader) + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newDataLoaderWithTry(BatchLoaderWithContext> batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>(batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** @@ -210,7 +231,10 @@ public static DataLoader newDataLoaderWithTry(BatchLoaderWithContex * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoader(MappedBatchLoader batchLoadFunction) { return newMappedDataLoader(batchLoadFunction, null); } @@ -224,9 +248,12 @@ public static DataLoader newMappedDataLoader(MappedBatchLoader the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoader(MappedBatchLoader batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>(batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** @@ -246,7 +273,10 @@ public static DataLoader newMappedDataLoader(MappedBatchLoader the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoader> batchLoadFunction) { return newMappedDataLoaderWithTry(batchLoadFunction, null); } @@ -263,10 +293,12 @@ public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoad * * @return a new DataLoader * - * @see #newDataLoaderWithTry(BatchLoader) + * @see DataLoaderFactory#newDataLoaderWithTry(BatchLoader) + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoader> batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>(batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** @@ -278,7 +310,10 @@ public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoad * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoader(MappedBatchLoaderWithContext batchLoadFunction) { return newMappedDataLoader(batchLoadFunction, null); } @@ -292,9 +327,12 @@ public static DataLoader newMappedDataLoader(MappedBatchLoaderWithC * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoader(MappedBatchLoaderWithContext batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>(batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** @@ -313,7 +351,10 @@ public static DataLoader newMappedDataLoader(MappedBatchLoaderWithC * @param the value type * * @return a new DataLoader + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoaderWithContext> batchLoadFunction) { return newMappedDataLoaderWithTry(batchLoadFunction, null); } @@ -330,19 +371,24 @@ public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoad * * @return a new DataLoader * - * @see #newDataLoaderWithTry(BatchLoader) + * @see DataLoaderFactory#newDataLoaderWithTry(BatchLoader) + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoaderWithContext> batchLoadFunction, DataLoaderOptions options) { - return new DataLoader<>(batchLoadFunction, options); + return DataLoaderFactory.mkDataLoader(batchLoadFunction, options); } /** * Creates a new data loader with the provided batch load function, and default options. * * @param batchLoadFunction the batch load function to use + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public DataLoader(BatchLoader batchLoadFunction) { - this(batchLoadFunction, null); + this((Object) batchLoadFunction, null); } /** @@ -350,12 +396,15 @@ public DataLoader(BatchLoader batchLoadFunction) { * * @param batchLoadFunction the batch load function to use * @param options the batch load options + * + * @deprecated use {@link DataLoaderFactory} instead */ + @Deprecated public DataLoader(BatchLoader batchLoadFunction, DataLoaderOptions options) { this((Object) batchLoadFunction, options); } - private DataLoader(Object batchLoadFunction, DataLoaderOptions options) { + DataLoader(Object batchLoadFunction, DataLoaderOptions options) { DataLoaderOptions loaderOptions = options == null ? new DataLoaderOptions() : options; this.futureCache = determineCacheMap(loaderOptions); // order of keys matter in data loader diff --git a/src/main/java/org/dataloader/DataLoaderFactory.java b/src/main/java/org/dataloader/DataLoaderFactory.java new file mode 100644 index 0000000..0f910c1 --- /dev/null +++ b/src/main/java/org/dataloader/DataLoaderFactory.java @@ -0,0 +1,284 @@ +package org.dataloader; + +import org.dataloader.annotations.PublicApi; + +/** + * A factory class to create {@link DataLoader}s + */ +@SuppressWarnings("unused") +@PublicApi +public class DataLoaderFactory { + + /** + * Creates new DataLoader with the specified batch loader function and default options + * (batching, caching and unlimited batch size). + * + * @param batchLoadFunction the batch load function to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newDataLoader(BatchLoader batchLoadFunction) { + return newDataLoader(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function with the provided options + * + * @param batchLoadFunction the batch load function to use + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newDataLoader(BatchLoader batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + /** + * Creates new DataLoader with the specified batch loader function and default options + * (batching, caching and unlimited batch size) where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + *

+ * 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. + *

+ * Using Try objects allows you to capture a value returned or an exception that might + * have occurred trying to get a value. . + * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newDataLoaderWithTry(BatchLoader> batchLoadFunction) { + return newDataLoaderWithTry(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function and with the provided options + * where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + * + * @see #newDataLoaderWithTry(BatchLoader) + */ + public static DataLoader newDataLoaderWithTry(BatchLoader> batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + /** + * Creates new DataLoader with the specified batch loader function and default options + * (batching, caching and unlimited batch size). + * + * @param batchLoadFunction the batch load function to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newDataLoader(BatchLoaderWithContext batchLoadFunction) { + return newDataLoader(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function with the provided options + * + * @param batchLoadFunction the batch load function to use + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newDataLoader(BatchLoaderWithContext batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + /** + * Creates new DataLoader with the specified batch loader function and default options + * (batching, caching and unlimited batch size) where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + *

+ * 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. + *

+ * Using Try objects allows you to capture a value returned or an exception that might + * have occurred trying to get a value. . + * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newDataLoaderWithTry(BatchLoaderWithContext> batchLoadFunction) { + return newDataLoaderWithTry(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function and with the provided options + * where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + * + * @see #newDataLoaderWithTry(BatchLoader) + */ + public static DataLoader newDataLoaderWithTry(BatchLoaderWithContext> batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + /** + * Creates new DataLoader with the specified batch loader function and default options + * (batching, caching and unlimited batch size). + * + * @param batchLoadFunction the batch load function to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newMappedDataLoader(MappedBatchLoader batchLoadFunction) { + return newMappedDataLoader(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function with the provided options + * + * @param batchLoadFunction the batch load function to use + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newMappedDataLoader(MappedBatchLoader batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + /** + * Creates new DataLoader with the specified batch loader function and default options + * (batching, caching and unlimited batch size) where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + *

+ * 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. + *

+ * Using Try objects allows you to capture a value returned or an exception that might + * have occurred trying to get a value. . + *

+ * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoader> batchLoadFunction) { + return newMappedDataLoaderWithTry(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function and with the provided options + * where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + * + * @see #newDataLoaderWithTry(BatchLoader) + */ + public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoader> batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + /** + * Creates new DataLoader with the specified mapped batch loader function and default options + * (batching, caching and unlimited batch size). + * + * @param batchLoadFunction the batch load function to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newMappedDataLoader(MappedBatchLoaderWithContext batchLoadFunction) { + return newMappedDataLoader(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function with the provided options + * + * @param batchLoadFunction the batch load function to use + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newMappedDataLoader(MappedBatchLoaderWithContext batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + /** + * Creates new DataLoader with the specified batch loader function and default options + * (batching, caching and unlimited batch size) where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + *

+ * 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. + *

+ * Using Try objects allows you to capture a value returned or an exception that might + * have occurred trying to get a value. . + * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param the key type + * @param the value type + * + * @return a new DataLoader + */ + public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoaderWithContext> batchLoadFunction) { + return newMappedDataLoaderWithTry(batchLoadFunction, null); + } + + /** + * Creates new DataLoader with the specified batch loader function and with the provided options + * where the batch loader function returns a list of + * {@link org.dataloader.Try} objects. + * + * @param batchLoadFunction the batch load function to use that uses {@link org.dataloader.Try} objects + * @param options the options to use + * @param the key type + * @param the value type + * + * @return a new DataLoader + * + * @see #newDataLoaderWithTry(BatchLoader) + */ + public static DataLoader newMappedDataLoaderWithTry(MappedBatchLoaderWithContext> batchLoadFunction, DataLoaderOptions options) { + return mkDataLoader(batchLoadFunction, options); + } + + static DataLoader mkDataLoader(Object batchLoadFunction, DataLoaderOptions options) { + return new DataLoader<>(batchLoadFunction, options); + } +} diff --git a/src/main/java/org/dataloader/DataLoaderHelper.java b/src/main/java/org/dataloader/DataLoaderHelper.java index ea1ec57..52b2f3a 100644 --- a/src/main/java/org/dataloader/DataLoaderHelper.java +++ b/src/main/java/org/dataloader/DataLoaderHelper.java @@ -242,7 +242,7 @@ private CompletableFuture> dispatchQueueBatch(List keys, List List clearCacheKeys = new ArrayList<>(); for (int idx = 0; idx < queuedFutures.size(); idx++) { - Object value = values.get(idx); + V value = values.get(idx); CompletableFuture future = queuedFutures.get(idx); if (value instanceof Throwable) { stats.incrementLoadErrorCount(); @@ -260,8 +260,7 @@ private CompletableFuture> dispatchQueueBatch(List keys, List clearCacheKeys.add(keys.get(idx)); } } else { - V val = (V) value; - future.complete(val); + future.complete(value); } } possiblyClearCacheEntriesOnExceptions(clearCacheKeys); diff --git a/src/main/java/org/dataloader/DataLoaderRegistry.java b/src/main/java/org/dataloader/DataLoaderRegistry.java index 627b82c..6f8a695 100644 --- a/src/main/java/org/dataloader/DataLoaderRegistry.java +++ b/src/main/java/org/dataloader/DataLoaderRegistry.java @@ -1,6 +1,10 @@ package org.dataloader; +import org.dataloader.annotations.PublicApi; +import org.dataloader.stats.Statistics; + import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -8,9 +12,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import org.dataloader.annotations.PublicApi; -import org.dataloader.stats.Statistics; - /** * This allows data loaders to be registered together into a single place so * they can be dispatched as one. It also allows you to retrieve data loaders by @@ -20,11 +21,19 @@ public class DataLoaderRegistry { private final Map> dataLoaders = new ConcurrentHashMap<>(); + public DataLoaderRegistry() { + } + + private DataLoaderRegistry(Builder builder) { + this.dataLoaders.putAll(builder.dataLoaders); + } + /** * This will register a new dataloader * * @param key the key to put the data loader under * @param dataLoader the data loader to register + * * @return this registry */ public DataLoaderRegistry register(String key, DataLoader dataLoader) { @@ -43,6 +52,7 @@ public DataLoaderRegistry register(String key, DataLoader dataLoader) { * @param mappingFunction the function to compute a data loader * @param the type of keys * @param the type of values + * * @return a data loader */ @SuppressWarnings("unchecked") @@ -56,6 +66,7 @@ public DataLoader computeIfAbsent(final String key, * and return a new combined registry * * @param registry the registry to combine into this registry + * * @return a new combined registry */ public DataLoaderRegistry combine(DataLoaderRegistry registry) { @@ -77,6 +88,7 @@ public DataLoaderRegistry combine(DataLoaderRegistry registry) { * This will unregister a new dataloader * * @param key the key of the data loader to unregister + * * @return this registry */ public DataLoaderRegistry unregister(String key) { @@ -90,6 +102,7 @@ public DataLoaderRegistry unregister(String key) { * @param key the key of the data loader * @param the type of keys * @param the type of values + * * @return a data loader or null if its not present */ @SuppressWarnings("unchecked") @@ -120,7 +133,7 @@ public void dispatchAll() { */ public int dispatchAllWithCount() { int sum = 0; - for (DataLoader dataLoader : getDataLoaders()) { + for (DataLoader dataLoader : getDataLoaders()) { sum += dataLoader.dispatchWithCounts().getKeysCount(); } return sum; @@ -132,7 +145,7 @@ public int dispatchAllWithCount() { */ public int dispatchDepth() { int totalDispatchDepth = 0; - for (DataLoader dataLoader : getDataLoaders()) { + for (DataLoader dataLoader : getDataLoaders()) { totalDispatchDepth += dataLoader.dispatchDepth(); } return totalDispatchDepth; @@ -149,4 +162,49 @@ public Statistics getStatistics() { } return stats; } + + /** + * @return A builder of {@link DataLoaderRegistry}s + */ + public static Builder newRegistry() { + return new Builder(); + } + + public static class Builder { + + private final Map> dataLoaders = new HashMap<>(); + + /** + * This will register a new dataloader + * + * @param key the key to put the data loader under + * @param dataLoader the data loader to register + * + * @return this builder for a fluent pattern + */ + public Builder register(String key, DataLoader dataLoader) { + dataLoaders.put(key, dataLoader); + return this; + } + + /** + * This will combine together the data loaders in this builder with the ones + * from a previous {@link DataLoaderRegistry} + * + * @param otherRegistry the previous {@link DataLoaderRegistry} + * + * @return this builder for a fluent pattern + */ + public Builder registerAll(DataLoaderRegistry otherRegistry) { + dataLoaders.putAll(otherRegistry.dataLoaders); + return this; + } + + /** + * @return the newly built {@link DataLoaderRegistry} + */ + public DataLoaderRegistry build() { + return new DataLoaderRegistry(this); + } + } } diff --git a/src/test/java/ReadmeExamples.java b/src/test/java/ReadmeExamples.java index 523cb5a..ccdd555 100644 --- a/src/test/java/ReadmeExamples.java +++ b/src/test/java/ReadmeExamples.java @@ -3,6 +3,7 @@ import org.dataloader.BatchLoaderWithContext; import org.dataloader.CacheMap; import org.dataloader.DataLoader; +import org.dataloader.DataLoaderFactory; import org.dataloader.DataLoaderOptions; import org.dataloader.MappedBatchLoaderWithContext; import org.dataloader.Try; @@ -59,7 +60,7 @@ public CompletionStage> load(List userIds) { } }; - DataLoader userLoader = DataLoader.newDataLoader(userBatchLoader); + DataLoader userLoader = DataLoaderFactory.newDataLoader(userBatchLoader); CompletionStage load1 = userLoader.load(1L); @@ -96,7 +97,7 @@ public CompletionStage> load(List keys, BatchLoaderEnvironm } }; - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = DataLoaderFactory.newDataLoader(batchLoader, options); } private void keyContextExample() { @@ -120,7 +121,7 @@ public CompletionStage> load(List keys, BatchLoaderEnvironm } }; - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = DataLoaderFactory.newDataLoader(batchLoader, options); loader.load("keyA", "contextForA"); loader.load("keyB", "contextForB"); } @@ -138,7 +139,7 @@ public CompletionStage> load(Set userIds, BatchLoaderEnvir } }; - DataLoader userLoader = DataLoader.newMappedDataLoader(mapBatchLoader); + DataLoader userLoader = DataLoaderFactory.newMappedDataLoader(mapBatchLoader); // ... } @@ -162,7 +163,7 @@ private void tryExample() { } private void tryBatcLoader() { - DataLoader dataLoader = DataLoader.newDataLoaderWithTry(new BatchLoader>() { + DataLoader dataLoader = DataLoaderFactory.newDataLoaderWithTry(new BatchLoader>() { @Override public CompletionStage>> load(List keys) { return CompletableFuture.supplyAsync(() -> { @@ -194,7 +195,7 @@ private void clearCacheOnError() { BatchLoader userBatchLoader; private void disableCache() { - DataLoader.newDataLoader(userBatchLoader, DataLoaderOptions.newOptions().setCachingEnabled(false)); + DataLoaderFactory.newDataLoader(userBatchLoader, DataLoaderOptions.newOptions().setCachingEnabled(false)); userDataLoader.load("A"); @@ -237,7 +238,7 @@ private void customCache() { MyCustomCache customCache = new MyCustomCache(); DataLoaderOptions options = DataLoaderOptions.newOptions().setCacheMap(customCache); - DataLoader.newDataLoader(userBatchLoader, options); + DataLoaderFactory.newDataLoader(userBatchLoader, options); } private void processUser(User user) { @@ -265,7 +266,7 @@ private void statsExample() { private void statsConfigExample() { DataLoaderOptions options = DataLoaderOptions.newOptions().setStatisticsCollector(() -> new ThreadLocalStatisticsCollector()); - DataLoader userDataLoader = DataLoader.newDataLoader(userBatchLoader, options); + DataLoader userDataLoader = DataLoaderFactory.newDataLoader(userBatchLoader, options); } } diff --git a/src/test/java/org/dataloader/DataLoaderBatchLoaderEnvironmentTest.java b/src/test/java/org/dataloader/DataLoaderBatchLoaderEnvironmentTest.java index 575fffd..36e0ed4 100644 --- a/src/test/java/org/dataloader/DataLoaderBatchLoaderEnvironmentTest.java +++ b/src/test/java/org/dataloader/DataLoaderBatchLoaderEnvironmentTest.java @@ -12,6 +12,8 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static org.dataloader.DataLoaderFactory.newDataLoader; +import static org.dataloader.DataLoaderFactory.newMappedDataLoader; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; @@ -36,14 +38,14 @@ private BatchLoaderWithContext contextBatchLoader() { @Test - public void context_is_passed_to_batch_loader_function() throws Exception { + public void context_is_passed_to_batch_loader_function() { BatchLoaderWithContext batchLoader = (keys, environment) -> { List list = keys.stream().map(k -> k + "-" + environment.getContext()).collect(Collectors.toList()); return CompletableFuture.completedFuture(list); }; DataLoaderOptions options = DataLoaderOptions.newOptions() .setBatchLoaderContextProvider(() -> "ctx"); - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = newDataLoader(batchLoader, options); loader.load("A"); loader.load("B"); @@ -55,11 +57,11 @@ public void context_is_passed_to_batch_loader_function() throws Exception { } @Test - public void key_contexts_are_passed_to_batch_loader_function() throws Exception { + public void key_contexts_are_passed_to_batch_loader_function() { BatchLoaderWithContext batchLoader = contextBatchLoader(); DataLoaderOptions options = DataLoaderOptions.newOptions() .setBatchLoaderContextProvider(() -> "ctx"); - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = newDataLoader(batchLoader, options); loader.load("A", "aCtx"); loader.load("B", "bCtx"); @@ -71,12 +73,12 @@ public void key_contexts_are_passed_to_batch_loader_function() throws Exception } @Test - public void key_contexts_are_passed_to_batch_loader_function_when_batching_disabled() throws Exception { + public void key_contexts_are_passed_to_batch_loader_function_when_batching_disabled() { BatchLoaderWithContext batchLoader = contextBatchLoader(); DataLoaderOptions options = DataLoaderOptions.newOptions() .setBatchingEnabled(false) .setBatchLoaderContextProvider(() -> "ctx"); - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = newDataLoader(batchLoader, options); CompletableFuture aLoad = loader.load("A", "aCtx"); CompletableFuture bLoad = loader.load("B", "bCtx"); @@ -89,11 +91,11 @@ public void key_contexts_are_passed_to_batch_loader_function_when_batching_disab } @Test - public void missing_key_contexts_are_passed_to_batch_loader_function() throws Exception { + public void missing_key_contexts_are_passed_to_batch_loader_function() { BatchLoaderWithContext batchLoader = contextBatchLoader(); DataLoaderOptions options = DataLoaderOptions.newOptions() .setBatchLoaderContextProvider(() -> "ctx"); - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = newDataLoader(batchLoader, options); loader.load("A", "aCtx"); loader.load("B"); @@ -105,7 +107,7 @@ public void missing_key_contexts_are_passed_to_batch_loader_function() throws Ex } @Test - public void context_is_passed_to_map_batch_loader_function() throws Exception { + public void context_is_passed_to_map_batch_loader_function() { MappedBatchLoaderWithContext mapBatchLoader = (keys, environment) -> { Map map = new HashMap<>(); keys.forEach(k -> { @@ -117,7 +119,7 @@ public void context_is_passed_to_map_batch_loader_function() throws Exception { }; DataLoaderOptions options = DataLoaderOptions.newOptions() .setBatchLoaderContextProvider(() -> "ctx"); - DataLoader loader = DataLoader.newMappedDataLoader(mapBatchLoader, options); + DataLoader loader = newMappedDataLoader(mapBatchLoader, options); loader.load("A", "aCtx"); loader.load("B"); @@ -129,12 +131,12 @@ public void context_is_passed_to_map_batch_loader_function() throws Exception { } @Test - public void null_is_passed_as_context_if_you_do_nothing() throws Exception { + public void null_is_passed_as_context_if_you_do_nothing() { BatchLoaderWithContext batchLoader = (keys, environment) -> { List list = keys.stream().map(k -> k + "-" + environment.getContext()).collect(Collectors.toList()); return CompletableFuture.completedFuture(list); }; - DataLoader loader = DataLoader.newDataLoader(batchLoader); + DataLoader loader = newDataLoader(batchLoader); loader.load("A"); loader.load("B"); @@ -146,13 +148,13 @@ public void null_is_passed_as_context_if_you_do_nothing() throws Exception { } @Test - public void null_is_passed_as_context_to_map_loader_if_you_do_nothing() throws Exception { + public void null_is_passed_as_context_to_map_loader_if_you_do_nothing() { MappedBatchLoaderWithContext mapBatchLoader = (keys, environment) -> { Map map = new HashMap<>(); keys.forEach(k -> map.put(k, k + "-" + environment.getContext())); return CompletableFuture.completedFuture(map); }; - DataLoader loader = DataLoader.newMappedDataLoader(mapBatchLoader); + DataLoader loader = newMappedDataLoader(mapBatchLoader); loader.load("A"); loader.load("B"); @@ -164,12 +166,12 @@ public void null_is_passed_as_context_to_map_loader_if_you_do_nothing() throws E } @Test - public void mmap_semantics_apply_to_batch_loader_context() throws Exception { + public void mmap_semantics_apply_to_batch_loader_context() { BatchLoaderWithContext batchLoader = contextBatchLoader(); DataLoaderOptions options = DataLoaderOptions.newOptions() .setBatchLoaderContextProvider(() -> "ctx") .setCachingEnabled(false); - DataLoader loader = DataLoader.newDataLoader(batchLoader, options); + DataLoader loader = newDataLoader(batchLoader, options); loader.load("A", "aCtx"); loader.load("B", "bCtx"); diff --git a/src/test/java/org/dataloader/DataLoaderIfPresentTest.java b/src/test/java/org/dataloader/DataLoaderIfPresentTest.java index c015be6..5e29d54 100644 --- a/src/test/java/org/dataloader/DataLoaderIfPresentTest.java +++ b/src/test/java/org/dataloader/DataLoaderIfPresentTest.java @@ -6,6 +6,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import static org.dataloader.DataLoaderFactory.newDataLoader; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.sameInstance; import static org.junit.Assert.assertThat; @@ -14,7 +15,6 @@ /** * Tests for IfPresent and IfCompleted functionality. */ -@SuppressWarnings("OptionalGetWithoutIsPresent") public class DataLoaderIfPresentTest { private BatchLoader keysAsValues() { @@ -23,7 +23,7 @@ private BatchLoader keysAsValues() { @Test public void should_detect_if_present_cf() { - DataLoader dataLoader = new DataLoader<>(keysAsValues()); + DataLoader dataLoader = newDataLoader(keysAsValues()); Optional> cachedPromise = dataLoader.getIfPresent(1); assertThat(cachedPromise.isPresent(), equalTo(false)); @@ -45,7 +45,7 @@ public void should_detect_if_present_cf() { @Test public void should_not_be_present_if_cleared() { - DataLoader dataLoader = new DataLoader<>(keysAsValues()); + DataLoader dataLoader = newDataLoader(keysAsValues()); dataLoader.load(1); @@ -64,7 +64,7 @@ public void should_not_be_present_if_cleared() { @Test public void should_allow_completed_cfs_to_be_found() { - DataLoader dataLoader = new DataLoader<>(keysAsValues()); + DataLoader dataLoader = newDataLoader(keysAsValues()); dataLoader.load(1); @@ -86,7 +86,7 @@ public void should_allow_completed_cfs_to_be_found() { @Test public void should_work_with_primed_caches() { - DataLoader dataLoader = new DataLoader<>(keysAsValues()); + DataLoader dataLoader = newDataLoader(keysAsValues()); dataLoader.prime(1, 666).prime(2, 999); Optional> cachedPromise = dataLoader.getIfPresent(1); diff --git a/src/test/java/org/dataloader/DataLoaderMapBatchLoaderTest.java b/src/test/java/org/dataloader/DataLoaderMapBatchLoaderTest.java index 1a436c1..2abdf1d 100644 --- a/src/test/java/org/dataloader/DataLoaderMapBatchLoaderTest.java +++ b/src/test/java/org/dataloader/DataLoaderMapBatchLoaderTest.java @@ -14,6 +14,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.awaitility.Awaitility.await; +import static org.dataloader.DataLoaderFactory.newDataLoader; import static org.dataloader.DataLoaderOptions.newOptions; import static org.dataloader.TestKit.futureError; import static org.dataloader.TestKit.listFrom; @@ -53,12 +54,12 @@ private static DataLoader idMapLoader(DataLoaderOptions options, Li keys.forEach(k -> map.put(k, (V) k)); return CompletableFuture.completedFuture(map); }; - return DataLoader.newMappedDataLoader(kvBatchLoader, options); + return DataLoaderFactory.newMappedDataLoader(kvBatchLoader, options); } private static DataLoader idMapLoaderBlowsUps( DataLoaderOptions options, List> loadCalls) { - return new DataLoader<>((keys) -> { + return newDataLoader((keys) -> { loadCalls.add(new ArrayList<>(keys)); return futureError(); }, options); @@ -66,8 +67,8 @@ private static DataLoader idMapLoaderBlowsUps( @Test - public void basic_map_batch_loading() throws Exception { - DataLoader loader = DataLoader.newMappedDataLoader(evensOnlyMappedBatchLoader); + public void basic_map_batch_loading() { + DataLoader loader = DataLoaderFactory.newMappedDataLoader(evensOnlyMappedBatchLoader); loader.load("A"); loader.load("B"); @@ -96,7 +97,7 @@ public void should_map_Batch_multiple_requests() throws ExecutionException, Inte } @Test - public void can_split_max_batch_sizes_correctly() throws Exception { + public void can_split_max_batch_sizes_correctly() { List> loadCalls = new ArrayList<>(); DataLoader identityLoader = idMapLoader(newOptions().setMaxBatchSize(5), loadCalls); diff --git a/src/test/java/org/dataloader/DataLoaderRegistryTest.java b/src/test/java/org/dataloader/DataLoaderRegistryTest.java index cd33ae3..6d70654 100644 --- a/src/test/java/org/dataloader/DataLoaderRegistryTest.java +++ b/src/test/java/org/dataloader/DataLoaderRegistryTest.java @@ -6,6 +6,7 @@ import java.util.concurrent.CompletableFuture; import static java.util.Arrays.asList; +import static org.dataloader.DataLoaderFactory.newDataLoader; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.sameInstance; @@ -15,10 +16,10 @@ public class DataLoaderRegistryTest { final BatchLoader identityBatchLoader = CompletableFuture::completedFuture; @Test - public void registration_works() throws Exception { - DataLoader dlA = new DataLoader<>(identityBatchLoader); - DataLoader dlB = new DataLoader<>(identityBatchLoader); - DataLoader dlC = new DataLoader<>(identityBatchLoader); + public void registration_works() { + DataLoader dlA = newDataLoader(identityBatchLoader); + DataLoader dlB = newDataLoader(identityBatchLoader); + DataLoader dlC = newDataLoader(identityBatchLoader); DataLoaderRegistry registry = new DataLoaderRegistry(); @@ -36,8 +37,9 @@ public void registration_works() throws Exception { assertThat(registry.getDataLoaders(), equalTo(asList(dlA, dlB, dlC))); - // and unregister - registry.unregister("c"); + // and unregister (fluently) + DataLoaderRegistry dlR = registry.unregister("c"); + assertThat(dlR,equalTo(registry)); assertThat(registry.getDataLoaders(), equalTo(asList(dlA, dlB))); @@ -49,12 +51,12 @@ public void registration_works() throws Exception { } @Test - public void registries_can_be_combined() throws Exception { + public void registries_can_be_combined() { - DataLoader dlA = new DataLoader<>(identityBatchLoader); - DataLoader dlB = new DataLoader<>(identityBatchLoader); - DataLoader dlC = new DataLoader<>(identityBatchLoader); - DataLoader dlD = new DataLoader<>(identityBatchLoader); + DataLoader dlA = newDataLoader(identityBatchLoader); + DataLoader dlB = newDataLoader(identityBatchLoader); + DataLoader dlC = newDataLoader(identityBatchLoader); + DataLoader dlD = newDataLoader(identityBatchLoader); DataLoaderRegistry registry1 = new DataLoaderRegistry(); @@ -71,13 +73,13 @@ public void registries_can_be_combined() throws Exception { } @Test - public void stats_can_be_collected() throws Exception { + public void stats_can_be_collected() { DataLoaderRegistry registry = new DataLoaderRegistry(); - DataLoader dlA = new DataLoader<>(identityBatchLoader); - DataLoader dlB = new DataLoader<>(identityBatchLoader); - DataLoader dlC = new DataLoader<>(identityBatchLoader); + DataLoader dlA = newDataLoader(identityBatchLoader); + DataLoader dlB = newDataLoader(identityBatchLoader); + DataLoader dlC = newDataLoader(identityBatchLoader); registry.register("a", dlA).register("b", dlB).register("c", dlC); @@ -107,7 +109,7 @@ public void computeIfAbsent_creates_a_data_loader_if_there_was_no_value_at_key() DataLoaderRegistry registry = new DataLoaderRegistry(); - DataLoader dlA = new DataLoader<>(identityBatchLoader); + DataLoader dlA = newDataLoader(identityBatchLoader); DataLoader registered = registry.computeIfAbsent("a", (key) -> dlA); assertThat(registered, equalTo(dlA)); @@ -120,11 +122,11 @@ public void computeIfAbsent_returns_an_existing_data_loader_if_there_was_a_value DataLoaderRegistry registry = new DataLoaderRegistry(); - DataLoader dlA = new DataLoader<>(identityBatchLoader); + DataLoader dlA = newDataLoader(identityBatchLoader); registry.computeIfAbsent("a", (key) -> dlA); // register again at same key - DataLoader dlA2 = new DataLoader<>(identityBatchLoader); + DataLoader dlA2 = newDataLoader(identityBatchLoader); DataLoader registered = registry.computeIfAbsent("a", (key) -> dlA2); assertThat(registered, equalTo(dlA)); @@ -137,8 +139,8 @@ public void dispatch_counts_are_maintained() { DataLoaderRegistry registry = new DataLoaderRegistry(); - DataLoader dlA = new DataLoader<>(identityBatchLoader); - DataLoader dlB = new DataLoader<>(identityBatchLoader); + DataLoader dlA = newDataLoader(identityBatchLoader); + DataLoader dlB = newDataLoader(identityBatchLoader); registry.register("a", dlA); registry.register("b", dlB); @@ -156,4 +158,39 @@ public void dispatch_counts_are_maintained() { assertThat(dispatchedCount, equalTo(4)); assertThat(dispatchDepth, equalTo(0)); } + + @Test + public void builder_works() { + DataLoader dlA = newDataLoader(identityBatchLoader); + DataLoader dlB = newDataLoader(identityBatchLoader); + + DataLoaderRegistry registry = DataLoaderRegistry.newRegistry() + .register("a", dlA) + .register("b", dlB) + .build(); + + assertThat(registry.getDataLoaders(), equalTo(asList(dlA, dlB))); + assertThat(registry.getDataLoader("a"), equalTo(dlA)); + + + DataLoader dlC = newDataLoader(identityBatchLoader); + DataLoader dlD = newDataLoader(identityBatchLoader); + + DataLoaderRegistry registry2 = DataLoaderRegistry.newRegistry() + .register("c", dlC) + .register("d", dlD) + .build(); + + + registry = DataLoaderRegistry.newRegistry() + .register("a", dlA) + .register("b", dlB) + .registerAll(registry2) + .build(); + + assertThat(registry.getDataLoaders(), equalTo(asList(dlA, dlB, dlC, dlD))); + assertThat(registry.getDataLoader("a"), equalTo(dlA)); + assertThat(registry.getDataLoader("c"), equalTo(dlC)); + + } } diff --git a/src/test/java/org/dataloader/DataLoaderStatsTest.java b/src/test/java/org/dataloader/DataLoaderStatsTest.java index c6a355b..1be2e8c 100644 --- a/src/test/java/org/dataloader/DataLoaderStatsTest.java +++ b/src/test/java/org/dataloader/DataLoaderStatsTest.java @@ -12,6 +12,7 @@ import static java.util.Arrays.asList; import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.dataloader.DataLoaderFactory.newDataLoader; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; @@ -21,9 +22,9 @@ public class DataLoaderStatsTest { @Test - public void stats_are_collected_by_default() throws Exception { + public void stats_are_collected_by_default() { BatchLoader batchLoader = CompletableFuture::completedFuture; - DataLoader loader = new DataLoader<>(batchLoader); + DataLoader loader = newDataLoader(batchLoader); loader.load("A"); loader.load("B"); @@ -57,7 +58,7 @@ public void stats_are_collected_by_default() throws Exception { @Test - public void stats_are_collected_with_specified_collector() throws Exception { + public void stats_are_collected_with_specified_collector() { // lets prime it with some numbers so we know its ours StatisticsCollector collector = new SimpleStatisticsCollector(); collector.incrementLoadCount(); @@ -65,7 +66,7 @@ public void stats_are_collected_with_specified_collector() throws Exception { BatchLoader batchLoader = CompletableFuture::completedFuture; DataLoaderOptions loaderOptions = DataLoaderOptions.newOptions().setStatisticsCollector(() -> collector); - DataLoader loader = new DataLoader<>(batchLoader, loaderOptions); + DataLoader loader = newDataLoader(batchLoader, loaderOptions); loader.load("A"); loader.load("B"); @@ -98,12 +99,12 @@ public void stats_are_collected_with_specified_collector() throws Exception { } @Test - public void stats_are_collected_with_caching_disabled() throws Exception { + public void stats_are_collected_with_caching_disabled() { StatisticsCollector collector = new SimpleStatisticsCollector(); BatchLoader batchLoader = CompletableFuture::completedFuture; DataLoaderOptions loaderOptions = DataLoaderOptions.newOptions().setStatisticsCollector(() -> collector).setCachingEnabled(false); - DataLoader loader = new DataLoader<>(batchLoader, loaderOptions); + DataLoader loader = newDataLoader(batchLoader, loaderOptions); loader.load("A"); loader.load("B"); @@ -152,8 +153,8 @@ public void stats_are_collected_with_caching_disabled() throws Exception { }; @Test - public void stats_are_collected_on_exceptions() throws Exception { - DataLoader loader = DataLoader.newDataLoaderWithTry(batchLoaderThatBlows); + public void stats_are_collected_on_exceptions() { + DataLoader loader = DataLoaderFactory.newDataLoaderWithTry(batchLoaderThatBlows); loader.load("A"); loader.load("exception"); diff --git a/src/test/java/org/dataloader/DataLoaderTest.java b/src/test/java/org/dataloader/DataLoaderTest.java index 0718225..f418b9c 100644 --- a/src/test/java/org/dataloader/DataLoaderTest.java +++ b/src/test/java/org/dataloader/DataLoaderTest.java @@ -35,6 +35,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.awaitility.Awaitility.await; +import static org.dataloader.DataLoaderFactory.newDataLoader; import static org.dataloader.DataLoaderOptions.newOptions; import static org.dataloader.TestKit.listFrom; import static org.dataloader.impl.CompletableFutureKit.cause; @@ -60,7 +61,7 @@ public class DataLoaderTest { @Test public void should_Build_a_really_really_simple_data_loader() { AtomicBoolean success = new AtomicBoolean(); - DataLoader identityLoader = new DataLoader<>(keysAsValues()); + DataLoader identityLoader = newDataLoader(keysAsValues()); CompletionStage future1 = identityLoader.load(1); @@ -75,7 +76,7 @@ public void should_Build_a_really_really_simple_data_loader() { @Test public void should_Support_loading_multiple_keys_in_one_call() { AtomicBoolean success = new AtomicBoolean(); - DataLoader identityLoader = new DataLoader<>(keysAsValues()); + DataLoader identityLoader = newDataLoader(keysAsValues()); CompletionStage> futureAll = identityLoader.loadMany(asList(1, 2)); futureAll.thenAccept(promisedValues -> { @@ -90,7 +91,7 @@ public void should_Support_loading_multiple_keys_in_one_call() { @Test public void should_Resolve_to_empty_list_when_no_keys_supplied() { AtomicBoolean success = new AtomicBoolean(); - DataLoader identityLoader = new DataLoader<>(keysAsValues()); + DataLoader identityLoader = newDataLoader(keysAsValues()); CompletableFuture> futureEmpty = identityLoader.loadMany(emptyList()); futureEmpty.thenAccept(promisedValues -> { assertThat(promisedValues.size(), is(0)); @@ -104,13 +105,13 @@ public void should_Resolve_to_empty_list_when_no_keys_supplied() { @Test public void should_Return_zero_entries_dispatched_when_no_keys_supplied() { AtomicBoolean success = new AtomicBoolean(); - DataLoader identityLoader = new DataLoader<>(keysAsValues()); + DataLoader identityLoader = newDataLoader(keysAsValues()); CompletableFuture> futureEmpty = identityLoader.loadMany(emptyList()); futureEmpty.thenAccept(promisedValues -> { assertThat(promisedValues.size(), is(0)); success.set(true); }); - DispatchResult dispatchResult = identityLoader.dispatchWithCounts(); + DispatchResult dispatchResult = identityLoader.dispatchWithCounts(); await().untilAtomic(success, is(true)); assertThat(dispatchResult.getKeysCount(), equalTo(0)); } @@ -131,12 +132,11 @@ public void should_Batch_multiple_requests() throws ExecutionException, Interrup } @Test - public void should_Return_number_of_batched_entries() throws ExecutionException, InterruptedException { + public void should_Return_number_of_batched_entries() { List> loadCalls = new ArrayList<>(); DataLoader identityLoader = idLoader(new DataLoaderOptions(), loadCalls); CompletableFuture future1 = identityLoader.load(1); - CompletableFuture future1a = identityLoader.load(1); CompletableFuture future2 = identityLoader.load(2); DispatchResult dispatchResult = identityLoader.dispatchWithCounts(); @@ -244,7 +244,9 @@ public void should_Clear_single_value_in_loader() throws ExecutionException, Int assertThat(future2.get(), equalTo("B")); assertThat(loadCalls, equalTo(singletonList(asList("A", "B")))); - identityLoader.clear("A"); + // fluency + DataLoader dl = identityLoader.clear("A"); + assertThat(dl, equalTo(identityLoader)); CompletableFuture future1a = identityLoader.load("A"); CompletableFuture future2a = identityLoader.load("B"); @@ -270,7 +272,8 @@ public void should_Clear_all_values_in_loader() throws ExecutionException, Inter assertThat(future2.get(), equalTo("B")); assertThat(loadCalls, equalTo(singletonList(asList("A", "B")))); - identityLoader.clearAll(); + DataLoader dlFluent = identityLoader.clearAll(); + assertThat(dlFluent, equalTo(identityLoader)); // fluency CompletableFuture future1a = identityLoader.load("A"); CompletableFuture future2a = identityLoader.load("B"); @@ -287,7 +290,8 @@ public void should_Allow_priming_the_cache() throws ExecutionException, Interrup List> loadCalls = new ArrayList<>(); DataLoader identityLoader = idLoader(new DataLoaderOptions(), loadCalls); - identityLoader.prime("A", "A"); + DataLoader dlFluency = identityLoader.prime("A", "A"); + assertThat(dlFluency, equalTo(identityLoader)); CompletableFuture future1 = identityLoader.load("A"); CompletableFuture future2 = identityLoader.load("B"); @@ -759,8 +763,8 @@ public void should_Accept_a_custom_cache_map_implementation() throws ExecutionEx // Fetches as expected - CompletableFuture future1 = identityLoader.load("a"); - CompletableFuture future2 = identityLoader.load("b"); + CompletableFuture future1 = identityLoader.load("a"); + CompletableFuture future2 = identityLoader.load("b"); CompletableFuture> composite = identityLoader.dispatch(); await().until(composite::isDone); @@ -770,8 +774,8 @@ public void should_Accept_a_custom_cache_map_implementation() throws ExecutionEx assertThat(loadCalls, equalTo(singletonList(asList("a", "b")))); assertArrayEquals(customMap.stash.keySet().toArray(), asList("a", "b").toArray()); - CompletableFuture future3 = identityLoader.load("c"); - CompletableFuture future2a = identityLoader.load("b"); + CompletableFuture future3 = identityLoader.load("c"); + CompletableFuture future2a = identityLoader.load("b"); composite = identityLoader.dispatch(); await().until(composite::isDone); @@ -786,7 +790,7 @@ public void should_Accept_a_custom_cache_map_implementation() throws ExecutionEx identityLoader.clear("b"); assertArrayEquals(customMap.stash.keySet().toArray(), asList("a", "c").toArray()); - CompletableFuture future2b = identityLoader.load("b"); + CompletableFuture future2b = identityLoader.load("b"); composite = identityLoader.dispatch(); await().until(composite::isDone); @@ -802,7 +806,7 @@ public void should_Accept_a_custom_cache_map_implementation() throws ExecutionEx } @Test - public void batching_disabled_should_dispatch_immediately() throws Exception { + public void batching_disabled_should_dispatch_immediately() { List> loadCalls = new ArrayList<>(); DataLoaderOptions options = newOptions().setBatchingEnabled(false); DataLoader identityLoader = idLoader(options, loadCalls); @@ -830,7 +834,7 @@ public void batching_disabled_should_dispatch_immediately() throws Exception { } @Test - public void batching_disabled_and_caching_disabled_should_dispatch_immediately_and_forget() throws Exception { + public void batching_disabled_and_caching_disabled_should_dispatch_immediately_and_forget() { List> loadCalls = new ArrayList<>(); DataLoaderOptions options = newOptions().setBatchingEnabled(false).setCachingEnabled(false); DataLoader identityLoader = idLoader(options, loadCalls); @@ -861,7 +865,7 @@ public void batching_disabled_and_caching_disabled_should_dispatch_immediately_a } @Test - public void batches_multiple_requests_with_max_batch_size() throws Exception { + public void batches_multiple_requests_with_max_batch_size() { List> loadCalls = new ArrayList<>(); DataLoader identityLoader = idLoader(newOptions().setMaxBatchSize(2), loadCalls); @@ -882,7 +886,7 @@ public void batches_multiple_requests_with_max_batch_size() throws Exception { } @Test - public void can_split_max_batch_sizes_correctly() throws Exception { + public void can_split_max_batch_sizes_correctly() { List> loadCalls = new ArrayList<>(); DataLoader identityLoader = idLoader(newOptions().setMaxBatchSize(5), loadCalls); @@ -938,19 +942,19 @@ public void should_Batch_loads_occurring_within_futures() { @Test public void can_call_a_loader_from_a_loader() throws Exception { List> deepLoadCalls = new ArrayList<>(); - DataLoader deepLoader = DataLoader.newDataLoader(keys -> { + DataLoader deepLoader = newDataLoader(keys -> { deepLoadCalls.add(keys); return CompletableFuture.completedFuture(keys); }); List> aLoadCalls = new ArrayList<>(); - DataLoader aLoader = new DataLoader<>(keys -> { + DataLoader aLoader = newDataLoader(keys -> { aLoadCalls.add(keys); return deepLoader.loadMany(keys); }); List> bLoadCalls = new ArrayList<>(); - DataLoader bLoader = new DataLoader<>(keys -> { + DataLoader bLoader = newDataLoader(keys -> { bLoadCalls.add(keys); return deepLoader.loadMany(keys); }); @@ -983,7 +987,7 @@ public void can_call_a_loader_from_a_loader() throws Exception { } @Test - public void should_allow_composition_of_data_loader_calls() throws Exception { + public void should_allow_composition_of_data_loader_calls() { UserManager userManager = new UserManager(); BatchLoader userBatchLoader = userIds -> CompletableFuture @@ -991,7 +995,7 @@ public void should_allow_composition_of_data_loader_calls() throws Exception { .stream() .map(userManager::loadUserById) .collect(Collectors.toList())); - DataLoader userLoader = new DataLoader<>(userBatchLoader); + DataLoader userLoader = newDataLoader(userBatchLoader); AtomicBoolean gandalfCalled = new AtomicBoolean(false); AtomicBoolean sarumanCalled = new AtomicBoolean(false); @@ -1027,7 +1031,7 @@ private static CacheKey getJsonObjectCacheMapFn() { } private static DataLoader idLoader(DataLoaderOptions options, List> loadCalls) { - return DataLoader.newDataLoader(keys -> { + return newDataLoader(keys -> { loadCalls.add(new ArrayList<>(keys)); @SuppressWarnings("unchecked") List values = keys.stream() @@ -1039,7 +1043,7 @@ private static DataLoader idLoader(DataLoaderOptions options, List< private static DataLoader idLoaderBlowsUps( DataLoaderOptions options, List> loadCalls) { - return new DataLoader<>(keys -> { + return newDataLoader(keys -> { loadCalls.add(new ArrayList<>(keys)); return TestKit.futureError(); }, options); @@ -1047,7 +1051,7 @@ private static DataLoader idLoaderBlowsUps( private static DataLoader idLoaderAllExceptions( DataLoaderOptions options, List> loadCalls) { - return new DataLoader<>(keys -> { + return newDataLoader(keys -> { loadCalls.add(new ArrayList<>(keys)); List errors = keys.stream().map(k -> new IllegalStateException("Error")).collect(Collectors.toList()); @@ -1057,7 +1061,7 @@ private static DataLoader idLoaderAllExceptions( private static DataLoader idLoaderOddEvenExceptions( DataLoaderOptions options, List> loadCalls) { - return new DataLoader<>(keys -> { + return newDataLoader(keys -> { loadCalls.add(new ArrayList<>(keys)); List errors = new ArrayList<>(); diff --git a/src/test/java/org/dataloader/DataLoaderTimeTest.java b/src/test/java/org/dataloader/DataLoaderTimeTest.java index c6f1af2..f3d1678 100644 --- a/src/test/java/org/dataloader/DataLoaderTimeTest.java +++ b/src/test/java/org/dataloader/DataLoaderTimeTest.java @@ -28,6 +28,7 @@ public void should_set_and_instant_if_dispatched() { Instant startInstant = now(); + @SuppressWarnings("deprecation") DataLoader dataLoader = new DataLoader(keysAsValues()) { @Override Clock clock() { diff --git a/src/test/java/org/dataloader/DataLoaderWithTryTest.java b/src/test/java/org/dataloader/DataLoaderWithTryTest.java index b2127e6..e9e8538 100644 --- a/src/test/java/org/dataloader/DataLoaderWithTryTest.java +++ b/src/test/java/org/dataloader/DataLoaderWithTryTest.java @@ -8,10 +8,10 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static org.dataloader.DataLoaderFactory.*; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; @@ -36,7 +36,7 @@ public void should_handle_Trys_coming_back_from_batchLoader() throws Exception { return CompletableFuture.completedFuture(result); }; - DataLoader dataLoader = DataLoader.newDataLoaderWithTry(batchLoader); + DataLoader dataLoader = newDataLoaderWithTry(batchLoader); commonTryAsserts(batchKeyCalls, dataLoader); } @@ -59,7 +59,7 @@ public void should_handle_Trys_coming_back_from_mapped_batchLoader() throws Exce return CompletableFuture.completedFuture(result); }; - DataLoader dataLoader = DataLoader.newMappedDataLoaderWithTry(batchLoader); + DataLoader dataLoader = newMappedDataLoaderWithTry(batchLoader); commonTryAsserts(batchKeyCalls, dataLoader); }