|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using Connected.Expressions.Expressions;
|
|
|
|
|
using Connected.Expressions.Translation.Resolvers;
|
|
|
|
|
using Connected.Expressions.Visitors;
|
|
|
|
|
|
|
|
|
|
namespace Connected.Expressions.Translation;
|
|
|
|
|
|
|
|
|
|
internal sealed class RedundantSubqueries : DatabaseVisitor
|
|
|
|
|
{
|
|
|
|
|
private RedundantSubqueries()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Expression Remove(Expression expression)
|
|
|
|
|
{
|
|
|
|
|
if (new RedundantSubqueries().Visit(expression) is not Expression redundandSubqueryExpression)
|
|
|
|
|
throw new NullReferenceException(nameof(redundandSubqueryExpression));
|
|
|
|
|
|
|
|
|
|
return SubqueryMerger.Merge(redundandSubqueryExpression);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override Expression VisitSelect(SelectExpression select)
|
|
|
|
|
{
|
|
|
|
|
select = (SelectExpression)base.VisitSelect(select);
|
|
|
|
|
|
|
|
|
|
var redundant = RedundandSubqueriesResolver.Resolve(select.From);
|
|
|
|
|
|
|
|
|
|
if (redundant is not null)
|
|
|
|
|
select = Subqueries.Remove(select, redundant);
|
|
|
|
|
|
|
|
|
|
return select;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override Expression VisitProjection(ProjectionExpression proj)
|
|
|
|
|
{
|
|
|
|
|
proj = (ProjectionExpression)base.VisitProjection(proj);
|
|
|
|
|
|
|
|
|
|
if (proj.Select.From is SelectExpression)
|
|
|
|
|
{
|
|
|
|
|
var redundant = RedundandSubqueriesResolver.Resolve(proj.Select);
|
|
|
|
|
|
|
|
|
|
if (redundant is not null)
|
|
|
|
|
proj = Subqueries.Remove(proj, redundant);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return proj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static bool IsNameMapProjection(SelectExpression select)
|
|
|
|
|
{
|
|
|
|
|
if (select.From is TableExpression)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (select.From is not SelectExpression fromSelect || select.Columns.Count != fromSelect.Columns.Count)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var fromColumns = fromSelect.Columns;
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < select.Columns.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (select.Columns[i].Expression is not ColumnExpression col || !(col.Name == fromColumns[i].Name))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static bool IsInitialProjection(SelectExpression select)
|
|
|
|
|
{
|
|
|
|
|
return select.From is TableExpression;
|
|
|
|
|
}
|
|
|
|
|
}
|