You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework/Connected.Expressions/Translation/Rewriters/CrossApplyRewriter.cs

68 lines
2.6 KiB

2 years ago
using Connected.Expressions.Expressions;
using Connected.Expressions.Languages;
using Connected.Expressions.Translation.Projections;
using Connected.Expressions.Translation.Resolvers;
using Connected.Expressions.Visitors;
using System.Linq.Expressions;
namespace Connected.Expressions.Translation.Rewriters;
public sealed class CrossApplyRewriter : DatabaseVisitor
{
private CrossApplyRewriter(QueryLanguage language)
{
Language = language;
}
private QueryLanguage Language { get; }
public static Expression Rewrite(QueryLanguage language, Expression expression)
{
if (new CrossApplyRewriter(language).Visit(expression) is not Expression crossApplyExpression)
throw new NullReferenceException(nameof(crossApplyExpression));
return crossApplyExpression;
}
protected override Expression VisitJoin(JoinExpression expression)
{
expression = (JoinExpression)base.VisitJoin(expression);
if (expression.Join == JoinType.CrossApply || expression.Join == JoinType.OuterApply)
{
if (expression.Right is TableExpression)
return new JoinExpression(JoinType.CrossJoin, expression.Left, expression.Right, null);
else
{
var select = expression.Right as SelectExpression;
if (select is not null && select.Take is null && select.Skip is null && !AggregateChecker.HasAggregates(select) && (select.GroupBy is null || !select.GroupBy.Any()))
{
var selectWithoutWhere = select.SetWhere(null);
var referencedAliases = ReferencedAliasesResolver.Resolve(selectWithoutWhere);
var declaredAliases = DeclaredAliasesResolver.Resolve(expression.Left);
referencedAliases.IntersectWith(declaredAliases);
if (!referencedAliases.Any())
{
var where = select.Where;
select = selectWithoutWhere;
var pc = ColumnProjector.ProjectColumns(Language, where, select.Columns, select.Alias, DeclaredAliasesResolver.Resolve(select.From));
select = select.SetColumns(pc.Columns);
where = pc.Projector;
var jt = (where == null) ? JoinType.CrossJoin : (expression.Join == JoinType.CrossApply ? JoinType.InnerJoin : JoinType.LeftOuter);
return new JoinExpression(jt, expression.Left, select, where);
}
}
}
}
return expression;
}
}