|
|
|
|
|
|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using Connected.Expressions.Expressions;
|
|
|
|
|
using Connected.Expressions.Languages;
|
|
|
|
|
using Connected.Expressions.Translation.Projections;
|
|
|
|
|
using Connected.Expressions.Visitors;
|
|
|
|
|
|
|
|
|
|
namespace Connected.Expressions.Evaluation;
|
|
|
|
|
|
|
|
|
|
internal sealed class ExpressionNominator : DatabaseVisitor
|
|
|
|
|
{
|
|
|
|
|
private ExpressionNominator(QueryLanguage language, ProjectionAffinity affinity)
|
|
|
|
|
{
|
|
|
|
|
Language = language;
|
|
|
|
|
Affinity = affinity;
|
|
|
|
|
|
|
|
|
|
Candidates = new HashSet<Expression>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private QueryLanguage Language { get; }
|
|
|
|
|
private ProjectionAffinity Affinity { get; }
|
|
|
|
|
|
|
|
|
|
private HashSet<Expression> Candidates { get; set; }
|
|
|
|
|
private bool IsBlocked { get; set; }
|
|
|
|
|
|
|
|
|
|
public static HashSet<Expression> Nominate(QueryLanguage language, ProjectionAffinity affinity, Expression expression)
|
|
|
|
|
{
|
|
|
|
|
var nominator = new ExpressionNominator(language, affinity);
|
|
|
|
|
|
|
|
|
|
nominator.Visit(expression);
|
|
|
|
|
|
|
|
|
|
return nominator.Candidates;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override Expression? Visit(Expression? expression)
|
|
|
|
|
{
|
|
|
|
|
if (expression is not null)
|
|
|
|
|
{
|
|
|
|
|
var saveIsBlocked = IsBlocked;
|
|
|
|
|
|
|
|
|
|
IsBlocked = false;
|
|
|
|
|
|
|
|
|
|
if (Language.MustBeColumn(expression))
|
|
|
|
|
Candidates.Add(expression);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
base.Visit(expression);
|
|
|
|
|
|
|
|
|
|
if (!IsBlocked)
|
|
|
|
|
{
|
|
|
|
|
if (Language.MustBeColumn(expression) || (Affinity == ProjectionAffinity.Server && Language.CanBeColumn(expression)))
|
|
|
|
|
Candidates.Add(expression);
|
|
|
|
|
else
|
|
|
|
|
IsBlocked = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IsBlocked |= saveIsBlocked;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return expression;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override Expression VisitProjection(ProjectionExpression expression)
|
|
|
|
|
{
|
|
|
|
|
Visit(expression.Projector);
|
|
|
|
|
|
|
|
|
|
return expression;
|
|
|
|
|
}
|
|
|
|
|
}
|