Merge pull request 'refactor(dedup): final pass — clear the last 4 src/ duplicate blocks' (#22) from chore/sonarqube-src-dedup-final into main
SonarQube Analysis / sonarqube (push) Successful in 4m30s
SonarQube Analysis / sonarqube (push) Successful in 4m30s
Reviewed-on: #22
This commit was merged in pull request #22.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
namespace Strata.SqlTools.Markdown.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Shared method bodies for the per-dialect <c>QueryBreakdownCollectionGenerator</c>
|
||||
/// classes. Each dialect wraps its <c>QueryBreakdownCollection</c> in an
|
||||
/// <see cref="ICollectionMarkdownData"/> adapter and supplies a dialect-specific
|
||||
/// <see cref="MarkdownDialectFormat"/>; this template handles the rest.
|
||||
/// </summary>
|
||||
internal static class CollectionMarkdownGenerator
|
||||
{
|
||||
public static string GenerateCollectionReport(ICollectionMarkdownData data, MarkdownDialectFormat format, string? title)
|
||||
=> CollectionReportWriter.CollectionReport(title, new[]
|
||||
{
|
||||
GenerateCollectionSummary(data),
|
||||
GenerateParameterAnalysis(data, format),
|
||||
GenerateQueryCompositionReport(data, format)
|
||||
});
|
||||
|
||||
public static string GenerateCollectionSummary(ICollectionMarkdownData data)
|
||||
=> CollectionReportWriter.CollectionSummary(
|
||||
data.QueryCount,
|
||||
data.UniqueParameterCount,
|
||||
data.TotalSelectedColumns,
|
||||
data.UniqueTableCount);
|
||||
|
||||
public static string GenerateParameterAnalysis(ICollectionMarkdownData data, MarkdownDialectFormat format)
|
||||
=> CollectionReportWriter.ParameterAnalysis(data.ParameterRows.ToList(), data.QueriesForReport, format);
|
||||
|
||||
public static string GenerateParameterDependencyDiagram(ICollectionMarkdownData data, MarkdownDialectFormat format)
|
||||
=> CollectionReportWriter.ParameterDependencyDiagram(data.QueriesForReport, format);
|
||||
|
||||
public static string GenerateQueryCompositionReport(ICollectionMarkdownData data, MarkdownDialectFormat format)
|
||||
=> CollectionReportWriter.QueryCompositionReport(data.QueriesForReport, format);
|
||||
|
||||
public static string GenerateBatchFlowDiagram(ICollectionMarkdownData data, string? openLabel, string? closeLabel)
|
||||
=> CollectionReportWriter.BatchFlowDiagram(data.QueryCount, openLabel, closeLabel);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using SqlServerBreakdowns = Strata.SqlTools.Breakdowns.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Dialect-neutral view of a <c>QueryBreakdownCollection</c> as seen by the Markdown
|
||||
/// generators. Each per-dialect <c>QueryBreakdownCollectionGenerator</c> wraps its
|
||||
/// dialect-specific collection in an implementation of this interface so the shared
|
||||
/// <see cref="CollectionMarkdownGenerator"/> template can operate uniformly.
|
||||
/// </summary>
|
||||
internal interface ICollectionMarkdownData
|
||||
{
|
||||
int QueryCount { get; }
|
||||
int UniqueParameterCount { get; }
|
||||
int TotalSelectedColumns { get; }
|
||||
int UniqueTableCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Queries as the base <see cref="SqlServerBreakdowns.QueryBreakdown"/> type. Used
|
||||
/// directly by <see cref="CollectionReportWriter.QueryCompositionReport"/>
|
||||
/// (which needs <see cref="IReadOnlyList{T}"/>) and via covariance by the other
|
||||
/// writer methods that accept <see cref="IEnumerable{T}"/>.
|
||||
/// </summary>
|
||||
IReadOnlyList<SqlServerBreakdowns.QueryBreakdown> QueriesForReport { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameter usage already mapped into the writer's dialect-agnostic row type.
|
||||
/// </summary>
|
||||
IEnumerable<ParameterUsageRow> ParameterRows { get; }
|
||||
}
|
||||
@@ -23,79 +23,63 @@ public static class QueryBreakdownCollectionGenerator
|
||||
/// <summary>
|
||||
/// Generates a comprehensive collection report in Markdown format with PostgreSQL-specific information.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to document.</param>
|
||||
/// <param name="title">Optional title for the report.</param>
|
||||
/// <returns>A string containing the Markdown documentation.</returns>
|
||||
public static string GenerateCollectionReport(QueryBreakdownCollection collection, string? title = null)
|
||||
=> CollectionReportWriter.CollectionReport(title, new[]
|
||||
{
|
||||
GenerateCollectionSummary(collection),
|
||||
GenerateParameterAnalysis(collection),
|
||||
GenerateQueryCompositionReport(collection)
|
||||
});
|
||||
=> CollectionMarkdownGenerator.GenerateCollectionReport(Adapt(collection), Format, title);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a summary section for the collection.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to summarize.</param>
|
||||
/// <returns>Markdown summary section.</returns>
|
||||
public static string GenerateCollectionSummary(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.CollectionSummary(
|
||||
collection.QueryBreakdowns.Count,
|
||||
collection.GetAllUniqueParameters().Count(),
|
||||
collection.GetTotalSelectedColumns(),
|
||||
collection.GetUniqueTableReferences().Count());
|
||||
=> CollectionMarkdownGenerator.GenerateCollectionSummary(Adapt(collection));
|
||||
|
||||
/// <summary>
|
||||
/// Generates a parameter analysis report with PostgreSQL parameter syntax support.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to analyze.</param>
|
||||
/// <returns>Markdown parameter analysis section.</returns>
|
||||
public static string GenerateParameterAnalysis(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.ParameterAnalysis(MapParameters(collection), collection.QueryBreakdowns, Format);
|
||||
=> CollectionMarkdownGenerator.GenerateParameterAnalysis(Adapt(collection), Format);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a Mermaid diagram showing parameter dependencies across queries.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to visualize.</param>
|
||||
/// <returns>Mermaid diagram markdown.</returns>
|
||||
public static string GenerateParameterDependencyDiagram(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.ParameterDependencyDiagram(collection.QueryBreakdowns, Format);
|
||||
=> CollectionMarkdownGenerator.GenerateParameterDependencyDiagram(Adapt(collection), Format);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a detailed query composition report.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to report on.</param>
|
||||
/// <returns>Markdown composition report section.</returns>
|
||||
public static string GenerateQueryCompositionReport(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.QueryCompositionReport(collection.QueryBreakdowns, Format);
|
||||
=> CollectionMarkdownGenerator.GenerateQueryCompositionReport(Adapt(collection), Format);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a batch execution flow diagram for PostgreSQL.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to visualize.</param>
|
||||
/// <param name="includeTransaction">Whether to show transaction wrapping.</param>
|
||||
/// <returns>Mermaid diagram markdown.</returns>
|
||||
public static string GenerateBatchFlowDiagram(QueryBreakdownCollection collection, bool includeTransaction = false)
|
||||
=> CollectionReportWriter.BatchFlowDiagram(
|
||||
collection.QueryBreakdowns.Count,
|
||||
=> CollectionMarkdownGenerator.GenerateBatchFlowDiagram(
|
||||
Adapt(collection),
|
||||
includeTransaction ? "BEGIN" : null,
|
||||
includeTransaction ? "COMMIT" : null);
|
||||
|
||||
/// <summary>
|
||||
/// Maps the collection's parameter usage report into the writer's dialect-agnostic rows.
|
||||
/// </summary>
|
||||
private static List<ParameterUsageRow> MapParameters(QueryBreakdownCollection collection)
|
||||
=> collection.GetParameterUsageReport()
|
||||
.Select(p => new ParameterUsageRow
|
||||
private static ICollectionMarkdownData Adapt(QueryBreakdownCollection collection) => new Adapter(collection);
|
||||
|
||||
private sealed class Adapter : ICollectionMarkdownData
|
||||
{
|
||||
private readonly QueryBreakdownCollection _c;
|
||||
public Adapter(QueryBreakdownCollection c) { _c = c; }
|
||||
public int QueryCount => _c.QueryBreakdowns.Count;
|
||||
public int UniqueParameterCount => _c.GetAllUniqueParameters().Count();
|
||||
public int TotalSelectedColumns => _c.GetTotalSelectedColumns();
|
||||
public int UniqueTableCount => _c.GetUniqueTableReferences().Count();
|
||||
public IReadOnlyList<Breakdowns.SqlServer.QueryBreakdown> QueriesForReport => _c.QueryBreakdowns;
|
||||
public IEnumerable<ParameterUsageRow> ParameterRows
|
||||
=> _c.GetParameterUsageReport().Select(p => new ParameterUsageRow
|
||||
{
|
||||
ParameterName = p.ParameterName,
|
||||
IsUsedInAllQueries = p.IsUsedInAllQueries,
|
||||
UsedInQueryCount = p.UsedInQueryCount,
|
||||
TotalQueries = p.TotalQueries,
|
||||
Value = p.Value
|
||||
})
|
||||
.ToList();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a parameter using PostgreSQL syntax: <c>$n</c> for positional, <c>:name</c> for named.
|
||||
|
||||
@@ -22,79 +22,63 @@ public static class QueryBreakdownCollectionGenerator
|
||||
/// <summary>
|
||||
/// Generates a comprehensive collection report in Markdown format.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to document.</param>
|
||||
/// <param name="title">Optional title for the report.</param>
|
||||
/// <returns>A string containing the Markdown documentation.</returns>
|
||||
public static string GenerateCollectionReport(QueryBreakdownCollection collection, string? title = null)
|
||||
=> CollectionReportWriter.CollectionReport(title, new[]
|
||||
{
|
||||
GenerateCollectionSummary(collection),
|
||||
GenerateParameterAnalysis(collection),
|
||||
GenerateQueryCompositionReport(collection)
|
||||
});
|
||||
=> CollectionMarkdownGenerator.GenerateCollectionReport(Adapt(collection), Format, title);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a summary section for the collection.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to summarize.</param>
|
||||
/// <returns>Markdown summary section.</returns>
|
||||
public static string GenerateCollectionSummary(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.CollectionSummary(
|
||||
collection.QueryBreakdowns.Count,
|
||||
collection.GetAllUniqueParameters().Count(),
|
||||
collection.GetTotalSelectedColumns(),
|
||||
collection.GetUniqueTableReferences().Count());
|
||||
=> CollectionMarkdownGenerator.GenerateCollectionSummary(Adapt(collection));
|
||||
|
||||
/// <summary>
|
||||
/// Generates a parameter analysis report.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to analyze.</param>
|
||||
/// <returns>Markdown parameter analysis section.</returns>
|
||||
public static string GenerateParameterAnalysis(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.ParameterAnalysis(MapParameters(collection), collection.QueryBreakdowns, Format);
|
||||
=> CollectionMarkdownGenerator.GenerateParameterAnalysis(Adapt(collection), Format);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a Mermaid diagram showing parameter dependencies across queries.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to visualize.</param>
|
||||
/// <returns>Mermaid diagram markdown.</returns>
|
||||
public static string GenerateParameterDependencyDiagram(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.ParameterDependencyDiagram(collection.QueryBreakdowns, Format);
|
||||
=> CollectionMarkdownGenerator.GenerateParameterDependencyDiagram(Adapt(collection), Format);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a detailed query composition report.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to report on.</param>
|
||||
/// <returns>Markdown composition report section.</returns>
|
||||
public static string GenerateQueryCompositionReport(QueryBreakdownCollection collection)
|
||||
=> CollectionReportWriter.QueryCompositionReport(collection.QueryBreakdowns, Format);
|
||||
=> CollectionMarkdownGenerator.GenerateQueryCompositionReport(Adapt(collection), Format);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a batch execution flow diagram.
|
||||
/// </summary>
|
||||
/// <param name="collection">The QueryBreakdownCollection to visualize.</param>
|
||||
/// <param name="includeTransaction">Whether to show transaction wrapping.</param>
|
||||
/// <returns>Mermaid diagram markdown.</returns>
|
||||
public static string GenerateBatchFlowDiagram(QueryBreakdownCollection collection, bool includeTransaction = false)
|
||||
=> CollectionReportWriter.BatchFlowDiagram(
|
||||
collection.QueryBreakdowns.Count,
|
||||
=> CollectionMarkdownGenerator.GenerateBatchFlowDiagram(
|
||||
Adapt(collection),
|
||||
includeTransaction ? "BEGIN TRANSACTION" : null,
|
||||
includeTransaction ? "COMMIT TRANSACTION" : null);
|
||||
|
||||
/// <summary>
|
||||
/// Maps the collection's parameter usage report into the writer's dialect-agnostic rows.
|
||||
/// </summary>
|
||||
private static List<ParameterUsageRow> MapParameters(QueryBreakdownCollection collection)
|
||||
=> collection.GetParameterUsageReport()
|
||||
.Select(p => new ParameterUsageRow
|
||||
private static ICollectionMarkdownData Adapt(QueryBreakdownCollection collection) => new Adapter(collection);
|
||||
|
||||
private sealed class Adapter : ICollectionMarkdownData
|
||||
{
|
||||
private readonly QueryBreakdownCollection _c;
|
||||
public Adapter(QueryBreakdownCollection c) { _c = c; }
|
||||
public int QueryCount => _c.QueryBreakdowns.Count;
|
||||
public int UniqueParameterCount => _c.GetAllUniqueParameters().Count();
|
||||
public int TotalSelectedColumns => _c.GetTotalSelectedColumns();
|
||||
public int UniqueTableCount => _c.GetUniqueTableReferences().Count();
|
||||
public IReadOnlyList<QueryBreakdown> QueriesForReport => _c.QueryBreakdowns;
|
||||
public IEnumerable<ParameterUsageRow> ParameterRows
|
||||
=> _c.GetParameterUsageReport().Select(p => new ParameterUsageRow
|
||||
{
|
||||
ParameterName = p.ParameterName,
|
||||
IsUsedInAllQueries = p.IsUsedInAllQueries,
|
||||
UsedInQueryCount = p.UsedInQueryCount,
|
||||
TotalQueries = p.TotalQueries,
|
||||
Value = p.Value
|
||||
})
|
||||
.ToList();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter type name from a parameter value.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -547,74 +547,79 @@ public class QueryBreakdown : SqlBreakdownBase, IQueryBreakdown
|
||||
return mergedParams;
|
||||
}
|
||||
|
||||
#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high
|
||||
/// <summary>
|
||||
/// Renders the <c>WITH [RECURSIVE]</c> CTE section into <paramref name="sb"/> if any
|
||||
/// <see cref="WithClauses"/> are present. Shared by dialects (SqlServer uses 5-space
|
||||
/// outer / 10-space inner indents; Snowflake passes 4-/8-space).
|
||||
/// </summary>
|
||||
/// <param name="sb">The builder accumulating the SQL.</param>
|
||||
/// <param name="withClauseIndent">Indent used for the CTE name line and the closing <c>)</c>.</param>
|
||||
/// <param name="queryBodyIndent">Indent used for each anchor/recursive query body line and the <c>UNION ALL</c>.</param>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SQL breakdown as a string (query-specific implementation).
|
||||
/// </summary>
|
||||
/// <returns>The SELECT SQL statement.</returns>
|
||||
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))
|
||||
|
||||
Reference in New Issue
Block a user