diff --git a/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs b/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs index 637a8f1..ae37519 100644 --- a/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs +++ b/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs @@ -451,62 +451,7 @@ public class QueryBreakdown : SqlServerQueryBreakdown } } - if (IsUsingWithClause) - { - // Check if any WITH clause is recursive - bool hasRecursive = WithClauses.Any(wc => wc.IsRecursive); - sb.Append("WITH"); - if (hasRecursive) - { - sb.Append(" RECURSIVE"); - } - sb.AppendLine(); - - for (int i = 0; i < WithClauses.Count; i++) - { - var withClause = WithClauses[i]; - - if (i > 0) - { - sb.Append(','); - sb.AppendLine(); - } - - // Include comment if present - if (!string.IsNullOrWhiteSpace(withClause.Comment)) - { - sb.AppendLine($" {withClause.Comment}"); - } - - // Write CTE name with optional column list - var cteName = withClause.TableName; - if (withClause.ColumnList != null && withClause.ColumnList.Count > 0) - { - var columnList = string.Join(", ", withClause.ColumnList); - cteName = $"{withClause.TableName} ({columnList})"; - } - - sb.AppendLine($" {cteName} AS ("); - - if (withClause.IsRecursive && withClause.RecursiveQuery != null) - { - // For recursive CTEs: anchor query UNION ALL recursive query - var anchorSql = withClause.Query?.GetSql(includeSetupFinish: false).Trim() ?? string.Empty; - var recursiveSql = withClause.RecursiveQuery.GetSql(includeSetupFinish: false).Trim() ?? string.Empty; - sb.AppendLine($" {anchorSql}"); - sb.AppendLine(" UNION ALL"); - sb.AppendLine($" {recursiveSql}"); - } - else - { - // For non-recursive CTEs: just the single query - var withSql = withClause.Query?.GetSql(includeSetupFinish: false).Trim() ?? string.Empty; - sb.AppendLine($" {withSql}"); - } - sb.Append(" )"); - } - sb.AppendLine(); - } + AppendWithClauseSection(sb, withClauseIndent: " ", queryBodyIndent: " "); // Snowflake SELECT syntax sb.Append(StatementParser.KeywordSelect); diff --git a/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs b/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs index 9d8187c..2382e06 100644 --- a/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs +++ b/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs @@ -547,74 +547,79 @@ public class QueryBreakdown : SqlBreakdownBase, IQueryBreakdown return mergedParams; } -#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high + /// + /// Renders the WITH [RECURSIVE] CTE section into if any + /// are present. Shared by dialects (SqlServer uses 5-space + /// outer / 10-space inner indents; Snowflake passes 4-/8-space). + /// + /// The builder accumulating the SQL. + /// Indent used for the CTE name line and the closing ). + /// Indent used for each anchor/recursive query body line and the UNION ALL. + protected virtual void AppendWithClauseSection(StringBuilder sb, string withClauseIndent, string queryBodyIndent) + { + if (!IsUsingWithClause) + { + return; + } + + bool hasRecursive = _withClauses.Any(wc => wc.IsRecursive); + sb.Append("WITH"); + if (hasRecursive) + { + sb.Append(" RECURSIVE"); + } + sb.AppendLine(); + + for (int i = 0; i < _withClauses.Count; i++) + { + var withClause = _withClauses[i]; + var anchorSql = withClause.Query?.GetSql(includeSetupFinish: false).Trim() ?? string.Empty; + + if (i > 0) + { + sb.Append(','); + sb.AppendLine(); + } + + if (!string.IsNullOrWhiteSpace(withClause.Comment)) + { + sb.AppendLine($"{withClauseIndent}{withClause.Comment}"); + } + + var cteName = withClause.TableName; + if (withClause.ColumnList != null && withClause.ColumnList.Count > 0) + { + var columnList = string.Join(", ", withClause.ColumnList); + cteName = $"{withClause.TableName} ({columnList})"; + } + sb.AppendLine($"{withClauseIndent}{cteName} AS ("); + + if (withClause.IsRecursive && withClause.RecursiveQuery != null) + { + var recursiveSql = withClause.RecursiveQuery.GetSql(includeSetupFinish: false).Trim(); + sb.AppendLine($"{queryBodyIndent}{anchorSql}"); + sb.AppendLine($"{queryBodyIndent}UNION ALL"); + sb.AppendLine($"{queryBodyIndent}{recursiveSql}"); + } + else + { + sb.AppendLine($"{queryBodyIndent}{anchorSql}"); + } + + sb.Append($"{withClauseIndent})"); + } + sb.AppendLine(); + } + /// /// Gets the SQL breakdown as a string (query-specific implementation). /// /// The SELECT SQL statement. protected override string GetSqlBreakdown() -#pragma warning restore S3776 { var sb = new StringBuilder(); - if (IsUsingWithClause) - { - // Check if any CTE is recursive - if so, add RECURSIVE keyword - bool hasRecursive = _withClauses.Any(wc => wc.IsRecursive); - sb.Append("WITH "); - if (hasRecursive) - { - sb.AppendLine("RECURSIVE"); - } - else - { - sb.AppendLine(); - } - - for (int i = 0; i < _withClauses.Count; i++) - { - var withClause = _withClauses[i]; - var anchorSql = withClause.Query?.GetSql(includeSetupFinish: false).Trim() ?? string.Empty; - - if (i > 0) - { - sb.Append(','); - sb.AppendLine(); - } - - // Include comment if present - if (!string.IsNullOrWhiteSpace(withClause.Comment)) - { - sb.AppendLine($" {withClause.Comment}"); - } - - // Write CTE name with optional column list - var cteName = withClause.TableName; - if (withClause.ColumnList != null && withClause.ColumnList.Count > 0) - { - var columnList = string.Join(", ", withClause.ColumnList); - cteName = $"{withClause.TableName} ({columnList})"; - } - sb.AppendLine($" {cteName} AS ("); - - if (withClause.IsRecursive && withClause.RecursiveQuery != null) - { - // For recursive CTEs: anchor query UNION ALL recursive query - var recursiveSql = withClause.RecursiveQuery.GetSql(includeSetupFinish: false).Trim(); - sb.AppendLine($" {anchorSql}"); - sb.AppendLine(" UNION ALL"); - sb.AppendLine($" {recursiveSql}"); - } - else - { - // For non-recursive CTEs: just the single query - sb.AppendLine($" {anchorSql}"); - } - - sb.Append(" )"); - } - sb.AppendLine(); - } + AppendWithClauseSection(sb, withClauseIndent: " ", queryBodyIndent: " "); sb.AppendLine("SELECT "); if (!string.IsNullOrEmpty(SelectClause.Comment))