Example #1
0
        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);
            }));
        }