Beispiel #1
0
        private FilterQueryContext GetQueryContexts(FilterQuery query, string parameterName)
        {
            var queryContext = new FilterQueryContext(query);
            var customQuery  = _requestResourceDefinition?.GetCustomQueryFilter(query.Target);

            if (customQuery != null)
            {
                queryContext.IsCustom    = true;
                queryContext.CustomQuery = customQuery;
                return(queryContext);
            }

            queryContext.Relationship = GetRelationship(parameterName, query.Relationship);
            var attribute = GetAttribute(parameterName, query.Attribute, queryContext.Relationship);

            if (queryContext.Relationship is HasManyAttribute)
            {
                throw new InvalidQueryStringParameterException(parameterName,
                                                               "Filtering on one-to-many and many-to-many relationships is currently not supported.",
                                                               $"Filtering on the relationship '{queryContext.Relationship.PublicRelationshipName}.{attribute.PublicAttributeName}' is currently not supported.");
            }

            if (!attribute.Capabilities.HasFlag(AttrCapabilities.AllowFilter))
            {
                throw new InvalidQueryStringParameterException(parameterName, "Filtering on the requested attribute is not allowed.",
                                                               $"Filtering on attribute '{attribute.PublicAttributeName}' is not allowed.");
            }

            queryContext.Attribute = attribute;

            return(queryContext);
        }
Beispiel #2
0
        private FilterQueryContext GetQueryContexts(FilterQuery query, string parameterName)
        {
            var queryContext = new FilterQueryContext(query);
            var customQuery  = _requestResourceDefinition?.GetCustomQueryFilter(query.Target);

            if (customQuery != null)
            {
                queryContext.IsCustom    = true;
                queryContext.CustomQuery = customQuery;
                return(queryContext);
            }

            queryContext.Relationship = GetRelationship(parameterName, query.Relationship);
            var attribute = GetAttribute(parameterName, query.Attribute, queryContext.Relationship);

            if (!attribute.IsFilterable)
            {
                throw new InvalidQueryStringParameterException(parameterName, "Filtering on the requested attribute is not allowed.",
                                                               $"Filtering on attribute '{attribute.PublicAttributeName}' is not allowed.");
            }

            queryContext.Attribute = attribute;

            return(queryContext);
        }
        private FilterQueryContext GetQueryContexts(FilterQuery query)
        {
            var queryContext = new FilterQueryContext(query);

            if (_requestResourceDefinition != null)
            {
                var customQuery = _requestResourceDefinition.GetCustomQueryFilter(query.Target);
                if (customQuery != null)
                {
                    queryContext.IsCustom    = true;
                    queryContext.CustomQuery = customQuery;
                    return(queryContext);
                }
            }

            queryContext.Relationship = GetRelationship(query.Relationship);
            var attribute = GetAttribute(query.Attribute, queryContext.Relationship);

            if (attribute.IsFilterable == false)
            {
                throw new JsonApiException(400, $"Filter is not allowed for attribute '{attribute.PublicAttributeName}'.");
            }
            queryContext.Attribute = attribute;

            return(queryContext);
        }
 /// <inheritdoc />
 public virtual IQueryable <TResource> Filter(IQueryable <TResource> entities, FilterQueryContext filterQueryContext)
 {
     if (filterQueryContext.IsCustom)
     {
         var query = (Func <IQueryable <TResource>, FilterQuery, IQueryable <TResource> >)filterQueryContext.CustomQuery;
         return(query(entities, filterQueryContext.Query));
     }
     return(entities.Filter(filterQueryContext));
 }
        public static IQueryable <TSource> Filter <TSource>(this IQueryable <TSource> source, FilterQueryContext filterQuery)
        {
            if (filterQuery == null)
            {
                return(source);
            }

            if (filterQuery.Operation == FilterOperation.@in || filterQuery.Operation == FilterOperation.nin)
            {
                return(CallGenericWhereContainsMethod(source, filterQuery));
            }

            return(CallGenericWhereMethod(source, filterQuery));
        }
        /// <summary>
        /// This calls a generic where method.. more explaining to follow
        ///
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        private static IQueryable <TSource> CallGenericWhereMethod <TSource>(IQueryable <TSource> source, FilterQueryContext filter)
        {
            var              op               = filter.Operation;
            var              concreteType     = typeof(TSource);
            PropertyInfo     relationProperty = null;
            PropertyInfo     property         = null;
            MemberExpression left;
            Expression       right;

            // {model}
            var parameter = Expression.Parameter(concreteType, "model");

            // Is relationship attribute
            if (filter.IsAttributeOfRelationship)
            {
                relationProperty = concreteType.GetProperty(filter.Relationship.InternalRelationshipName);
                if (relationProperty == null)
                {
                    throw new ArgumentException($"'{filter.Relationship.InternalRelationshipName}' is not a valid relationship of '{concreteType}'");
                }

                var relatedType = filter.Relationship.RightType;
                property = relatedType.GetProperty(filter.Attribute.PropertyInfo.Name);
                if (property == null)
                {
                    throw new ArgumentException($"'{filter.Attribute.PropertyInfo.Name}' is not a valid attribute of '{filter.Relationship.InternalRelationshipName}'");
                }

                var leftRelationship = Expression.PropertyOrField(parameter, filter.Relationship.InternalRelationshipName);
                // {model.Relationship}
                left = Expression.PropertyOrField(leftRelationship, property.Name);
            }
            // Is standalone attribute
            else
            {
                property = concreteType.GetProperty(filter.Attribute.PropertyInfo.Name);
                if (property == null)
                {
                    throw new ArgumentException($"'{filter.Attribute.PropertyInfo.Name}' is not a valid property of '{concreteType}'");
                }

                // {model.Id}
                left = Expression.PropertyOrField(parameter, property.Name);
            }

            try
            {
                if (op == FilterOperation.isnotnull || op == FilterOperation.isnull)
                {
                    right = Expression.Constant(null);
                }
                else
                {
                    // convert the incoming value to the target value type
                    // "1" -> 1
                    var convertedValue = TypeHelper.ConvertType(filter.Value, property.PropertyType);

                    right = CreateTupleAccessForConstantExpression(convertedValue, property.PropertyType);
                }

                var body   = GetFilterExpressionLambda(left, right, filter.Operation);
                var lambda = Expression.Lambda <Func <TSource, bool> >(body, parameter);

                return(source.Where(lambda));
            }
            catch (FormatException)
            {
                throw new JsonApiException(400, $"Could not cast {filter.Value} to {property.PropertyType.Name}");
            }
        }
        private static IQueryable <TSource> CallGenericWhereContainsMethod <TSource>(IQueryable <TSource> source, FilterQueryContext filter)
        {
            var concreteType = typeof(TSource);
            var property     = concreteType.GetProperty(filter.Attribute.PropertyInfo.Name);

            try
            {
                var propertyValues         = filter.Value.Split(QueryConstants.COMMA);
                ParameterExpression entity = Expression.Parameter(concreteType, "entity");
                MemberExpression    member;
                if (filter.IsAttributeOfRelationship)
                {
                    var relation = Expression.PropertyOrField(entity, filter.Relationship.InternalRelationshipName);
                    member = Expression.Property(relation, filter.Attribute.PropertyInfo.Name);
                }
                else
                {
                    member = Expression.Property(entity, filter.Attribute.PropertyInfo.Name);
                }

                var method = ContainsMethod.MakeGenericMethod(member.Type);
                var obj    = TypeHelper.ConvertListType(propertyValues, member.Type);

                if (filter.Operation == FilterOperation.@in)
                {
                    // Where(i => arr.Contains(i.column))
                    var contains = Expression.Call(method, new Expression[] { Expression.Constant(obj), member });
                    var lambda   = Expression.Lambda <Func <TSource, bool> >(contains, entity);

                    return(source.Where(lambda));
                }
                else
                {
                    // Where(i => !arr.Contains(i.column))
                    var notContains = Expression.Not(Expression.Call(method, new Expression[] { Expression.Constant(obj), member }));
                    var lambda      = Expression.Lambda <Func <TSource, bool> >(notContains, entity);

                    return(source.Where(lambda));
                }
            }
            catch (FormatException)
            {
                throw new JsonApiException(400, $"Could not cast {filter.Value} to {property.PropertyType.Name}");
            }
        }
Beispiel #8
0
        private static IQueryable <TSource> CallGenericWhereContainsMethod <TSource>(IQueryable <TSource> source, FilterQueryContext filter)
        {
            var concreteType = typeof(TSource);
            var property     = concreteType.GetProperty(filter.Attribute.PropertyInfo.Name);

            var propertyValues         = filter.Value.Split(QueryConstants.COMMA);
            ParameterExpression entity = Expression.Parameter(concreteType, "entity");
            MemberExpression    member;

            if (filter.IsAttributeOfRelationship)
            {
                var relation = Expression.PropertyOrField(entity, filter.Relationship.InternalRelationshipName);
                member = Expression.Property(relation, filter.Attribute.PropertyInfo.Name);
            }
            else
            {
                member = Expression.Property(entity, filter.Attribute.PropertyInfo.Name);
            }

            var method = ContainsMethod.MakeGenericMethod(member.Type);

            var list = TypeHelper.CreateListFor(member.Type);

            foreach (var value in propertyValues)
            {
                object targetType;
                try
                {
                    targetType = TypeHelper.ConvertType(value, member.Type);
                }
                catch (FormatException)
                {
                    throw new InvalidQueryStringParameterException("filter",
                                                                   "Mismatch between query string parameter value and resource attribute type.",
                                                                   $"Failed to convert '{value}' in set '{filter.Value}' to '{property.PropertyType.Name}' for filtering on '{filter.Query.Attribute}' attribute.");
                }

                list.Add(targetType);
            }

            if (filter.Operation == FilterOperation.@in)
            {
                // Where(i => arr.Contains(i.column))
                var contains = Expression.Call(method, new Expression[] { Expression.Constant(list), member });
                var lambda   = Expression.Lambda <Func <TSource, bool> >(contains, entity);

                return(source.Where(lambda));
            }
            else
            {
                // Where(i => !arr.Contains(i.column))
                var notContains = Expression.Not(Expression.Call(method, new Expression[] { Expression.Constant(list), member }));
                var lambda      = Expression.Lambda <Func <TSource, bool> >(notContains, entity);

                return(source.Where(lambda));
            }
        }
        /// <inheritdoc />
        public virtual IQueryable <TResource> Filter(IQueryable <TResource> entities, FilterQueryContext filterQueryContext)
        {
            _logger.LogTrace($"Entering {nameof(Filter)}({nameof(entities)}, {nameof(filterQueryContext)}).");

            if (filterQueryContext.IsCustom)
            {
                var query = (Func <IQueryable <TResource>, FilterQuery, IQueryable <TResource> >)filterQueryContext.CustomQuery;
                return(query(entities, filterQueryContext.Query));
            }
            return(entities.Filter(filterQueryContext));
        }
        /// <summary>
        /// This calls a generic where method.. more explaining to follow
        ///
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        private static IQueryable <TSource> CallGenericWhereMethod <TSource>(IQueryable <TSource> source, FilterQueryContext filter)
        {
            var              op           = filter.Operation;
            var              concreteType = typeof(TSource);
            PropertyInfo     property;
            MemberExpression left;

            // {model}
            var parameter = Expression.Parameter(concreteType, "model");

            // Is relationship attribute
            if (filter.IsAttributeOfRelationship)
            {
                var relationProperty = concreteType.GetProperty(filter.Relationship.PropertyInfo.Name);
                if (relationProperty == null)
                {
                    throw new ArgumentException($"'{filter.Relationship.PropertyInfo.Name}' is not a valid relationship of '{concreteType}'");
                }

                var relatedType = filter.Relationship.RightType;
                property = relatedType.GetProperty(filter.Attribute.PropertyInfo.Name);
                if (property == null)
                {
                    throw new ArgumentException($"'{filter.Attribute.PropertyInfo.Name}' is not a valid attribute of '{filter.Relationship.PropertyInfo.Name}'");
                }

                var leftRelationship = Expression.PropertyOrField(parameter, filter.Relationship.PropertyInfo.Name);
                // {model.Relationship}
                left = Expression.PropertyOrField(leftRelationship, property.Name);
            }
            // Is standalone attribute
            else
            {
                property = concreteType.GetProperty(filter.Attribute.PropertyInfo.Name);
                if (property == null)
                {
                    throw new ArgumentException($"'{filter.Attribute.PropertyInfo.Name}' is not a valid property of '{concreteType}'");
                }

                // {model.Id}
                left = Expression.PropertyOrField(parameter, property.Name);
            }

            Expression right;

            if (op == FilterOperation.isnotnull || op == FilterOperation.isnull)
            {
                right = Expression.Constant(null);
            }
            else
            {
                // convert the incoming value to the target value type
                // "1" -> 1
                object convertedValue;
                try
                {
                    convertedValue = TypeHelper.ConvertType(filter.Value, property.PropertyType);
                }
                catch (FormatException)
                {
                    throw new InvalidQueryStringParameterException("filter",
                                                                   "Mismatch between query string parameter value and resource attribute type.",
                                                                   $"Failed to convert '{filter.Value}' to '{property.PropertyType.Name}' for filtering on '{filter.Query.Attribute}' attribute.");
                }

                right = CreateTupleAccessForConstantExpression(convertedValue, property.PropertyType);
            }

            var body   = GetFilterExpressionLambda(left, right, filter.Operation);
            var lambda = Expression.Lambda <Func <TSource, bool> >(body, parameter);

            return(source.Where(lambda));
        }