Last active
April 24, 2020 23:13
-
-
Save andersstorhaug/76122879f6ddc353cf38fcc7fc1e2f95 to your computer and use it in GitHub Desktop.
DynamicData `ManyInnerJoin`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| internal class ManyInnerJoin<TLeft, TLeftKey, TRight, TRightKey, TDestination> | |
| { | |
| private readonly IObservable<IChangeSet<TLeft, TLeftKey>> _left; | |
| private readonly IObservable<IChangeSet<TRight, TRightKey>> _right; | |
| private readonly Func<TLeft, TRightKey> _rightKeySelector; | |
| private readonly Func<TLeft, TRight, TDestination> _resultSelector; | |
| public ManyInnerJoin(IObservable<IChangeSet<TLeft, TLeftKey>> left, | |
| IObservable<IChangeSet<TRight, TRightKey>> right, | |
| Func<TLeft, TRightKey> rightKeySelector, | |
| Func<TLeft, TRight, TDestination> resultSelector) | |
| { | |
| _left = left ?? throw new ArgumentNullException(nameof(left)); | |
| _right = right ?? throw new ArgumentNullException(nameof(right)); | |
| _rightKeySelector = rightKeySelector ?? throw new ArgumentNullException(nameof(rightKeySelector)); | |
| _resultSelector = resultSelector ?? throw new ArgumentNullException(nameof(resultSelector)); | |
| } | |
| public IObservable<IChangeSet<TDestination, TLeftKey>> Run() | |
| { | |
| var leftGroups = _left | |
| .Transform((left, leftKey) => new LeftContainer(left, leftKey)) | |
| .Group(leftContainer => _rightKeySelector(leftContainer.Item)); | |
| return _right | |
| .InnerJoin(leftGroups, leftGroup => leftGroup.Key, (right, leftGroup) => new ManyJoinContainer(right, leftGroup)) | |
| .OnItemRemoved(joinContainer => joinContainer.Dispose()) | |
| .MergeMany(joinContainer => joinContainer.LeftGroup.Cache | |
| .Connect() | |
| .Concat(Observable.Defer(() => Observable.Return(GetRemovedChangeSet(joinContainer)))) | |
| .Transform(leftContainer => _resultSelector(leftContainer.Item, joinContainer.Right))); | |
| } | |
| private static IChangeSet<LeftContainer, TLeftKey> GetRemovedChangeSet(ManyJoinContainer container) | |
| { | |
| var changes = container.LeftGroup.Cache.Items | |
| .Select(current => new Change<LeftContainer, TLeftKey>(ChangeReason.Remove, current.Key, current)) | |
| .ToList(); | |
| return new ChangeSet<LeftContainer, TLeftKey>(changes); | |
| } | |
| private class LeftContainer | |
| { | |
| public LeftContainer(TLeft item, TLeftKey key) => (Item, Key) = (item, key); | |
| public TLeft Item { get; } | |
| public TLeftKey Key { get; } | |
| } | |
| private class ManyJoinContainer : IDisposable | |
| { | |
| public ManyJoinContainer(TRight right, IGroup<LeftContainer, TLeftKey, TRightKey> leftGroup) => (Right, LeftGroup) = (right, leftGroup); | |
| public TRight Right { get; } | |
| public IGroup<LeftContainer, TLeftKey, TRightKey> LeftGroup { get; } | |
| public void Dispose() => LeftGroup?.Cache.Dispose(); | |
| } | |
| } | |
| public static class ObservableCacheEx | |
| { | |
| public static IObservable<IChangeSet<TDestination, TLeftKey>> ManyInnerJoin<TLeft, TLeftKey, TRight, TRightKey, TDestination>( | |
| this IObservable<IChangeSet<TLeft, TLeftKey>> left, | |
| IObservable<IChangeSet<TRight, TRightKey>> right, | |
| Func<TLeft, TRightKey> leftKeySelector, | |
| Func<TLeft, TRight, TDestination> resultSelector) | |
| { | |
| return new ManyInnerJoin<TLeft, TLeftKey, TRight, TRightKey, TDestination>(left, right, leftKeySelector, resultSelector).Run(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment