Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class JoinResultSelector<TOuter, TInner>
- {
- private IJoinEntry _outer;
- private IJoinEntry _inner;
- public JoinResultSelector(object outer, object inner)
- {
- Debug.Assert(outer != null);
- Debug.Assert(inner != null);
- _outer = CreateEntry<TOuter>(outer);
- _inner = CreateEntry<TInner>(inner);
- }
- private static IJoinEntry CreateEntry<T>(object o)
- {
- if (o.GetType().IsDictionary())
- return new DictionaryJoinEntry(o, typeof(T));
- return new ObjectJoinEntry(o);
- }
- public object this[string key]
- {
- get
- {
- // if the key is prefixed we know whether to go for the inner or outer specifically
- if (key.StartsWith("this.", StringComparison.OrdinalIgnoreCase))
- return _outer[key.Substring(key.IndexOf(".") + 1)];
- if (key.StartsWith("that.", StringComparison.OrdinalIgnoreCase))
- return _inner[key.Substring(key.IndexOf(".") + 1)];
- // otherwise look at the outer object first and then the inner
- if (_outer.ContainsKey(key))
- return _outer[key];
- if (_inner.ContainsKey(key))
- return _inner[key];
- throw new IndexOutOfRangeException("An item with the specified key does not exist " + key);
- }
- }
- }
- static class TypeExtensions
- {
- public static Type GetFieldType(this Type t, string field)
- {
- if (t.IsDictionary())
- return t.GetDictionaryValueType();
- if (t.Name.Contains("JoinResultSelector")) // special case for this internal type
- return typeof(object);
- if (t.HasPropertyOrField(field))
- return t.GetPropertyOrFieldType(field);
- return null;
- }
- }
- public abstract class Join : NonTerminalNode
- {
- internal Func<IEnumerable<TOuter>, IEnumerable<TInner>, IEnumerable<JoinResultSelector<TOuter, TInner>>> CreateJoinFunction<TOuter, TInner>()
- {
- Type keyType = typeof(TOuter);
- if (!OuterKey.Equals("this", StringComparison.OrdinalIgnoreCase))
- keyType = typeof(TOuter).GetFieldType(OuterKey);
- var outer = Expression.Parameter(typeof(TOuter), "outerKey");
- var inner = Expression.Parameter(typeof(TInner), "innerKey");
- var outerKeySelector = CreateKeySelector<TOuter>(OuterKey, keyType, outer);
- var innerKeySelector = CreateKeySelector<TInner>(InnerKey, keyType, inner);
- var _new = Expression.New(typeof(JoinResultSelector<TOuter, TInner>).GetConstructor(new Type[] { typeof(object), typeof(object) }), outer, inner);
- var resultSelector = Expression.Lambda(_new, outer, inner);
- var outerData = Expression.Parameter(typeof(IEnumerable<TOuter>), "outer"); // the outer input data
- var innerData = Expression.Parameter(typeof(IEnumerable<TInner>), "inner"); // the inner input data
- var call = Expression.Call(typeof(Enumerable), "Join", new Type[] { typeof(TOuter), typeof(TInner), keyType, typeof(JoinResultSelector<TOuter, TInner>) }, outerData, innerData, outerKeySelector, innerKeySelector, resultSelector);
- return Expression.Lambda<Func<IEnumerable<TOuter>, IEnumerable<TInner>, IEnumerable<JoinResultSelector<TOuter, TInner>>>>(call, outerData, innerData).Compile();
- }
- }
- public class JoinQuery<TSource, TInner, TResult> : QueryBase<TResult>
- {
- public JoinQuery(string sql)
- : base(sql)
- {
- }
- private Func<IEnumerable<TSource>, IEnumerable<TInner>, IEnumerable<JoinResultSelector<TSource, TInner>>> _joinFunction;
- private Filter<JoinResultSelector<TSource, TInner>> _joinFilters = new Filter<JoinResultSelector<TSource, TInner>>();
- private Func<IEnumerable<JoinResultSelector<TSource, TInner>>, IEnumerable<TResult>> _resultSelector;
- protected override void OnCompile()
- {
- if (SyntaxNode.FromClause.Join == null)
- throw new SqlException("The query does not contain a JOIN expression\n" + Sql);
- _joinFunction = SyntaxNode.FromClause.Join.CreateJoinFunction<TSource, TInner>();
- if (SyntaxNode.GroupByClause != null)
- _resultSelector = SyntaxNode.GroupByClause.CreateGroupBySelector<JoinResultSelector<TSource, TInner>, TResult>(SyntaxNode.Columns.Aggregates);
- else
- _resultSelector = SyntaxNode.Columns.CreateSelector<JoinResultSelector<TSource, TInner>, TResult>();
- if (SyntaxNode.WhereClause != null)
- _joinFilters.Add(list => list.Where(SyntaxNode.WhereClause.CreateEvaluator<JoinResultSelector<TSource, TInner>>()));
- if (SyntaxNode.OrderByClause != null)
- _joinFilters.Add(SyntaxNode.OrderByClause.CreateEvaluator<JoinResultSelector<TSource, TInner>>());
- if (SyntaxNode.HavingClause != null)
- ResultFilters.Add(list => list.Where(SyntaxNode.HavingClause.CreateEvaluator<TResult>()));
- if (SyntaxNode.Columns.Distinct)
- ResultFilters.Add(list => list.Distinct(CreateDistinctComparer()));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement