public Expression Build(Expression source)
 {
     return(ReplaceVisitor.Replace(
                this.unary,
                x => x == this.root,
                x => source));
 }
        private static LambdaExpression CreatePostSelectManyResultSelector(
            Type innerType,
            Type groupJoinResultType,
            LambdaExpression originalResultSelector)
        {
            ParameterExpression groupJoinResult =
                Expression.Parameter(groupJoinResultType, "group");
            ParameterExpression inner =
                Expression.Parameter(innerType, "inner");

            // JoinGroup<,>.Outer property
            PropertyInfo outerElement =
                groupJoinResultType.GetProperty(JoinGroupOuter);

            Expression expression = originalResultSelector.Body;

            // Change the first parameter
            expression = ReplaceVisitor.Replace(
                expression,
                e => e == originalResultSelector.Parameters[0],
                e => Expression.Property(groupJoinResult, outerElement));

            // Change the second parameter
            expression = ReplaceVisitor.Replace(
                expression,
                e => e == originalResultSelector.Parameters[1],
                e => inner);

            return(Expression.Lambda(expression, groupJoinResult, inner));
        }
예제 #3
0
        /// <summary>
        /// Reemplaza las referencias a las tablas de los join anteriores en un LATERAL subquery con RawSQL, devuelve el body reemplazado
        /// </summary>
        public static Expression ReplaceSubqueryLambda(LambdaExpression subquery, Expression leftParam, IEnumerable<ExprStrRawSql> replaceMembers)
        {
            var body = subquery.Body;
            var lateralParam = subquery.Parameters[0];

            //Reemplazar el parametro del lateral con el leftParam:
            var bodyLeft = ReplaceVisitor.Replace(body, lateralParam, leftParam);

            return ReplaceSubqueryBody(bodyLeft, replaceMembers);
        }
예제 #4
0
 /// <summary>
 /// Reemplaza las ocurrencias de replace members en el cuerpo de un subquery por llamadas al Sql.Raw
 /// </summary>
 /// <param name="body"></param>
 /// <param name="replaceMembers"></param>
 /// <returns></returns>
 public static Expression ReplaceSubqueryBody(Expression body, IEnumerable<ExprStrRawSql> replaceMembers)
 {
     //Sustituir con el replace members, con un RawSql
     Func<Expression, Expression> replaceRaw = (ex) =>
     {
         var sql = ReplaceStringAliasMembers(ex, replaceMembers);
         if (sql == null) return ex;
         var ret = RawSqlTableExpr(ex.Type, sql);
         return ret;
     };
     var bodyRaw = ReplaceVisitor.Replace(body, replaceRaw);
     return bodyRaw;
 }
예제 #5
0
        /// <summary>
        /// (min, max, val) => bool
        /// Crea una expresión que devuelve true si val se encuentra dentro del rango (inclusivo en min y max), se aceptan valores nulos para min y max.
        /// </summary>
        /// <typeparam name="T">Tipo que debe de soportar los operadores de comparasión</typeparam>
        public static Expression <Func <T?, T?, T?, bool> > Range <T>()
            where T : struct
        {
            Expression <Func <int?, int?, int?, bool> > expr = (min, max, v) =>
                                                               (min == null || (v >= min)) &&
                                                               (max == null || (v <= max));

            var subs = (Expression <Func <T?, T?, T?, bool> >)ReplaceVisitor.Replace(expr, new Dictionary <Expression, Expression>(), new Dictionary <Type, Type>
            {
                { typeof(int), typeof(T) }
            }, x => false);

            return(subs);
        }
        /// <summary>
        /// Correlates all of the elements of an outer sequence with any matching elements of an inner sequence, based on matching keys.
        /// </summary>
        /// <typeparam name="TOuter">The type of the elements of the outer sequence.</typeparam>
        /// <typeparam name="TInner">The type of the elements of the inner sequence.</typeparam>
        /// <typeparam name="TKey">The type of the keys returned by the key selector functions.</typeparam>
        /// <typeparam name="TResult">The type of the result elements.</typeparam>
        /// <param name="outer">The outer sequence to join.</param>
        /// <param name="inner">The inner sequence to join.</param>
        /// <param name="outerKeySelector">A function to extract the join key from each element of the outer sequence.</param>
        /// <param name="innerKeySelector">A function to extract the join key from each element of the inner sequence.</param>
        /// <param name="resultSelector">A function to create a result element from two matching elements.</param>
        /// <returns>An <see cref="T:System.Collections.Generic.IEnumerable`1" /> that has elements of type <typeparamref name="TResult" /> that are obtained by performing an outer join on the input sequences.</returns>
        /// <remarks><para>All elements of <paramref name="outer" /> will be selected, even if there is no matching element in <paramref name="inner" />; in that case, the value that is passed as the second parameter to <paramref name="resultSelector" /> will be the default value for <typeparamref name="TInner" />.</para></remarks>
        public static IQueryable <TResult> LeftJoin <TOuter, TInner, TKey, TResult>(this IQueryable <TOuter> outer, IEnumerable <TInner> inner, Expression <Func <TOuter, TKey> > outerKeySelector, Expression <Func <TInner, TKey> > innerKeySelector, Expression <Func <TOuter, TInner, TResult> > resultSelector)
        {
            if (outer == null)
            {
                throw new ArgumentNullException(nameof(outer));
            }
            if (inner == null)
            {
                throw new ArgumentNullException(nameof(inner));
            }
            if (outerKeySelector == null)
            {
                throw new ArgumentNullException(nameof(outerKeySelector));
            }
            if (innerKeySelector == null)
            {
                throw new ArgumentNullException(nameof(innerKeySelector));
            }
            if (resultSelector == null)
            {
                throw new ArgumentNullException(nameof(resultSelector));
            }
            // TODO: this
            var outerExample = new
            {
                o = default(TOuter),
                i = (IEnumerable <TInner>)null
            };
            var type       = outerExample.GetType();
            var expression = Expression.Parameter(type, "a");

            return(outer
                   .GroupJoin(inner, outerKeySelector, innerKeySelector, (o, i) => new { o, i })
                   .SelectMany(
                       x => x.i.DefaultIfEmpty(),
                       Lambda(
                           outerExample,
                           default(TInner),
                           default(TResult),
                           ReplaceVisitor.Replace(resultSelector.Body, resultSelector.Parameters[0], Expression.Property(expression, type.GetProperty("o"))),
                           new[] { expression, resultSelector.Parameters[1] }
                           )
                       ));
        }
예제 #7
0
        /// <summary>
        /// Remplaza todas las referencias a un elemento del WITH con un SqlTableRefRaw
        /// </summary>
        public static Expression SubqueryRawSubs(Expression subquery, ParameterExpression repParam)
        {
            if (subquery == null)
            {
                return(null);
            }

            //Sustituir todo param.X o param por el nombre:
            var ret = ReplaceVisitor.Replace(subquery, expr =>
            {
                if (typeof(IFromListItemTarget).GetTypeInfo().IsAssignableFrom(expr.Type.GetTypeInfo()))
                {
                    var selectInt = expr.Type.GetTypeInfo().ImplementedInterfaces.Concat(new[] { expr.Type }).Where(x => x.GetTypeInfo().IsGenericType&& x.GetGenericTypeDefinition() == typeof(IFromListItemTarget <>)).FirstOrDefault();
                    if (selectInt == null)
                    {
                        throw new ArgumentException("Debe de ser un IFromListItemTarget<T>");
                    }

                    var selectType = selectInt.GetTypeInfo().GenericTypeArguments[0];

                    if (expr is MemberExpression mem && CompareExpr.ExprEquals(mem.Expression, repParam))
                    {
                        return(RawSqlTableRefExpr(selectType, $"\"{mem.Member.Name}\""));
                    }
예제 #8
0
        /// <summary>
        /// Devuelve el resultado de aplicar una regla al niver superior de la expresión o la expresión original si la regla no se pudo aplicar a la expresión
        /// </summary>
        public static Expression GlobalApplyRule(Expression expr, RewriteRule rule, Func <Expression, Expression> visit)
        {
            if (rule.DebugName == "convertFromParam" || rule.DebugName == "fromParam")
            {
                ;
            }
            var          parameters = rule.Find.Parameters;
            var          pattBody   = rule.Find.Body;
            PartialMatch partialMatch;

            try
            {
                partialMatch = GlobalMatch(expr, parameters, pattBody);
            }
            catch (Exception ex)
            {
                throw new ApplyRuleException("Error al obtener el match", rule.DebugName, expr, ex);
            }
            var match = PartialMatch.ToFullMatch(partialMatch, parameters);

            if (match == null)
            {
                return(expr);
            }

            if (rule.Condition != null && !rule.Condition(match, expr))
            {
                return(expr);
            }

            //Sustituir la expresión:
            var ret           = expr;
            var replaceLambda = rule.Replace;

            if (replaceLambda != null)
            {
                var subDic = replaceLambda.Parameters
                             .Select((x, i) => (par: x, value: match.Args[i]))
                             .ToDictionary(x => (Expression)x.par, x => x.value)
                ;

                Expression repRet;
                try
                {
                    repRet = ReplaceVisitor.Replace(replaceLambda.Body, subDic, match.Types, x => false);
                }
                catch (Exception ex)
                {
                    throw new ApplyRuleException("Error al reemplazar", rule.DebugName, expr, ex);
                }

                ret = repRet;
            }

            //Aplicar los transforms:
            {
                Expression nextRet;

                try
                {
                    nextRet = ReplaceVisitor.Replace(ret, ex =>
                    {
                        if (ex is MethodCallExpression call && call.Method.DeclaringType == typeof(RewriteSpecial) && call.Method.Name == nameof(RewriteSpecial.Transform))
                        {
                            //Aplica el transform a la expresión:
                            var arg     = call.Arguments[0];
                            var func    = ExprEval.EvalExpr <Func <Expression, Expression> >(call.Arguments[1]);
                            var tResult = func.Value(arg);
                            return(tResult);
                        }
                        return(ex);
                    });
                }
예제 #9
0
        static IReadOnlyList<ExprAliasList> ExtractJoinAliasT(IFromListItem left, Expression leftParam, Expression rightParam, Expression onParam, Expression mapExprBody)
        {
            if (left == null)
            {
                return new[] { new ExprAliasList(new ExprRep[0], leftParam, onParam, null) };
            }

            var subRet = ExtractJoinAliasTree(left);
            var leftOnParam = subRet[0].CurrParam;

            var currAliases = mapExprBody == null ? new ExpressionAlias[0] : ExtractAliases(mapExprBody);
            var ret = new List<ExprAliasList>();

            //Si el left no tiene OnParam, debe de existir el lado izquierdo en el mapeo
            var existirLeft = leftOnParam == null;
            if (existirLeft && !currAliases.Any(x => x.Expr == leftParam))
            {
                throw new ArgumentException($"El argumento '{leftParam}' debe de existir en el mapeo del ON del JOIN '{mapExprBody}' ya que el lado izquierdo es un from list que no esta nombrado");
            }

            var mapAliases = currAliases.Select(x => new ExprRep(

                         find: Expression.Property(onParam, x.Alias),
                         rep: Expression.Property(onParam, x.Alias)
                     ))
                     .ToList();

            //Encontrar el alias del left:
            var rightAlias = currAliases.Where(x => x.Expr == rightParam).Select(x => new ExprRep(x.Expr, Expression.Property(onParam, x.Alias))).FirstOrDefault();
            if (rightAlias != null)
            {
                mapAliases.Add(rightAlias);
            }

            var currentExprAlias = new ExprAliasList(mapAliases, leftParam, onParam, null);
            ret.Add(currentExprAlias);

            var repList = currAliases.Select(x => new ExprRep(
                    find: leftOnParam == null ? x.Expr : ReplaceVisitor.Replace(x.Expr, leftParam, leftOnParam),
                    rep: Expression.Property(onParam, x.Alias)
                    ))
                    .ToList();

            //Sustituir todos los subRet:
            var subRetSubs = subRet.Select(list =>
            new ExprAliasList(
                items: list.Items.Select(item => new ExprRep(
                    item.Find,
                    ReplaceExprList(item.Rep, repList)

                    )).ToList(),
                leftParam: list.LeftParam,
                currParam: list.CurrParam,
                leftOn: null
                ))
                .ToList()
                ;
            ret.AddRange(subRetSubs);
            //Agregar el alias del lado izquierdo:
            var leftAlias = currAliases.Where(x => x.Expr == leftParam).Select(x => new ExprRep(x.Expr, Expression.Property(onParam, x.Alias))).FirstOrDefault();
            if (leftAlias != null)
            {
                var fromAlias = new ExprAliasList(new[] { leftAlias }, leftParam, onParam, null);
                ret.Add(fromAlias);
            }
            else
            {
                //Reemplazar el lado izquierdo de este JOIN con el ON del JOIN izquierdo
                leftAlias = new ExprRep(leftParam, leftOnParam);
                var mapAlRep = currAliases.Select(x => new ExprRep(x.Expr, ReplaceVisitor.Replace(x.Expr, leftParam, leftOnParam))).ToList();
                var fromAlias = new ExprAliasList(mapAlRep, leftParam, onParam, null);
                ret.Add(fromAlias);
            }

            return ret;
        }