Example #1
0
        public override LambdaExpression VisitValPathExp(ScimFilterParser.ValPathExpContext context)
        {
            // brackets MAY change the field type (TResource) thus, the expression within the brackets
            // should be visited in context of the new field's type

            var argument           = Expression.Parameter(typeof(TResource));
            var attrPathExpression = Visit(context.attrPath());

            if (attrPathExpression.ReturnType != typeof(TResource))
            {
                Type childFilterType = attrPathExpression.ReturnType;
                bool isEnumerable    = childFilterType.IsNonStringEnumerable();

                if (isEnumerable)
                {
                    childFilterType = childFilterType.GetGenericArguments()[0]; // set childFilterType to enumerable type argument
                }

                var childVisitorType    = typeof(ScimFilterVisitor <>).MakeGenericType(childFilterType);
                var childVisitor        = (IScimFilterVisitor)childVisitorType.CreateInstance(ServerConfiguration);
                var childLambda         = childVisitor.VisitExpression(context.valPathFilter()); // Visit the nested filter expression.
                var childLambdaArgument = Expression.TryCatch(
                    Expression.Block(Expression.Invoke(attrPathExpression, argument)),
                    Expression.Catch(typeof(Exception),
                                     Expression.Constant(attrPathExpression.ReturnType.GetDefaultValue(), attrPathExpression.ReturnType))
                    );

                if (isEnumerable)
                {
                    // if we have an enumerable, then we need to see if any of its elements satisfy the childLambda
                    // to accomplish this, let's just make use of .NET's Any<TSource>(enumerable, predicate)

                    var anyMethod    = MethodCache["any"].MakeGenericMethod(childFilterType);
                    var anyPredicate = Expression.TryCatch(
                        Expression.Block(
                            Expression.Call(
                                anyMethod,
                                new List <Expression>
                    {
                        childLambdaArgument,
                        childLambda
                    })),
                        Expression.Catch(typeof(ArgumentNullException), Expression.Constant(false)));

                    return(Expression.Lambda(anyPredicate, argument));
                }

                return(Expression.Lambda(
                           Expression.Invoke(
                               childLambda,
                               Expression.Invoke(attrPathExpression, argument)),
                           argument));
            }

            // TODO: (DG) This is probably incorrect if the property is nested and the same type as its parent.
            // We'll most likely still need a childLambda.
            return(Visit(context.valPathFilter()));
        }
Example #2
0
        public override LambdaExpression VisitValPathExp(ScimFilterParser.ValPathExpContext context)
        {
            // brackets MAY change the field type (TResource) thus, the expression within the brackets
            // should be visited in context of the new field's type

            var propertyNameToken = context.FIELD().GetText();
            var property          = PropertyCache
                                    .GetOrAdd(
                typeof(TResource),
                type =>
                type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .ToDictionary(pi => pi.Name, pi => pi, StringComparer.OrdinalIgnoreCase))[propertyNameToken];

            if (property == null)
            {
                throw new Exception("ERROR");                   // TODO: (DG) make proper error
            }
            if (property.PropertyType != typeof(TResource))
            {
                bool isEnumerable    = property.PropertyType.IsNonStringEnumerable();
                Type childFilterType = property.PropertyType;
                if (isEnumerable)
                {
                    childFilterType = childFilterType.GetGenericArguments()[0]; // set childFilterType to enumerable type argument
                }

                var argument            = Expression.Parameter(typeof(TResource));
                var childVisitorType    = typeof(ScimFilterVisitor <>).MakeGenericType(childFilterType);
                var childVisitor        = (IScimFilterVisitor)childVisitorType.CreateInstance();
                var childLambda         = childVisitor.VisitExpression(context.valPathFilter()); // Visit the nested filter expression.
                var childLambdaArgument = Expression.TryCatch(
                    Expression.Block(Expression.Property(argument, property)),
                    Expression.Catch(typeof(Exception),
                                     Expression.Constant(property.PropertyType.GetDefaultValue(), property.PropertyType))
                    );

                if (isEnumerable)
                {
                    // if we have an enumerable, then we need to see if any of its elements satisfy the childLambda
                    // to accomplish this, let's just make use of .NET's Any<TSource>(enumerable, predicate)

                    var anyMethod    = MethodCache["any"].MakeGenericMethod(childFilterType);
                    var anyPredicate = Expression.TryCatch(
                        Expression.Block(
                            Expression.Call(
                                anyMethod,
                                new List <Expression>
                    {
                        childLambdaArgument,
                        childLambda
                    })),
                        Expression.Catch(typeof(ArgumentNullException), Expression.Constant(false)));

                    return(Expression.Lambda(anyPredicate, argument));
                }

                return(Expression.Lambda(
                           Expression.Invoke(
                               childLambda,
                               new List <Expression>
                {
                    Expression.TypeAs(childLambdaArgument, childFilterType)
                }),
                           argument));
            }

            // TODO: (DG) This is probably incorrect if the property is nested and the same type as its parent.
            // We'll most likely still need a childLambda.
            return(Visit(context.valPathFilter()));
        }