Example #1
0
        protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
        {
            var nodeExpression = AliasedExpression.WrapIfNeeded(node.Expression, node.Member);
            var expression     = BookmarkAndVisit(nodeExpression).AddCast(node.Expression.Type);

            return(Expression.Bind(node.Member, expression));
        }
Example #2
0
        private Expression RewriteValueExtension(MethodCallExpression expression, MemberInfo alias)
        {
            if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SelectMethod)
            {
                var source           = expression.Arguments[0];
                var selectExpression = expression.Arguments[1];
                var lambda           = selectExpression.GetLambda();
                var instance         = Visit(AliasedExpression.WrapIfNeeded(source, alias));
                var select           = (LambdaExpression)Visit(lambda);

                return(Expression.Call(
                           Rewritten.Value.SelectMethod.MakeGenericMethod(select.ReturnType),
                           instance,
                           select));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SelectListMethod)
            {
                var source           = expression.Arguments[0];
                var selectExpression = expression.Arguments[1];
                var lambda           = selectExpression.GetLambda();
                var instance         = Visit(source);
                var select           = (LambdaExpression)Visit(lambda);
                var itemType         = select.ReturnType == typeof(JToken) ?
                                       select.ReturnType :
                                       GetEnumerableItemType(select.ReturnType);

                return(Expression.Call(
                           Rewritten.Value.SelectListMethod.MakeGenericMethod(itemType),
                           instance,
                           select));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SingleMethod)
            {
                var source   = expression.Arguments[0];
                var instance = Visit(AliasedExpression.WrapIfNeeded(source, alias));

                return(Expression.Call(
                           Rewritten.Value.SingleMethod.MakeGenericMethod(instance.Type),
                           instance));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SingleOrDefaultMethod)
            {
                var source   = expression.Arguments[0];
                var instance = Visit(AliasedExpression.WrapIfNeeded(source, alias));

                return(Expression.Call(
                           Rewritten.Value.SingleOrDefaultMethod.MakeGenericMethod(instance.Type),
                           instance));
            }
            else
            {
                throw new NotSupportedException($"{expression.Method.Name}() is not supported");
            }
        }
Example #3
0
        private Expression VisitUnary(UnaryExpression node, MemberInfo alias)
        {
            if (node.NodeType == ExpressionType.Convert)
            {
                var rewritten = Visit(AliasedExpression.WrapIfNeeded(node.Operand, alias));
                return(Expression.Convert(
                           rewritten.AddCast(node.Operand.Type),
                           node.Type));
            }

            return(node.Update(Visit(node.Operand)));
        }
Example #4
0
        private Expression RewriteListExtension(MethodCallExpression expression, MemberInfo alias)
        {
            if (expression.Method.GetGenericMethodDefinition() == QueryableListExtensions.SelectMethod)
            {
                var       source           = expression.Arguments[0];
                var       selectExpression = expression.Arguments[1];
                var       lambda           = selectExpression.GetLambda();
                var       instance         = Visit(AliasedExpression.WrapIfNeeded(source, alias));
                ISubquery subquery         = null;

                if (instance is AllPagesExpression allPages)
                {
                    // .AllPages() was called on the instance. The expression is just a marker for
                    // this, the actual instance is in `allPages.Instance`
                    instance = Visit(allPages.Method);

                    // Select the "id" fields for the subquery.
                    var parentSelection = syntax.FieldStack.Take(syntax.FieldStack.Count - 1);
                    AddIdSelection(parentSelection.Last());
                    parentIds = CreateSelectTokensExpression(
                        parentSelection.Select(x => x.Name).Concat(new[] { "id" }));

                    // Add a "first: 100" argument to the query field.
                    syntax.AddArgument("first", MaxPageSize);

                    // Add the required "pageInfo" field selections then select "nodes".
                    syntax.Head.Selections.Add(PageInfoSelection());

                    // Create the subquery
                    subquery = AddSubquery(allPages.Method, expression, instance.AddIndexer("pageInfo"));

                    // And continue the query as normal after selecting "nodes".
                    syntax.AddField("nodes");
                    instance = instance.AddIndexer("nodes");
                }

                var select          = (LambdaExpression)Visit(lambda);
                var rewrittenSelect = Expression.Call(
                    Rewritten.List.SelectMethod.MakeGenericMethod(select.ReturnType),
                    instance,
                    select);

                // If the expression was an .AllPages() call then return a SubqueryExpression with
                // the related SubQuery to the .ToList() or .ToDictionary() method that follows.
                return(subquery == null ?
                       (Expression)rewrittenSelect :
                       new SubqueryExpression(subquery, rewrittenSelect));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableListExtensions.ToDictionaryMethod)
            {
                var source      = expression.Arguments[0];
                var instance    = Visit(AliasedExpression.WrapIfNeeded(source, alias));
                var keySelect   = expression.Arguments[1].GetLambda();
                var valueSelect = expression.Arguments[2].GetLambda();
                var inputType   = GetEnumerableItemType(instance.Type);

                if (inputType == typeof(JToken))
                {
                    throw new NotImplementedException();
                }
                else
                {
                    return(Expression.Call(
                               LinqMethods.ToDictionaryMethod.MakeGenericMethod(
                                   inputType,
                                   keySelect.ReturnType,
                                   valueSelect.ReturnType),
                               instance,
                               keySelect,
                               valueSelect));
                }
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableListExtensions.ToListMethod)
            {
                var source     = expression.Arguments[0];
                var instance   = Visit(AliasedExpression.WrapIfNeeded(source, alias));
                var inputType  = GetEnumerableItemType(instance.Type);
                var resultType = GetQueryableListItemType(source.Type);

                if (instance is SubqueryExpression subquery)
                {
                    instance = subquery.MethodCall;

                    if (inputType == typeof(JToken))
                    {
                        instance = Expression.Call(
                            Rewritten.List.ToListMethod.MakeGenericMethod(resultType),
                            instance);
                    }

                    return(Expression.Call(
                               Rewritten.List.ToSubqueryListMethod.MakeGenericMethod(resultType),
                               instance,
                               CreateGetQueryContextExpression(),
                               Expression.Constant(subquery.Subquery)));
                }
                else
                {
                    if (inputType == typeof(JToken))
                    {
                        return(Expression.Call(
                                   Rewritten.List.ToListMethod.MakeGenericMethod(resultType),
                                   instance));
                    }
                    else
                    {
                        return(Expression.Call(
                                   LinqMethods.ToListMethod.MakeGenericMethod(resultType),
                                   instance));
                    }
                }
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableListExtensions.OfTypeMethod)
            {
                var source     = expression.Arguments[0];
                var instance   = Visit(source);
                var resultType = GetQueryableListItemType(source.Type);
                var fragment   = syntax.AddInlineFragment(expression.Method.GetGenericArguments()[0], true);

                return(Expression.Call(
                           Rewritten.List.OfTypeMethod,
                           instance,
                           Expression.Constant(fragment.TypeCondition.Name)));
            }
            else
            {
                throw new NotSupportedException($"{expression.Method.Name}() is not supported");
            }
        }
Example #5
0
        private Expression VisitMember(MemberExpression node, MemberInfo alias)
        {
            if (IsUnionMember(node.Member))
            {
                var source   = Visit(node.Expression);
                var fragment = syntax.AddInlineFragment(((PropertyInfo)node.Member).PropertyType, true);
                return(Expression.Call(
                           Rewritten.Value.OfTypeMethod,
                           source,
                           Expression.Constant(fragment.TypeCondition.Name)));
            }
            else if (IsQueryableValueMember(node.Member))
            {
                var  expression      = node.Expression;
                bool isSubqueryPager = false;

                if (expression is SubqueryPagerExpression subqueryPager)
                {
                    // This signals that a parent query has designated this method call as the
                    // paging method for a subquery. Mark it as such and get the real method call
                    // expression.
                    isSubqueryPager = true;
                    expression      = subqueryPager.MethodCall;
                }

                if (expression is ParameterExpression parameterExpression)
                {
                    var parameter       = (ParameterExpression)Visit(parameterExpression);
                    var parentSelection = GetSelectionSet(parameterExpression);
                    var field           = syntax.AddField(parentSelection, node.Member, alias);
                    return(Visit(parameterExpression).AddIndexer(field));
                }
                else
                {
                    var instance = Visit(AliasedExpression.WrapIfNeeded(expression, alias));

                    if (isSubqueryPager)
                    {
                        // This is the paging method for a subquery: add the required `pageInfo`
                        // field selections.
                        var pageInfo = PageInfoSelection();
                        syntax.Head.Selections.Add(pageInfo);

                        // And store an expression to read the `pageInfo` from the subquery.
                        var selections = syntax.FieldStack
                                         .Select(x => x.Name)
                                         .Concat(new[] { "pageInfo" });
                        this.pageInfo = CreateSelectTokenExpression(selections);
                    }

                    var field = syntax.AddField(node.Member);
                    return(instance.AddIndexer(field));
                }
            }
            else
            {
                var instance = Visit(AliasedExpression.WrapIfNeeded(node.Expression, alias));

                if (ExpressionWasRewritten(node.Expression, instance))
                {
                    instance = instance.AddCast(node.Expression.Type);
                }

                return(node.Update(instance));
            }
        }
Example #6
0
        private Expression RewriteValueExtension(MethodCallExpression expression, MemberInfo alias)
        {
            if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SelectMethod)
            {
                var source           = expression.Arguments[0];
                var selectExpression = expression.Arguments[1];
                var lambda           = selectExpression.GetLambda();
                var instance         = Visit(AliasedExpression.WrapIfNeeded(source, alias));
                var select           = (LambdaExpression)Visit(lambda);

                return(Expression.Call(
                           Rewritten.Value.SelectMethod.MakeGenericMethod(select.ReturnType),
                           instance,
                           select));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SelectFragmentMethod)
            {
                var source = expression.Arguments[0];

                IFragment fragment = null;

                if (expression.Arguments[1] is ConstantExpression constantExpression1)
                {
                    fragment = (IFragment)constantExpression1.Value;
                }
                else
                {
                    if (expression.Arguments[1] is MemberExpression memberExpression)
                    {
                        var memberExpressionMember = (FieldInfo)memberExpression.Member;
                        fragment = (IFragment)memberExpressionMember.GetValue(((ConstantExpression)memberExpression.Expression).Value);
                    }
                }

                if (fragment == null)
                {
                    throw new InvalidOperationException("Fragment instance cannot be found");
                }

                var instance = Visit(AliasedExpression.WrapIfNeeded(source, alias));
                var select   = VisitFragment(fragment);
                syntax.AddFragmentSpread(fragment.Name);

                return(Expression.Call(
                           Rewritten.Value.SelectFragmentMethod.MakeGenericMethod(fragment.ReturnType),
                           instance,
                           select));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SelectListMethod)
            {
                var source           = expression.Arguments[0];
                var selectExpression = expression.Arguments[1];
                var lambda           = selectExpression.GetLambda();
                var instance         = Visit(source);
                var select           = (LambdaExpression)Visit(lambda);
                var itemType         = select.ReturnType == typeof(JToken) ?
                                       select.ReturnType :
                                       GetEnumerableItemType(select.ReturnType);

                return(Expression.Call(
                           Rewritten.Value.SelectListMethod.MakeGenericMethod(itemType),
                           instance,
                           select));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SingleMethod)
            {
                var source   = expression.Arguments[0];
                var instance = Visit(AliasedExpression.WrapIfNeeded(source, alias));

                return(Expression.Call(
                           Rewritten.Value.SingleMethod.MakeGenericMethod(instance.Type),
                           instance));
            }
            else if (expression.Method.GetGenericMethodDefinition() == QueryableValueExtensions.SingleOrDefaultMethod)
            {
                var source   = expression.Arguments[0];
                var instance = Visit(AliasedExpression.WrapIfNeeded(source, alias));

                return(Expression.Call(
                           Rewritten.Value.SingleOrDefaultMethod.MakeGenericMethod(instance.Type),
                           instance));
            }
            else
            {
                throw new NotSupportedException($"{expression.Method.Name}() is not supported");
            }
        }