66
77 internal class DictionaryQueryRunner
88 {
9+ const string AutoColumnPrefix = "___having___" ;
910 private static readonly
1011 Dictionary < Type , Func < SimpleQueryClauseBase , IEnumerable < IDictionary < string , object > > , IEnumerable < IDictionary < string , object > > > > ClauseHandlers =
1112 new Dictionary < Type , Func < SimpleQueryClauseBase , IEnumerable < IDictionary < string , object > > , IEnumerable < IDictionary < string , object > > > >
1213 {
1314 { typeof ( DistinctClause ) , ( c , d ) => d . Distinct ( new DictionaryEqualityComparer ( ) ) } ,
1415 { typeof ( SkipClause ) , ( c , d ) => d . Skip ( ( ( SkipClause ) c ) . Count ) } ,
1516 { typeof ( TakeClause ) , ( c , d ) => d . Take ( ( ( TakeClause ) c ) . Count ) } ,
16- { typeof ( SelectClause ) , ( c , d ) => new SelectClauseHandler ( ( SelectClause ) c ) . Run ( d ) } ,
17- { typeof ( WhereClause ) , ( c , d ) => new WhereClauseHandler ( ( WhereClause ) c ) . Run ( d ) } ,
1817 { typeof ( OrderByClause ) , ( c , d ) => new OrderByClauseHandler ( ( OrderByClause ) c ) . Run ( d ) }
1918 } ;
2019
@@ -37,15 +36,13 @@ public DictionaryQueryRunner(IEnumerable<IDictionary<string, object>> source, pa
3736
3837 public IEnumerable < IDictionary < string , object > > Run ( )
3938 {
40- IEnumerable < IDictionary < string , object > > source ;
39+ var source = RunWhereClauses ( _source ) ;
40+
4141 if ( _withCountClause != null )
4242 {
43- source = _source . ToList ( ) ;
44- _withCountClause . SetCount ( source . Count ( ) ) ;
45- }
46- else
47- {
48- source = _source ;
43+ var list = source . ToList ( ) ;
44+ _withCountClause . SetCount ( list . Count ) ;
45+ source = list ;
4946 }
5047
5148 foreach ( var clause in _clauses )
@@ -57,24 +54,116 @@ public IEnumerable<IDictionary<string, object>> Run()
5754 }
5855 }
5956
57+ source = RunHavingClauses ( source ) ;
58+ source = RunSelectClauses ( source ) ;
59+ return source ;
60+ }
61+
62+ private IEnumerable < IDictionary < string , object > > RunWhereClauses ( IEnumerable < IDictionary < string , object > > source )
63+ {
64+ foreach ( var whereClause in _clauses . OfType < WhereClause > ( ) )
65+ {
66+ source = new WhereClauseHandler ( whereClause ) . Run ( source ) ;
67+ }
6068 return source ;
6169 }
70+
71+ private IEnumerable < IDictionary < string , object > > RunSelectClauses ( IEnumerable < IDictionary < string , object > > source )
72+ {
73+ foreach ( var selectClause in _clauses . OfType < SelectClause > ( ) )
74+ {
75+ source = new SelectClauseHandler ( selectClause ) . Run ( source ) ;
76+ }
77+ return source ;
78+ }
79+
80+ private IEnumerable < IDictionary < string , object > > RunHavingClauses ( IEnumerable < IDictionary < string , object > > source )
81+ {
82+ var havingClauses = _clauses . OfType < HavingClause > ( ) . ToList ( ) ;
83+ if ( havingClauses . Count == 0 ) return source ;
84+
85+ var selectClause = _clauses . OfType < SelectClause > ( ) . FirstOrDefault ( ) ;
86+
87+ List < SimpleReference > selectReferences ;
88+
89+ if ( selectClause != null )
90+ {
91+ selectReferences = selectClause . Columns . ToList ( ) ;
92+ }
93+ else
94+ {
95+ selectReferences = new List < SimpleReference > { new AllColumnsSpecialReference ( ) } ;
96+ }
97+
98+ foreach ( var clause in havingClauses )
99+ {
100+ var criteria = HavingToWhere ( clause . Criteria , selectReferences ) ;
101+ source = new SelectClauseHandler ( new SelectClause ( selectReferences ) ) . Run ( source ) . ToList ( ) ;
102+ source = new WhereClauseHandler ( new WhereClause ( criteria ) ) . Run ( source ) ;
103+ source = source . Select ( d => d . Where ( kvp => ! kvp . Key . StartsWith ( AutoColumnPrefix ) ) . ToDictionary ( kvp => kvp . Key , kvp => kvp . Value ) ) ;
104+ }
105+
106+ return source ;
107+ }
108+
109+ private SimpleExpression HavingToWhere ( SimpleExpression criteria , List < SimpleReference > selectReferences )
110+ {
111+ if ( criteria . LeftOperand is SimpleExpression )
112+ {
113+ return new SimpleExpression ( HavingToWhere ( ( SimpleExpression ) criteria . LeftOperand , selectReferences ) ,
114+ HavingToWhere ( ( SimpleExpression ) criteria . RightOperand , selectReferences ) ,
115+ criteria . Type ) ;
116+ }
117+
118+ object leftOperand = ReplaceFunctionOperand ( criteria . LeftOperand , selectReferences ) ;
119+ object rightOperand = ReplaceFunctionOperand ( criteria . RightOperand , selectReferences ) ;
120+
121+ return new SimpleExpression ( leftOperand , rightOperand , criteria . Type ) ;
122+ }
123+
124+ private static object ReplaceFunctionOperand ( object operand , List < SimpleReference > selectReferences )
125+ {
126+ var leftFunction = operand as FunctionReference ;
127+ if ( ! leftFunction . IsNull ( ) )
128+ {
129+ var alias = AutoColumnPrefix + Guid . NewGuid ( ) . ToString ( "N" ) ;
130+ selectReferences . Add ( leftFunction . As ( alias ) ) ;
131+ return new ObjectReference ( alias ) ;
132+ }
133+ return operand ;
134+ }
135+
136+ private static bool AreEquivalentReferences ( FunctionReference reference1 , FunctionReference reference2 )
137+ {
138+ if ( reference1 . IsNull ( ) ) return reference2 . IsNull ( ) ;
139+ if ( reference2 . IsNull ( ) ) return false ;
140+ return reference1 . Name == reference2 . Name && reference1 . Argument == reference2 . Argument ;
141+ }
62142 }
63143
64- internal class OrderByClauseHandler
144+ internal class GenericEqualityComparer < T > : IEqualityComparer < T >
65145 {
66- private readonly OrderByClause _orderByClause ;
146+ private readonly Func < T , T , bool > _equals ;
147+ private readonly Func < T , int > _getHashCode ;
148+
149+ public GenericEqualityComparer ( Func < T , T , bool > @equals ) : this ( @equals , _ => 1 )
150+ {
151+ }
152+
153+ public GenericEqualityComparer ( Func < T , T , bool > @equals , Func < T , int > getHashCode )
154+ {
155+ _equals = @equals ;
156+ _getHashCode = getHashCode ;
157+ }
67158
68- public OrderByClauseHandler ( OrderByClause orderByClause )
159+ public bool Equals ( T x , T y )
69160 {
70- _orderByClause = orderByClause ;
161+ return _equals ( x , y ) ;
71162 }
72163
73- public IEnumerable < IDictionary < string , object > > Run ( IEnumerable < IDictionary < string , object > > source )
164+ public int GetHashCode ( T obj )
74165 {
75- return _orderByClause . Direction == OrderByDirection . Ascending
76- ? source . OrderBy ( d => d [ _orderByClause . Reference . GetName ( ) ] )
77- : source . OrderByDescending ( d => d [ _orderByClause . Reference . GetName ( ) ] ) ;
166+ return _getHashCode ( obj ) ;
78167 }
79168 }
80169}
0 commit comments