diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index b85b3ea8b9d..3835de1c673 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -17,12 +17,19 @@
}
},
{
- "label": "Build src/All.sln",
+ "type": "dotnet",
+ "task": "build",
+ "group": "build",
+ "problemMatcher": [],
+ "label": "dotnet: build"
+ },
+ {
+ "label": "Build src/All.slnx",
"command": "dotnet",
"type": "shell",
"args": [
"build",
- "src/All.sln",
+ "src/All.slnx",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
@@ -49,12 +56,12 @@
"problemMatcher": "$msCompile"
},
{
- "label": "Test src/All.sln",
+ "label": "Test src/All.slnx",
"command": "dotnet",
"type": "shell",
"args": [
"test",
- "src/All.sln",
+ "src/All.slnx",
"--verbosity q",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
@@ -64,6 +71,6 @@
"reveal": "silent"
},
"problemMatcher": "$msCompile"
- },
+ }
]
}
diff --git a/src/CookieCrumble/src/CookieCrumble.Xunit/CookieCrumble.Xunit.csproj b/src/CookieCrumble/src/CookieCrumble.Xunit/CookieCrumble.Xunit.csproj
index ecc54d94a23..b9e5062e13c 100644
--- a/src/CookieCrumble/src/CookieCrumble.Xunit/CookieCrumble.Xunit.csproj
+++ b/src/CookieCrumble/src/CookieCrumble.Xunit/CookieCrumble.Xunit.csproj
@@ -7,7 +7,9 @@
-
+
+
+
diff --git a/src/CookieCrumble/src/CookieCrumble.Xunit3/CookieCrumble.Xunit3.csproj b/src/CookieCrumble/src/CookieCrumble.Xunit3/CookieCrumble.Xunit3.csproj
index 4f920d2ee7f..caee8700f21 100644
--- a/src/CookieCrumble/src/CookieCrumble.Xunit3/CookieCrumble.Xunit3.csproj
+++ b/src/CookieCrumble/src/CookieCrumble.Xunit3/CookieCrumble.Xunit3.csproj
@@ -7,7 +7,8 @@
-
+
+
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index a3d046b0431..144732b7b7f 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -59,11 +59,16 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/GreenDonut/src/GreenDonut/BatchDataLoader.cs b/src/GreenDonut/src/GreenDonut/BatchDataLoader.cs
index d4b34e2ca69..d4e47df966b 100644
--- a/src/GreenDonut/src/GreenDonut/BatchDataLoader.cs
+++ b/src/GreenDonut/src/GreenDonut/BatchDataLoader.cs
@@ -28,10 +28,6 @@ protected BatchDataLoader(
DataLoaderOptions options)
: base(batchScheduler, options)
{
- if (options is null)
- {
- throw new ArgumentNullException(nameof(options));
- }
}
///
diff --git a/src/GreenDonut/src/GreenDonut/BranchedDataLoader.cs b/src/GreenDonut/src/GreenDonut/BranchedDataLoader.cs
new file mode 100644
index 00000000000..731feff1e96
--- /dev/null
+++ b/src/GreenDonut/src/GreenDonut/BranchedDataLoader.cs
@@ -0,0 +1,42 @@
+namespace GreenDonut;
+
+///
+/// This class represents a branched .
+///
+///
+/// The type of the key.
+///
+///
+/// The type of the value.
+///
+public class BranchedDataLoader
+ : DataLoaderBase
+ where TKey : notnull
+{
+ private readonly DataLoaderBase _root;
+
+ public BranchedDataLoader(
+ DataLoaderBase root,
+ string key)
+ : base(root.BatchScheduler, root.Options)
+ {
+ _root = root;
+ CacheKeyType = $"{root.CacheKeyType}:{key}";
+ ContextData = root.ContextData;
+ }
+
+ public IDataLoader Root => _root;
+
+ protected internal override string CacheKeyType { get; }
+
+ protected sealed override bool AllowCachePropagation => false;
+
+ protected override bool AllowBranching => true;
+
+ protected internal override ValueTask FetchAsync(
+ IReadOnlyList keys,
+ Memory> results,
+ DataLoaderFetchContext context,
+ CancellationToken cancellationToken)
+ => _root.FetchAsync(keys, results, context, cancellationToken);
+}
diff --git a/src/GreenDonut/src/GreenDonut/DataLoaderBase.cs b/src/GreenDonut/src/GreenDonut/DataLoaderBase.cs
index a9782f649bc..2b00050be0c 100644
--- a/src/GreenDonut/src/GreenDonut/DataLoaderBase.cs
+++ b/src/GreenDonut/src/GreenDonut/DataLoaderBase.cs
@@ -46,9 +46,11 @@ public abstract partial class DataLoaderBase
///
/// Throws if is null.
///
- protected DataLoaderBase(IBatchScheduler batchScheduler, DataLoaderOptions? options = null)
+ protected DataLoaderBase(IBatchScheduler batchScheduler, DataLoaderOptions options)
{
- options ??= new DataLoaderOptions();
+ ArgumentNullException.ThrowIfNull(batchScheduler);
+ ArgumentNullException.ThrowIfNull(options);
+
_diagnosticEvents = options.DiagnosticEvents ?? Default;
Cache = options.Cache;
_batchScheduler = batchScheduler;
@@ -226,7 +228,7 @@ void Initialize()
ct);
}
}
-
+
///
public void SetCacheEntry(TKey key, Task value)
{
diff --git a/src/GreenDonut/src/GreenDonut/GroupedDataLoader.cs b/src/GreenDonut/src/GreenDonut/GroupedDataLoader.cs
index 1e676ba7fca..fc61d6b28e4 100644
--- a/src/GreenDonut/src/GreenDonut/GroupedDataLoader.cs
+++ b/src/GreenDonut/src/GreenDonut/GroupedDataLoader.cs
@@ -25,7 +25,7 @@ public abstract class GroupedDataLoader
///
protected GroupedDataLoader(
IBatchScheduler batchScheduler,
- DataLoaderOptions? options = null)
+ DataLoaderOptions options)
: base(batchScheduler, options)
{ }
@@ -92,7 +92,7 @@ public abstract class StatefulGroupedDataLoader
///
protected StatefulGroupedDataLoader(
IBatchScheduler batchScheduler,
- DataLoaderOptions? options = null)
+ DataLoaderOptions options)
: base(batchScheduler, options)
{ }
diff --git a/src/GreenDonut/test/GreenDonut.Tests/DataLoader.cs b/src/GreenDonut/test/GreenDonut.Tests/DataLoader.cs
index d0001f962b0..168968ffe62 100644
--- a/src/GreenDonut/test/GreenDonut.Tests/DataLoader.cs
+++ b/src/GreenDonut/test/GreenDonut.Tests/DataLoader.cs
@@ -3,7 +3,7 @@ namespace GreenDonut;
public class DataLoader(
FetchDataDelegate fetch,
IBatchScheduler batchScheduler,
- DataLoaderOptions? options = null)
+ DataLoaderOptions options)
: DataLoaderBase(batchScheduler, options)
where TKey : notnull
{
diff --git a/src/GreenDonut/test/GreenDonut.Tests/DataLoaderExtensionsTests.cs b/src/GreenDonut/test/GreenDonut.Tests/DataLoaderExtensionsTests.cs
index 1f05265710a..7311146d52d 100644
--- a/src/GreenDonut/test/GreenDonut.Tests/DataLoaderExtensionsTests.cs
+++ b/src/GreenDonut/test/GreenDonut.Tests/DataLoaderExtensionsTests.cs
@@ -1,5 +1,7 @@
// ReSharper disable InconsistentNaming
+using System.Reflection.Metadata;
+
namespace GreenDonut;
public class DataLoaderExtensionsTests
@@ -24,7 +26,7 @@ public void SetCacheEntryKeyNull()
// arrange
var fetch = TestHelpers.CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var value = "Bar";
// act
@@ -40,7 +42,7 @@ public void SetCacheEntryNoException()
// arrange
var fetch = TestHelpers.CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var key = "Foo";
// act
@@ -149,7 +151,7 @@ public void IDataLoaderSetCacheEntryNoException()
// arrange
var fetch = TestHelpers.CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- IDataLoader loader = new DataLoader(fetch, batchScheduler);
+ IDataLoader loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
object key = "Foo";
// act
diff --git a/src/GreenDonut/test/GreenDonut.Tests/DataLoaderStateTests.cs b/src/GreenDonut/test/GreenDonut.Tests/DataLoaderStateTests.cs
index 71bd0da33c1..3a7497f641a 100644
--- a/src/GreenDonut/test/GreenDonut.Tests/DataLoaderStateTests.cs
+++ b/src/GreenDonut/test/GreenDonut.Tests/DataLoaderStateTests.cs
@@ -6,7 +6,7 @@ public static class DataLoaderStateTests
public static async Task SetStateInferredKey()
{
// arrange
- var loader = new DummyDataLoader(typeof(string).FullName!);
+ var loader = new DummyDataLoader(typeof(string).FullName!, new DataLoaderOptions());
// act
await loader.SetState("abc").LoadAsync("def");
@@ -19,7 +19,7 @@ public static async Task SetStateInferredKey()
public static async Task SetStateExplicitKey()
{
// arrange
- var loader = new DummyDataLoader("abc");
+ var loader = new DummyDataLoader("abc", new DataLoaderOptions());
// act
await loader.SetState("abc", "def").LoadAsync("ghi");
@@ -32,7 +32,7 @@ public static async Task SetStateExplicitKey()
public static async Task TrySetStateInferredKey()
{
// arrange
- var loader = new DummyDataLoader(typeof(string).FullName!);
+ var loader = new DummyDataLoader(typeof(string).FullName!, new DataLoaderOptions());
// act
await loader.SetState("abc").TrySetState("xyz").LoadAsync("def");
@@ -45,7 +45,7 @@ public static async Task TrySetStateInferredKey()
public static async Task TrySetStateExplicitKey()
{
// arrange
- var loader = new DummyDataLoader("abc");
+ var loader = new DummyDataLoader("abc", new DataLoaderOptions());
// act
await loader.SetState("abc", "def").TrySetState("abc", "xyz").LoadAsync("def");
@@ -58,7 +58,7 @@ public static async Task TrySetStateExplicitKey()
public static async Task AddStateEnumerableInferredKey()
{
// arrange
- var loader = new DummyDataLoader(typeof(string).FullName!);
+ var loader = new DummyDataLoader(typeof(string).FullName!, new DataLoaderOptions());
// act
await loader.AddStateEnumerable("abc").AddStateEnumerable("xyz").LoadAsync("def");
@@ -74,7 +74,7 @@ public static async Task AddStateEnumerableInferredKey()
public static async Task AddStateEnumerableExplicitKey()
{
// arrange
- var loader = new DummyDataLoader("abc");
+ var loader = new DummyDataLoader("abc", new DataLoaderOptions());
// act
await loader.AddStateEnumerable("abc", "def").AddStateEnumerable("abc", "xyz").LoadAsync("def");
@@ -86,7 +86,7 @@ public static async Task AddStateEnumerableExplicitKey()
item => Assert.Equal("xyz", item));
}
- public class DummyDataLoader(string expectedKey, DataLoaderOptions? options = null)
+ public class DummyDataLoader(string expectedKey, DataLoaderOptions options)
: DataLoaderBase(AutoBatchScheduler.Default, options)
{
public object? State { get; set; }
diff --git a/src/GreenDonut/test/GreenDonut.Tests/DataLoaderTests.cs b/src/GreenDonut/test/GreenDonut.Tests/DataLoaderTests.cs
index 0903b25a300..6db353d5e7e 100644
--- a/src/GreenDonut/test/GreenDonut.Tests/DataLoaderTests.cs
+++ b/src/GreenDonut/test/GreenDonut.Tests/DataLoaderTests.cs
@@ -15,7 +15,10 @@ public void ClearCacheNoException()
var fetch = CreateFetch();
var services = new ServiceCollection()
.AddScoped()
- .AddDataLoader(sp => new DataLoader(fetch, sp.GetRequiredService()));
+ .AddDataLoader(sp => new DataLoader(
+ fetch,
+ sp.GetRequiredService(),
+ sp.GetRequiredService()));
var scope = services.BuildServiceProvider().CreateScope();
var dataLoader = scope.ServiceProvider.GetRequiredService>();
@@ -52,7 +55,7 @@ public async Task LoadSingleKeyNull()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
// act
Task Verify() => loader.LoadAsync(default(string)!, CancellationToken.None);
@@ -67,7 +70,7 @@ public async Task LoadSingleResult()
// arrange
var fetch = CreateFetch("Bar");
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var key = "Foo";
// act
@@ -85,7 +88,7 @@ public async Task LoadSingleResultTwice()
// arrange
var fetch = CreateFetch("Bar");
var batchScheduler = new DelayDispatcher();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var key = "Foo";
// first load.
@@ -106,7 +109,8 @@ public async Task LoadSingleResultNoCache()
var batchScheduler = new ManualBatchScheduler();
var loader = new DataLoader(
fetch,
- batchScheduler);
+ batchScheduler,
+ new DataLoaderOptions());
var key = "Foo";
// act
@@ -124,7 +128,7 @@ public async Task LoadSingleErrorResult()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var key = "Foo";
// act
@@ -144,7 +148,7 @@ public async Task LoadParamsKeysNull()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
// act
Task> Verify() => loader.LoadAsync(default(string[])!);
@@ -159,7 +163,7 @@ public async Task LoadParamsZeroKeys()
// arrange
var fetch = TestHelpers.CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var keys = Array.Empty();
// act
@@ -178,7 +182,7 @@ public async Task LoadParamsResult()
var fetch = TestHelpers
.CreateFetch("Bar");
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var keys = new[] { "Foo", };
// act
@@ -196,7 +200,7 @@ public async Task LoadCollectionKeysNull()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
// act
Task> Verify()
@@ -212,7 +216,7 @@ public async Task LoadCollectionZeroKeys()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var keys = new List();
// act
@@ -230,7 +234,7 @@ public async Task LoadCollectionResult()
// arrange
var fetch = CreateFetch("Bar");
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var keys = new List { "Foo", };
// act
@@ -249,7 +253,8 @@ public async Task LoadCollectionResultTwice()
var batchScheduler = new DelayDispatcher();
var loader = new DataLoader(
fetch,
- batchScheduler);
+ batchScheduler,
+ new DataLoaderOptions());
var keys = new List { "Foo", };
(await loader.LoadAsync(keys, CancellationToken.None)).MatchSnapshot();
@@ -269,7 +274,8 @@ public async Task LoadCollectionResultNoCache()
var batchScheduler = new ManualBatchScheduler();
var loader = new DataLoader(
fetch,
- batchScheduler);
+ batchScheduler,
+ new DataLoaderOptions());
var keys = new List { "Foo", };
// act
@@ -311,7 +317,7 @@ ValueTask Fetch(
}
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(Fetch, batchScheduler);
+ var loader = new DataLoader(Fetch, batchScheduler, new DataLoaderOptions());
var requestKeys = new[] { "Foo", "Bar", "Baz", "Qux", };
// act
@@ -356,7 +362,7 @@ ValueTask Fetch(
}
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(Fetch, batchScheduler);
+ var loader = new DataLoader(Fetch, batchScheduler, new DataLoaderOptions());
var requestKeys = new[] { "Foo", "Bar", "Baz", "Qux", };
// act
@@ -379,7 +385,7 @@ public async Task LoadBatchingError()
// arrange
var expectedException = new Exception("Foo");
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(Fetch, batchScheduler);
+ var loader = new DataLoader(Fetch, batchScheduler, new DataLoaderOptions());
var requestKeys = new[] { "Foo", "Bar", "Baz", "Qux", };
ValueTask Fetch(
@@ -503,7 +509,7 @@ public void RemoveCacheEntryKeyNull()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
loader.SetCacheEntry("Foo", Task.FromResult("Bar"));
@@ -520,7 +526,7 @@ public void RemoveCacheEntryNoException()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var key = "Foo";
// act
@@ -556,7 +562,7 @@ public void SetCacheEntryKeyNull()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
var value = Task.FromResult("Foo");
// act
@@ -572,8 +578,8 @@ public void SetCacheEntryValueNull()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- var loader = new DataLoader(fetch, batchScheduler);
- var key = "Foo";
+ var loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
+ const string key = "Foo";
// act
void Verify() => loader.SetCacheEntry(key, default!);
@@ -628,7 +634,7 @@ public async Task IDataLoaderLoadSingleKeyNull()
// arrange
var fetch = CreateFetch();
var batchScheduler = new ManualBatchScheduler();
- IDataLoader loader = new DataLoader(fetch, batchScheduler);
+ IDataLoader loader = new DataLoader(fetch, batchScheduler, new DataLoaderOptions());
// act
Task