|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|