From 4408692d7c6b359227cb3780da65a3194767ee98 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sat, 3 Jul 2021 22:05:51 +0930 Subject: [PATCH] InlineFormatter: Optionally support spacing around commas (#549) Fixes #539 Default is enabled, like the existing GetReadableCommand logic. --- docs/Releases.md | 4 + .../SqlFormatters/InlineFormatter.cs | 11 +++ .../SqlFormatters/SqlFormatterExtensions.cs | 2 +- .../SqlFormatters/SqlServerFormatter.cs | 13 ++++ tests/MiniProfiler.Tests/SqlFormatterTests.cs | 73 ++++++++++++++++++- 5 files changed, 101 insertions(+), 2 deletions(-) diff --git a/docs/Releases.md b/docs/Releases.md index 292e92514..067fb8f09 100644 --- a/docs/Releases.md +++ b/docs/Releases.md @@ -5,6 +5,10 @@ layout: "default" ### Release Notes This page tracks major changes included in any update starting with version 4.0.0.3 +#### Unreleased +- **New**: + - Added an option to control `SpacesAfterCommas` to `InlineSqlFormatter` and `SqlServerFormatter` ([#549](https://github.com/MiniProfiler/dotnet/pull/549) - thanks [Turnerj](https://github.com/Turnerj)) + #### Version 4.2.1 - **New**: - Added RavenDB Storage provider ([#483](https://github.com/MiniProfiler/dotnet/pull/483) - thanks [@lillo42](https://github.com/lillo42)!) diff --git a/src/MiniProfiler.Shared/SqlFormatters/InlineFormatter.cs b/src/MiniProfiler.Shared/SqlFormatters/InlineFormatter.cs index 34d5cc6a9..531f8e705 100644 --- a/src/MiniProfiler.Shared/SqlFormatters/InlineFormatter.cs +++ b/src/MiniProfiler.Shared/SqlFormatters/InlineFormatter.cs @@ -9,8 +9,14 @@ namespace StackExchange.Profiling.SqlFormatters /// public class InlineFormatter : ISqlFormatter { + private static readonly Regex CommandSpacing = new Regex(@",([^\s])", RegexOptions.Compiled); private static bool includeTypeInfo; + /// + /// Whether to modify the output query by adding spaces after commas. + /// + public bool InsertSpacesAfterCommas { get; set; } = true; + /// /// Creates a new , optionally including the parameter type info /// in comments beside the replaced value @@ -34,6 +40,11 @@ public string FormatSql(string commandText, List parameters) return commandText; } + if (InsertSpacesAfterCommas) + { + commandText = CommandSpacing.Replace(commandText, ", $1"); + } + var paramValuesByName = new Dictionary(parameters.Count); foreach (var p in parameters) { diff --git a/src/MiniProfiler.Shared/SqlFormatters/SqlFormatterExtensions.cs b/src/MiniProfiler.Shared/SqlFormatters/SqlFormatterExtensions.cs index fe6c8efea..d713dc3a1 100644 --- a/src/MiniProfiler.Shared/SqlFormatters/SqlFormatterExtensions.cs +++ b/src/MiniProfiler.Shared/SqlFormatters/SqlFormatterExtensions.cs @@ -35,7 +35,7 @@ public static string GetFormattedSql(this ISqlFormatter sqlFormatter, string com /// The being represented. public static string GetFormattedSql(this ISqlFormatter sqlFormatter, IDbCommand command) { - var commandText = command.GetReadableCommand(); + var commandText = command.CommandText; var parameters = command.GetParameters(); return sqlFormatter.GetFormattedSql(commandText, parameters, command); diff --git a/src/MiniProfiler.Shared/SqlFormatters/SqlServerFormatter.cs b/src/MiniProfiler.Shared/SqlFormatters/SqlServerFormatter.cs index 0b835ff74..0d7d42ab6 100644 --- a/src/MiniProfiler.Shared/SqlFormatters/SqlServerFormatter.cs +++ b/src/MiniProfiler.Shared/SqlFormatters/SqlServerFormatter.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Text; +using System.Text.RegularExpressions; namespace StackExchange.Profiling.SqlFormatters { @@ -12,11 +13,18 @@ namespace StackExchange.Profiling.SqlFormatters /// public class SqlServerFormatter : ISqlFormatter { + private static readonly Regex CommandSpacing = new Regex(@",([^\s])", RegexOptions.Compiled); + /// /// Whether to include parameter declarations in the formatted output. /// public bool IncludeParameterValues { get; set; } = true; + /// + /// Whether to modify the output query by adding spaces after commas. + /// + public bool InsertSpacesAfterCommas { get; set; } = true; + /// /// Lookup a function for translating a parameter by parameter type /// @@ -112,6 +120,11 @@ public virtual string FormatSql(string commandText, List par .Append("\n\n"); } + if (InsertSpacesAfterCommas) + { + commandText = CommandSpacing.Replace(commandText, ", $1"); + } + // only treat 'StoredProcedure' differently since 'Text' may contain 'TableDirect' or 'StoredProcedure' if (command?.CommandType == CommandType.StoredProcedure) { diff --git a/tests/MiniProfiler.Tests/SqlFormatterTests.cs b/tests/MiniProfiler.Tests/SqlFormatterTests.cs index df5586a84..c2ac8c73f 100644 --- a/tests/MiniProfiler.Tests/SqlFormatterTests.cs +++ b/tests/MiniProfiler.Tests/SqlFormatterTests.cs @@ -101,7 +101,6 @@ public void InlineParameterNamesInParameterValues() var formatted = formatter.FormatSql(command, parameters); Assert.Equal("SELECT * FROM urls WHERE url = 'http://www.example.com?myid=1' OR myid = '1'", formatted); } - [Fact] public void InlineParameterValuesDisplayNullForStrings() { @@ -116,6 +115,40 @@ public void InlineParameterValuesDisplayNullForStrings() Assert.Equal("SELECT * FROM urls WHERE url = 'http://www.example.com?myid=1' OR null IS NULL", formatted); } + [Fact] + public void InlineSpacesAfterCommasEnabled() + { + var formatter = new InlineFormatter() + { + InsertSpacesAfterCommas = true + }; + var parameters = new List + { + new SqlTimingParameter() { DbType = "string", Name = "url", Value = "http://www.example.com?myid=1" }, + new SqlTimingParameter() { DbType = "string", Name = "myid", Value = "1" } + }; + const string command = "SELECT myid,url FROM urls WHERE url = @url OR myid = @myid"; + var formatted = formatter.FormatSql(command, parameters); + Assert.Equal("SELECT myid, url FROM urls WHERE url = 'http://www.example.com?myid=1' OR myid = '1'", formatted); + } + + [Fact] + public void InlineSpacesAfterCommasDisabled() + { + var formatter = new InlineFormatter() + { + InsertSpacesAfterCommas = false + }; + var parameters = new List + { + new SqlTimingParameter() { DbType = "string", Name = "url", Value = "http://www.example.com?myid=1" }, + new SqlTimingParameter() { DbType = "string", Name = "myid", Value = "1" } + }; + const string command = "SELECT myid,url FROM urls WHERE url = @url OR myid = @myid"; + var formatted = formatter.FormatSql(command, parameters); + Assert.Equal("SELECT myid,url FROM urls WHERE url = 'http://www.example.com?myid=1' OR myid = '1'", formatted); + } + [Fact] public void EnsureVerboseSqlServerFormatterOnlyAddsInformation() { @@ -226,6 +259,44 @@ public void TableQueryWithTwoParametersDisabled(string at) Assert.Equal(expectedOutput, actualOutput); } + [Theory] + [MemberData(nameof(GetParamPrefixes))] + public void TableQueryWithSpacesAfterCommasEnabled(string at) + { + const string text = "select 1 from dbo.Table where x = @x,y = @y"; + var cmd = CreateDbCommand(CommandType.Text, text); + AddDbParameter(cmd, at + "x", 123); + AddDbParameter(cmd, at + "y", 123); + + var formatter = new SqlServerFormatter() + { + InsertSpacesAfterCommas = true + }; + var actualOutput = GenerateOutput(formatter, cmd, text); + + const string expectedOutput = "DECLARE @x int = 123,\n @y bigint = 123;\n\nselect 1 from dbo.Table where x = @x, y = @y;"; + Assert.Equal(expectedOutput, actualOutput); + } + + [Theory] + [MemberData(nameof(GetParamPrefixes))] + public void TableQueryWithSpacesAfterCommasDisabled(string at) + { + const string text = "select 1 from dbo.Table where x = @x,y = @y"; + var cmd = CreateDbCommand(CommandType.Text, text); + AddDbParameter(cmd, at + "x", 123); + AddDbParameter(cmd, at + "y", 123); + + var formatter = new SqlServerFormatter() + { + InsertSpacesAfterCommas = false + }; + var actualOutput = GenerateOutput(formatter, cmd, text); + + const string expectedOutput = "DECLARE @x int = 123,\n @y bigint = 123;\n\nselect 1 from dbo.Table where x = @x,y = @y;"; + Assert.Equal(expectedOutput, actualOutput); + } + [Theory] [MemberData(nameof(GetParamPrefixes))] public void TableQueryWithBit(string at)