From 2c23ba4a88b0462a58c04af45527adeed4565a85 Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Wed, 27 May 2026 14:18:31 -0500 Subject: [PATCH 1/5] chore(sonar)!: return empty IQueryable instead of null from GetQuery (S1168) Replaces `null` returns from `SqlBreakdownBase.GetQuery()` and its four overrides (LinqQueryBreakdown, SqlServer/PostgreSql/Snowflake QueryBreakdown) with `Enumerable.Empty().AsQueryable()`, and tightens the signature from `IQueryable?` to `IQueryable`. The "we can't reconstruct" semantic now lives in "the query yields zero rows" rather than a nullable return, which is what callers in LINQ pipelines actually want. Three LinqQueryBreakdownTests tests asserting `Is.Null` are renamed and updated to assert `Is.Empty`. BREAKING CHANGE: SqlBreakdownBase.GetQuery and the SqlServer / PostgreSql / Snowflake / LinqToSql QueryBreakdown.GetQuery overrides no longer return `IQueryable?`; they now return a non-nullable `IQueryable` that is empty when reconstruction isn't possible. External NuGet consumers null- checking the result must switch to `.Any()` / `Is.Empty` checks instead. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Breakdowns/LinqQueryBreakdown.cs | 22 ++++++------------- .../Breakdowns/QueryBreakdown.cs | 12 ++++------ .../Breakdowns/QueryBreakdown.cs | 12 ++++------ .../Classes/SqlBreakdownBase.cs | 6 ++--- .../Breakdowns/QueryBreakdown.cs | 12 ++++------ .../LinqQueryBreakdownTests.cs | 16 +++++++------- 6 files changed, 30 insertions(+), 50 deletions(-) diff --git a/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs b/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs index 341b1fa..db49c0a 100644 --- a/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs +++ b/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs @@ -185,39 +185,31 @@ public class LinqQueryBreakdown : QueryBreakdown /// Gets a LINQ to SQL query of the specified type based on this breakdown. /// /// The entity type for the query. - /// An IQueryable of the specified type reconstructed from the breakdown, or null if the type doesn't match the original entity type. + /// An IQueryable of the specified type reconstructed from the breakdown; an empty queryable if the type doesn't match the original entity type or the original data source isn't available. /// /// This method attempts to reconstruct a LINQ query from the analyzed components (WHERE, ORDER BY, etc.). /// If a data source (IQueryable) is available in the breakdown's OriginalExpression, it will be used. - /// Otherwise, returns null to indicate the query cannot be reconstructed without the original data source. + /// Otherwise, returns an empty queryable — breakdown analysis is one-way; reconstruction requires the original provider. /// - public override IQueryable? GetQuery() where T : class + public override IQueryable GetQuery() where T : class { - // If we don't have the original expression, we cannot reconstruct the LINQ query if (OriginalExpression == null) { - return null; + return Enumerable.Empty().AsQueryable(); } - // The original expression is the full LINQ query that was analyzed - // To use it, we need it to be an IQueryable try { - // If the original expression can be converted to IQueryable, use it - // Otherwise, we cannot safely reconstruct without the original query provider if (OriginalExpression is Expression && EntityType == typeof(T)) { - // We have the expression, but we don't have the provider to create IQueryable - // The breakdown analysis is one-way; reconstruction requires the original provider - return null; + return Enumerable.Empty().AsQueryable(); } - return null; + return Enumerable.Empty().AsQueryable(); } catch { - // If any error occurs during reconstruction, return null - return null; + return Enumerable.Empty().AsQueryable(); } } diff --git a/src/Strata.SqlTools.PostgreSql/Breakdowns/QueryBreakdown.cs b/src/Strata.SqlTools.PostgreSql/Breakdowns/QueryBreakdown.cs index 30d2f74..0a07d1c 100644 --- a/src/Strata.SqlTools.PostgreSql/Breakdowns/QueryBreakdown.cs +++ b/src/Strata.SqlTools.PostgreSql/Breakdowns/QueryBreakdown.cs @@ -272,17 +272,13 @@ public class QueryBreakdown : SqlServerQueryBreakdown /// Gets a LINQ to SQL query of the specified type based on this breakdown. /// /// The entity type for the query. - /// null by default, as QueryBreakdown operates on SQL. Override in derived classes to provide LINQ query reconstruction. + /// An empty queryable by default, as QueryBreakdown operates on SQL. Override in derived classes to provide LINQ query reconstruction. /// - /// This PostgreSQL-specific implementation returns null since PostgreSQL QueryBreakdown represents parsed SQL statements. + /// This PostgreSQL-specific implementation returns an empty queryable since PostgreSQL QueryBreakdown + /// represents parsed SQL statements and has no built-in way to create LINQ queries. /// Derived classes can override this method to reconstruct LINQ queries from the analyzed components. /// - public override IQueryable? GetQuery() where T : class - { - // PostgreSQL breakdown represents parsed SQL statements and does not have a built-in way to create LINQ queries - // Override in derived classes to provide LINQ query reconstruction if needed - return null; - } + public override IQueryable GetQuery() where T : class => Enumerable.Empty().AsQueryable(); } diff --git a/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs b/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs index 4ab2451..773f3f7 100644 --- a/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs +++ b/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdown.cs @@ -863,17 +863,13 @@ public class QueryBreakdown : SqlServerQueryBreakdown /// Gets a LINQ to SQL query of the specified type based on this breakdown. /// /// The entity type for the query. - /// null by default, as QueryBreakdown operates on SQL. Override in derived classes to provide LINQ query reconstruction. + /// An empty queryable by default, as QueryBreakdown operates on SQL. Override in derived classes to provide LINQ query reconstruction. /// - /// This Snowflake-specific implementation returns null since Snowflake QueryBreakdown represents parsed SQL statements. + /// This Snowflake-specific implementation returns an empty queryable since Snowflake QueryBreakdown + /// represents parsed SQL statements and has no built-in way to create LINQ queries. /// Derived classes can override this method to reconstruct LINQ queries from the analyzed components. /// - public override IQueryable? GetQuery() where T : class - { - // Snowflake breakdown represents parsed SQL statements and does not have a built-in way to create LINQ queries - // Override in derived classes to provide LINQ query reconstruction if needed - return null; - } + public override IQueryable GetQuery() where T : class => Enumerable.Empty().AsQueryable(); } diff --git a/src/Strata.SqlTools.SqlBreakdown/Classes/SqlBreakdownBase.cs b/src/Strata.SqlTools.SqlBreakdown/Classes/SqlBreakdownBase.cs index fa3d00a..4663657 100644 --- a/src/Strata.SqlTools.SqlBreakdown/Classes/SqlBreakdownBase.cs +++ b/src/Strata.SqlTools.SqlBreakdown/Classes/SqlBreakdownBase.cs @@ -57,13 +57,13 @@ public abstract class SqlBreakdownBase : ISqlBreakdown /// Gets a LINQ to SQL query of the specified type based on this breakdown. /// /// The entity type for the query. - /// An IQueryable of the specified type, or null if the breakdown cannot be converted to a LINQ query. + /// An IQueryable of the specified type; an empty queryable if the breakdown cannot be converted to a LINQ query. /// /// This method allows derived breakdown classes to reconstruct or generate LINQ queries /// from the analyzed components (SELECT, WHERE, ORDER BY, etc.). - /// The default implementation returns null. + /// The default implementation returns an empty queryable. /// - public virtual IQueryable? GetQuery() where T : class => null; + public virtual IQueryable GetQuery() where T : class => Enumerable.Empty().AsQueryable(); /// /// Gets the complete SQL query including optional setup and finish clauses. diff --git a/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs b/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs index 5fe8692..d99f887 100644 --- a/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs +++ b/src/Strata.SqlTools.SqlServer/Breakdowns/QueryBreakdown.cs @@ -731,18 +731,14 @@ public class QueryBreakdown : SqlBreakdownBase, IQueryBreakdown /// Gets a LINQ to SQL query of the specified type based on this breakdown. /// /// The entity type for the query. - /// null by default, as QueryBreakdown operates on SQL. Override in derived classes to provide LINQ query reconstruction. + /// An empty queryable by default, as QueryBreakdown operates on SQL. Override in derived classes to provide LINQ query reconstruction. /// - /// This base implementation returns null since QueryBreakdown represents parsed SQL statements. + /// This base implementation returns an empty queryable since QueryBreakdown represents parsed SQL statements + /// and has no built-in way to create LINQ queries. /// Derived classes (such as LinqQueryBreakdown) can override this method to reconstruct LINQ queries /// from the analyzed components. /// - public override IQueryable? GetQuery() where T : class - { - // Base implementation returns null - SQL-based breakdowns don't have a built-in way to create LINQ queries - // Override in derived classes (e.g., LinqQueryBreakdown) to provide LINQ query reconstruction - return null; - } + public override IQueryable GetQuery() where T : class => Enumerable.Empty().AsQueryable(); /// /// Gets the complete SQL query string (interface implementation). diff --git a/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs b/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs index 2a7f9b3..04c579d 100644 --- a/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs +++ b/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs @@ -513,21 +513,21 @@ public class GetQueryTests } [Test] - public void GetQuery_LinqBreakdown_ReturnsNullByDefault() + public void GetQuery_LinqBreakdown_ReturnsEmptyByDefault() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 18); var breakdown = LinqQueryBreakdown.Analyze(query); - // Act - GetQuery returns null because LinqQueryBreakdown needs the original provider + // Act - GetQuery returns empty because LinqQueryBreakdown needs the original provider var result = breakdown.GetQuery(); // Assert - Assert.That(result, Is.Null); + Assert.That(result, Is.Empty); } [Test] - public void GetQuery_SqlServerQueryBreakdown_ReturnsNull() + public void GetQuery_SqlServerQueryBreakdown_ReturnsEmpty() { // Arrange var breakdown = new QueryBreakdown("Id, Name", "Users", "Age > 18"); @@ -536,11 +536,11 @@ public class GetQueryTests var result = breakdown.GetQuery(); // Assert - Assert.That(result, Is.Null); + Assert.That(result, Is.Empty); } [Test] - public void GetQuery_MultipleBreakdownTypes_AllReturnNull() + public void GetQuery_MultipleBreakdownTypes_AllReturnEmpty() { // Arrange var linqBreakdown = LinqQueryBreakdown.Analyze(TestDataContext.Users); @@ -553,8 +553,8 @@ public class GetQueryTests Assert.Multiple(() => { // Assert - Assert.That(linqResult, Is.Null); - Assert.That(sqlResult, Is.Null); + Assert.That(linqResult, Is.Empty); + Assert.That(sqlResult, Is.Empty); }); } -- 2.54.0 From 3c602a4625f91fc029818ac7f01b4a0e5f598304 Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Wed, 27 May 2026 14:19:26 -0500 Subject: [PATCH 2/5] chore(sonar): mark private helpers static (CA1822) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two private methods that don't touch instance state get the `static` keyword: - `LinqExpressionVisitor.ExtractMemberName` - `Markdown.Expressions.ExpressionGenerator.GenerateMermaidDiagram(Expression)` Both have only intra-class callers, so this is a non-breaking change — the call sites continue to work unchanged under C# method-resolution. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs | 2 +- src/Strata.SqlTools.Markdown/Expressions/ExpressionGenerator.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs b/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs index c4b3e20..ab548fb 100644 --- a/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs +++ b/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs @@ -303,7 +303,7 @@ public class LinqExpressionVisitor : ExpressionVisitor return string.IsNullOrEmpty(name) ? "*" : name; } - private string ExtractMemberName(Expression expression) + private static string ExtractMemberName(Expression expression) { if (expression is MemberExpression member) { diff --git a/src/Strata.SqlTools.Markdown/Expressions/ExpressionGenerator.cs b/src/Strata.SqlTools.Markdown/Expressions/ExpressionGenerator.cs index 706d197..8f19153 100644 --- a/src/Strata.SqlTools.Markdown/Expressions/ExpressionGenerator.cs +++ b/src/Strata.SqlTools.Markdown/Expressions/ExpressionGenerator.cs @@ -245,7 +245,7 @@ public class ExpressionGenerator : IVisitor /// /// Generates a Mermaid tree diagram from an Expression tree. /// - private string GenerateMermaidDiagram(Expression expression) + private static string GenerateMermaidDiagram(Expression expression) { var sb = new StringBuilder(); sb.AppendLine("```mermaid"); -- 2.54.0 From 5202d93e8e75af7c861258c11508abc9909b409c Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Wed, 27 May 2026 14:22:27 -0500 Subject: [PATCH 3/5] chore(sonar)!: mark public Markdown generator methods static (CA1822) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three public methods on the SqlServer-namespaced Markdown generators no longer touch instance state and now carry the `static` keyword: - `Markdown.SqlServer.QueryBreakdownGenerator.GenerateMermaidDiagram(QueryBreakdown, string?)` - `Markdown.SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(ISqlBreakdown, string?)` - `Markdown.SqlServer.SqlStatementGenerator.GenerateEntityRelationshipDiagram(IEnumerable, string?)` Plus one private bonus the analyzer caught on the same pass: - `LinqExpressionVisitor.ExtractSelectExpression` → static (non-breaking). Internal callers in the Snowflake/LinqToSql/PostgreSql wrapper classes and in the test fixtures are updated to the type-name form (`SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(...)`). The wrappers retain their `_baseGenerator` field for now even though it is no longer used — that S4487 / unused-field cleanup is its own commit. BREAKING CHANGE: External NuGet consumers calling `generatorInstance.GenerateMermaidDiagram(...)`, `generatorInstance.GenerateSequenceDiagram(...)`, or `generatorInstance.GenerateEntityRelationshipDiagram(...)` on the SqlServer-namespaced generators must switch to type-name form, e.g. `Markdown.SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(...)`. Calls through the Snowflake / LinqToSql / PostgreSql wrapper classes are unaffected at the call site. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Visitors/LinqExpressionVisitor.cs | 2 +- .../LinqToSql/QueryBreakdownGenerator.cs | 2 +- .../LinqToSql/SqlStatementGenerator.cs | 4 ++-- .../PostgreSql/QueryBreakdownGenerator.cs | 2 +- .../PostgreSql/SqlStatementGenerator.cs | 4 ++-- .../Snowflake/QueryBreakdownGenerator.cs | 2 +- .../Snowflake/SqlStatementGenerator.cs | 4 ++-- .../SqlServer/QueryBreakdownGenerator.cs | 2 +- .../SqlServer/SqlStatementGenerator.cs | 4 ++-- .../SqlServer/QueryBreakdownGeneratorTests.cs | 14 +++++++------- .../SqlServer/QueryMarkdownGenerationTests.cs | 4 ++-- .../SqlServer/SqlStatementGeneratorTests.cs | 14 +++++++------- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs b/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs index ab548fb..72b8902 100644 --- a/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs +++ b/src/Strata.SqlTools.LinqToSql/Visitors/LinqExpressionVisitor.cs @@ -277,7 +277,7 @@ public class LinqExpressionVisitor : ExpressionVisitor return base.VisitMember(node); } - private string ExtractSelectExpression(Expression expression) + private static string ExtractSelectExpression(Expression expression) { if (expression is NewExpression newExpr) { diff --git a/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs index c55953b..3281319 100644 --- a/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs @@ -28,7 +28,7 @@ public class QueryBreakdownGenerator { // Since LinqQueryBreakdown inherits from SqlServer.QueryBreakdown, // we can use the base generator which works with the shared properties - return _baseGenerator.GenerateMermaidDiagram(queryBreakdown, title); + return SqlServer.QueryBreakdownGenerator.GenerateMermaidDiagram(queryBreakdown, title); } /// diff --git a/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs b/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs index b46c933..2d76349 100644 --- a/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs +++ b/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs @@ -28,7 +28,7 @@ public class SqlStatementGenerator /// A string containing the Mermaid sequence diagram markdown. public string GenerateSequenceDiagram(ISqlBreakdown sqlBreakdown, string? title = null) { - return _baseGenerator.GenerateSequenceDiagram(sqlBreakdown, title); + return SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(sqlBreakdown, title); } /// @@ -49,7 +49,7 @@ public class SqlStatementGenerator tableNames.Add(fromClauseText); } - return _baseGenerator.GenerateEntityRelationshipDiagram(tableNames, title); + return SqlServer.SqlStatementGenerator.GenerateEntityRelationshipDiagram(tableNames, title); } /// diff --git a/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs index 17aaa1b..e92bf27 100644 --- a/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs @@ -28,6 +28,6 @@ public class QueryBreakdownGenerator { // Since PostgreSql.QueryBreakdown inherits from SqlServer.QueryBreakdown, // we can use the base generator which works with the shared properties - return _baseGenerator.GenerateMermaidDiagram(queryBreakdown, title); + return SqlServer.QueryBreakdownGenerator.GenerateMermaidDiagram(queryBreakdown, title); } } diff --git a/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs b/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs index b63011d..c17bd25 100644 --- a/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs +++ b/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs @@ -26,7 +26,7 @@ public class SqlStatementGenerator /// A string containing the Mermaid sequence diagram markdown. public string GenerateSequenceDiagram(SqlBreakdownBase sqlBreakdown, string? title = null) { - return _baseGenerator.GenerateSequenceDiagram(sqlBreakdown, title); + return SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(sqlBreakdown, title); } /// @@ -37,6 +37,6 @@ public class SqlStatementGenerator /// A string containing the Mermaid ER diagram markdown. public string GenerateEntityRelationshipDiagram(IEnumerable tables, string? title = null) { - return _baseGenerator.GenerateEntityRelationshipDiagram(tables, title); + return SqlServer.SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables, title); } } diff --git a/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs index 47c8e9a..b01cbe8 100644 --- a/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs @@ -28,6 +28,6 @@ public class QueryBreakdownGenerator { // Since Snowflake.QueryBreakdown inherits from SqlServer.QueryBreakdown, // we can use the base generator which works with the shared properties - return _baseGenerator.GenerateMermaidDiagram(queryBreakdown, title); + return SqlServer.QueryBreakdownGenerator.GenerateMermaidDiagram(queryBreakdown, title); } } diff --git a/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs b/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs index 725ea8e..c246b35 100644 --- a/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs +++ b/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs @@ -26,7 +26,7 @@ public class SqlStatementGenerator /// A string containing the Mermaid sequence diagram markdown. public string GenerateSequenceDiagram(SqlBreakdownBase sqlBreakdown, string? title = null) { - return _baseGenerator.GenerateSequenceDiagram(sqlBreakdown, title); + return SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(sqlBreakdown, title); } /// @@ -37,6 +37,6 @@ public class SqlStatementGenerator /// A string containing the Mermaid ER diagram markdown. public string GenerateEntityRelationshipDiagram(IEnumerable tables, string? title = null) { - return _baseGenerator.GenerateEntityRelationshipDiagram(tables, title); + return SqlServer.SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables, title); } } diff --git a/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs index aa735a3..1a02e09 100644 --- a/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs @@ -16,7 +16,7 @@ public class QueryBreakdownGenerator /// The QueryBreakdown to visualize. /// Optional title for the diagram. /// A string containing the Mermaid markdown diagram. - public string GenerateMermaidDiagram(QueryBreakdown queryBreakdown, string? title = null) + public static string GenerateMermaidDiagram(QueryBreakdown queryBreakdown, string? title = null) { var sb = new StringBuilder(); diff --git a/src/Strata.SqlTools.Markdown/SqlServer/SqlStatementGenerator.cs b/src/Strata.SqlTools.Markdown/SqlServer/SqlStatementGenerator.cs index 30cce70..0905715 100644 --- a/src/Strata.SqlTools.Markdown/SqlServer/SqlStatementGenerator.cs +++ b/src/Strata.SqlTools.Markdown/SqlServer/SqlStatementGenerator.cs @@ -14,7 +14,7 @@ public class SqlStatementGenerator /// The SQL breakdown to visualize. /// Optional title for the diagram. /// A string containing the Mermaid markdown sequence diagram. - public string GenerateSequenceDiagram(ISqlBreakdown sqlBreakdown, string? title = null) + public static string GenerateSequenceDiagram(ISqlBreakdown sqlBreakdown, string? title = null) { var sb = new StringBuilder(); @@ -74,7 +74,7 @@ public class SqlStatementGenerator /// List of table names referenced in the query. /// Optional title for the diagram. /// A string containing the Mermaid markdown ER diagram. - public string GenerateEntityRelationshipDiagram(IEnumerable tableNames, string? title = null) + public static string GenerateEntityRelationshipDiagram(IEnumerable tableNames, string? title = null) { var sb = new StringBuilder(); diff --git a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs index 2414830..d92bcce 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs @@ -22,7 +22,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("ID, Name", "Users"); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -46,7 +46,7 @@ public class QueryBreakdownGeneratorTests query.OrderByClause.Clause = "OrderCount DESC"; // Act - var result = _generator.GenerateMermaidDiagram(query, "User Orders Query"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "User Orders Query"); // Assert Assert.That(result, Does.Contain("### User Orders Query")); @@ -65,7 +65,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("*", "Products", "Price > 100"); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("WHERE")); @@ -86,7 +86,7 @@ public class QueryBreakdownGeneratorTests var query = QueryBreakdown.Parse(sql); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Is.Not.Null); @@ -102,7 +102,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("*", "Users"); // Act - var result = _generator.GenerateMermaidDiagram(query, "Test Query"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Test Query"); // Assert Assert.That(result, Does.StartWith("### Test Query")); @@ -115,7 +115,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("*", "Users"); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Not.StartWith("###")); @@ -130,7 +130,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown(longSelect, "LargeTable"); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("...")); diff --git a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryMarkdownGenerationTests.cs b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryMarkdownGenerationTests.cs index 5ffd0aa..e01392d 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryMarkdownGenerationTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryMarkdownGenerationTests.cs @@ -59,7 +59,7 @@ public class QueryMarkdownGenerationTests var queryBreakdown = QueryBreakdown.Parse(sqlContent); // Generate markdown with the filename as title - var markdown = _generator.GenerateMermaidDiagram(queryBreakdown, fileName); + var markdown = QueryBreakdownGenerator.GenerateMermaidDiagram(queryBreakdown, fileName); // Verify markdown was generated Assert.That(markdown, Is.Not.Null); @@ -107,7 +107,7 @@ public class QueryMarkdownGenerationTests try { var queryBreakdown = QueryBreakdown.Parse(sqlContent); - var markdown = _generator.GenerateMermaidDiagram(queryBreakdown, fileName); + var markdown = QueryBreakdownGenerator.GenerateMermaidDiagram(queryBreakdown, fileName); // Add source SQL to the markdown var fullMarkdown = $"{markdown}\n\n## Source SQL\n\n```sql\n{sqlContent}\n```\n"; diff --git a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/SqlStatementGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/SqlStatementGeneratorTests.cs index bed15a7..570f43d 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/SqlStatementGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/SqlStatementGeneratorTests.cs @@ -21,7 +21,7 @@ public class SqlStatementGeneratorTests var query = new QueryBreakdown("*", "Users"); // Act - var result = _generator.GenerateSequenceDiagram(query); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -39,7 +39,7 @@ public class SqlStatementGeneratorTests query.SetupClauses.Add("CREATE TEMP TABLE #Temp (ID INT)"); // Act - var result = _generator.GenerateSequenceDiagram(query); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query); // Assert Assert.That(result, Does.Contain("Setup Clauses")); @@ -55,7 +55,7 @@ public class SqlStatementGeneratorTests query.FinishClauses.Add("DROP TABLE #Temp"); // Act - var result = _generator.GenerateSequenceDiagram(query); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query); // Assert Assert.That(result, Does.Contain("Finish Clauses")); @@ -69,7 +69,7 @@ public class SqlStatementGeneratorTests var query = new QueryBreakdown("*", "Users"); // Act - var result = _generator.GenerateSequenceDiagram(query, "Query Execution"); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, "Query Execution"); // Assert Assert.That(result, Does.StartWith("### Query Execution")); @@ -82,7 +82,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "Users", "Orders", "Products" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -100,7 +100,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "Users", "Orders" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables, "Database Schema"); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables, "Database Schema"); // Assert Assert.That(result, Does.StartWith("### Database Schema")); @@ -113,7 +113,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "[dbo].[Users]", "schema.Orders" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables); // Assert Assert.That(result, Does.Contain("dbo_Users")); -- 2.54.0 From 3ba7a7e9f3b94eace9c8befa1cee533eef26a4c0 Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Wed, 27 May 2026 14:33:48 -0500 Subject: [PATCH 4/5] refactor(linq): extract GetEmptyQueryable helper for empty-return paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DRYs the four `Enumerable.Empty().AsQueryable()` returns added in `2c23ba4` (S1168 fix) into a single `public static IQueryable GetEmptyQueryable()` helper on `LinqQueryBreakdown`. No behavior change — all 1180 tests stay green. Co-Authored-By: Thom Lamb --- .../Breakdowns/LinqQueryBreakdown.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs b/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs index db49c0a..1f2d208 100644 --- a/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs +++ b/src/Strata.SqlTools.LinqToSql/Breakdowns/LinqQueryBreakdown.cs @@ -1,5 +1,5 @@ -using System.Linq.Expressions; using Strata.SqlTools.Breakdowns.SqlServer; +using System.Linq.Expressions; using PostgreSqlBreakdown = Strata.SqlTools.Breakdowns.PostgreSql.QueryBreakdown; using SnowflakeBreakdown = Strata.SqlTools.Breakdowns.Snowflake.QueryBreakdown; @@ -195,24 +195,32 @@ public class LinqQueryBreakdown : QueryBreakdown { if (OriginalExpression == null) { - return Enumerable.Empty().AsQueryable(); + return GetEmptyQueryable(); } try { if (OriginalExpression is Expression && EntityType == typeof(T)) { - return Enumerable.Empty().AsQueryable(); + return GetEmptyQueryable(); } - return Enumerable.Empty().AsQueryable(); + return GetEmptyQueryable(); } catch { - return Enumerable.Empty().AsQueryable(); + return GetEmptyQueryable(); } } + /// + /// Get and empty queryable of T + /// + /// The entity type for the query. + /// An empty IQueryable of the type. + public static IQueryable GetEmptyQueryable() where T : class + => Enumerable.Empty().AsQueryable(); + /// /// Analyzes an INSERT operation for the given entity. /// -- 2.54.0 From 6175dcde96ba17047c9e918a5e8e72135abc289f Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Wed, 27 May 2026 14:38:58 -0500 Subject: [PATCH 5/5] chore(sonar)!: cascade CA1822 through Markdown dialect wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 5202d93 made the SqlServer-namespaced Markdown generator methods static, which left the LinqToSql / PostgreSql / Snowflake wrapper classes' instance methods delegating to nothing but a static call. SonarQube re-flagged those 10 wrapper methods as CA1822 on the next scan. This sweep: - Makes all 10 wrapper instance methods `static` (`dotnet format` driven). - Makes `Markdown.LinqToSql.QueryBreakdownGenerator.GenerateCombinedDiagram` static preemptively — it composes two static helpers and would otherwise be the next-iteration cascade flag. - Removes the now-dead `_baseGenerator` field and its initializing constructor from all six dialect wrappers (LinqToSql / PostgreSql / Snowflake × QueryBreakdownGenerator + SqlStatementGenerator). The classes keep their implicit parameterless constructor so `new Snowflake.QueryBreakdownGenerator()` still compiles. - Updates the one test call site (`GenerateCombinedDiagram`) the fixer didn't catch to use type-name form. BREAKING CHANGE: External NuGet consumers calling `instance.Generate*Diagram(...)` on `Markdown.LinqToSql.*`, `Markdown.PostgreSql.*`, or `Markdown.Snowflake.*` generators must switch to type-name form, e.g. `Markdown.Snowflake.SqlStatementGenerator.GenerateSequenceDiagram(...)`. The class types and parameterless constructors remain — only the call syntax for these methods changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../LinqToSql/QueryBreakdownGenerator.cs | 14 ++-------- .../LinqToSql/SqlStatementGenerator.cs | 14 ++-------- .../PostgreSql/QueryBreakdownGenerator.cs | 12 +------- .../PostgreSql/SqlStatementGenerator.cs | 14 ++-------- .../Snowflake/QueryBreakdownGenerator.cs | 12 +------- .../Snowflake/SqlStatementGenerator.cs | 14 ++-------- .../SqlServer/QueryBreakdownGenerator.cs | 2 +- .../LinqToSql/QueryBreakdownGeneratorTests.cs | 8 +++--- .../LinqToSql/SqlStatementGeneratorTests.cs | 4 +-- .../QueryBreakdownGeneratorTests.cs | 28 +++++++++---------- .../PostgreSql/SqlStatementGeneratorTests.cs | 18 ++++++------ .../Snowflake/QueryBreakdownGeneratorTests.cs | 22 +++++++-------- .../Snowflake/SqlStatementGeneratorTests.cs | 14 +++++----- .../SqlServer/QueryBreakdownGeneratorTests.cs | 2 +- 14 files changed, 59 insertions(+), 119 deletions(-) diff --git a/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs index 3281319..e00c19a 100644 --- a/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/LinqToSql/QueryBreakdownGenerator.cs @@ -8,23 +8,13 @@ namespace Strata.SqlTools.Markdown.LinqToSql; /// public class QueryBreakdownGenerator { - private readonly SqlServer.QueryBreakdownGenerator _baseGenerator; - - /// - /// Initializes a new instance of the QueryBreakdownGenerator class. - /// - public QueryBreakdownGenerator() - { - _baseGenerator = new SqlServer.QueryBreakdownGenerator(); - } - /// /// Generates a Mermaid flowchart diagram from a LINQ to SQL QueryBreakdown. /// /// The LINQ QueryBreakdown to visualize. /// Optional title for the diagram. /// A string containing the Mermaid markdown diagram. - public string GenerateMermaidDiagram(LinqQueryBreakdown queryBreakdown, string? title = null) + public static string GenerateMermaidDiagram(LinqQueryBreakdown queryBreakdown, string? title = null) { // Since LinqQueryBreakdown inherits from SqlServer.QueryBreakdown, // we can use the base generator which works with the shared properties @@ -85,7 +75,7 @@ public class QueryBreakdownGenerator /// The LINQ QueryBreakdown to visualize. /// Optional title for the diagram. /// A string containing both diagrams. - public string GenerateCombinedDiagram(LinqQueryBreakdown queryBreakdown, string? title = null) + public static string GenerateCombinedDiagram(LinqQueryBreakdown queryBreakdown, string? title = null) { var sb = new System.Text.StringBuilder(); diff --git a/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs b/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs index 2d76349..b3e8814 100644 --- a/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs +++ b/src/Strata.SqlTools.Markdown/LinqToSql/SqlStatementGenerator.cs @@ -10,23 +10,13 @@ namespace Strata.SqlTools.Markdown.LinqToSql; /// public class SqlStatementGenerator { - private readonly SqlServer.SqlStatementGenerator _baseGenerator; - - /// - /// Initializes a new instance of the SqlStatementGenerator class. - /// - public SqlStatementGenerator() - { - _baseGenerator = new SqlServer.SqlStatementGenerator(); - } - /// /// Generates a Mermaid sequence diagram showing LINQ to SQL statement execution flow. /// /// The LINQ to SQL breakdown object. /// Optional title for the diagram. /// A string containing the Mermaid sequence diagram markdown. - public string GenerateSequenceDiagram(ISqlBreakdown sqlBreakdown, string? title = null) + public static string GenerateSequenceDiagram(ISqlBreakdown sqlBreakdown, string? title = null) { return SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(sqlBreakdown, title); } @@ -37,7 +27,7 @@ public class SqlStatementGenerator /// The SQL breakdown containing query information. /// Optional title for the diagram. /// A string containing the Mermaid ER diagram markdown. - public string GenerateEntityRelationshipDiagram(ISqlBreakdown sqlBreakdown, string? title = null) + public static string GenerateEntityRelationshipDiagram(ISqlBreakdown sqlBreakdown, string? title = null) { //Extract table names from breakdown - just use FROM clause for now var queryBreakdown = sqlBreakdown as IQueryBreakdown; diff --git a/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs index e92bf27..f467bb1 100644 --- a/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/PostgreSql/QueryBreakdownGenerator.cs @@ -8,23 +8,13 @@ namespace Strata.SqlTools.Markdown.PostgreSql; /// public class QueryBreakdownGenerator { - private readonly SqlServer.QueryBreakdownGenerator _baseGenerator; - - /// - /// Initializes a new instance of the QueryBreakdownGenerator class. - /// - public QueryBreakdownGenerator() - { - _baseGenerator = new SqlServer.QueryBreakdownGenerator(); - } - /// /// Generates a Mermaid flowchart diagram from a PostgreSQL QueryBreakdown. /// /// The PostgreSQL QueryBreakdown to visualize. /// Optional title for the diagram. /// A string containing the Mermaid markdown diagram. - public string GenerateMermaidDiagram(QueryBreakdown queryBreakdown, string? title = null) + public static string GenerateMermaidDiagram(QueryBreakdown queryBreakdown, string? title = null) { // Since PostgreSql.QueryBreakdown inherits from SqlServer.QueryBreakdown, // we can use the base generator which works with the shared properties diff --git a/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs b/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs index c17bd25..dbcf677 100644 --- a/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs +++ b/src/Strata.SqlTools.Markdown/PostgreSql/SqlStatementGenerator.cs @@ -8,23 +8,13 @@ namespace Strata.SqlTools.Markdown.PostgreSql; /// public class SqlStatementGenerator { - private readonly SqlServer.SqlStatementGenerator _baseGenerator; - - /// - /// Initializes a new instance of the SqlStatementGenerator class. - /// - public SqlStatementGenerator() - { - _baseGenerator = new SqlServer.SqlStatementGenerator(); - } - /// /// Generates a Mermaid sequence diagram showing PostgreSQL SQL statement execution flow. /// /// The PostgreSQL SQL breakdown object. /// Optional title for the diagram. /// A string containing the Mermaid sequence diagram markdown. - public string GenerateSequenceDiagram(SqlBreakdownBase sqlBreakdown, string? title = null) + public static string GenerateSequenceDiagram(SqlBreakdownBase sqlBreakdown, string? title = null) { return SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(sqlBreakdown, title); } @@ -35,7 +25,7 @@ public class SqlStatementGenerator /// Collection of table names to include in the diagram. /// Optional title for the diagram. /// A string containing the Mermaid ER diagram markdown. - public string GenerateEntityRelationshipDiagram(IEnumerable tables, string? title = null) + public static string GenerateEntityRelationshipDiagram(IEnumerable tables, string? title = null) { return SqlServer.SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables, title); } diff --git a/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs index b01cbe8..c6d197a 100644 --- a/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/Snowflake/QueryBreakdownGenerator.cs @@ -8,23 +8,13 @@ namespace Strata.SqlTools.Markdown.Snowflake; /// public class QueryBreakdownGenerator { - private readonly SqlServer.QueryBreakdownGenerator _baseGenerator; - - /// - /// Initializes a new instance of the QueryBreakdownGenerator class. - /// - public QueryBreakdownGenerator() - { - _baseGenerator = new SqlServer.QueryBreakdownGenerator(); - } - /// /// Generates a Mermaid flowchart diagram from a Snowflake QueryBreakdown. /// /// The Snowflake QueryBreakdown to visualize. /// Optional title for the diagram. /// A string containing the Mermaid markdown diagram. - public string GenerateMermaidDiagram(QueryBreakdown queryBreakdown, string? title = null) + public static string GenerateMermaidDiagram(QueryBreakdown queryBreakdown, string? title = null) { // Since Snowflake.QueryBreakdown inherits from SqlServer.QueryBreakdown, // we can use the base generator which works with the shared properties diff --git a/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs b/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs index c246b35..c5abdd6 100644 --- a/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs +++ b/src/Strata.SqlTools.Markdown/Snowflake/SqlStatementGenerator.cs @@ -8,23 +8,13 @@ namespace Strata.SqlTools.Markdown.Snowflake; /// public class SqlStatementGenerator { - private readonly SqlServer.SqlStatementGenerator _baseGenerator; - - /// - /// Initializes a new instance of the SqlStatementGenerator class. - /// - public SqlStatementGenerator() - { - _baseGenerator = new SqlServer.SqlStatementGenerator(); - } - /// /// Generates a Mermaid sequence diagram showing Snowflake SQL statement execution flow. /// /// The Snowflake SQL breakdown object. /// Optional title for the diagram. /// A string containing the Mermaid sequence diagram markdown. - public string GenerateSequenceDiagram(SqlBreakdownBase sqlBreakdown, string? title = null) + public static string GenerateSequenceDiagram(SqlBreakdownBase sqlBreakdown, string? title = null) { return SqlServer.SqlStatementGenerator.GenerateSequenceDiagram(sqlBreakdown, title); } @@ -35,7 +25,7 @@ public class SqlStatementGenerator /// Collection of table names to include in the diagram. /// Optional title for the diagram. /// A string containing the Mermaid ER diagram markdown. - public string GenerateEntityRelationshipDiagram(IEnumerable tables, string? title = null) + public static string GenerateEntityRelationshipDiagram(IEnumerable tables, string? title = null) { return SqlServer.SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables, title); } diff --git a/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs b/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs index 1a02e09..a0f048d 100644 --- a/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs +++ b/src/Strata.SqlTools.Markdown/SqlServer/QueryBreakdownGenerator.cs @@ -127,7 +127,7 @@ public class QueryBreakdownGenerator /// The SQL breakdown to visualize. /// Optional title for the diagram. /// A string containing the Mermaid markdown diagram. - public string GenerateMermaidDiagram(ISqlBreakdown sqlBreakdown, string? title = null) + public static string GenerateMermaidDiagram(ISqlBreakdown sqlBreakdown, string? title = null) { // If it's a QueryBreakdown, use the specialized method if (sqlBreakdown is QueryBreakdown qb) diff --git a/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/QueryBreakdownGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/QueryBreakdownGeneratorTests.cs index d10d930..70d3ca4 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/QueryBreakdownGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/QueryBreakdownGeneratorTests.cs @@ -24,7 +24,7 @@ public class QueryBreakdownGeneratorTests var breakdown = LinqQueryBreakdown.Analyze(query); // Act - var result = _generator.GenerateMermaidDiagram(breakdown, "Simple User Query"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(breakdown, "Simple User Query"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -81,7 +81,7 @@ public class QueryBreakdownGeneratorTests var breakdown = LinqQueryBreakdown.Analyze(query); // Act - var result = _generator.GenerateCombinedDiagram(breakdown, "User Query Analysis"); + var result = QueryBreakdownGenerator.GenerateCombinedDiagram(breakdown, "User Query Analysis"); // Assert Assert.That(result, Does.Contain("## User Query Analysis")); @@ -99,7 +99,7 @@ public class QueryBreakdownGeneratorTests var breakdown = LinqQueryBreakdown.Analyze(query); // Act - var result = _generator.GenerateMermaidDiagram(breakdown); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(breakdown); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -114,7 +114,7 @@ public class QueryBreakdownGeneratorTests var breakdown = LinqQueryBreakdown.Analyze(query); // Act - var result = _generator.GenerateMermaidDiagram(breakdown, null); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(breakdown, null); // Assert Assert.That(result, Does.Not.Contain("###")); diff --git a/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/SqlStatementGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/SqlStatementGeneratorTests.cs index 5dafdfd..c043500 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/SqlStatementGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/LinqToSql/SqlStatementGeneratorTests.cs @@ -87,7 +87,7 @@ public class SqlStatementGeneratorTests var query = new LinqQueryBreakdown("*", "Users"); // Act - var result = _generator.GenerateSequenceDiagram(query, "Sequence Test"); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, "Sequence Test"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -102,7 +102,7 @@ public class SqlStatementGeneratorTests var query = new LinqQueryBreakdown("Id, Name", "Users"); // Act - var result = _generator.GenerateEntityRelationshipDiagram(query, "ER Test"); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(query, "ER Test"); // Assert Assert.That(result, Does.Contain("```mermaid")); diff --git a/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/QueryBreakdownGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/QueryBreakdownGeneratorTests.cs index 5a52ad2..371e6fe 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/QueryBreakdownGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/QueryBreakdownGeneratorTests.cs @@ -21,7 +21,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("user_id, user_name", "users"); // Act - var result = _generator.GenerateMermaidDiagram(query, "Simple User Query"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Simple User Query"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -44,7 +44,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("WHERE")); @@ -64,7 +64,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("WHERE")); @@ -89,7 +89,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query, "Users with Orders"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Users with Orders"); // Assert Assert.That(result, Does.Contain("### Users with Orders")); @@ -110,7 +110,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query, "Recent Users"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Recent Users"); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -131,7 +131,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -150,7 +150,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -185,7 +185,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query, "Regional Sales Analysis"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Regional Sales Analysis"); // Assert Assert.That(result, Does.Contain("### Regional Sales Analysis")); @@ -209,7 +209,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("GROUP BY")); @@ -223,7 +223,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("id", "orders"); // Act - var result = _generator.GenerateMermaidDiagram(query, null); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, null); // Assert Assert.That(result, Does.Not.Contain("###")); @@ -238,7 +238,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("order_id", "orders"); // Act - var result = _generator.GenerateMermaidDiagram(query, ""); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, ""); // Assert Assert.That(result, Does.Not.Contain("###")); @@ -258,7 +258,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query, "Type Cast Example"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Type Cast Example"); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -279,7 +279,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query, "JSON Data"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "JSON Data"); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -298,7 +298,7 @@ public class QueryBreakdownGeneratorTests "); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("SELECT")); diff --git a/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/SqlStatementGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/SqlStatementGeneratorTests.cs index 19cba8c..ee70a0a 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/SqlStatementGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/PostgreSql/SqlStatementGeneratorTests.cs @@ -25,7 +25,7 @@ public class SqlStatementGeneratorTests "); // Act - var result = _generator.GenerateSequenceDiagram(query, "User Query Flow"); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, "User Query Flow"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -51,7 +51,7 @@ public class SqlStatementGeneratorTests "); // Act - var result = _generator.GenerateSequenceDiagram(query); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query); // Assert Assert.That(result, Does.Contain("Execute Main Statement")); @@ -73,7 +73,7 @@ public class SqlStatementGeneratorTests "); // Act - var result = _generator.GenerateSequenceDiagram(query, "Sales Analysis"); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, "Sales Analysis"); // Assert Assert.That(result, Does.Contain("### Sales Analysis")); @@ -90,7 +90,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "customers", "orders", "order_items", "products" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables, "E-Commerce Schema"); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables, "E-Commerce Schema"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -109,7 +109,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "\"Customers\"", "\"Orders\"", "\"OrderItems\"" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables); // Assert Assert.That(result, Does.Contain("erDiagram")); @@ -123,7 +123,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "public.users", "sales.orders", "inventory.products" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables); // Assert Assert.That(result, Does.Contain("erDiagram")); @@ -137,7 +137,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "users" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables); // Assert Assert.That(result, Does.Contain("erDiagram")); @@ -151,7 +151,7 @@ public class SqlStatementGeneratorTests var query = new QueryBreakdown("order_id", "orders"); // Act - var result = _generator.GenerateSequenceDiagram(query, null); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, null); // Assert Assert.That(result, Does.Not.Contain("###")); @@ -170,7 +170,7 @@ public class SqlStatementGeneratorTests "); // Act - var result = _generator.GenerateSequenceDiagram(query); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query); // Assert Assert.That(result, Does.Contain("sequenceDiagram")); diff --git a/tests/Strata.SqlTools.Markdown.Tests/Snowflake/QueryBreakdownGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/Snowflake/QueryBreakdownGeneratorTests.cs index 69bb44c..189cd1c 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/Snowflake/QueryBreakdownGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/Snowflake/QueryBreakdownGeneratorTests.cs @@ -21,7 +21,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("USER_ID, USER_NAME", "USERS"); // Act - var result = _generator.GenerateMermaidDiagram(query, "Simple User Query"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Simple User Query"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -44,7 +44,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("WHERE")); @@ -69,7 +69,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query, "Users with Orders"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Users with Orders"); // Assert Assert.That(result, Does.Contain("WITH Clause")); @@ -92,7 +92,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query, "Latest Orders per Customer"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Latest Orders per Customer"); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -111,7 +111,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -146,7 +146,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query, "Regional Sales Analysis"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Regional Sales Analysis"); // Assert Assert.That(result, Does.Contain("### Regional Sales Analysis")); @@ -171,7 +171,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("GROUP BY")); @@ -185,7 +185,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("ID", "ORDERS"); // Act - var result = _generator.GenerateMermaidDiagram(query, null); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, null); // Assert Assert.That(result, Does.Not.Contain("###")); @@ -200,7 +200,7 @@ public class QueryBreakdownGeneratorTests var query = new QueryBreakdown("ORDER_ID", "ORDERS"); // Act - var result = _generator.GenerateMermaidDiagram(query, ""); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, ""); // Assert Assert.That(result, Does.Not.Contain("###")); @@ -220,7 +220,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query, "Type Cast Example"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Type Cast Example"); // Assert Assert.That(result, Does.Contain("SELECT")); @@ -241,7 +241,7 @@ public class QueryBreakdownGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateMermaidDiagram(query, "JSON Data"); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "JSON Data"); // Assert Assert.That(result, Does.Contain("SELECT")); diff --git a/tests/Strata.SqlTools.Markdown.Tests/Snowflake/SqlStatementGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/Snowflake/SqlStatementGeneratorTests.cs index 9b7ac68..9e4173a 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/Snowflake/SqlStatementGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/Snowflake/SqlStatementGeneratorTests.cs @@ -25,7 +25,7 @@ public class SqlStatementGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateSequenceDiagram(query, "User Query Flow"); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, "User Query Flow"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -51,7 +51,7 @@ public class SqlStatementGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateSequenceDiagram(query); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query); // Assert Assert.That(result, Does.Contain("Execute Main Statement")); @@ -73,7 +73,7 @@ public class SqlStatementGeneratorTests ", isMicrosoftSql: false); // Act - var result = _generator.GenerateSequenceDiagram(query, "Sales Analysis"); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, "Sales Analysis"); // Assert Assert.That(result, Does.Contain("### Sales Analysis")); @@ -90,7 +90,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "CUSTOMERS", "ORDERS", "ORDER_ITEMS", "PRODUCTS" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables, "E-Commerce Schema"); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables, "E-Commerce Schema"); // Assert Assert.That(result, Does.Contain("```mermaid")); @@ -109,7 +109,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "\"customers\"", "\"orders\"", "\"orderItems\"" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables); // Assert Assert.That(result, Does.Contain("erDiagram")); @@ -123,7 +123,7 @@ public class SqlStatementGeneratorTests var tables = new[] { "USERS" }; // Act - var result = _generator.GenerateEntityRelationshipDiagram(tables); + var result = SqlStatementGenerator.GenerateEntityRelationshipDiagram(tables); // Assert Assert.That(result, Does.Contain("erDiagram")); @@ -137,7 +137,7 @@ public class SqlStatementGeneratorTests var query = new QueryBreakdown("ORDER_ID", "ORDERS"); // Act - var result = _generator.GenerateSequenceDiagram(query, null); + var result = SqlStatementGenerator.GenerateSequenceDiagram(query, null); // Assert Assert.That(result, Does.Not.Contain("###")); diff --git a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs index d92bcce..b3d8e60 100644 --- a/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs +++ b/tests/Strata.SqlTools.Markdown.Tests/SqlServer/QueryBreakdownGeneratorTests.cs @@ -144,7 +144,7 @@ public class QueryBreakdownGeneratorTests query.SetupClauses.Add("CREATE TEMP TABLE #Temp (ID INT)"); // Act - var result = _generator.GenerateMermaidDiagram((Interfaces.ISqlBreakdown)query); + var result = QueryBreakdownGenerator.GenerateMermaidDiagram((Interfaces.ISqlBreakdown)query); // Assert Assert.That(result, Does.Contain("mermaid")); -- 2.54.0