Exemplo n.º 1
0
        /// <summary>
        /// The entry-point of <see cref="PageSelectVisitor"/>.
        /// </summary>
        public static IEnumerable <PropQueryParameters> Process <TSource, TResult>(
            Expression <Func <TSource, TResult> > expression, out Func <PageData, TResult> processedExpression)
        {
            var visitor = new PageSelectVisitor(expression.Parameters.Single());
            var body    = visitor.Visit(expression.Body);

            var gatherer = new UsedPropertiesGatherer();

            gatherer.Gather(body, visitor.m_pageDataGetInfoCall);

            var parameters = visitor.m_parameters;

            if (!gatherer.UsedDirectly && gatherer.UsedProperties.Any(p => !NonInfoProperties.Contains(p)))
            {
                var propQueryParameters = new PropQueryParameters("info").WithProperties(gatherer.UsedProperties);

                var tokens = gatherer.UsedProperties
                             .Where(p => p.EndsWith("token"))
                             .Select(p => p.Substring(0, p.Length - "token".Length))
                             .ToArray();

                if (tokens.Any())
                {
                    propQueryParameters = propQueryParameters.AddSingleValue("token", tokens.ToQueryString());
                }

                parameters["info"] = propQueryParameters;
            }

            processedExpression =
                Expression.Lambda <Func <PageData, TResult> >(body, visitor.m_pageDataParameter).Compile();

            return(parameters.Values);
        }
Exemplo n.º 2
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var methodName    = node.Method.Name;
            var declaringType = node.Method.DeclaringType;

            if (node.Object == m_pageParameter)
            {
                if (declaringType == typeof(object))
                {
                    throw new InvalidOperationException(
                              string.Format("The method '{0}' is not supported.", methodName));
                }

                return(Expression.Call(
                           m_pageDataParameter,
                           PageDataGetDataMethod.MakeGenericMethod(node.Method.ReturnType.GetGenericArguments().Last()),
                           Expression.Constant(methodName)));
            }

            // ToEnumerable, ToList or FirstOrDefault
            var toEnumerableOrToList = (declaringType.IsGenericType && declaringType.GetGenericTypeDefinition() == typeof(WikiQueryResult <,>));
            var first = declaringType == typeof(WikiQueryFirstExtension);

            if (toEnumerableOrToList || first)
            {
                var instance       = first ? node.Arguments.Single() : node.Object;
                var propExpression = ExpressionFinder.Single <MethodCallExpression>(
                    instance, e => e.Object == m_pageParameter && e.Method.DeclaringType == m_pageParameter.Type);

                var propName = propExpression.Method.Name;

                if (m_parameters.ContainsKey(propName))
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  "Each prop module can be use at most once in a single query, but you used the module '{0}' more than once.",
                                  propName));
                }

                var createQueryParametersMethod = typeof(QueryParameters).GetMethod("Create")
                                                  .MakeGenericMethod(propExpression.Type.GetGenericArguments().Last());

                var queryObject = Activator.CreateInstance(
                    propExpression.Type, new[] { null, createQueryParametersMethod.Invoke(null, null) });

                var withQueryObject = ExpressionReplacer.Replace(
                    instance, propExpression, Expression.Constant(queryObject));

                var processedQueryObject =
                    Expression.Lambda <Func <IWikiQueryResult> >(withQueryObject).Compile().Invoke();

                var parameter = new PropQueryParameters(propName);

                parameter.CopyFrom(processedQueryObject.Parameters);

                if (first)
                {
                    parameter = parameter.WithOnlyFirst();
                }

                m_parameters.Add(propName, parameter);

                m_canUsePage = true;

                var obj = Visit(instance);

                m_canUsePage = false;

                if (methodName == "ToEnumerable")
                {
                    return(obj);
                }

                if (first)
                {
                    methodName = "SingleOrDefault";
                }

                return(Expression.Call(
                           typeof(Enumerable), methodName, new[] { obj.Type.GetGenericArguments().Single() }, obj));
            }
            // one of the LINQ methods
            if (BaseTypes(declaringType).Contains(typeof(WikiQueryResult <,>)))
            {
                var obj = Visit(node.Object);

                if (methodName != "Select")
                {
                    return(obj);
                }

                var argument         = ((UnaryExpression)node.Arguments.Single()).Operand;
                var genericArguments = argument.Type.GetGenericArguments();

                return(Expression.Call(
                           typeof(Enumerable), methodName, new[] { genericArguments[0], genericArguments[1] }, obj, argument));
            }

            return(base.VisitMethodCall(node));
        }