public static Expression CreateFilterExpression(Type type, InvocationQuerySyntaxNode node) { var visitor = new ExpressionFilterQuerySyntaxVisitor(type); var filterBody = visitor.Visit(node); return(Expression.Lambda(filterBody, visitor.Parameter)); }
// KnownFunctions private static Expression NotInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // not(condition) --> !condition var condition = visitor.Visit(node.Arguments[0]); return(Expression.Not(condition)); }
private static Expression LteInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // lte(property, value) --> i.property <= value var property = visitor.Visit(node.Arguments[0]); var value = visitor.Visit(node.Arguments[1]); return(QuerySyntaxHelper.Compare(property, value, Expression.LessThanOrEqual)); }
private static Expression GtInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // gt(property, value) --> i.property > value var property = visitor.Visit(node.Arguments[0]); var value = visitor.Visit(node.Arguments[1]); return(QuerySyntaxHelper.Compare(property, value, Expression.GreaterThan)); }
private static Expression InInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // in(property, value1, value2, value3, ...) --> Enumerable.Contains(new[] { value1, value2, value3, ... }, i.property) var property = visitor.Visit(node.Arguments[0]); var values = QuerySyntaxHelper.NewArray(property.Type, node.Arguments.Skip(1).Select(visitor.Visit)); return(QuerySyntaxHelper.InvokeContains(property.Type, values, property)); }
private static Expression DateInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // date('value') --> DateTime.Parse('value') var dateTimeString = node.Arguments[0].AsStringLiteral(); var dateTime = DateTime.Parse(dateTimeString); return(Expression.Constant(dateTime)); }
private static Expression CreateSizeFilterForArrayProperty(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node, Func <Expression, Expression, Expression> filter) { // filter(arrayProperty, value) --> filter(Enumerable.Count(i.arrayProperty), value) var arrayProperty = visitor.Visit(node.Arguments[0]); var value = visitor.Visit(node.Arguments[1]); var itemType = QuerySyntaxHelper.GetCollectionItemType(arrayProperty.Type); return(QuerySyntaxHelper.Compare(QuerySyntaxHelper.InvokeCount(itemType, arrayProperty), value, filter)); }
private static Expression MatchInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // match(arrayProperty, filter) --> Enumerable.Any(i.arrayProperty, ii => filter(ii)) var arrayProperty = visitor.Visit(node.Arguments[0]); var itemType = QuerySyntaxHelper.GetCollectionItemType(arrayProperty.Type); var itemFilter = CreateFilterExpression(itemType, (InvocationQuerySyntaxNode)node.Arguments[1]); return(QuerySyntaxHelper.InvokeAny(itemType, arrayProperty, itemFilter)); }
private static Expression RegexInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // regex(property, pattern, 'option1', 'option2', 'option3', ...) --> Regex.IsMatch(i.property, pattern, option1 | option2 | option3 | ...) var property = visitor.Visit(node.Arguments[0]); var pattern = visitor.Visit(node.Arguments[1]); var options = Expression.Constant(node.Arguments.Skip(2).Aggregate(RegexOptions.None, (r, n) => r | n.AsEnumIdentifier <RegexOptions>())); return(QuerySyntaxHelper.InvokeRegex(property, pattern, options)); }
private static Expression CreateAnyFilterForArrayProperty(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node, Func <Expression, Expression, Expression> filter) { // filter(arrayProperty, item) --> Enumerable.Any(i.arrayProperty, ii => filter(ii, item)) var arrayProperty = visitor.Visit(node.Arguments[0]); var item = visitor.Visit(node.Arguments[1]); var itemType = QuerySyntaxHelper.GetCollectionItemType(arrayProperty.Type); var itemParameter = Expression.Parameter(itemType); return(QuerySyntaxHelper.InvokeAny(itemType, arrayProperty, Expression.Lambda(QuerySyntaxHelper.Compare(itemParameter, item, filter), itemParameter))); }
private static Expression ExistsInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // exists(property, true) --> i.property != null // exists(property, false) --> i.property == null var property = visitor.Visit(node.Arguments[0]); var exists = (node.Arguments.Count < 2 || node.Arguments[1].AsBooleanLiteral()); var nullValue = Expression.Constant(null); return(exists ? Expression.NotEqual(property, nullValue) : Expression.Equal(property, nullValue)); }
// Helpers private static Expression CreateFilterForArrayProperty(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node, Func <Type, Expression, Expression, Expression> filter) { // filter(arrayProperty, item1, item2, item3, ...) --> filter(new[] { item1, item2, item3, ... }, ii => Enumerable.Contains(i.arrayProperty, ii)) var arrayProperty = visitor.Visit(node.Arguments[0]); var itemType = QuerySyntaxHelper.GetCollectionItemType(arrayProperty.Type); var items = QuerySyntaxHelper.NewArray(itemType, node.Arguments.Skip(1).Select(visitor.Visit)); var itemParameter = Expression.Parameter(itemType); var itemFilter = QuerySyntaxHelper.InvokeContains(itemType, arrayProperty, itemParameter); return(filter(itemType, items, Expression.Lambda(itemFilter, itemParameter))); }
private Expression <Func <TDocument, bool> > BuildFilter(IHttpRequest request, string documentIdKey) { var filterMethod = ParseFilter(request, documentIdKey); if (filterMethod != null) { return((Expression <Func <TDocument, bool> >)ExpressionFilterQuerySyntaxVisitor.CreateFilterExpression(typeof(TDocument), filterMethod)); } return(null); }
private static Expression AndInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // and(condition1, condition2, condition3, ...) --> (((condition1 && condition2) && condition3) && ...) Expression result = null; var conditions = node.Arguments.Select(visitor.Visit); foreach (var condition in conditions) { result = (result != null) ? Expression.AndAlso(result, condition) : condition; } return(result); }
private static Expression OrInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // or(condition1, condition2, condition3, ...) --> (((condition1 || condition2) || condition3) || ...) Expression result = null; var conditions = node.Arguments.Select(visitor.Visit); foreach (var condition in conditions) { result = (result != null) ? Expression.OrElse(result, condition) : condition; } return(result); }
private static Expression AnyNotEqInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // anyNotEq(arrayProperty, item) --> !Enumerable.Any(i.arrayProperty, ii => ii == item) return(Expression.Not(AnyEqInvocation(visitor, node))); }
private static Expression AnyInInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // anyIn(arrayProperty, item1, item2, item3, ...) --> Enumerable.Any(new[] { item1, item2, item3, ... }, ii => Enumerable.Contains(i.arrayProperty, ii)) return(CreateFilterForArrayProperty(visitor, node, QuerySyntaxHelper.InvokeAny)); }
private static Expression NotInInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // notIn(property, value1, value2, value3, ...) --> !Enumerable.Contains(new[] { value1, value2, value3, ... }, i.property) return(Expression.Not(InInvocation(visitor, node))); }
private static Expression AnyNotInInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // anyNotIn(arrayProperty, item1, item2, item3, ...) --> !Enumerable.Any(new[] { item1, item2, item3, ... }, ii => Enumerable.Contains(i.arrayProperty, ii)) return(Expression.Not(AnyInInvocation(visitor, node))); }
private static Expression AnyGtInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // anyGt(arrayProperty, item) --> Enumerable.Any(i.arrayProperty, ii => ii > item) return(CreateAnyFilterForArrayProperty(visitor, node, Expression.GreaterThan)); }
private static Expression AnyLteInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // anyLte(arrayProperty, item) --> Enumerable.Any(i.arrayProperty, ii => ii <= item) return(CreateAnyFilterForArrayProperty(visitor, node, Expression.LessThanOrEqual)); }
private static Expression SizeGtInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // sizeGt(arrayProperty, value) --> Enumerable.Count(i.arrayProperty) > value return(CreateSizeFilterForArrayProperty(visitor, node, Expression.GreaterThan)); }
private static Expression SizeLteInvocation(ExpressionFilterQuerySyntaxVisitor visitor, InvocationQuerySyntaxNode node) { // sizeLte(arrayProperty, value) --> Enumerable.Count(i.arrayProperty) <= value return(CreateSizeFilterForArrayProperty(visitor, node, Expression.LessThanOrEqual)); }