private void ProcessChainedExpression(ChainedExpression chainedExpression, List <SearchParamTableExpression> tableExpressions, int chainLevel)
        {
            SearchParamTableExpressionQueryGenerator queryGenerator = chainedExpression.Expression.AcceptVisitor(_searchParamTableExpressionQueryGeneratorFactory, null);

            Expression expressionOnTarget = queryGenerator == null ? chainedExpression.Expression : null;

            var sqlChainLinkExpression = new SqlChainLinkExpression(
                chainedExpression.ResourceTypes,
                chainedExpression.ReferenceSearchParameter,
                chainedExpression.TargetResourceTypes,
                chainedExpression.Reversed,
                expressionOnTarget: expressionOnTarget);

            tableExpressions.Add(
                new SearchParamTableExpression(
                    ChainLinkQueryGenerator.Instance,
                    sqlChainLinkExpression,
                    SearchParamTableExpressionKind.Chain,
                    chainLevel));

            if (chainedExpression.Expression is ChainedExpression nestedChainedExpression)
            {
                ProcessChainedExpression(nestedChainedExpression, tableExpressions, chainLevel + 1);
            }
            else if (queryGenerator != null)
            {
                tableExpressions.Add(
                    new SearchParamTableExpression(
                        queryGenerator,
                        chainedExpression.Expression,
                        SearchParamTableExpressionKind.Normal,
                        chainLevel));
            }
        }
        public virtual Expression VisitSqlChainLink(SqlChainLinkExpression sqlChainLinkExpression, TContext context)
        {
            Expression visitedExpressionOnSource = sqlChainLinkExpression.ExpressionOnSource?.AcceptVisitor(this, context);
            Expression visitedExpressionOnTarget = sqlChainLinkExpression.ExpressionOnTarget?.AcceptVisitor(this, context);

            if (ReferenceEquals(visitedExpressionOnSource, sqlChainLinkExpression.ExpressionOnSource) &&
                ReferenceEquals(visitedExpressionOnTarget, sqlChainLinkExpression.ExpressionOnTarget))
            {
                return(sqlChainLinkExpression);
            }

            return(new SqlChainLinkExpression(
                       sqlChainLinkExpression.ResourceTypes,
                       sqlChainLinkExpression.ReferenceSearchParameter,
                       sqlChainLinkExpression.TargetResourceTypes,
                       sqlChainLinkExpression.Reversed,
                       visitedExpressionOnSource,
                       visitedExpressionOnTarget));
        }
예제 #3
0
        public override Expression VisitSqlRoot(SqlRootExpression expression, object context)
        {
            if (expression.SearchParamTableExpressions.Count == 0 || expression.ResourceTableExpressions.Count == 0 ||
                expression.SearchParamTableExpressions.All(e => e.Kind == SearchParamTableExpressionKind.Include))
            {
                // if only Include expressions, the case is handled in IncludeMatchSeedRewriter
                return(expression);
            }

            Expression extractedCommonResourceExpressions = null;
            bool       containsResourceExpressionFoundOnlyOnResourceTable = false;

            for (int i = 0; i < expression.ResourceTableExpressions.Count; i++)
            {
                SearchParameterExpressionBase currentExpression = expression.ResourceTableExpressions[i];

                if (currentExpression is SearchParameterExpression searchParameterExpression)
                {
                    if (searchParameterExpression.Parameter.ColumnLocation().HasFlag(SearchParameterColumnLocation.SearchParamTable))
                    {
                        extractedCommonResourceExpressions = extractedCommonResourceExpressions == null ? (Expression)currentExpression : Expression.And(extractedCommonResourceExpressions, currentExpression);
                    }
                    else
                    {
                        containsResourceExpressionFoundOnlyOnResourceTable = true;
                    }
                }
            }

            var newTableExpressions = new List <SearchParamTableExpression>(expression.SearchParamTableExpressions.Count);

            if (containsResourceExpressionFoundOnlyOnResourceTable)
            {
                // There is a predicate over _id, which is on the Resource table but not on the search parameter tables.
                // So the first table expression should be an "All" expression, where we restrict the resultset to resources with that ID.
                newTableExpressions.Add(new SearchParamTableExpression(null, Expression.And(expression.ResourceTableExpressions), SearchParamTableExpressionKind.All));
            }

            foreach (var tableExpression in expression.SearchParamTableExpressions)
            {
                if (tableExpression.Kind == SearchParamTableExpressionKind.Include ||
                    (tableExpression.Kind == SearchParamTableExpressionKind.Normal && tableExpression.ChainLevel > 0) ||
                    (tableExpression.Kind == SearchParamTableExpressionKind.Chain && tableExpression.ChainLevel > 1))
                {
                    // these predicates do not apply to referenced resources

                    newTableExpressions.Add(tableExpression);
                }
                else if (tableExpression.Kind == SearchParamTableExpressionKind.Chain)
                {
                    var sqlChainLinkExpression = (SqlChainLinkExpression)tableExpression.Predicate;

                    Debug.Assert(sqlChainLinkExpression.ExpressionOnSource == null);

                    var newChainLinkExpression = new SqlChainLinkExpression(
                        sqlChainLinkExpression.ResourceTypes,
                        sqlChainLinkExpression.ReferenceSearchParameter,
                        sqlChainLinkExpression.TargetResourceTypes,
                        sqlChainLinkExpression.Reversed,
                        extractedCommonResourceExpressions,
                        sqlChainLinkExpression.ExpressionOnTarget);

                    newTableExpressions.Add(new SearchParamTableExpression(tableExpression.QueryGenerator, newChainLinkExpression, tableExpression.Kind, chainLevel: tableExpression.ChainLevel));
                }
                else
                {
                    Expression predicate = tableExpression.Predicate == null
                        ? extractedCommonResourceExpressions
                        : Expression.And(tableExpression.Predicate, extractedCommonResourceExpressions);

                    newTableExpressions.Add(new SearchParamTableExpression(tableExpression.QueryGenerator, predicate, tableExpression.Kind, tableExpression.ChainLevel));
                }
            }

            return(new SqlRootExpression(newTableExpressions, Array.Empty <SearchParameterExpressionBase>()));
        }
예제 #4
0
 public virtual TOutput VisitSqlChainLink(SqlChainLinkExpression sqlChainLinkExpression, TContext context) => default;