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)); }
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"); } }
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))); }
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"); } }
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)); } }
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"); } }