From f5d539b906ebd88b5a75272369c8502a9a208792 Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Tue, 26 May 2026 15:45:16 -0500 Subject: [PATCH] chore(sonar): hoist constant array literals to static readonly fields (CA1861) Applied via `dotnet format analyzers --diagnostics CA1861 --severity info`, plus manual cleanup: - Renamed two cryptic fixer-generated field names: - QueryBreakdownCollection.stringArray -> SnowflakeFunctionNames (and inlined the now-redundant local alias) - ExpressionObjectTests.arg2 -> NotInValues - Deduped three identical `separator = ['\r','\n']` fields the fixer emitted in the same test class (kept the first declaration; the other two test methods now reuse it). 8 files touched. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Breakdowns/QueryBreakdownCollection.cs | 21 +++++++++---------- .../Utilities/SqlUtils.cs | 3 ++- .../Statements/StatementParser.cs | 3 ++- .../LinqQueryBreakdownTests.cs | 3 ++- .../Snowflake/QueryBreakdownTests.cs | 8 ++++--- .../ExpressionFactoryFilterTests.cs | 4 +++- .../ExpressionTests/ExpressionObjectTests.cs | 4 +++- .../QueryBreakdownExtensionsTests.cs | 4 +++- 8 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdownCollection.cs b/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdownCollection.cs index e4d469f..7875456 100644 --- a/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdownCollection.cs +++ b/src/Strata.SqlTools.Snowflake/Breakdowns/QueryBreakdownCollection.cs @@ -182,6 +182,15 @@ public class QueryBreakdownCollection : SqlServer.QueryBreakdownCollectionBase /// Filters queries that use Snowflake functions (PARSE_JSON, OBJECT_INSERT, ARRAY, etc.). /// @@ -191,17 +200,7 @@ public class QueryBreakdownCollection : SqlServer.QueryBreakdownCollectionBase { var sql = q.GetSql().ToUpperInvariant(); - - var snowflakeFunctions = new[] - { - "PARSE_JSON", "OBJECT_INSERT", "ARRAY_CONSTRUCT", "ARRAY_AGG", - "FLATTEN", "GET_PATH", "TRY_PARSE_JSON", "JSON_EXTRACT_PATH_TEXT", - "JSON_EXTRACT_PATH_WITH_DEFAULT", "HASHAGGREGATE", "LISTAGG", - "APPROX_COUNT_DISTINCT", "APPROX_PERCENTILE", "GREATEST", "LEAST", - "NULLIF", "ZEROIFNULL", "STRTOK", "SPLIT_PART", "PIVOT", "UNPIVOT" - }; - - return snowflakeFunctions.Any(func => sql.Contains(func)); + return SnowflakeFunctionNames.Any(func => sql.Contains(func)); }); } diff --git a/src/Strata.SqlTools.SqlBreakdown/Utilities/SqlUtils.cs b/src/Strata.SqlTools.SqlBreakdown/Utilities/SqlUtils.cs index ec6d6ee..fb3c1fd 100644 --- a/src/Strata.SqlTools.SqlBreakdown/Utilities/SqlUtils.cs +++ b/src/Strata.SqlTools.SqlBreakdown/Utilities/SqlUtils.cs @@ -23,6 +23,7 @@ public static partial class SqlUtils public const string DATETIME_INSERT_FORMAT = "yyyyMMdd HH:mm:ss"; private const string DEFAULT_SCHEMA = "dbo"; + private static readonly char[] separator = new[] { ',' }; #region SQL String Manipulation @@ -34,7 +35,7 @@ public static partial class SqlUtils public static string StripColumnTableAlias(string sql) { // Break sql into words and remove "abc." from each column - string[] commaWords = sql.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + string[] commaWords = sql.Split(separator, StringSplitOptions.RemoveEmptyEntries); var newParts = new List(); foreach (string commaWord in commaWords) diff --git a/src/Strata.SqlTools.SqlServer/Statements/StatementParser.cs b/src/Strata.SqlTools.SqlServer/Statements/StatementParser.cs index 7bf7db3..79a6383 100644 --- a/src/Strata.SqlTools.SqlServer/Statements/StatementParser.cs +++ b/src/Strata.SqlTools.SqlServer/Statements/StatementParser.cs @@ -21,6 +21,7 @@ public class StatementParser public const string KeywordGroupBy = "GROUP BY"; public const string KeywordHaving = "HAVING"; public const string KeywordOrderBy = "ORDER BY"; + private static readonly char[] separator = new[] { '\r', '\n' }; #endregion @@ -50,7 +51,7 @@ public class StatementParser // Replace multiple spaces/tabs with single space, but preserve newlines for comment handling sql = Regex.Replace(sql, @"[ \t]+", " ", RegexOptions.None, RegexDefaults.MatchTimeout); // Remove leading/trailing whitespace from each line - var lines = sql.Split(new[] { '\r', '\n' }, StringSplitOptions.None); + var lines = sql.Split(separator, StringSplitOptions.None); sql = string.Join("\n", lines.Select(line => line.Trim())); return sql.Trim(); } diff --git a/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs b/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs index e507480..3464611 100644 --- a/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs +++ b/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownTests.cs @@ -7,6 +7,7 @@ namespace Strata.SqlTools.LinqToSql.Tests; public class LinqQueryBreakdownTests { private TestDataContext _context = null!; + private static readonly string[] separator = new[] { "AND" }; [SetUp] public void Setup() @@ -303,7 +304,7 @@ public class LinqQueryBreakdownTests Assert.That(filterSql, Does.Contain("IsActive = 1")); // Should have multiple AND conditions - var andCount = filterSql.Split(new[] { "AND" }, StringSplitOptions.None).Length - 1; + var andCount = filterSql.Split(separator, StringSplitOptions.None).Length - 1; Assert.That(andCount, Is.GreaterThanOrEqualTo(2)); } diff --git a/tests/Strata.SqlTools.Snowflake.Tests/Snowflake/QueryBreakdownTests.cs b/tests/Strata.SqlTools.Snowflake.Tests/Snowflake/QueryBreakdownTests.cs index 28a97ec..58848b7 100644 --- a/tests/Strata.SqlTools.Snowflake.Tests/Snowflake/QueryBreakdownTests.cs +++ b/tests/Strata.SqlTools.Snowflake.Tests/Snowflake/QueryBreakdownTests.cs @@ -98,6 +98,8 @@ public class QueryBreakdownTests Assert.That(sql, Does.Contain("ORDER BY")); } + private static readonly char[] separator = new[] { '\r', '\n' }; + [Test] public void GetSql_WithSingleWithClause_UsesSnowflakeIndentation() { @@ -114,7 +116,7 @@ public class QueryBreakdownTests Assert.That(sql, Does.Contain("WITH")); Assert.That(sql, Does.Contain("PRODUCT_SUMMARY AS (")); // Verify 4-space Snowflake indentation - var lines = sql.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + var lines = sql.Split(separator, StringSplitOptions.RemoveEmptyEntries); var indentedLines = lines.Where(l => l.StartsWith(" ")).ToList(); Assert.That(indentedLines.Count, Is.GreaterThan(0)); } @@ -1118,7 +1120,7 @@ public class QueryBreakdownTests _ = baseQueryBreakdown.GetSql(); // Assert - Snowflake should use 4-space indent, base uses 5-space - var snowflakeLines = snowflakeSql.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + var snowflakeLines = snowflakeSql.Split(separator, StringSplitOptions.RemoveEmptyEntries); var snowflakeIndentedLines = snowflakeLines.Where(l => l.StartsWith(" ") && !l.StartsWith(" ")).ToList(); Assert.That(snowflakeIndentedLines.Count, Is.GreaterThan(0), "Snowflake should use 4-space indentation"); } @@ -1322,7 +1324,7 @@ public class QueryBreakdownTests Assert.That(snowflakeSql, Does.Contain("WHERE")); Assert.That(snowflakeSql, Does.Contain("ORDER BY")); // Verify Snowflake-style formatting (4-space indentation) - var lines = snowflakeSql.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + var lines = snowflakeSql.Split(separator, StringSplitOptions.RemoveEmptyEntries); var indentedLines = lines.Where(l => l.StartsWith(" ")).ToList(); Assert.That(indentedLines.Count, Is.GreaterThan(0), "Should have Snowflake-style indentation"); } diff --git a/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionFactoryFilterTests.cs b/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionFactoryFilterTests.cs index dc9f9ee..25ce2f1 100644 --- a/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionFactoryFilterTests.cs +++ b/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionFactoryFilterTests.cs @@ -5,6 +5,8 @@ namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests; [TestFixture] public class ExpressionFactoryFilterTests : ExpressionTestsBase { + private static readonly string[] values = new[] { "FY2019", "FY2020", "FY2021", "FY2022" }; + private static IEnumerable FilterTestCases() { var dischargeDate = DateTime.Now.Date.AddMonths(1); @@ -16,7 +18,7 @@ public class ExpressionFactoryFilterTests : ExpressionTestsBase ).SetName("ListFilterContinuous_{m}"); yield return new TestCaseData( - new Filter(4, FilterType.List, new[] { "FY2019", "FY2020", "FY2021", "FY2022" }, Array.Empty(), DatePart.FiscalYear, false, 0, 0), + new Filter(4, FilterType.List, values, Array.Empty(), DatePart.FiscalYear, false, 0, 0), "(DEPT.DISCHARGE_DATE >= '2018-07-01' AND DEPT.DISCHARGE_DATE < '2019-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2019-07-01' AND DEPT.DISCHARGE_DATE < '2020-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2020-07-01' AND DEPT.DISCHARGE_DATE < '2021-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2021-07-01' AND DEPT.DISCHARGE_DATE < '2022-07-01')" ).SetName("DateListFilterFiscalYear_{m}"); diff --git a/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionObjectTests.cs b/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionObjectTests.cs index 5aa05b2..ed6af05 100644 --- a/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionObjectTests.cs +++ b/tests/Strata.SqlTools.SqlBreakdown.Tests/ExpressionTests/ExpressionObjectTests.cs @@ -29,6 +29,8 @@ public class ExpressionObjectTests : ExpressionTestsBase Assert.That(paramExp.ParameterName, Is.EqualTo("MY_PARAM")); } + private static readonly string[] NotInValues = new[] { "value1", "value2", "value3" }; + private static IEnumerable ComparisonExpressionTestCases() { yield return new TestCaseData("GreaterThanOrEqual", 250, typeof(GreaterThanOrEqualToExpression)) @@ -40,7 +42,7 @@ public class ExpressionObjectTests : ExpressionTestsBase yield return new TestCaseData("Equals", "TestDept", typeof(EqualToExpression)) .SetName("Equals_{m}"); - yield return new TestCaseData("NotIn", new[] { "value1", "value2", "value3" }, typeof(NotInExpression)) + yield return new TestCaseData("NotIn", NotInValues, typeof(NotInExpression)) .SetName("NotIn_{m}"); yield return new TestCaseData("Like", "%pattern%", typeof(LikeExpression)) diff --git a/tests/Strata.SqlTools.SqlBreakdown.Tests/Extensions/QueryBreakdownExtensionsTests.cs b/tests/Strata.SqlTools.SqlBreakdown.Tests/Extensions/QueryBreakdownExtensionsTests.cs index 5061e75..8b4185e 100644 --- a/tests/Strata.SqlTools.SqlBreakdown.Tests/Extensions/QueryBreakdownExtensionsTests.cs +++ b/tests/Strata.SqlTools.SqlBreakdown.Tests/Extensions/QueryBreakdownExtensionsTests.cs @@ -243,12 +243,14 @@ public class QueryBreakdownExtensionsTests Assert.That(query.WithClauses[1].TableName, Is.EqualTo("recent_orders")); } + private static readonly string[] columns = new[] { "id", "name", "email" }; + [Test] public void WithCte_WithColumnList_AddsCtesWithColumns() { // Arrange & Act var query = new QueryBreakdown() - .WithCte("active_users", new[] { "id", "name", "email" }, cte => cte + .WithCte("active_users", columns, cte => cte .Select("user_id, user_name, user_email") .From("users") .Where("status = 'active'"))