Skip to content

Commit 86b01f7

Browse files
committed
style(sources): extract merge group helper; explicit/concrete types (S3776/CA1859/IDE0008)
1 parent 48a7987 commit 86b01f7

2 files changed

Lines changed: 32 additions & 16 deletions

File tree

src/Sources/NeoReports.Sources.Join/Join.cs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public static IStreamingSource<TResult> MergeJoin<TLeft, TRight, TKey, TResult>(
4242
ArgumentNullException.ThrowIfNull(right);
4343
ArgumentNullException.ThrowIfNull(keyRight);
4444
ArgumentNullException.ThrowIfNull(map);
45-
var comparer = keyComparer ?? Comparer<TKey>.Default;
45+
IComparer<TKey> comparer = keyComparer ?? Comparer<TKey>.Default;
4646

4747
async IAsyncEnumerable<TResult> Merge(
4848
ReportExecutionContext execution, [EnumeratorCancellation] CancellationToken cancellationToken)
@@ -52,7 +52,7 @@ async IAsyncEnumerable<TResult> Merge(
5252
var rightHasCurrent = await rightEnum.MoveNextAsync().ConfigureAwait(false);
5353

5454
var group = new List<TRight>();
55-
IReadOnlyList<TRight> current = Array.Empty<TRight>();
55+
TRight[] current = Array.Empty<TRight>();
5656
TKey? currentKey = default;
5757
var haveKey = false;
5858

@@ -61,28 +61,44 @@ async IAsyncEnumerable<TResult> Merge(
6161
TKey key = keyLeft(leftRow);
6262
if (!haveKey || comparer.Compare(currentKey!, key) != 0)
6363
{
64-
group.Clear();
65-
while (rightHasCurrent && comparer.Compare(keyRight(rightEnum.Current), key) < 0)
66-
rightHasCurrent = await rightEnum.MoveNextAsync().ConfigureAwait(false);
67-
while (rightHasCurrent && comparer.Compare(keyRight(rightEnum.Current), key) == 0)
68-
{
69-
group.Add(rightEnum.Current);
70-
rightHasCurrent = await rightEnum.MoveNextAsync().ConfigureAwait(false);
71-
}
72-
64+
rightHasCurrent = await GatherGroupAsync(rightEnum, rightHasCurrent, key, keyRight, comparer, group)
65+
.ConfigureAwait(false);
7366
current = group.Count == 0 ? Array.Empty<TRight>() : group.ToArray();
7467
currentKey = key;
7568
haveKey = true;
7669
}
7770

78-
if (current.Count > 0 || kind == JoinKind.LeftOuter)
71+
if (current.Length > 0 || kind == JoinKind.LeftOuter)
7972
yield return map(leftRow, current);
8073
}
8174
}
8275

8376
return new DelegatingStreamingSource<TResult>(left.Schema, Merge);
8477
}
8578

79+
// Advances the right enumerator past keys below <paramref name="key"/>, then buffers the
80+
// contiguous group of right rows whose key equals it. Returns whether the right enumerator still
81+
// has a current row.
82+
private static async Task<bool> GatherGroupAsync<TRight, TKey>(
83+
IAsyncEnumerator<TRight> right,
84+
bool hasCurrent,
85+
TKey key,
86+
Func<TRight, TKey> keyRight,
87+
IComparer<TKey> comparer,
88+
List<TRight> group)
89+
{
90+
group.Clear();
91+
while (hasCurrent && comparer.Compare(keyRight(right.Current), key) < 0)
92+
hasCurrent = await right.MoveNextAsync().ConfigureAwait(false);
93+
while (hasCurrent && comparer.Compare(keyRight(right.Current), key) == 0)
94+
{
95+
group.Add(right.Current);
96+
hasCurrent = await right.MoveNextAsync().ConfigureAwait(false);
97+
}
98+
99+
return hasCurrent;
100+
}
101+
86102
/// <summary>Reads a batch source page by page as a flat async sequence (O(pageSize) memory).</summary>
87103
private static async IAsyncEnumerable<T> Paginate<T>(
88104
IBatchSource<T> source, ReportExecutionContext execution, [EnumeratorCancellation] CancellationToken cancellationToken)

tests/NeoReports.Sources.Join.UnitTests/MergeJoinTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ private sealed record Order(long CustomerId, string Item);
2424
private sealed record Row(long CustomerId, int OrderCount, string Items);
2525

2626
// customer 1 → 2 orders, customer 2 → none, customer 3 → 1 order (all ordered by key).
27-
private static IBatchSource<Customer> Customers() =>
28-
new Paged<Customer>(new[] { new Customer(1, "A"), new Customer(2, "B"), new Customer(3, "C") }, pageSize: 2);
27+
private static Paged<Customer> Customers() =>
28+
new(new[] { new Customer(1, "A"), new Customer(2, "B"), new Customer(3, "C") }, pageSize: 2);
2929

30-
private static IBatchSource<Order> Orders() =>
31-
new Paged<Order>(new[] { new Order(1, "x"), new Order(1, "y"), new Order(3, "z") }, pageSize: 2);
30+
private static Paged<Order> Orders() =>
31+
new(new[] { new Order(1, "x"), new Order(1, "y"), new Order(3, "z") }, pageSize: 2);
3232

3333
private static Row Map(Customer c, IReadOnlyList<Order> orders) =>
3434
new(c.Id, orders.Count, string.Join(",", orders.Select(o => o.Item)));

0 commit comments

Comments
 (0)