Permalink
Browse files

Refactoring to make grouping easier

  • Loading branch information...
Harry McIntyre Harry McIntyre
Harry McIntyre authored and Harry McIntyre committed Nov 24, 2016
1 parent 3e23768 commit a84b36dfaa4f39b8c739c423ba0c12342645347c
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqToAnything.Tests
{
public static class AutoIndexExtension
{
public static IQueryable<T> AutoIndex<T>(this IQueryable<T> items)
{
var getters = typeof(T).GetProperties()
.Select(p => new {p.Name, func = new Func<T, object>(t => p.GetValue(t))})
.ToDictionary(pair => pair.Name, pair => pair.func);
var lookups = new Dictionary<string, ILookup<object, T>>();
return new DelegateQueryable<T>(qi =>
{
Func<IEnumerable<Where>> whereClauses =
() => qi.Clauses.OfType<Where>().Where(c => c.Operator == "Equal");
IQueryable<T> filteredItems = items;
for (var whereClause = whereClauses().FirstOrDefault();
whereClause != null;
whereClause = whereClauses().FirstOrDefault())
{
ILookup<object, T> lookup;
if (!lookups.TryGetValue(whereClause.PropertyName, out lookup))
{
lookup = filteredItems.ToLookup(d => (object) getters[whereClause.PropertyName].Invoke(d),
d => d);
lookups[whereClause.PropertyName] = lookup;
}
filteredItems = lookup[whereClause.Value].AsQueryable();
qi.Clauses = qi.Clauses.Except(new[] {whereClause}).ToArray();
}
return qi.ApplyTo(filteredItems);
});
}
}
}
@@ -36,6 +36,7 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Compile Include="AutoIndexExtension.cs" />
<Compile Include="IndexExtensionTests.cs" />
<Compile Include="Tests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -9,6 +9,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqToAnything.Tests", "Lin
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LinqToAnything", "LinqToAnything\LinqToAnything.xproj", "{0944BE53-451C-403A-A1DE-4696EA831166}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F26FA645-A6E9-486D-B3D7-48D0E9385BBA}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
View
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Linq;
namespace LinqToAnything
{
public class Count : ResultType
{
public override ResultType Clone()
{
return new Count();
}
}
}
@@ -6,51 +6,47 @@
namespace LinqToAnything
{
public class DelegateQueryable<T> : IOrderedQueryable<T>
public static class DelegateQueryable
{
QueryProvider<T> provider;
Expression expression;
public DelegateQueryable(Func<QueryInfo, IEnumerable<T>> dataQuery, Func<QueryInfo, int> countQuery = null)
public static IQueryable<TRes> Create<TRes>(Func<QueryInfo, object> dataQuery)
{
this.provider = new QueryProvider<T>(dataQuery, countQuery ?? (qi => dataQuery(qi).Count()));
this.expression = Expression.Constant(this);
return new DelegateQueryable<TRes>(dataQuery);
}
internal DelegateQueryable(Func<QueryInfo, IEnumerable<T>> dataQuery, Func<QueryInfo, int> countQuery, Expression expression, QueryVisitor ev)
public static IQueryable<TRes> Create<TRes>(Func<QueryInfo, IEnumerable<TRes>> dataQuery, Func<QueryInfo, int> countQuery = null)
{
this.provider = new QueryProvider<T>(dataQuery, countQuery, ev);
this.expression = expression ?? Expression.Constant(this);
return new DelegateQueryable<TRes>(qi =>
{
return dataQuery(qi);
});
}
}
public class DelegateQueryable<T> : IOrderedQueryable<T>
{
readonly QueryProvider<T> _provider;
readonly Expression _expression;
Expression IQueryable.Expression
{
get { return this.expression; }
}
Type IQueryable.ElementType
public DelegateQueryable(Func<QueryInfo, object> dataQuery)
{
get { return typeof(T); }
this._provider = new QueryProvider<T>(dataQuery);
this._expression = Expression.Constant(this);
}
IQueryProvider IQueryable.Provider
internal DelegateQueryable(Func<QueryInfo, object> dataQuery, Expression expression, QueryVisitor ev)
{
get { return this.provider; }
this._provider = new QueryProvider<T>(dataQuery, ev);
this._expression = expression ?? Expression.Constant(this);
}
public IEnumerator<T> GetEnumerator()
{
return this.provider.GetEnumerable<T>().GetEnumerator();
}
Expression IQueryable.Expression => this._expression;
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
Type IQueryable.ElementType => typeof(T);
IQueryProvider IQueryable.Provider => this._provider;
public IEnumerator<T> GetEnumerator() => this._provider.GetEnumerable<T>().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
@@ -0,0 +1,24 @@
using System.Collections.Generic;
namespace LinqToAnything
{
public class GroupByClause : Clause
{
public override IEnumerable<string> PropertyNames { get; }
public GroupByClause(params string[] propertyNames) : this((IEnumerable<string>)propertyNames)
{
}
public GroupByClause(IEnumerable<string> propertyNames)
{
PropertyNames = propertyNames;
}
public override Clause Clone()
{
return new GroupByClause(PropertyNames);
}
}
}
@@ -40,11 +40,14 @@ public QueryInfo Clone()
{
Take = this.Take,
Skip = this.Skip,
OrderBy = this.OrderBy == null ? null : this.OrderBy.Clone(),
Clauses = this.Clauses.Select(c => c.Clone()).ToList()
OrderBy = this.OrderBy?.Clone(),
Clauses = this.Clauses.Select(c => c.Clone()).ToList(),
ResultType = this.ResultType?.Clone()
};
}
public ResultType ResultType { get; set; }
public IQueryable<T> ApplyTo<T>(IQueryable<T> q)
{
var qi = this;
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
@@ -8,15 +9,13 @@ namespace LinqToAnything
{
public class QueryProvider<T> : IQueryProvider
{
private readonly Func<QueryInfo, IEnumerable<T>> _dataQuery;
private readonly Func<QueryInfo, int> countQuery;
private QueryVisitor _queryVisitor;
private readonly Func<QueryInfo, object> _dataQuery;
private readonly QueryVisitor _queryVisitor;
public QueryProvider(Func<QueryInfo, IEnumerable<T>> dataQuery, Func<QueryInfo, int> countQuery, QueryVisitor queryVisitor = null)
public QueryProvider(Func<QueryInfo, object> dataQuery, QueryVisitor queryVisitor = null)
{
_dataQuery = dataQuery;
this.countQuery = countQuery;
this._queryVisitor = queryVisitor ?? new QueryVisitor();
}
@@ -31,10 +30,10 @@ public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
queryVisitor.Visit(expression);
if (typeof(TElement) != typeof(T))
{
Func<QueryInfo, IEnumerable<TElement>> q = info => _dataQuery(info).Select(queryVisitor.Transform<T, TElement>());
return new DelegateQueryable<TElement>(q, countQuery, null, queryVisitor);
Func<QueryInfo, object> q = info => ((IEnumerable)_dataQuery(info)).Cast<T>().Select(queryVisitor.Transform<T, TElement>());
return new DelegateQueryable<TElement>(q, null, queryVisitor);
}
return new DelegateQueryable<TElement>((Func<QueryInfo, IEnumerable<TElement>>)((object)_dataQuery), countQuery, expression, queryVisitor);
return new DelegateQueryable<TElement>(_dataQuery, expression, queryVisitor);
}
@@ -43,11 +42,6 @@ public IEnumerable<TResult> GetEnumerable<TResult>()
{
var queryVisitor = new QueryVisitor(_queryVisitor.QueryInfo.Clone());
var results = _dataQuery(queryVisitor.QueryInfo);
//if (countQuery.Select != null)
//{
// var projectionFunc = (Func<T, TResult>)countQuery.Select.Lambda.Compile();
// return results.Select(projectionFunc);
//}
return (IEnumerable<TResult>) results;
}
@@ -62,56 +56,70 @@ public TResult Execute<TResult>(Expression expression)
var queryVisitor = new QueryVisitor(_queryVisitor.QueryInfo.Clone());
queryVisitor.Visit(expression);
if (methodCallExpression.Method.Name == "Count" && typeof(TResult) == typeof(int))
var dataQueryResult = _dataQuery(queryVisitor.QueryInfo);
if (methodCallExpression.Method.Name == "Count")
{
return (TResult) (object) countQuery(queryVisitor.QueryInfo);
if (dataQueryResult is IEnumerable)
{
return (TResult)(object)((IEnumerable<object>)dataQueryResult).Count();
}else if (dataQueryResult is TResult)
{
return (TResult) dataQueryResult;
}
}
if (methodCallExpression.Method.Name == "Single")
{
var array = _dataQuery(queryVisitor.QueryInfo).ToList();
return (TResult)(object)((IEnumerable<object>)dataQueryResult).Single();
}
var array = ((IEnumerable)dataQueryResult).Cast<IEnumerable<object>>().ToList();
var data = array.AsQueryable();
var newExp = Expression.Call(methodCallExpression.Method, Expression.Constant(data));
return data.Provider.Execute<TResult>(newExp);
}
}
public class SwitchoutArgumentVisitor : ExpressionVisitor
{
private readonly object arg;
public SwitchoutArgumentVisitor(object arg)
{
this.arg = arg;
}
protected override Expression VisitConstant(ConstantExpression node)
{
return Expression.Constant(arg);
}
}
internal class SwitchoutVisitor<T> : ExpressionVisitor
{
private readonly object data;
public SwitchoutVisitor(object data)
{
this.data = data;
}
public override Expression Visit(Expression node)
{
return base.Visit(node);
}
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value != null && node.Value is T)
{
return Expression.Constant(data);
}
return base.VisitConstant(node);
}
}
//public class SwitchoutArgumentVisitor : ExpressionVisitor
//{
// private readonly object arg;
// public SwitchoutArgumentVisitor(object arg)
// {
// this.arg = arg;
// }
// protected override Expression VisitConstant(ConstantExpression node)
// {
// return Expression.Constant(arg);
// }
//}
//internal class SwitchoutVisitor<T> : ExpressionVisitor
//{
// private readonly object data;
// public SwitchoutVisitor(object data)
// {
// this.data = data;
// }
// public override Expression Visit(Expression node)
// {
// return base.Visit(node);
// }
// protected override Expression VisitConstant(ConstantExpression node)
// {
// if (node.Value != null && node.Value is T)
// {
// return Expression.Constant(data);
// }
// return base.VisitConstant(node);
// }
//}
}
@@ -82,8 +82,14 @@ protected override Expression VisitMethodCall(MethodCallExpression m)
whereClauseVisitor.Visit(whereClause);
QueryInfo.Clauses = QueryInfo.Clauses.Concat((whereClauseVisitor.Filters)).ToArray();
}
else if (m.Method.Name.Equals("Single")) { }
else if (m.Method.Name.Equals("Count")) { }
else if (m.Method.Name.Equals("Single"))
{
QueryInfo.ResultType = new Single();
}
else if (m.Method.Name.Equals("Count"))
{
QueryInfo.ResultType = new Count();
}
else
{
throw new NotImplementedException($"Operator {m.Method.Name} not supported. Please update the project at https://github.com/mcintyre321/LinqToAnything/blob/master/LinqToAnything/QueryVisitor.cs");
Oops, something went wrong.

0 comments on commit a84b36d

Please sign in to comment.