Skip to content
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

Added DataLoader Base Classes #1505

Merged
merged 3 commits into from
Feb 28, 2020
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
51 changes: 51 additions & 0 deletions src/Core/Types/DataLoader/BatchDataLoader.cs
Original file line number Diff line number Diff line change
@@ -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<TKey, TValue>
: DataLoaderBase<TKey, TValue>
{
private static DataLoaderOptions<TKey> _options = new DataLoaderOptions<TKey>
{
AutoDispatching = false,
Batching = true,
CacheSize = DataLoaderDefaults.CacheSize,
MaxBatchSize = DataLoaderDefaults.MaxBatchSize,
SlidingExpiration = TimeSpan.Zero
};

protected BatchDataLoader()
: base(_options)
{
}

protected sealed override async Task<IReadOnlyList<Result<TValue>>> FetchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken)
{
IReadOnlyDictionary<TKey, TValue> result =
await LoadBatchAsync(keys, cancellationToken)
.ConfigureAwait(false);

var items = new Result<TValue>[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<IReadOnlyDictionary<TKey, TValue>> LoadBatchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken);
}
}
59 changes: 59 additions & 0 deletions src/Core/Types/DataLoader/CacheDataLoader.cs
Original file line number Diff line number Diff line change
@@ -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<TKey, TValue>
: DataLoaderBase<TKey, TValue>
{
private static readonly DataLoaderOptions<TKey> _defaultOptions =
CreateOptions(DataLoaderDefaults.CacheSize);

protected CacheDataLoader(FetchCache<TKey, TValue> fetch)
: base(_defaultOptions)
{
}

protected CacheDataLoader(int cacheSize)
: base(CreateOptions(cacheSize))
{
}

protected sealed override async Task<IReadOnlyList<Result<TValue>>> FetchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken)
{
var items = new Result<TValue>[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<TValue> LoadSingleAsync(TKey key, CancellationToken cancellationToken);

private static DataLoaderOptions<TKey> CreateOptions(int cacheSize) =>
new DataLoaderOptions<TKey>
{
AutoDispatching = false,
Batching = false,
CacheSize = cacheSize,
MaxBatchSize = DataLoaderDefaults.MaxBatchSize,
SlidingExpiration = TimeSpan.Zero
};
}
}
4 changes: 2 additions & 2 deletions src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ public static bool Register<TKey, TValue>(
}

return registry.Register(key, services =>
new FetchDataLoader<TKey, TValue>(
new FetchBatchDataLoader<TKey, TValue>(
factory(services)));
}

@@ -47,7 +47,7 @@ public static bool Register<TKey, TValue>(
}

return registry.Register(key, services =>
new FetchDataLoader<TKey, TValue>(fetch));
new FetchBatchDataLoader<TKey, TValue>(fetch));
}

public static bool Register<TKey, TValue>(
22 changes: 22 additions & 0 deletions src/Core/Types/DataLoader/FetchBatchDataLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace HotChocolate.DataLoader
{
internal sealed class FetchBatchDataLoader<TKey, TValue>
: BatchDataLoader<TKey, TValue>
{
private readonly FetchBatch<TKey, TValue> _fetch;

public FetchBatchDataLoader(FetchBatch<TKey, TValue> fetch)
{
_fetch = fetch ?? throw new ArgumentNullException(nameof(fetch));
}

protected override Task<IReadOnlyDictionary<TKey, TValue>> LoadBatchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken) => _fetch(keys);
}
}
47 changes: 0 additions & 47 deletions src/Core/Types/DataLoader/FetchDataLoader.cs

This file was deleted.

30 changes: 5 additions & 25 deletions src/Core/Types/DataLoader/FetchGroupedDataLoader.cs
Original file line number Diff line number Diff line change
@@ -3,44 +3,24 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using GreenDonut;

namespace HotChocolate.DataLoader
{
internal sealed class FetchGroupedDataLoader<TKey, TValue>
: DataLoaderBase<TKey, TValue[]>
: GroupedDataLoader<TKey, TValue>
{
private readonly FetchGroup<TKey, TValue> _fetch;

public FetchGroupedDataLoader(FetchGroup<TKey, TValue> fetch)
: base(new DataLoaderOptions<TKey>
{
AutoDispatching = false,
Batching = true,
CacheSize = DataLoaderDefaults.CacheSize,
MaxBatchSize = DataLoaderDefaults.MaxBatchSize,
SlidingExpiration = TimeSpan.Zero
})
{
_fetch = fetch ?? throw new ArgumentNullException(nameof(fetch));
}

protected override async Task<IReadOnlyList<Result<TValue[]>>>
FetchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken)
protected override Task<ILookup<TKey, TValue>> LoadGroupedBatchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken)
{
ILookup<TKey, TValue> result = await _fetch(keys)
.ConfigureAwait(false);

var items = new Result<TValue[]>[keys.Count];

for (int i = 0; i < keys.Count; i++)
{
items[i] = result[keys[i]].ToArray();
}

return items;
return _fetch(keys);
}
}
}
42 changes: 7 additions & 35 deletions src/Core/Types/DataLoader/FetchSingleDataLoader.cs
Original file line number Diff line number Diff line change
@@ -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<TKey, TValue>
: DataLoaderBase<TKey, TValue>
: CacheDataLoader<TKey, TValue>
{
private readonly FetchCache<TKey, TValue> _fetch;

@@ -16,41 +14,15 @@ public FetchSingleDataLoader(FetchCache<TKey, TValue> fetch)
{
}

public FetchSingleDataLoader(
FetchCache<TKey, TValue> fetch,
int cacheSize)
: base(new DataLoaderOptions<TKey>
{
AutoDispatching = false,
Batching = false,
CacheSize = cacheSize,
MaxBatchSize = DataLoaderDefaults.MaxBatchSize,
SlidingExpiration = TimeSpan.Zero
})
public FetchSingleDataLoader(FetchCache<TKey, TValue> fetch, int cacheSize)
: base(cacheSize)
{
_fetch = fetch ?? throw new ArgumentNullException(nameof(fetch));
}

protected override async Task<IReadOnlyList<Result<TValue>>> FetchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken)
{
var items = new Result<TValue>[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<TValue> LoadSingleAsync(
TKey key,
CancellationToken cancellationToken) =>
_fetch(key);
}
}
49 changes: 49 additions & 0 deletions src/Core/Types/DataLoader/GroupedDataLoader.cs
Original file line number Diff line number Diff line change
@@ -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<TKey, TValue>
: DataLoaderBase<TKey, TValue[]>
{
private static DataLoaderOptions<TKey> _options = new DataLoaderOptions<TKey>
{
AutoDispatching = false,
Batching = true,
CacheSize = DataLoaderDefaults.CacheSize,
MaxBatchSize = DataLoaderDefaults.MaxBatchSize,
SlidingExpiration = TimeSpan.Zero
};

protected GroupedDataLoader()
: base(_options)
{
}

protected sealed override async Task<IReadOnlyList<Result<TValue[]>>> FetchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken)
{
ILookup<TKey, TValue> result =
await LoadGroupedBatchAsync(keys, cancellationToken)
.ConfigureAwait(false);

var items = new Result<TValue[]>[keys.Count];

for (int i = 0; i < keys.Count; i++)
{
items[i] = result[keys[i]].ToArray();
}

return items;
}

protected abstract Task<ILookup<TKey, TValue>> LoadGroupedBatchAsync(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken);
}
}
13 changes: 6 additions & 7 deletions src/Core/Types/DataLoader/IDataLoaderRegistry.cs
Original file line number Diff line number Diff line change
@@ -10,13 +10,12 @@ namespace HotChocolate.DataLoader
public delegate FetchBatch<TKey, TValue> FetchBatchFactory<TKey, TValue>(
IServiceProvider services);

public delegate Task<IReadOnlyDictionary<TKey, TValue>>
FetchBatch<TKey, TValue>(IReadOnlyList<TKey> keys);
public delegate Task<IReadOnlyDictionary<TKey, TValue>> FetchBatch<TKey, TValue>(
IReadOnlyList<TKey> keys);

public delegate Task<IReadOnlyDictionary<TKey, TValue>>
FetchBatchCt<TKey, TValue>(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken);
public delegate Task<IReadOnlyDictionary<TKey, TValue>> FetchBatchCt<TKey, TValue>(
IReadOnlyList<TKey> keys,
CancellationToken cancellationToken);

public delegate FetchGroup<TKey, TValue> FetchGroupeFactory<TKey, TValue>(
IServiceProvider services);
@@ -46,7 +45,7 @@ public delegate Task<TValue> FetchOnceCt<TValue>(
CancellationToken cancellationToken);

/// <summary>
/// The DataLoader-registry holds the instances of DataLoders
/// The DataLoader-registry holds the instances of DataLoaders
/// that are used by the execution engine.
/// </summary>
public interface IDataLoaderRegistry