private QueryOperator UpdateSelect(SelectOperator op, MonadMember src, QueryTree selector) { if (src != op.Source || selector != op.Selector) { return(MakeSelect(op, src, selector)); } return(op); }
/// <summary> /// Visits a <see cref="SelectOperator" /> and coalesces it with any possible child operators. /// </summary> /// <param name="op">The operator to visit.</param> /// <returns>The coalesced operator.</returns> protected internal override QueryOperator VisitSelect(SelectOperator op) { var source = VisitAndConvert <MonadMember>(op.Source); var selector = Visit(op.Selector); var srcOperator = source.QueryNodeType == QueryNodeType.Operator ? (QueryOperator)source : null; var srcSelect = srcOperator != null && srcOperator.NodeType == OperatorType.Select ? (SelectOperator)srcOperator : null; if (srcSelect != null && op.InputElementType == srcSelect.ElementType) { var p = Expression.Parameter(srcSelect.InputElementType); // Optimization when both lambda abstractions don't abstract over anything if (TryExtractNullaryLambdaBody(srcSelect.Selector, out Expression selector1) && TryExtractNullaryLambdaBody(selector, out Expression selector2)) { var reduced = BetaReducer.Reduce(Expression.Invoke(selector2, Expression.Invoke(selector1, p))); return(op.QueryExpressionFactory.Select( op.ElementType, srcSelect.InputElementType, srcSelect.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda( Expression.Lambda( reduced, p ) ), Array.Empty <QueryTree>() ) )); } var p1 = Expression.Parameter(typeof(Func <,>).MakeGenericType(srcSelect.InputElementType, srcSelect.ElementType)); var p2 = Expression.Parameter(typeof(Func <,>).MakeGenericType(op.InputElementType, op.ElementType)); return(op.QueryExpressionFactory.Select( op.ElementType, srcSelect.InputElementType, srcSelect.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda( Expression.Lambda( Expression.Invoke(p2, Expression.Invoke(p1, p)), p ), p1, p2 ), new[] { srcSelect.Selector, selector } ) )); } return(op.Update(source, selector)); }
/// <summary> /// Visits a <see cref="SelectOperator" /> node. /// </summary> /// <param name="op">Node to visit.</param> /// <returns>Result of visiting the node.</returns> protected internal override QueryOperator VisitSelect(SelectOperator op) { var src = VisitAndConvert <MonadMember>(op.Source); var selector = Visit(op.Selector); if (src != op.Source || selector != op.Selector) { return(MakeSelect(op, src, selector)); } return(op); }
/// <summary> /// Visits a <see cref="SelectOperator" /> node. /// </summary> /// <param name="op">Node to visit.</param> /// <returns>Result of visiting the node.</returns> protected internal override QueryOperator VisitSelect(SelectOperator op) { var elementType = VisitType(op.ElementType); var inputElementType = VisitType(op.InputElementType); var src = VisitAndConvert <MonadMember>(op.Source); var selector = Visit(op.Selector); if (src != op.Source || selector != op.Selector || elementType != op.ElementType || inputElementType != op.InputElementType) { return(MakeSelect(op, elementType, inputElementType, src, selector)); } return(op); }
/// <summary> /// Makes a <see cref="SelectOperator" /> with the given children. /// </summary> /// <param name="node">Original query expression.</param> /// <param name="source">Source query expression.</param> /// <param name="selector">Selector query expression.</param> /// <returns>Representation of the original query expression.</returns> protected sealed override QueryOperator MakeSelect(SelectOperator node, MonadMember source, QueryTree selector) { return(node.QueryExpressionFactory.Select(node.ElementType, node.InputElementType, source, selector)); }
/// <summary> /// Creates a textual representation of the SelectOperator with the given children. /// </summary> /// <param name="node">Original query expression.</param> /// <param name="source">Source query expression.</param> /// <param name="selector">Selector query expression.</param> /// <returns>Representation of the original query expression.</returns> protected override string MakeSelect(SelectOperator node, string source, string selector) { return(string.Format(CultureInfo.InvariantCulture, "@Select({0}, {1})", source, selector)); }
protected internal override QueryOperator VisitSelect(SelectOperator op) { var src = VisitAndConvert <MonadMember>(op.Source); var selector = Visit(op.Selector); if (TryCast <SelectOperator>(src, OperatorType.Select, out SelectOperator select1) && TryExtractNullaryLambdaBody <LambdaExpression>(select1.Selector, ExpressionType.Lambda, out LambdaExpression selector1) && TryGetNewAnonymousType(selector1.Body, out NewExpression anonCtor1) && TryExtractNullaryLambdaBody <LambdaExpression>(selector, ExpressionType.Lambda, out LambdaExpression selector2)) { if (TryGetNewAnonymousType(selector2.Body, out NewExpression anonCtor2)) { if (anonCtor2.Members.Count > 0 && anonCtor2.Arguments[0] == selector2.Parameters[0]) { var newArgs = new Expression[anonCtor2.Members.Count]; newArgs[0] = anonCtor1; for (var i = 1; i < newArgs.Length; i++) { var visitor = new ValidateMemberAccessesAndInlineVisitor(anonCtor1, selector1.Parameters[0], selector2.Parameters[0]); newArgs[i] = visitor.Visit(anonCtor2.Arguments[i]); if (!visitor.Valid) { return(UpdateSelect(op, src, selector)); } } var updated = anonCtor2.Update(newArgs); var newBody = DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda(Expression.Lambda(updated, selector1.Parameters[0])), Array.Empty <QueryTree>() ); return (op.QueryExpressionFactory.Select( op.ElementType, select1.InputElementType, select1.Source, newBody )); } } else { var flatteningValidationVisitor = new ValidateMemberAccessVisitor(anonCtor1, selector2.Parameters[0]); flatteningValidationVisitor.Visit(selector2.Body); if (flatteningValidationVisitor.Valid) { var flattener = new AnonymousTypeFlattener(anonCtor1); if (flattener.TryConstruct(out NewExpression c)) { var t = c.Type; var newParam = Expression.Parameter(t); var flatteningVisitor = new InlineFlattenedTypeVisitor(anonCtor1, newParam, selector2.Parameters[0], flattener); var f = flatteningVisitor.Visit(selector2.Body); var child = select1.QueryExpressionFactory.Select( t, select1.InputElementType, select1.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda(Expression.Lambda(c, selector1.Parameters[0])), Array.Empty <QueryTree>() ) ); return (op.QueryExpressionFactory.Select( op.ElementType, t, child, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda(Expression.Lambda(f, newParam)), Array.Empty <QueryTree>() ) )); } } } } return(UpdateSelect(op, src, selector)); }
/// <summary> /// Makes a <see cref="SelectOperator" /> with the given children. /// </summary> /// <param name="node">Original query expression.</param> /// <param name="source">Source query expression.</param> /// <param name="elementType">Element type for the resulting operator.</param> /// <param name="inputElementType">Input element type for the resulting operator.</param> /// <param name="selector">Selector query expression.</param> /// <returns>Representation of the original query expression.</returns> protected virtual QueryOperator MakeSelect(SelectOperator node, Type elementType, Type inputElementType, MonadMember source, QueryTree selector) { return(node.QueryExpressionFactory.Select(elementType, inputElementType, source, selector)); }