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)); }
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); }
// (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)); }
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)); }
// 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>())); }
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)); }
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)); }
public virtual TOutput VisitTable(SearchParamTableExpression searchParamTableExpression, TContext context) => default;