private async Task <IAsyncEnumerable <Row> > GetRightEnumerable(CancellationToken cancellationToken = default) { IAsyncEnumerable <Row> rightEnumerable = new CachingEnumerable <Row>(new EventRaisingEnumerator(right, right.Execute(null, cancellationToken)), cancellationToken); await rightEnumerable.ForEachAsync(row => { ObjectArrayKeys key = row.CreateKey(rightColumns); List <Row> rowsForKey; if (this.rightRowsByJoinKey.TryGetValue(key, out rowsForKey) == false) { this.rightRowsByJoinKey[key] = rowsForKey = new List <Row>(); } rowsForKey.Add(row); }, cancellationToken); return(rightEnumerable); }
/// <summary> /// Executes this operation /// </summary> /// <param name="rows">Rows in pipeline. These are only used if a left part of the join was not specified.</param> /// <param name="cancellationToken">A CancellationToken to stop execution</param> /// <returns></returns> public override IAsyncEnumerable <Row> Execute(IAsyncEnumerable <Row> rows, CancellationToken cancellationToken = default) { return(new AsyncEnumerable <Row>(async yield => { PrepareForJoin(); Dictionary <Row, object> matchedRightRows = new Dictionary <Row, object>(); CachingEnumerable <Row> rightEnumerable = new CachingEnumerable <Row>( new EventRaisingEnumerator(right, right.Execute(null, cancellationToken)), cancellationToken); IAsyncEnumerable <Row> execute = left.Execute(leftRegistered ? null : rows, cancellationToken); await new EventRaisingEnumerator(left, execute) .ForEachAsync(async leftRow => { bool leftNeedOuterJoin = true; currentLeftRow = leftRow; await rightEnumerable.ForEachAsync(async rightRow => { currentRightRow = rightRow; if (MatchJoinCondition(leftRow, rightRow)) { leftNeedOuterJoin = false; matchedRightRows[rightRow] = null; await yield .ReturnAsync(MergeRows(leftRow, rightRow)); } }, cancellationToken); if (leftNeedOuterJoin) { Row emptyRow = new Row(); emptyRow[IsEmptyRowMarker] = IsEmptyRowMarker; currentRightRow = emptyRow; if (MatchJoinCondition(leftRow, emptyRow)) { await yield.ReturnAsync(MergeRows(leftRow, emptyRow)); } else { LeftOrphanRow(leftRow); } } }, cancellationToken); await rightEnumerable.ForEachAsync(async rightRow => { if (matchedRightRows.ContainsKey(rightRow)) { return; } currentRightRow = rightRow; Row emptyRow = new Row(); emptyRow[IsEmptyRowMarker] = IsEmptyRowMarker; currentLeftRow = emptyRow; if (MatchJoinCondition(emptyRow, rightRow)) { await yield.ReturnAsync(MergeRows(emptyRow, rightRow)); } else { RightOrphanRow(rightRow); } }, cancellationToken); })); }