|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using ZeroLevel.Services.ObjectMapping;
|
|
|
|
|
using ZeroLevel.Services.Reflection;
|
|
|
|
|
using ZeroLevel.Specification;
|
|
|
|
|
|
|
|
|
|
namespace ZeroLevel.Patterns.Queries
|
|
|
|
|
{
|
|
|
|
|
internal sealed class MemoryQuery<T>
|
|
|
|
|
: IRealQuery<T, Func<T, bool>>
|
|
|
|
|
{
|
|
|
|
|
public MemoryQuery(Func<T, bool> predicate)
|
|
|
|
|
{
|
|
|
|
|
this.Query = predicate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Func<T, bool> Query { get; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal sealed class MemoryStorageQueryBuilder<T> :
|
|
|
|
|
IQueryBuilder<T, Func<T, bool>>
|
|
|
|
|
{
|
|
|
|
|
public IRealQuery<T, Func<T, bool>> Build(IQuery query)
|
|
|
|
|
{
|
|
|
|
|
var exp = ResolveQuery(query);
|
|
|
|
|
return new MemoryQuery<T>(exp.Compile());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Expression<Func<T, bool>> ResolveQuery(IQuery query)
|
|
|
|
|
{
|
|
|
|
|
if (query is AndQuery)
|
|
|
|
|
{
|
|
|
|
|
return ResolveQueryAnd(query as AndQuery);
|
|
|
|
|
}
|
|
|
|
|
else if (query is OrQuery)
|
|
|
|
|
{
|
|
|
|
|
return ResolveQueryOr(query as OrQuery);
|
|
|
|
|
}
|
|
|
|
|
else if (query is NotQuery)
|
|
|
|
|
{
|
|
|
|
|
return ResolveQueryNot(query as NotQuery);
|
|
|
|
|
}
|
|
|
|
|
return ResolveQueryOp(query as QueryOp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Expression<Func<T, bool>> ResolveQueryOp(QueryOp query)
|
|
|
|
|
{
|
|
|
|
|
if (query.Operation == QueryOperation.ALL)
|
|
|
|
|
{
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(Expression.Constant(true, typeof(bool)), new[] { Expression.Parameter(typeof(object)) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var mapper = TypeMapper.Create<T>(true);
|
|
|
|
|
var argument = Expression.Parameter(typeof(T));
|
|
|
|
|
Expression param;
|
|
|
|
|
if (mapper[query.FieldName].IsField)
|
|
|
|
|
{
|
|
|
|
|
param = Expression.Field(argument, query.FieldName);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
param = Expression.Property(argument, query.FieldName);
|
|
|
|
|
}
|
|
|
|
|
object value;
|
|
|
|
|
Expression constant;
|
|
|
|
|
if (query.Operation == QueryOperation.IN)
|
|
|
|
|
{
|
|
|
|
|
if (TypeHelpers.IsArray(mapper[query.FieldName].ClrType.GetElementType()) ||
|
|
|
|
|
TypeHelpers.IsEnumerable(mapper[query.FieldName].ClrType.GetElementType()))
|
|
|
|
|
{
|
|
|
|
|
value = Convert.ChangeType(query.Value, mapper[query.FieldName].ClrType.GetElementType());
|
|
|
|
|
constant = Expression.Constant(value, mapper[query.FieldName].ClrType.GetElementType());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
value = query.Value;
|
|
|
|
|
constant = Expression.Constant(value, mapper[query.FieldName].ClrType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
value = Convert.ChangeType(query.Value, mapper[query.FieldName].ClrType);
|
|
|
|
|
constant = Expression.Constant(value, mapper[query.FieldName].ClrType);
|
|
|
|
|
}
|
|
|
|
|
switch (query.Operation)
|
|
|
|
|
{
|
|
|
|
|
case QueryOperation.EQ:
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(Expression.Equal(param, constant),
|
|
|
|
|
new[] { argument });
|
|
|
|
|
case QueryOperation.GT:
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(param, constant),
|
|
|
|
|
new[] { argument });
|
|
|
|
|
case QueryOperation.GTE:
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(param, constant),
|
|
|
|
|
new[] { argument });
|
|
|
|
|
case QueryOperation.LT:
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(Expression.LessThan(param, constant),
|
|
|
|
|
new[] { argument });
|
|
|
|
|
case QueryOperation.LTE:
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(param, constant),
|
|
|
|
|
new[] { argument });
|
|
|
|
|
case QueryOperation.NEQ:
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(Expression.NotEqual(param, constant),
|
|
|
|
|
new[] { argument });
|
|
|
|
|
case QueryOperation.IN:
|
|
|
|
|
var overload = typeof(Enumerable).GetMethods()
|
|
|
|
|
.Single(mi => mi.Name.Equals("Contains", StringComparison.Ordinal) && mi.GetParameters().Count() == 2);
|
|
|
|
|
var call = Expression.Call(
|
|
|
|
|
overload.MakeGenericMethod(mapper[query.FieldName].ClrType.GetElementType()),
|
|
|
|
|
param, constant);
|
|
|
|
|
return Expression.Lambda<Func<T, bool>>(call, new[] { argument });
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Expression<Func<T, bool>> ResolveQueryAnd(AndQuery query)
|
|
|
|
|
{
|
|
|
|
|
var left = ResolveQuery(query.Left);
|
|
|
|
|
var right = ResolveQuery(query.Right);
|
|
|
|
|
return PredicateBuilder.And(left, right);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Expression<Func<T, bool>> ResolveQueryOr(OrQuery query)
|
|
|
|
|
{
|
|
|
|
|
var left = ResolveQuery(query.Left);
|
|
|
|
|
var right = ResolveQuery(query.Right);
|
|
|
|
|
return PredicateBuilder.Or(left, right);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Expression<Func<T, bool>> ResolveQueryNot(NotQuery query)
|
|
|
|
|
{
|
|
|
|
|
return PredicateBuilder.Not(ResolveQuery(query.Query));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|