public override Expression VisitSqlRoot(SqlRootExpression expression, object context)
        {
            List <SearchParamTableExpression> newTableExpressions = null;

            for (var i = 0; i < expression.SearchParamTableExpressions.Count; i++)
            {
                SearchParamTableExpression searchParamTableExpression = expression.SearchParamTableExpressions[i];
                if (searchParamTableExpression.Kind != SearchParamTableExpressionKind.Chain)
                {
                    newTableExpressions?.Add(searchParamTableExpression);
                    continue;
                }

                EnsureAllocatedAndPopulated(ref newTableExpressions, expression.SearchParamTableExpressions, i);

                ProcessChainedExpression((ChainedExpression)searchParamTableExpression.Predicate, newTableExpressions, 1);
            }

            if (newTableExpressions == null)
            {
                return(expression);
            }

            return(new SqlRootExpression(newTableExpressions, expression.ResourceTableExpressions));
        }
Example #2
0
        private static void ValidateNotExpression(Expression subExpression, SearchParamTableExpression expressionToValidate)
        {
            Assert.Equal(SearchParamTableExpressionKind.NotExists, expressionToValidate.Kind);

            var spExpression = Assert.IsType <SearchParameterExpression>(expressionToValidate.Predicate);

            Assert.Equal(subExpression, spExpression.Expression);
        }
Example #3
0
            // (x, y) is a graph edge if x needs to appear before y in the sorted query. That is, y has dependency on x.
            private static bool IsDependencyEdge(SearchParamTableExpression x, SearchParamTableExpression y)
            {
                // Assumes both expressions are include iterate expressions
                var xInclude = (IncludeExpression)x.Predicate;
                var yInclude = (IncludeExpression)y.Predicate;

                return(xInclude.Produces.Intersect(yInclude.Requires).Any());
            }
        public override Expression VisitTable(SearchParamTableExpression tableExpression, object context)
        {
            var visitedPredicate = tableExpression.Predicate.AcceptVisitor(this, context);

            return(new SearchParamTableExpression(
                       tableExpression.QueryGenerator,
                       visitedPredicate,
                       SearchParamTableExpressionKind.NotExists));
        }
        public virtual Expression VisitTable(SearchParamTableExpression searchParamTableExpression, TContext context)
        {
            Expression rewrittenPredicate = searchParamTableExpression.Predicate?.AcceptVisitor(this, context);

            if (ReferenceEquals(rewrittenPredicate, searchParamTableExpression.Predicate))
            {
                return(searchParamTableExpression);
            }

            return(new SearchParamTableExpression(searchParamTableExpression.QueryGenerator, rewrittenPredicate, searchParamTableExpression.Kind));
        }
Example #6
0
        public override Expression VisitTable(SearchParamTableExpression searchParamTableExpression, object context)
        {
            var predicate = searchParamTableExpression.Predicate.AcceptVisitor(this, context);

            Debug.Assert(predicate != searchParamTableExpression.Predicate, "expecting table expression to have been rewritten for concatenation");

            return(new SearchParamTableExpression(
                       searchParamTableExpression.QueryGenerator,
                       predicate,
                       SearchParamTableExpressionKind.Concatenation,
                       searchParamTableExpression.ChainLevel));
        }
        public override Expression VisitSqlRoot(SqlRootExpression expression, object context)
        {
            if (expression.SearchParamTableExpressions.Count == 0)
            {
                return(expression);
            }

            List <SearchParamTableExpression> newTableExpressions = null;

            for (var i = 0; i < expression.SearchParamTableExpressions.Count; i++)
            {
                SearchParamTableExpression tableExpression = expression.SearchParamTableExpressions[i];

                // process only normalized predicates. Ignore Sort as it has its own visitor.
                if (tableExpression.Kind != SearchParamTableExpressionKind.Sort && tableExpression.Predicate?.AcceptVisitor(Scout.Instance, context) == true)
                {
                    EnsureAllocatedAndPopulated(ref newTableExpressions, expression.SearchParamTableExpressions, i);

                    // If this is the first expression, we need to add another expression before it
                    if (i == 0)
                    {
                        // seed with all resources so that we have something to restrict
                        newTableExpressions.Add(
                            new SearchParamTableExpression(
                                tableExpression.QueryGenerator,
                                null,
                                SearchParamTableExpressionKind.All));
                    }

                    newTableExpressions.Add((SearchParamTableExpression)tableExpression.AcceptVisitor(this, context));
                }
                else
                {
                    newTableExpressions?.Add(tableExpression);
                }
            }

            if (newTableExpressions == null)
            {
                return(expression);
            }

            return(new SqlRootExpression(newTableExpressions, expression.ResourceTableExpressions));
        }
Example #8
0
            // Remove v and all v's edges and update incoming edge count accordingly
            public void RemoveNodeAndAllOutgoingEdges(SearchParamTableExpression v)
            {
                if (OutgoingEdges.ContainsKey(v))
                {
                    // Remove all edges
                    IList <SearchParamTableExpression> edges;
                    if (OutgoingEdges.TryGetValue(v, out edges))
                    {
                        while (edges.Any())
                        {
                            var u = edges[0];
                            edges.RemoveAt(0);
                            IncomingEdgesCount[u]--;
                        }
                    }

                    // Remove node
                    OutgoingEdges.Remove(v);
                    IncomingEdgesCount.Remove(v);
                }
            }
        public override Expression VisitSqlRoot(SqlRootExpression expression, object context)
        {
            if (expression.SearchParamTableExpressions.Count == 0)
            {
                return(expression);
            }

            if (!expression.SearchParamTableExpressions.All(te => te.Kind == SearchParamTableExpressionKind.Include))
            {
                return(expression);
            }

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

            Expression resourceExpression = Expression.And(expression.ResourceTableExpressions);
            var        allExpression      = new SearchParamTableExpression(null, resourceExpression, SearchParamTableExpressionKind.All);

            newTableExpressions.Add(allExpression);
            newTableExpressions.AddRange(expression.SearchParamTableExpressions);

            return(new SqlRootExpression(newTableExpressions, Array.Empty <SearchParameterExpression>()));
        }
Example #10
0
        public override Expression VisitSqlRoot(SqlRootExpression expression, SqlSearchOptions context)
        {
            // If we only need the count, we don't want to execute any sort specific queries.
            if (context.CountOnly)
            {
                return(expression);
            }

            // Proceed if no sort params were requested.
            if (context.Sort.Count == 0)
            {
                return(expression);
            }

            // _type and _lastUpdated sort params are handled differently than others, because they can be
            // inferred directly from the resource table itself.
            if (context.Sort.All(s => s.searchParameterInfo.Name is SearchParameterNames.ResourceType or SearchParameterNames.LastUpdated))
            {
                return(expression);
            }

            // Check if the parameter being sorted on is also part of another parameter for the search.
            // If the parameter being sorted on is part of a filter then we don't need to run the seperate search for resources that are missing a value for the field being sorted on.
            // If the parameter being sorted on is not part of a filter we need to run a seperate search to get resources that don't have a value for the field being sorted on.
            bool matchFound = false;

            for (int i = 0; i < expression.SearchParamTableExpressions.Count; i++)
            {
                Expression updatedExpression = expression.SearchParamTableExpressions[i].Predicate.AcceptVisitor(this, context);
                if (updatedExpression == null)
                {
                    matchFound = true;
                    break;
                }
            }

            var newTableExpressions = new List <SearchParamTableExpression>();

            newTableExpressions.AddRange(expression.SearchParamTableExpressions);
            var continuationToken = ContinuationToken.FromString(context.ContinuationToken);

            if (!matchFound)
            {
                // We are running a sort query where the parameter by which we are sorting
                // is not present as part of other search parameters in the query.

                // Check whether we have to execute the second phase of the search for a sort query.
                // This can occur when SearchService decides to run a second search while processing the current query.
                // Or it could be a query from the client with a hardcoded "special" continuation token.
                if (context.SortQuerySecondPhase ||
                    (continuationToken != null &&
                     continuationToken.ResourceSurrogateId == 0 &&
                     continuationToken.SortValue == SqlSearchConstants.SortSentinelValueForCt))
                {
                    context.ContinuationToken = null;
                    if (context.Sort[0].sortOrder == SortOrder.Descending)
                    {
                        // For descending order, the second phase of the sort query deals with searching
                        // for resources that do not have a value for the _sort parameter.
                        var missingExpression   = Expression.MissingSearchParameter(context.Sort[0].searchParameterInfo, isMissing: true);
                        var queryGenForMissing  = _searchParamTableExpressionQueryGeneratorFactory.GetSearchParamTableExpressionQueryGenerator(context.Sort[0].searchParameterInfo);
                        var notExistsExpression = new SearchParamTableExpression(
                            queryGenForMissing,
                            missingExpression,
                            SearchParamTableExpressionKind.NotExists);

                        newTableExpressions.Add(notExistsExpression);

                        return(new SqlRootExpression(newTableExpressions, expression.ResourceTableExpressions));
                    }

                    // For ascending, the second phase of the sort query deals with searching
                    // for resources that have a value for the _sort parameter. So we will generate
                    // the appropriate Sort expression below.
                }
                else if (continuationToken != null && continuationToken.SortValue == null)
                {
                    // We have a ct for resourceid but not for the sort value.
                    // This means we are paging through resources that do not have values for the _sort parameter.
                    var missingExpression   = Expression.MissingSearchParameter(context.Sort[0].searchParameterInfo, isMissing: true);
                    var queryGenForMissing  = _searchParamTableExpressionQueryGeneratorFactory.GetSearchParamTableExpressionQueryGenerator(context.Sort[0].searchParameterInfo);
                    var notExistsExpression = new SearchParamTableExpression(
                        queryGenForMissing,
                        missingExpression,
                        SearchParamTableExpressionKind.NotExists);

                    newTableExpressions.Add(notExistsExpression);

                    return(new SqlRootExpression(newTableExpressions, expression.ResourceTableExpressions));
                }
                else if (continuationToken == null)
                {
                    // This means we are in the first "phase" of searching for resources for the _sort query.
                    // For ascending order, we will search for resources that do not have a value for the
                    // corresponding _sort parameter.
                    if (context.Sort[0].sortOrder == SortOrder.Ascending)
                    {
                        var missingExpression   = Expression.MissingSearchParameter(context.Sort[0].searchParameterInfo, isMissing: true);
                        var queryGenForMissing  = _searchParamTableExpressionQueryGeneratorFactory.GetSearchParamTableExpressionQueryGenerator(context.Sort[0].searchParameterInfo);
                        var notExistsExpression = new SearchParamTableExpression(
                            queryGenForMissing,
                            missingExpression,
                            SearchParamTableExpressionKind.NotExists);

                        newTableExpressions.Add(notExistsExpression);

                        return(new SqlRootExpression(newTableExpressions, expression.ResourceTableExpressions));
                    }

                    // For descending order, we will search for resources that have a value for the
                    // corresponding _sort parameter. We will generate the appropriate Sort expression below.
                }
            }

            SearchParamTableExpressionKind sortKind = matchFound ? SearchParamTableExpressionKind.SortWithFilter : SearchParamTableExpressionKind.Sort;

            if (sortKind == SearchParamTableExpressionKind.SortWithFilter)
            {
                context.IsSortWithFilter = true;
            }

            var queryGenerator = _searchParamTableExpressionQueryGeneratorFactory.GetSearchParamTableExpressionQueryGenerator(context.Sort[0].searchParameterInfo);

            newTableExpressions.Add(new SearchParamTableExpression(queryGenerator, new SortExpression(context.Sort[0].searchParameterInfo), sortKind));

            return(new SqlRootExpression(newTableExpressions, expression.ResourceTableExpressions));
        }
Example #11
0
        public override Expression VisitSqlRoot(SqlRootExpression expression, object context)
        {
            if (expression.SearchParamTableExpressions.Count == 0)
            {
                return(expression);
            }

            List <SearchParamTableExpression> newTableExpressions = null;

            for (var i = 0; i < expression.SearchParamTableExpressions.Count; i++)
            {
                SearchParamTableExpression searchParamTableExpression = expression.SearchParamTableExpressions[i];
                bool found = false;

                switch (searchParamTableExpression.Kind)
                {
                case SearchParamTableExpressionKind.Chain:
                case SearchParamTableExpressionKind.Include:
                case SearchParamTableExpressionKind.Sort:
                case SearchParamTableExpressionKind.All:
                    // The expressions contained within a ChainExpression, IncludeExpression, SortExpression, AllExpression
                    // have been promoted to SearchParamTableExpressions in this list and are not considered.
                    break;

                default:
                    if (_rewritingScout != null)
                    {
                        var newPredicate = searchParamTableExpression.Predicate.AcceptVisitor(_rewritingScout, null);
                        if (!ReferenceEquals(newPredicate, searchParamTableExpression.Predicate))
                        {
                            found = true;
                            searchParamTableExpression = new SearchParamTableExpression(searchParamTableExpression.QueryGenerator, newPredicate, searchParamTableExpression.Kind, searchParamTableExpression.ChainLevel);
                        }
                    }
                    else
                    {
                        found = searchParamTableExpression.Predicate.AcceptVisitor(_booleanScout, null);
                    }

                    break;
                }

                if (found)
                {
                    EnsureAllocatedAndPopulated(ref newTableExpressions, expression.SearchParamTableExpressions, i);

                    newTableExpressions.Add(searchParamTableExpression);
                    newTableExpressions.Add((SearchParamTableExpression)searchParamTableExpression.AcceptVisitor(this, context));
                }
                else
                {
                    newTableExpressions?.Add(searchParamTableExpression);
                }
            }

            if (newTableExpressions == null)
            {
                return(expression);
            }

            return(new SqlRootExpression(newTableExpressions, expression.ResourceTableExpressions));
        }
Example #12
0
 public virtual TOutput VisitTable(SearchParamTableExpression searchParamTableExpression, TContext context) => default;