Advertisement
Guest User

SqlLinq

a guest
Aug 2nd, 2013
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.39 KB | None | 0 0
  1.  class JoinResultSelector<TOuter, TInner>
  2.     {
  3.         private IJoinEntry _outer;
  4.         private IJoinEntry _inner;
  5.  
  6.         public JoinResultSelector(object outer, object inner)
  7.         {
  8.             Debug.Assert(outer != null);
  9.             Debug.Assert(inner != null);
  10.  
  11.             _outer = CreateEntry<TOuter>(outer);
  12.             _inner = CreateEntry<TInner>(inner);
  13.         }
  14.  
  15.         private static IJoinEntry CreateEntry<T>(object o)
  16.         {
  17.             if (o.GetType().IsDictionary())
  18.                 return new DictionaryJoinEntry(o, typeof(T));
  19.  
  20.             return new ObjectJoinEntry(o);
  21.         }
  22.  
  23.         public object this[string key]
  24.         {
  25.             get
  26.             {
  27.                 // if the key is prefixed we know whether to go for the inner or outer specifically
  28.                 if (key.StartsWith("this.", StringComparison.OrdinalIgnoreCase))
  29.                     return _outer[key.Substring(key.IndexOf(".") + 1)];
  30.  
  31.                 if (key.StartsWith("that.", StringComparison.OrdinalIgnoreCase))
  32.                     return _inner[key.Substring(key.IndexOf(".") + 1)];
  33.  
  34.                 // otherwise look at the outer object first and then the inner
  35.                 if (_outer.ContainsKey(key))
  36.                     return _outer[key];
  37.  
  38.                 if (_inner.ContainsKey(key))
  39.                     return _inner[key];
  40.  
  41.                 throw new IndexOutOfRangeException("An item with the specified key does not exist " + key);
  42.             }
  43.         }
  44.     }
  45.  
  46.     static class TypeExtensions
  47.     {
  48.         public static Type GetFieldType(this Type t, string field)
  49.         {
  50.             if (t.IsDictionary())
  51.                 return t.GetDictionaryValueType();
  52.  
  53.             if (t.Name.Contains("JoinResultSelector")) // special case for this internal type
  54.                 return typeof(object);
  55.  
  56.             if (t.HasPropertyOrField(field))
  57.                 return t.GetPropertyOrFieldType(field);
  58.  
  59.             return null;
  60.         }
  61. }
  62.  
  63.     public abstract class Join : NonTerminalNode
  64.     {
  65.         internal Func<IEnumerable<TOuter>, IEnumerable<TInner>, IEnumerable<JoinResultSelector<TOuter, TInner>>> CreateJoinFunction<TOuter, TInner>()
  66.         {
  67.             Type keyType = typeof(TOuter);
  68.             if (!OuterKey.Equals("this", StringComparison.OrdinalIgnoreCase))
  69.                 keyType = typeof(TOuter).GetFieldType(OuterKey);
  70.  
  71.             var outer = Expression.Parameter(typeof(TOuter), "outerKey");
  72.             var inner = Expression.Parameter(typeof(TInner), "innerKey");
  73.  
  74.             var outerKeySelector = CreateKeySelector<TOuter>(OuterKey, keyType, outer);
  75.             var innerKeySelector = CreateKeySelector<TInner>(InnerKey, keyType, inner);
  76.  
  77.             var _new = Expression.New(typeof(JoinResultSelector<TOuter, TInner>).GetConstructor(new Type[] { typeof(object), typeof(object) }), outer, inner);
  78.  
  79.             var resultSelector = Expression.Lambda(_new, outer, inner);
  80.  
  81.             var outerData = Expression.Parameter(typeof(IEnumerable<TOuter>), "outer");   // the outer input data
  82.             var innerData = Expression.Parameter(typeof(IEnumerable<TInner>), "inner");   // the inner input data
  83.  
  84.             var call = Expression.Call(typeof(Enumerable), "Join", new Type[] { typeof(TOuter), typeof(TInner), keyType, typeof(JoinResultSelector<TOuter, TInner>) }, outerData, innerData, outerKeySelector, innerKeySelector, resultSelector);
  85.  
  86.             return Expression.Lambda<Func<IEnumerable<TOuter>, IEnumerable<TInner>, IEnumerable<JoinResultSelector<TOuter, TInner>>>>(call, outerData, innerData).Compile();
  87.         }
  88. }
  89.  
  90.     public class JoinQuery<TSource, TInner, TResult> : QueryBase<TResult>
  91.     {
  92.         public JoinQuery(string sql)
  93.             : base(sql)
  94.         {
  95.         }
  96.  
  97.         private Func<IEnumerable<TSource>, IEnumerable<TInner>, IEnumerable<JoinResultSelector<TSource, TInner>>> _joinFunction;
  98.         private Filter<JoinResultSelector<TSource, TInner>> _joinFilters = new Filter<JoinResultSelector<TSource, TInner>>();
  99.         private Func<IEnumerable<JoinResultSelector<TSource, TInner>>, IEnumerable<TResult>> _resultSelector;
  100.  
  101.         protected override void OnCompile()
  102.         {
  103.             if (SyntaxNode.FromClause.Join == null)
  104.                 throw new SqlException("The query does not contain a JOIN expression\n" + Sql);
  105.  
  106.             _joinFunction = SyntaxNode.FromClause.Join.CreateJoinFunction<TSource, TInner>();
  107.  
  108.             if (SyntaxNode.GroupByClause != null)
  109.                 _resultSelector = SyntaxNode.GroupByClause.CreateGroupBySelector<JoinResultSelector<TSource, TInner>, TResult>(SyntaxNode.Columns.Aggregates);
  110.             else
  111.                 _resultSelector = SyntaxNode.Columns.CreateSelector<JoinResultSelector<TSource, TInner>, TResult>();
  112.  
  113.             if (SyntaxNode.WhereClause != null)
  114.                 _joinFilters.Add(list => list.Where(SyntaxNode.WhereClause.CreateEvaluator<JoinResultSelector<TSource, TInner>>()));
  115.  
  116.             if (SyntaxNode.OrderByClause != null)
  117.                 _joinFilters.Add(SyntaxNode.OrderByClause.CreateEvaluator<JoinResultSelector<TSource, TInner>>());
  118.  
  119.             if (SyntaxNode.HavingClause != null)
  120.                 ResultFilters.Add(list => list.Where(SyntaxNode.HavingClause.CreateEvaluator<TResult>()));
  121.  
  122.             if (SyntaxNode.Columns.Distinct)
  123.                 ResultFilters.Add(list => list.Distinct(CreateDistinctComparer()));
  124.         }
  125. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement