Aetheria/Assets/Scripts/ServerShared/NIH/RethinkDb.Driver.Linq/RethinkDbQueryModelVisitor.cs

190 lines
7.3 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Remotion.Linq;
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.Expressions;
using Remotion.Linq.Clauses.ResultOperators;
using RethinkDb.Driver.Ast;
using RethinkDb.Driver.Linq.Attributes;
using RethinkDb.Driver.Linq.WhereClauseParsers;
using ExpressionVisitor = RethinkDb.Driver.Linq.WhereClauseParsers.ExpressionVisitor;
using RethinkDb.Driver.Utils;
namespace RethinkDb.Driver.Linq
{
public class RethinkDbQueryModelVisitor : QueryModelVisitorBase
{
private readonly Table _table;
public ReqlAst Query => Stack.Peek();
public Stack<ReqlExpr> Stack = new Stack<ReqlExpr>();
public RethinkDbQueryModelVisitor( Table table )
{
_table = table;
}
public override void VisitQueryModel( QueryModel queryModel )
{
Stack.Push( _table );
base.VisitQueryModel( queryModel );
}
public override void VisitMainFromClause( MainFromClause fromClause, QueryModel queryModel )
{
var subQuery = fromClause.FromExpression as SubQueryExpression;
if( subQuery != null )
{
var query = subQuery.QueryModel;
VisitBodyClauses( query.BodyClauses, query );
base.VisitMainFromClause( fromClause, queryModel );
}
base.VisitMainFromClause( fromClause, queryModel );
}
public override void VisitWhereClause( WhereClause whereClause, QueryModel queryModel, int index )
{
var expressions = SplitWhereClause( whereClause.Predicate );
foreach( var expression in expressions.ToList() )
{
var whereClauseParsers = new List<IWhereClauseParser>
{
new GroupItemsParser(),
new PrimaryIndexParser(),
new SecondaryIndexParser(),
new DefaultParser()
};
var reql = Stack.Pop();
var matchingParser = whereClauseParsers.FirstOrDefault( x => x.IsAppropriate( reql, expression, queryModel.ResultTypeOverride ) );
if( matchingParser != null )
Stack.Push( matchingParser.Parse( reql, queryModel, expression ) );
else
throw new NotSupportedException( "Unable to vist Where clause" );
}
}
private static IEnumerable<Expression> SplitWhereClause( Expression predicate )
{
if( predicate.NodeType != ExpressionType.AndAlso )
{
yield return predicate;
yield break;
}
var binaryExpression = predicate as BinaryExpression;
if( binaryExpression == null )
yield break;
foreach( var expression in SplitWhereClause( binaryExpression.Left ) )
yield return expression;
yield return binaryExpression.Right;
}
private static ReqlExpr GetSelectReqlAst( Expression selector )
{
var visitor = new SelectionProjector();
visitor.Visit( selector );
return visitor.Current;
}
public override void VisitOrderByClause( OrderByClause orderByClause, QueryModel queryModel, int index )
{
var expression = orderByClause.Orderings[0].Expression as MemberExpression;
if( expression == null )
return;
OrderBy reql;
var currentStack = Stack.Pop();
var memberName = QueryHelper.GetJsonMemberName( expression.Member );
if( orderByClause.Orderings[0].OrderingDirection == OrderingDirection.Asc )
reql = currentStack.OrderBy( memberName );
else
reql = currentStack.OrderBy( RethinkDB.R.Desc( memberName ) );
if( currentStack is Table && expression.Member.CustomAttributes.Any( x => x.AttributeType == typeof( PrimaryIndexAttribute ) || x.AttributeType == typeof( SecondaryIndexAttribute ) ) )
reql = reql.OptArg( "index", memberName );
Stack.Push( reql );
}
public override void VisitSelectClause( SelectClause selectClause, QueryModel queryModel )
{
if( queryModel.ResultOperators.FirstOrDefault() is AverageResultOperator )
{
var memberExpression = selectClause.Selector as MemberExpression;
var memberNameResolver = new MemberNameResolver( memberExpression );
Stack.Push( Stack.Pop().Avg( x => memberNameResolver.Resolve( x ) ) );
return;
}
if( queryModel.ResultOperators.FirstOrDefault() is CountResultOperator )
{
Stack.Push( Stack.Pop().Count( ) );
return;
}
var expr = GetSelectReqlAst( selectClause.Selector );
if( !ReferenceEquals( expr, null ) )
{
}
base.VisitSelectClause( selectClause, queryModel );
}
protected override void VisitBodyClauses( ObservableCollection<IBodyClause> bodyClauses, QueryModel queryModel )
{
if( queryModel.ResultTypeOverride.GetTypeInfo().IsGenericTypeDefinition && queryModel.ResultTypeOverride.GetGenericArguments()[0].GetGenericTypeDefinition() != typeof( IGrouping<,> ) )
{
base.VisitBodyClauses( bodyClauses, queryModel );
return;
}
var group = queryModel.ResultOperators.FirstOrDefault() as GroupResultOperator;
if( group == null )
{
base.VisitBodyClauses( bodyClauses, queryModel );
return;
}
var keySelector = (MemberExpression)group.KeySelector;
var groupReql = Stack.Pop().Group( QueryHelper.GetJsonMemberName( keySelector.Member ) );
var memberAccess = group.ElementSelector as MemberExpression;
Stack.Push( memberAccess != null ? groupReql.GetField( QueryHelper.GetJsonMemberName( memberAccess.Member ) ).Ungroup() : groupReql.Ungroup() );
}
public override void VisitResultOperator( ResultOperatorBase resultOperator, QueryModel queryModel, int index )
{
if( resultOperator is AnyResultOperator )
Stack.Push( Stack.Pop().Count() );
else if( resultOperator is AllResultOperator )
{
var allResultOperator = resultOperator as AllResultOperator;
Stack.Push( Stack.Pop().Filter( x => GetWhereReqlAst( x, allResultOperator.Predicate ).Not() ).Count() );
}
else if( resultOperator is FirstResultOperator )
Stack.Push( Stack.Pop().Nth( 0 ) );
else if( resultOperator is LastResultOperator )
Stack.Push( Stack.Pop().Nth( -1 ) );
base.VisitResultOperator( resultOperator, queryModel, index );
}
private static ReqlExpr GetWhereReqlAst( ReqlExpr reqlExpr, Expression predicate )
{
var visitor = new ExpressionVisitor( reqlExpr, typeof( bool ) );
visitor.Visit( predicate );
return visitor.Current;
}
}
}