/// <summary> /// Convierte un <see cref="MemberExpression"/> a SQL, tomando en cuenta los aliases de la lista de froms /// y la lógica descrita en <see cref="SqlExprParams"/> /// </summary> static string SingleMemberToSql(SqlExprParams pars, string baseMemberName, string subpath, MemberExpression mem) { var memberName = baseMemberName + subpath; if (pars.FromListNamed) { //Si la lista de FROM tiene aliases, el parametro del select no hace referencia a una tabla, //si no a un objeto de aliases donde cada propiedad es una tabla o un elemento de un JOIN MemberExpression firstExpr = mem; while (firstExpr is MemberExpression sm1 && sm1.Expression is MemberExpression sm2) { firstExpr = sm2; } if (IsFromParam(mem.Expression)) { throw new ArgumentException("No esta soportado obtener una expresión de * en el SingleMemberSql"); } else if (IsFromParam(firstExpr.Expression)) { return(TableRefToSql(firstExpr.Member.Name, memberName)); } else if (IsRawTableRef(firstExpr.Expression, out var raw)) { return(RawTableRefToSql(raw, SqlSelect.ColNameToStr(memberName))); } } else { //Si la lista de FROM no tiene aliases, el parámetro del SELECT hace referencia a la tabla del SELECT Expression firstExpr = mem; while (firstExpr is MemberExpression sm) { firstExpr = sm.Expression; } if (IsFromParam(firstExpr)) { return(TableRefToSql(pars.FromListAlias, memberName)); } else if (IsRawTableRef(firstExpr, out var raw)) { return(RawTableRefToSql(raw, SqlSelect.ColNameToStr(memberName))); } } //Intentamos convertir al Expr a string con el replace: var exprRep = SqlFromList.ReplaceStringAliasMembers(mem.Expression, pars.Replace); if (exprRep != null) { return($"{exprRep}.\"{memberName}\""); } var exprStr = ExprToSql(mem.Expression, pars, false); return($"{exprStr}.\"{memberName}\""); }
public static string SubqueryToSql(Expression expr, SqlExprParams pars) { var selectCall = expr; var callSub = SqlFromList.ReplaceSubqueryBody(selectCall, pars.Replace); var subqueryFunc = Expression.Lambda(callSub).Compile(); var subqueryExec = (ISqlSelectHasClause)subqueryFunc.DynamicInvoke(new object[0]); var selectStr = SqlSelect.TabStr(SqlSelect.SelectToString(subqueryExec.Clause, pars.ParamMode, pars.ParamDic)); return($"({Environment.NewLine}{selectStr}{Environment.NewLine})"); }
/// <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()); }
/// <summary> /// Convierte una cláusula de SELECT a string /// </summary> public static SelectToStrResult SelectToStringScalar(SelectClause clause, ParamMode paramMode, SqlParamDic paramDic) { var selectExpr = clause.Select; var paramName = selectExpr.Parameters[0].Name; var from = SqlFromList.FromListToStr(clause.From, paramName, true, paramMode, paramDic); var selectParam = selectExpr.Parameters[0]; var aliases = from.Aliases.ToList(); if (!from.Named) { //Agregar el parametro del select como el nombre del fromList, esto para que se sustituya correctamente en los subqueries aliases.Add(new SqlFromList.ExprStrRawSql(selectParam, TableNameToStr(from.Alias))); } var pars = new SqlExprParams(selectParam, selectExpr.Parameters[1], from.Named, from.Alias, aliases, paramMode, paramDic); var select = SelectBodyToStr(selectExpr.Body, pars); //The query converted to string, before the PostUnion var query = new StringBuilder(); query.Append("SELECT"); if (clause.DistinctType != SelectType.All) { query.Append(" "); switch (clause.DistinctType) { case SelectType.Distinct: query.Append("DISTINCT"); break; case SelectType.DistinctOn: query.Append(DistinctOnStr(clause.DistinctOn, pars)); break; } } query.AppendLine(); query.AppendLine($"{TabStr(SelectExprToStr(select.Values))}"); query.AppendLine(from.Sql); if (clause.Where != null) { query.AppendLine(WhereStr(clause.Where, pars)); } if (clause.GroupBy?.Any() == true) { query.AppendLine(GroupByStr(clause.GroupBy, pars)); } if (clause.Window != null) { query.AppendLine(WindowToStr(clause.Window, pars)); } if (clause.OrderBy?.Any() == true) { query.AppendLine(OrderByStr(clause.OrderBy, pars)); } if (clause.Limit != null) { query.AppendLine("LIMIT " + clause.Limit); } //Delete the last line jump, note that the lenght of the line-jump //depends on the operating system query.Length = query.Length - Environment.NewLine.Length; StringBuilder ret; if (clause.Unions?.Any() == true) { ret = new StringBuilder(); //Put the query whole inside parenthesis ret.AppendLine("("); ret.AppendLine(TabStr(query.ToString())); ret.AppendLine(")"); foreach (var union in clause.Unions) { ret.AppendLine(UnionToStr(union, pars)); } //Remove the last lineJump: ret.Length = ret.Length - Environment.NewLine.Length; } else { ret = query; } return(new SelectToStrResult(ret.ToString(), select.Values.Select(x => x.Column).ToList(), select.Scalar)); }