src/LogicalPlanner/LogicalPlan.cs
/// <summary>
/// Create logical operators for a partial query part
/// </summary>
/// <param name="treeNode">the current query part</param>
/// <param name="pipedData"></param>
/// <param name="allLogicalOps"></param>
/// <param name="previousNode">the query part immediate before the current query part (treeNode) 
///     that may contains expressions that can be accessed by clauses in this query part</param>
/// <returns></returns>
Create logical operators for a partial query part
Create logical operators for a partial query part
private LogicalOperator CreateLogicalTree(PartialQueryNode treeNode, LogicalOperator pipedData, ISet<LogicalOperator> allLogicalOps, PartialQueryNode previousNode)
        {
            LogicalOperator lastOperator = pipedData;
            Debug.Assert(treeNode.MatchData == null || treeNode.IsImplicitProjection == true);
            if (treeNode.MatchData != null)
            {
                var isOptionalMatch = treeNode.MatchData.MatchPatterns.Any(p => p.IsOptionalMatch);
                Debug.Assert(treeNode.MatchData.MatchPatterns.All(p => p.IsOptionalMatch == isOptionalMatch));
                if (treeNode.FilterExpression != null)
                {
                    if (isOptionalMatch)
                    {
                        var modifiedMatch = new MatchClause()
                        {
                            MatchPatterns = treeNode.MatchData.MatchPatterns.Select(p => new MatchPattern(false, p)).ToList()
                        };
                        var omOperator = CreateLogicalTree(modifiedMatch, lastOperator, allLogicalOps);
                        var condOmOperator = CreateLogicalTree(treeNode.FilterExpression, omOperator, allLogicalOps);
                        var leftEntityAliases = lastOperator.OutputSchema
                            .Where(f => f is EntityField).Select(f => (f as EntityField).FieldAlias);
                        var explicitlyMatchedAliasesToJoinWithLeft = modifiedMatch.AllEntitiesOrdered
                            .Select(e => e.Alias)
                            .Where(a => a != null)
                            .Intersect(leftEntityAliases);
                        lastOperator = CreateLogicalTree(lastOperator, condOmOperator, explicitlyMatchedAliasesToJoinWithLeft, true, allLogicalOps);
                    }
                    else
                    {
                        lastOperator = CreateLogicalTree(treeNode.MatchData, lastOperator, allLogicalOps);
                        lastOperator = CreateLogicalTree(treeNode.FilterExpression, lastOperator, allLogicalOps);
                    }
                }
                else
                {
                    lastOperator = CreateLogicalTree(treeNode.MatchData, lastOperator, allLogicalOps);
                }
                lastOperator = CreateLogicalTree(treeNode.ProjectedExpressions, treeNode.IsDistinct, lastOperator, allLogicalOps);
            }
            else
            {
                lastOperator = CreateLogicalTree(
                    lastOperator,
                    treeNode.IsDistinct,
                    treeNode.ProjectedExpressions,
                    previousNode?.ProjectedExpressions,
                    treeNode.Limit,
                    treeNode.OrderByClause,
                    treeNode.FilterExpression,
                    allLogicalOps
                    );
            }
            return lastOperator;
        }
private LogicalOperator CreateLogicalTree ( PartialQueryNode treeNode , LogicalOperator pipedData , ISet < LogicalOperator > allLogicalOps , PartialQueryNode previousNode ) { LogicalOperator lastOperator = pipedData ; Debug . Assert ( treeNode . MatchData == null || treeNode . IsImplicitProjection == true ) ; if ( treeNode . MatchData != null ) { var isOptionalMatch = treeNode . MatchData . MatchPatterns . Any ( p => p . IsOptionalMatch ) ; Debug . Assert ( treeNode . MatchData . MatchPatterns . All ( p => p . IsOptionalMatch == isOptionalMatch ) ) ; if ( treeNode . FilterExpression != null ) { if ( isOptionalMatch ) { var modifiedMatch = new MatchClause ( ) { MatchPatterns = treeNode . MatchData . MatchPatterns . Select ( p => new MatchPattern ( false , p ) ) . ToList ( ) } ; var omOperator = CreateLogicalTree ( modifiedMatch , lastOperator , allLogicalOps ) ; var condOmOperator = CreateLogicalTree ( treeNode . FilterExpression , omOperator , allLogicalOps ) ; var leftEntityAliases = lastOperator . OutputSchema . Where ( f => f is EntityField ) . Select ( f => ( f as EntityField ) . FieldAlias ) ; var explicitlyMatchedAliasesToJoinWithLeft = modifiedMatch . AllEntitiesOrdered . Select ( e => e . Alias ) . Where ( a => a != null ) . Intersect ( leftEntityAliases ) ; lastOperator = CreateLogicalTree ( lastOperator , condOmOperator , explicitlyMatchedAliasesToJoinWithLeft , true , allLogicalOps ) ; } else { lastOperator = CreateLogicalTree ( treeNode . MatchData , lastOperator , allLogicalOps ) ; lastOperator = CreateLogicalTree ( treeNode . FilterExpression , lastOperator , allLogicalOps ) ; } } else { lastOperator = CreateLogicalTree ( treeNode . MatchData , lastOperator , allLogicalOps ) ; } lastOperator = CreateLogicalTree ( treeNode . ProjectedExpressions , treeNode . IsDistinct , lastOperator , allLogicalOps ) ; } else { lastOperator = CreateLogicalTree ( lastOperator , treeNode . IsDistinct , treeNode . ProjectedExpressions , previousNode ? . ProjectedExpressions , treeNode . Limit , treeNode . OrderByClause , treeNode . FilterExpression , allLogicalOps ) ; } return lastOperator ; }
Create logical operators for a partial query part
Create logical operators for a partial query part
// parser tree does not mix MATCH and WITH into a single query part today // the query part contains a MATCH clause // since the parser tree guarantees no explicit projection (by WITH/RETURN), we do not need to handle things like  // DISTINCT or ORDER BY as they appears only with WITH/RETURN // we do, however, need to handle WHERE // with WHERE conditions, optional match requires a fork to apply filtering first and then rejoin with piped data,  // where non-optional doesn't require it // e.g. MATCH ... OPTIONAL MATCH ... WHERE ... WITH/RETURN ... // apply filtering conditions to the optional match pattern ... // ... then left outter join back with the piped data // inner join with match data // apply filtering // without filtering conditions, optional and non-optional match can join directly, and  // we only need to apply different join type // e.g. MATCH ... OPTIONAL MATCH ... WITH/RETURN ... // apply the implicit project, where the expressions are carried fields plus named entities // pure projection (WITH/RETURN) // we will need to handle ORDER BY/LIMIT
None
treeNode
PartialQueryNode
the current query part
the current query part
pipedData
LogicalOperator
None
allLogicalOps
ISet<LogicalOperator>
None
previousNode
PartialQueryNode
the query part immediate before the current query part (treeNode)
that may contains expressions that can be accessed by clauses in this query part
the query part immediate before the current query part ( treeNode ) that may contains expressions that can be accessed by clauses in this query part