diff --git a/src/Core/Types/DataLoader/BatchDataLoader.cs b/src/Core/Types/DataLoader/BatchDataLoader.cs new file mode 100644 index 00000000000..ba672c6393b --- /dev/null +++ b/src/Core/Types/DataLoader/BatchDataLoader.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using GreenDonut; + +namespace HotChocolate.DataLoader +{ + public abstract class BatchDataLoader + : DataLoaderBase + { + private static DataLoaderOptions _options = new DataLoaderOptions + { + AutoDispatching = false, + Batching = true, + CacheSize = DataLoaderDefaults.CacheSize, + MaxBatchSize = DataLoaderDefaults.MaxBatchSize, + SlidingExpiration = TimeSpan.Zero + }; + + protected BatchDataLoader() + : base(_options) + { + } + + protected sealed override async Task>> FetchAsync( + IReadOnlyList keys, + CancellationToken cancellationToken) + { + IReadOnlyDictionary result = + await LoadBatchAsync(keys, cancellationToken) + .ConfigureAwait(false); + + var items = new Result[keys.Count]; + + for (int i = 0; i < keys.Count; i++) + { + if (result.TryGetValue(keys[i], out TValue value)) + { + items[i] = value; + } + } + + return items; + } + + protected abstract Task> LoadBatchAsync( + IReadOnlyList keys, + CancellationToken cancellationToken); + } +} diff --git a/src/Core/Types/DataLoader/CacheDataLoader.cs b/src/Core/Types/DataLoader/CacheDataLoader.cs new file mode 100644 index 00000000000..fd37feff0f3 --- /dev/null +++ b/src/Core/Types/DataLoader/CacheDataLoader.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using GreenDonut; + +namespace HotChocolate.DataLoader +{ + public abstract class CacheDataLoader + : DataLoaderBase + { + private static readonly DataLoaderOptions _defaultOptions = + CreateOptions(DataLoaderDefaults.CacheSize); + + protected CacheDataLoader(FetchCache fetch) + : base(_defaultOptions) + { + } + + protected CacheDataLoader(int cacheSize) + : base(CreateOptions(cacheSize)) + { + } + + protected sealed override async Task>> FetchAsync( + IReadOnlyList keys, + CancellationToken cancellationToken) + { + var items = new Result[keys.Count]; + + for (int i = 0; i < keys.Count; i++) + { + try + { + items[i] = await LoadSingleAsync(keys[i], cancellationToken) + .ConfigureAwait(false); + } + catch (Exception ex) + { + items[i] = ex; + } + } + + return items; + } + + protected abstract Task LoadSingleAsync(TKey key, CancellationToken cancellationToken); + + private static DataLoaderOptions CreateOptions(int cacheSize) => + new DataLoaderOptions + { + AutoDispatching = false, + Batching = false, + CacheSize = cacheSize, + MaxBatchSize = DataLoaderDefaults.MaxBatchSize, + SlidingExpiration = TimeSpan.Zero + }; + } +} diff --git a/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs b/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs index 6f1cac04d81..80fb4733467 100644 --- a/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs +++ b/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs @@ -25,7 +25,7 @@ public static bool Register( } return registry.Register(key, services => - new FetchDataLoader( + new FetchBatchDataLoader( factory(services))); } @@ -47,7 +47,7 @@ public static bool Register( } return registry.Register(key, services => - new FetchDataLoader(fetch)); + new FetchBatchDataLoader(fetch)); } public static bool Register( diff --git a/src/Core/Types/DataLoader/FetchBatchDataLoader.cs b/src/Core/Types/DataLoader/FetchBatchDataLoader.cs new file mode 100644 index 00000000000..b9165f6a638 --- /dev/null +++ b/src/Core/Types/DataLoader/FetchBatchDataLoader.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace HotChocolate.DataLoader +{ + internal sealed class FetchBatchDataLoader + : BatchDataLoader + { + private readonly FetchBatch _fetch; + + public FetchBatchDataLoader(FetchBatch fetch) + { + _fetch = fetch ?? throw new ArgumentNullException(nameof(fetch)); + } + + protected override Task> LoadBatchAsync( + IReadOnlyList keys, + CancellationToken cancellationToken) => _fetch(keys); + } +} diff --git a/src/Core/Types/DataLoader/FetchDataLoader.cs b/src/Core/Types/DataLoader/FetchDataLoader.cs deleted file mode 100644 index 948150f48de..00000000000 --- a/src/Core/Types/DataLoader/FetchDataLoader.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using GreenDonut; - -namespace HotChocolate.DataLoader -{ - internal sealed class FetchDataLoader - : DataLoaderBase - { - private readonly FetchBatch _fetch; - - public FetchDataLoader(FetchBatch fetch) - : base(new DataLoaderOptions - { - AutoDispatching = false, - Batching = true, - CacheSize = DataLoaderDefaults.CacheSize, - MaxBatchSize = DataLoaderDefaults.MaxBatchSize, - SlidingExpiration = TimeSpan.Zero - }) - { - _fetch = fetch ?? throw new ArgumentNullException(nameof(fetch)); - } - - protected override async Task>> FetchAsync( - IReadOnlyList keys, - CancellationToken cancellationToken) - { - IReadOnlyDictionary result = - await _fetch(keys).ConfigureAwait(false); - - var items = new Result[keys.Count]; - - for (int i = 0; i < keys.Count; i++) - { - if (result.TryGetValue(keys[i], out TValue value)) - { - items[i] = value; - } - } - - return items; - } - } -} diff --git a/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs b/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs index b1d34b72833..f69f75a4453 100644 --- a/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs +++ b/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs @@ -3,44 +3,24 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using GreenDonut; namespace HotChocolate.DataLoader { internal sealed class FetchGroupedDataLoader - : DataLoaderBase + : GroupedDataLoader { private readonly FetchGroup _fetch; public FetchGroupedDataLoader(FetchGroup fetch) - : base(new DataLoaderOptions - { - AutoDispatching = false, - Batching = true, - CacheSize = DataLoaderDefaults.CacheSize, - MaxBatchSize = DataLoaderDefaults.MaxBatchSize, - SlidingExpiration = TimeSpan.Zero - }) { _fetch = fetch ?? throw new ArgumentNullException(nameof(fetch)); } - protected override async Task>> - FetchAsync( - IReadOnlyList keys, - CancellationToken cancellationToken) + protected override Task> LoadGroupedBatchAsync( + IReadOnlyList keys, + CancellationToken cancellationToken) { - ILookup result = await _fetch(keys) - .ConfigureAwait(false); - - var items = new Result[keys.Count]; - - for (int i = 0; i < keys.Count; i++) - { - items[i] = result[keys[i]].ToArray(); - } - - return items; + return _fetch(keys); } } } diff --git a/src/Core/Types/DataLoader/FetchSingleDataLoader.cs b/src/Core/Types/DataLoader/FetchSingleDataLoader.cs index aef87566828..c9b1a170ef5 100644 --- a/src/Core/Types/DataLoader/FetchSingleDataLoader.cs +++ b/src/Core/Types/DataLoader/FetchSingleDataLoader.cs @@ -1,13 +1,11 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using GreenDonut; namespace HotChocolate.DataLoader { internal sealed class FetchSingleDataLoader - : DataLoaderBase + : CacheDataLoader { private readonly FetchCache _fetch; @@ -16,41 +14,15 @@ public FetchSingleDataLoader(FetchCache fetch) { } - public FetchSingleDataLoader( - FetchCache fetch, - int cacheSize) - : base(new DataLoaderOptions - { - AutoDispatching = false, - Batching = false, - CacheSize = cacheSize, - MaxBatchSize = DataLoaderDefaults.MaxBatchSize, - SlidingExpiration = TimeSpan.Zero - }) + public FetchSingleDataLoader(FetchCache fetch, int cacheSize) + : base(cacheSize) { _fetch = fetch ?? throw new ArgumentNullException(nameof(fetch)); } - protected override async Task>> FetchAsync( - IReadOnlyList keys, - CancellationToken cancellationToken) - { - var items = new Result[keys.Count]; - - for (int i = 0; i < keys.Count; i++) - { - try - { - TValue value = await _fetch(keys[i]).ConfigureAwait(false); - items[i] = value; - } - catch (Exception ex) - { - items[i] = ex; - } - } - - return items; - } + protected override Task LoadSingleAsync( + TKey key, + CancellationToken cancellationToken) => + _fetch(key); } } diff --git a/src/Core/Types/DataLoader/GroupedDataLoader.cs b/src/Core/Types/DataLoader/GroupedDataLoader.cs new file mode 100644 index 00000000000..e545f291782 --- /dev/null +++ b/src/Core/Types/DataLoader/GroupedDataLoader.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using GreenDonut; + +namespace HotChocolate.DataLoader +{ + public abstract class GroupedDataLoader + : DataLoaderBase + { + private static DataLoaderOptions _options = new DataLoaderOptions + { + AutoDispatching = false, + Batching = true, + CacheSize = DataLoaderDefaults.CacheSize, + MaxBatchSize = DataLoaderDefaults.MaxBatchSize, + SlidingExpiration = TimeSpan.Zero + }; + + protected GroupedDataLoader() + : base(_options) + { + } + + protected sealed override async Task>> FetchAsync( + IReadOnlyList keys, + CancellationToken cancellationToken) + { + ILookup result = + await LoadGroupedBatchAsync(keys, cancellationToken) + .ConfigureAwait(false); + + var items = new Result[keys.Count]; + + for (int i = 0; i < keys.Count; i++) + { + items[i] = result[keys[i]].ToArray(); + } + + return items; + } + + protected abstract Task> LoadGroupedBatchAsync( + IReadOnlyList keys, + CancellationToken cancellationToken); + } +} diff --git a/src/Core/Types/DataLoader/IDataLoaderRegistry.cs b/src/Core/Types/DataLoader/IDataLoaderRegistry.cs index 8d8db3b8da0..40e9aa5b2b7 100644 --- a/src/Core/Types/DataLoader/IDataLoaderRegistry.cs +++ b/src/Core/Types/DataLoader/IDataLoaderRegistry.cs @@ -10,13 +10,12 @@ namespace HotChocolate.DataLoader public delegate FetchBatch FetchBatchFactory( IServiceProvider services); - public delegate Task> - FetchBatch(IReadOnlyList keys); + public delegate Task> FetchBatch( + IReadOnlyList keys); - public delegate Task> - FetchBatchCt( - IReadOnlyList keys, - CancellationToken cancellationToken); + public delegate Task> FetchBatchCt( + IReadOnlyList keys, + CancellationToken cancellationToken); public delegate FetchGroup FetchGroupeFactory( IServiceProvider services); @@ -46,7 +45,7 @@ public delegate Task FetchOnceCt( CancellationToken cancellationToken); /// - /// The DataLoader-registry holds the instances of DataLoders + /// The DataLoader-registry holds the instances of DataLoaders /// that are used by the execution engine. /// public interface IDataLoaderRegistry