Example #1
0
        internal virtual Expression <Func <T, bool> > ToWhereClause <T>(ParameterExpression parameterExpression)
        {
            // default implementation is to search all fields specified by the
            // DefaultSearchField option in SearchConfigurationOptions
            var entityConfig = Options.Entity <T>();

            if (entityConfig.DefaultSearchFields == null || !entityConfig.DefaultSearchFields.Any())
            {
                throw new InvalidOperationException($"There are no DefaultSearchFields specified for the enity of type { typeof(T).FullName }");
            }

            Expression expr = null;

            foreach (var searchField in entityConfig.DefaultSearchFields)
            {
                Expression currentExpression;
                var        oldParameter     = searchField.Parameters.First();
                var        convertParameter = new ParameterConversionVisitor(parameterExpression, oldParameter);
                var        newBody          = convertParameter.Visit(searchField.Body);
                if (searchField.ReturnType == typeof(string))
                {
                    // we'll use the null-coalescing operator so we don't get null refernces
                    var nullCoalesceExpression = Expression.Coalesce(newBody, Expression.Constant(string.Empty));

                    currentExpression = Expression.Call(nullCoalesceExpression,
                                                        typeof(string).GetMethod("Contains", new[] { typeof(string) }),
                                                        Expression.Constant(Text, typeof(string)));
                }
                else
                {
                    throw new InvalidOperationException("Currently only expressions of type string are supported");
                }

                if (expr == null)
                {
                    expr = currentExpression;
                }
                else
                {
                    // we combine the previous expression with the current in an OR clause
                    expr = Expression.Or(expr, currentExpression);
                }
            }

            return(Expression.Lambda <Func <T, bool> >(expr, parameterExpression));
        }
        private Expression <Func <T, bool> > GetParameterConstantExpression <T>(
            ParameterExpression parameterExpression,
            EntitySearchConfiguration <T> entityConfig)
        {
            // we'll need this later in a couple places:
            var toUpperMethod = typeof(string).GetMethod("ToUpper", Type.EmptyTypes);

            var searchField = entityConfig.GetTypeMapping(Left.Text);

            if (searchField == null)
            {
                throw new SearchParseException($"Unable to find a field with name { Left.Text }");
            }

            var oldParameter     = searchField.Parameters.First();
            var convertParameter = new ParameterConversionVisitor(parameterExpression, oldParameter);
            var leftExpression   = convertParameter.Visit(searchField.Body);

            // the right side is easy since it is a constant,
            // however we have to try to force it to the correct type
            var  leftType     = leftExpression.Type;
            bool isEnumerable = false;

            if (leftType.IsGenericType && typeof(IEnumerable <>).IsAssignableFrom(leftType.GetGenericTypeDefinition()))
            {
                isEnumerable = true;
                // if IEnumerable, get the underlying type
                leftType = leftType.GetGenericArguments().Single();
            }
            Expression rightExpression;

            if (leftType == typeof(string))
            {
                // special case for strings, we don't have to convert them
                // but we should uppercase them
                rightExpression = Expression.Call(
                    Expression.Constant(Right.Text),
                    toUpperMethod);
            }
            else
            {
                // any other types we have to convert
                var typeConverter = System.ComponentModel.TypeDescriptor.GetConverter(leftType);
                var rightValue    = typeConverter.ConvertFromString(Right.Text);
                rightExpression = Expression.Constant(rightValue, leftType);
            }

            // now all that's left is the operator, which should be supplied by a base class
            Expression expr;

            // special case for IEnumerable types, we need to do an ANY
            if (isEnumerable)
            {
                var anyExpression = typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
                                    .Where(x => x.Name == "Any")
                                    .Single(mi => mi.GetParameters().Count() == 2)
                                    .MakeGenericMethod(leftType);
                var newParam          = Expression.Parameter(leftType);
                var newLeftExpression = leftType == typeof(string) ? (Expression)Expression.Call(newParam, toUpperMethod) : newParam;

                var subExpression = CreateOperatorExpression <T>(newLeftExpression, rightExpression, parameterExpression);

                var func = Expression.Lambda(
                    subExpression,
                    newParam);

                expr = Expression.Call(
                    anyExpression,
                    leftExpression,
                    func);
            }
            else
            {
                // don't forget to uppercase string!
                if (leftType == typeof(string))
                {
                    leftExpression = Expression.Call(leftExpression, toUpperMethod);
                }
                expr = CreateOperatorExpression <T>(leftExpression, rightExpression, parameterExpression);
            }


            return(Expression.Lambda <Func <T, bool> >(expr, parameterExpression));
        }