public void ToSqlRuleContainsifCond() { string[] nombres = null; Expression <Func <Cliente, bool> > selectBody = x => SqlExpr.IfCond.Invoke(nombres.Any(), nombres.Contains(x.Nombre)); var pars = new SqlExprParams(selectBody.Parameters[0], null, false, "cli", new SqlFromList.ExprStrRawSql[0], ParamMode.None, new SqlParamDic()); var visitor = new SqlRewriteVisitor(pars); { nombres = new[] { "rafa", "hola" }; var ret = visitor.Visit(selectBody); var rawBody = ((MethodCallExpression)((LambdaExpression)ret).Body).Arguments[0]; ExprEval.TryEvalExpr <string>(rawBody, out var rawStr); var expected = "(\"cli\".\"Nombre\" IN ('rafa', 'hola'))"; Assert.AreEqual(expected, rawStr); } { nombres = new string[0]; var ret = visitor.Visit(selectBody); var rawBody = ((MethodCallExpression)((LambdaExpression)ret).Body).Arguments[0]; ExprEval.TryEvalExpr <string>(rawBody, out var rawStr); var expected = "True"; Assert.AreEqual(expected, rawStr); } }
public void MultipleIfCond() { var filtro = new Uruz.FiltroFacturas { FechaInicio = new DateTime(2019, 01, 26) }; Expression <Func <Uruz.FacturaDTO, bool> > expr = x => SqlExpr.IfCond.Invoke(filtro.FechaInicio != null, x.FechaCreacion >= filtro.FechaInicio) && SqlExpr.IfCond.Invoke(filtro.FechaFinal != null, x.FechaCreacion <= filtro.FechaFinal) && SqlExpr.IfCond.Invoke(filtro.FechaPagoInicio != null, x.FechaPago >= filtro.FechaPagoInicio) && SqlExpr.IfCond.Invoke(filtro.FechaPagoFinal != null, x.FechaPago <= filtro.FechaPagoFinal) ; var pars = new SqlExprParams(expr.Parameters[0], null, false, "fac", new SqlFromList.ExprStrRawSql[0], ParamMode.EntityFramework, new SqlParamDic()); var visitor = new SqlRewriteVisitor(pars); var ret = visitor.Visit(expr); var apps = RewriteVisitor.applications; var expected = "x => Raw(\"(\"fac\".\"FechaCreacion\" >= @FechaInicio)\")"; var actual = ret.ToString(); Assert.AreEqual(expected, actual); }
/// <summary> /// Convierte la expresión de proyección de un SELECT a sql, devuelve si la proyección es escalar /// </summary> public static SelectExprToStrResult SelectBodyToStr(Expression body, SqlExprParams pars) { var visitor = new SqlRewriteVisitor(pars); body = visitor.Visit(body); IEnumerable <ValueCol> MemberAssigToSql(Expression expr, MemberInfo prop) { var exprSql = SqlExpression.ExprToSqlStar(expr, pars, false); if (exprSql.star) { return(new[] { new ValueCol(SqlExpression.SqlSubpath.Single(exprSql.sql), null) }); } var asList = exprSql.sql.Select(subpath => new ValueCol(subpath.Sql, MemberToColumnName(prop, subpath)) ); return(asList); } if (body is MemberInitExpression || body is NewExpression) { var exprs = ExtractInitExpr(body) .SelectMany(x => MemberAssigToSql(x.expr, x.mem)) .ToList() ; return(new SelectExprToStrResult(exprs, false)); } var bodySql = SqlExpression.ExprToSqlStar(body, pars, false); if (bodySql.sql.Count > 1) { throw new ArgumentException("Por ahora no esta permitido devolver un ComplexType como el resultado de un SELECT"); } return(new SelectExprToStrResult( new[] { new ValueCol(bodySql.sql.First().Sql, null) }, !bodySql.star)); }
public void ToSqlStringConcat() { Expression <Func <Uruz.Factura, string> > nombreFactura = x => x.Serie + "-" + x.Folio; Expression <Func <Uruz.Factura, string> > selectBody = x => nombreFactura.Invoke(x); var pars = new SqlExprParams(selectBody.Parameters[0], null, false, "cli", new SqlFromList.ExprStrRawSql[0], ParamMode.None, new SqlParamDic()); var visitor = new SqlRewriteVisitor(pars); var ret = visitor.Visit(selectBody); var rawBody = ((MethodCallExpression)((LambdaExpression)ret).Body).Arguments[0]; ExprEval.TryEvalExpr <string>(rawBody, out var rawStr); var expected = @"((""cli"".""Serie"" || '-') || ""cli"".""Folio"")"; Assert.AreEqual(expected, rawStr); }
/// <summary> /// Convierte a string la parte del VALUE de un INSERT /// </summary> static string InsertValueToString(InsertClause clause, ParamMode paramMode, SqlParamDic paramDic) { var b = new StringBuilder(); //Note que aquí el fromAlias no afecta ya se se usan directamente los nombres de las columnas //y no se puede referenciar a la tabla de origen en los VALUES var pars = new SqlExprParams(null, null, false, null, new SqlFromList.ExprStrRawSql[0], paramMode, paramDic); //Hacer el rewrite en todo el body: var visitor = new SqlRewriteVisitor(pars); var body = visitor.Visit(clause.Value); var exprs = SqlSelect .ExtractInitExpr(body) .Select(x => (x.mem, sql: SqlExpression.ExprToSqlStar(x.expr, pars, false))) ; if (exprs.Any(y => y.sql.star)) { throw new ArgumentException("No esta soportado una expresión star '*' en la asignación de los valores de un INSERT"); } var subpaths = exprs.SelectMany(x => x.sql.sql, (parent, child) => (member: parent.mem, subpath: child)); //Nombres de las columnas del INSERT var columns = subpaths .Select(x => SqlSelect.MemberToColumnName(x.member, x.subpath)) .Select(SqlSelect.ColNameToStr); ; //Valores: var values = subpaths.Select(x => x.subpath.Sql); //Texto de las columnas: b.Append("("); b.Append(string.Join(", ", columns)); b.AppendLine(")"); //Texto de los vaues: b.Append("VALUES ("); b.Append(string.Join(", ", values)); b.Append(")"); return(b.ToString()); }
public void ToSqlRuleContainsEmpty() { var nombres = new string[0]; Expression <Func <Cliente, bool> > selectBody = x => nombres.Contains(x.Nombre); var pars = new SqlExprParams(selectBody.Parameters[0], null, false, "cli", new SqlFromList.ExprStrRawSql[0], ParamMode.None, new SqlParamDic()); var visitor = new SqlRewriteVisitor(pars); { nombres = new string[0]; var ret = visitor.Visit(selectBody); var rawBody = ((MethodCallExpression)((LambdaExpression)ret).Body).Arguments[0]; ExprEval.TryEvalExpr <string>(rawBody, out var rawStr); var expected = "False"; Assert.AreEqual(expected, rawStr); } }
/// <summary> /// Convierte el cuerpo de la expresión SET a SQL /// </summary> public static string SetToSql(Expression body, ParamMode paramMode, SqlParamDic paramDic, IEnumerable <SqlFromList.ExprStrRawSql> exprAlias ) { var b = new StringBuilder(); var pars = new SqlExprParams(null, null, false, null, exprAlias.ToList(), paramMode, paramDic); //Hacer el rewrite en todo el body: var visitor = new SqlRewriteVisitor(pars); body = visitor.Visit(body); var exprs = SqlSelect .ExtractInitExpr(body) .Select(x => (x.mem, sql: SqlExpression.ExprToSqlStar(x.expr, pars, false))) ; if (exprs.Any(y => y.sql.star)) { throw new ArgumentException("No esta soportado una expresión star '*' en la asignación de los valores de un INSERT"); } var subpaths = exprs.SelectMany(x => x.sql.sql, (parent, child) => (member: parent.mem, subpath: child)); var sets = subpaths.Select(x => ( column: SqlSelect.MemberToColumnName(x.member, x.subpath), value: x.subpath.Sql)) ; var setSql = sets .Select(x => $"{SqlSelect.ColNameToStr(x.column)} = {x.value}" ); var sql = string.Join($", {Environment.NewLine}", setSql); return(sql); }
public void MultipleIfCond2() { var filtro = new Uruz.FiltroFacturas { IdCliente = 10, }; Expression <Func <Uruz.FacturaDTO, bool> > expr = x => SqlExpr.EqualsNullable.Invoke(x.IdCliente, filtro.IdCliente) && SqlExpr.EqualsNullable.Invoke(x.IdSucursal, filtro.IdSucursal) ; var pars = new SqlExprParams(expr.Parameters[0], null, false, "fac", new SqlFromList.ExprStrRawSql[0], ParamMode.EntityFramework, new SqlParamDic()); var visitor = new SqlRewriteVisitor(pars); var ret = visitor.Visit(expr); var apps = RewriteVisitor.applications; var expected = "x => Raw(\"(\"fac\".\"IdCliente\" = @IdCliente)\")"; var actual = ret.ToString(); Assert.AreEqual(expected, actual); }
/// <summary> /// Convierte una expresión a SQL /// </summary> public static (IReadOnlyList <SqlSubpath> sql, bool star) ExprToSqlStar(Expression expr, SqlExprParams pars, bool rewrite) { if (rewrite) { var visitor = new SqlRewriteVisitor(pars); expr = visitor.Visit(expr); } //Es importante primero comprobar la igualdad del parametro, ya que el replace list tiene una entrada para el parametro tambien if (IsFromParam(expr)) { if (pars.FromListNamed) { return(SqlSubpath.FromString($"*"), true); } return(SqlSubpath.FromString(SqlExpression.TableRefToSql(pars.FromListAlias, "*")), true); } var replace = SqlFromList.ReplaceStringAliasMembers(expr, pars.Replace); if (replace != null) { return(SqlSubpath.FromString(replace), false); } if (expr is MemberExpression mem) { return(MemberToSql(mem, pars)); } else if (expr is ConditionalExpression cond) { return(SqlSubpath.FromString(ConditionalToSql(cond, pars)), false); } else if (expr is MethodCallExpression call) { return(SqlSubpath.FromString(CallToSql(call, pars)), false); } else if (expr is MemberInitExpression || expr is NewExpression) { //TODO: Note la similaridad de este código, del InsertToString y del SelectStr //Puede ser que estas 3 funciones sean lógicamente equivalentes y que se puedan unificar var exprs = SqlSelect .ExtractInitExpr(expr) .Select(x => (x.mem, sql: ExprToSqlStar(x.expr, pars, false))); ; if (exprs.Any(y => y.sql.star)) { throw new ArgumentException("No esta soportado una expresión star '*' en una subexpresión"); } var subpaths = exprs .SelectMany(x => x.sql.sql, (parent, child) => (member: parent.mem, subpath: child)) .Select(x => new SqlSubpath(x.subpath.Sql, "_" + x.member.Name + x.subpath.Subpath)) .ToList() ; return(subpaths, false); } throw new ArgumentException("No se pudo convertir a SQL la expresión " + expr.ToString()); }