Skip to content

Commit

Permalink
Merge pull request #550 from mk3008/547-request-support-for-leading-c…
Browse files Browse the repository at this point in the history
…omma-sql-formatting

Support for Leading Comma SQL Formatting
  • Loading branch information
mk3008 authored Oct 20, 2024
2 parents 23057c7 + d02df78 commit 8982cf7
Show file tree
Hide file tree
Showing 10 changed files with 415 additions and 101 deletions.
52 changes: 44 additions & 8 deletions demo/CarbunqlWeb/Pages/Format.razor
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,21 @@
</RadzenCard>
</div>
</div>

</RadzenTabsItem>
<RadzenTabsItem Text="Config">
<div class="row">
<div class="col-md-6 p-3">
<RadzenCard>
<RadzenText TextStyle="TextStyle.Subtitle2">Comma formatting</RadzenText>
<RadzenRadioButtonList @bind-Value=@formatting TValue="commaFormatting" class="mb-5" Change=@OnFormattingChange>
<Items>
<RadzenRadioButtonListItem Text="Leading" Value=commaFormatting.Leading />
<RadzenRadioButtonListItem Text="Trailing" Value=commaFormatting.Traiging />
</Items>
</RadzenRadioButtonList>
</RadzenCard>
</div>
</div>
</RadzenTabsItem>
<RadzenTabsItem Text="Source">
<RadzenText Style="font-family: 'Ricty Diminished', SFMono-Regular, Consolas, 'Courier New', 'BIZ UDGothic', Meiryo, monospace; font-size: 18px; white-space: pre;" ReadOnly="true" >using Carbunql;
Expand All @@ -40,17 +54,39 @@ var sql = QueryCommandableParser.Parse("select id, val from table_a as a")

@code {

enum commaFormatting{
Leading,
Traiging,
}

commaFormatting formatting ;

string fsql = string.Empty;

protected override void OnInitialized()
{
OnChange(sql);
}
{
formatting = CommandTextBuilder.FORMATTER switch
{
LeadingCommaTokenFormattingLogic => commaFormatting.Leading,
_ => commaFormatting.Traiging
};
OnChange(sql);
}

void OnClear()
{
sql = string.Empty;
OnChange(sql);
void OnClear()
{
sql = string.Empty;
OnChange(sql);
}

void OnFormattingChange()
{
CommandTextBuilder.FORMATTER = formatting switch
{
commaFormatting.Leading => new LeadingCommaTokenFormattingLogic(),
_ => new TrailingCommaTokenFormattingLogic()
};
OnChange(sql);
}

void OnChange(string value)
Expand Down
8 changes: 7 additions & 1 deletion src/Carbunql.sln
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.DynamicColumn", "..\de
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.DatasourceCompare", "..\demo\DatasourceCompare\Demo.DatasourceCompare.csproj", "{474E5EDD-E41E-4394-B2E5-F1DF745F75E7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Carbunql.Fluent.Test", "..\test\Carbunql.Fluent.Test\Carbunql.Fluent.Test.csproj", "{596E923B-6E21-4A17-9E83-50B5DE44EBD6}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Carbunql.Fluent.Test", "..\test\Carbunql.Fluent.Test\Carbunql.Fluent.Test.csproj", "{596E923B-6E21-4A17-9E83-50B5DE44EBD6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Carbunql.Formatting.Test.LeadingCommaFormatting", "..\test\Carbunql.Formatting.Test\Carbunql.Formatting.Test.LeadingCommaFormatting.csproj", "{AD43B45C-0FA1-46D5-862C-7EF1DDB1E5EF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -147,6 +149,10 @@ Global
{596E923B-6E21-4A17-9E83-50B5DE44EBD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{596E923B-6E21-4A17-9E83-50B5DE44EBD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{596E923B-6E21-4A17-9E83-50B5DE44EBD6}.Release|Any CPU.Build.0 = Release|Any CPU
{AD43B45C-0FA1-46D5-862C-7EF1DDB1E5EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD43B45C-0FA1-46D5-862C-7EF1DDB1E5EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD43B45C-0FA1-46D5-862C-7EF1DDB1E5EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD43B45C-0FA1-46D5-862C-7EF1DDB1E5EF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion src/Carbunql/Carbunql.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Title></Title>
<Copyright>mk3008net</Copyright>
<Description>Carbunql is an advanced Raw SQL editing library.</Description>
<Version>0.8.12</Version>
<Version>0.8.13</Version>
<Authors>mk3008net</Authors>
<PackageProjectUrl>https://github.com/mk3008/Carbunql</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
34 changes: 16 additions & 18 deletions src/Carbunql/CommandTextBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,8 @@ namespace Carbunql;
/// </summary>
public class CommandTextBuilder
{
/// <summary>
/// Initializes a new instance of the <see cref="CommandTextBuilder"/> class with the specified formatter.
/// </summary>
/// <param name="formatter">The token format logic to use.</param>
public CommandTextBuilder(TokenFormatLogic formatter)
{
Formatter = formatter;
}

/// <summary>
/// Initializes a new instance of the <see cref="CommandTextBuilder"/> class with a default formatter.
/// </summary>
public CommandTextBuilder()
{
Formatter = new TokenFormatLogic();
}

/// <summary>
Expand All @@ -33,7 +20,7 @@ public CommandTextBuilder()
/// <summary>
/// Gets the token format logic used by the builder.
/// </summary>
public TokenFormatLogic Formatter { get; init; }
public static ITokenFormattingLogic FORMATTER { get; set; } = new TrailingCommaTokenFormattingLogic();

private Token? PrevToken { get; set; }

Expand Down Expand Up @@ -84,7 +71,7 @@ public string Execute(IEnumerable<Token> tokens)

if (t.Parents().Count() > PrevToken.Parents().Count())
{
if (t.Parent != null && Formatter.IsIncrementIndentOnBeforeWriteToken(t.Parent))
if (t.Parent != null && FORMATTER.IsIncrementIndentOnBeforeWriteToken(t.Parent))
{
Logger?.Invoke($"increment indent and line break on before : {t.Text}");
Level++;
Expand All @@ -95,7 +82,7 @@ public string Execute(IEnumerable<Token> tokens)
continue;
}

if (Formatter.IsDecrementIndentOnBeforeWriteToken(t))
if (FORMATTER.IsDecrementIndentOnBeforeWriteToken(t))
{
var q = IndentLevels.Where(x => x.Token != null && x.Token.Equals(t.Parent)).Select(x => x.Level);
var lv = 0;
Expand All @@ -122,12 +109,12 @@ private IEnumerable<string> GetTokenTexts(Token? token)
if (token == null) yield break;
if (string.IsNullOrEmpty(token.Text)) yield break;

if (PrevToken != null && Formatter.IsLineBreakOnBeforeWriteToken(token))
if (PrevToken != null && FORMATTER.IsLineBreakOnBeforeWriteToken(token))
{
yield return GetLineBreakText();
}
yield return GetTokenTextCore(token);
if (Formatter.IsLineBreakOnAfterWriteToken(token))
if (FORMATTER.IsLineBreakOnAfterWriteToken(token))
{
yield return GetLineBreakText();
}
Expand Down Expand Up @@ -179,3 +166,14 @@ private string GetLineBreakText()
return "\r\n" + SpacerCache[Level];
}
}

public interface ITokenFormattingLogic
{
bool IsIncrementIndentOnBeforeWriteToken(Token token);

bool IsDecrementIndentOnBeforeWriteToken(Token token);

bool IsLineBreakOnBeforeWriteToken(Token token);

bool IsLineBreakOnAfterWriteToken(Token token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Carbunql;
/// <summary>
/// Provides logic for formatting tokens in query writing.
/// </summary>
public class TokenFormatLogic
public class LeadingCommaTokenFormattingLogic : ITokenFormattingLogic
{
/// <summary>
/// Gets or sets the logger action for logging.
Expand All @@ -30,6 +30,22 @@ public virtual bool IsLineBreakOnBeforeWriteToken(Token token)

if (token.Text.Equals(",") && token.Sender is Relation) return false;

if (token.Text.Equals(","))
{
if (token.Sender is WithClause) return true;
if (token.Sender is WindowClause) return true;
if (token.Sender is SelectClause) return true;
if (token.Sender is Relation) return true;
if (token.Sender is GroupClause) return true;
if (token.Sender is OrderClause) return true;
if (token.Sender is ValuesQuery) return true;
if (token.Sender is SetClause) return true;
if (token.Sender is PartitionClause) return true;
if (token.Sender is TableDefinitionClause) return true;
if (token.Sender is IndexOnClause) return true;
if (token.Sender is AlterTableClause) return true;
}

if (token.Text.IsEqualNoCase("as") && token.Sender is CreateTableQuery) return true;

if (!token.Text.IsEqualNoCase("on") && token.Sender is Relation) return true;
Expand Down Expand Up @@ -58,24 +74,6 @@ public virtual bool IsLineBreakOnAfterWriteToken(Token token)

if (token.Text.Equals("*/")) return true;

if (token.Text.Equals(","))
{
if (token.Sender is WithClause) return true;
if (token.Sender is WindowClause) return true;
if (token.Sender is SelectClause) return true;
if (token.Sender is Relation) return true;
if (token.Sender is GroupClause) return true;
if (token.Sender is OrderClause) return true;
if (token.Sender is ValuesQuery) return true;
if (token.Sender is SetClause) return true;
if (token.Sender is PartitionClause) return true;
if (token.Sender is TableDefinitionClause) return true;
if (token.Sender is IndexOnClause) return true;
if (token.Sender is AlterTableClause) return true;
}



return false;
}

Expand Down
124 changes: 124 additions & 0 deletions src/Carbunql/TrailingCommaTokenFormattingLogic.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using Carbunql.Clauses;
using Carbunql.Extensions;
using Carbunql.Tables;
using Carbunql.Values;

namespace Carbunql;

/// <summary>
/// Provides logic for formatting tokens in query writing.
/// </summary>
public class TrailingCommaTokenFormattingLogic : ITokenFormattingLogic
{
/// <summary>
/// Gets or sets the logger action for logging.
/// </summary>
public Action<string>? Logger { get; set; }

/// <summary>
/// Determines whether a line break should occur before writing the specified token.
/// </summary>
/// <param name="token">The token to evaluate.</param>
/// <returns>True if a line break is required before writing the token; otherwise, false.</returns>
public virtual bool IsLineBreakOnBeforeWriteToken(Token token)
{
if (token.Text.IsEqualNoCase("with")) return true;
if (token.Text.IsEqualNoCase("window")) return true;
if (token.Text.IsEqualNoCase("select")) return true;

if (token.Text.Equals("/*")) return true;

if (token.Text.Equals(",") && token.Sender is Relation) return false;

if (token.Text.IsEqualNoCase("as") && token.Sender is CreateTableQuery) return true;

if (!token.Text.IsEqualNoCase("on") && token.Sender is Relation) return true;
if (token.Text.IsEqualNoCase("else") || token.Text.IsEqualNoCase("when")) return true;
if (token.Text.IsEqualNoCase("and"))
{
if (token.Sender is BetweenClause) return false;
if (token.Parent != null && token.Parent.Sender is WhereClause) return true;
if (token.Parent != null && token.Parent.Sender is HavingClause) return true;
return false;
}

if (token.Text.IsEqualNoCase("where") && token.Parent == null) return true;

return false;
}

/// <summary>
/// Determines whether a line break should occur after writing the specified token.
/// </summary>
/// <param name="token">The token to evaluate.</param>
/// <returns>True if a line break is required after writing the token; otherwise, false.</returns>
public virtual bool IsLineBreakOnAfterWriteToken(Token token)
{
if (token.Sender is OperatableQuery) return true;

if (token.Text.Equals("*/")) return true;

if (token.Text.Equals(","))
{
if (token.Sender is WithClause) return true;
if (token.Sender is WindowClause) return true;
if (token.Sender is SelectClause) return true;
if (token.Sender is Relation) return true;
if (token.Sender is GroupClause) return true;
if (token.Sender is OrderClause) return true;
if (token.Sender is ValuesQuery) return true;
if (token.Sender is SetClause) return true;
if (token.Sender is PartitionClause) return true;
if (token.Sender is TableDefinitionClause) return true;
if (token.Sender is IndexOnClause) return true;
if (token.Sender is AlterTableClause) return true;
}



return false;
}

/// <summary>
/// Determines whether the indent level should be incremented before writing the specified token.
/// </summary>
/// <param name="token">The token to evaluate.</param>
/// <returns>True if the indent level should be incremented before writing the token; otherwise, false.</returns>
public virtual bool IsIncrementIndentOnBeforeWriteToken(Token token)
{
if (token.Sender is OperatableQuery) return false;

if (token.Text.Equals("(") && token.IsReserved == false) return false;
if (token.Text.Equals("(") && token.Sender is DistinctClause) return false;
if (token.Text.Equals("(") && token.Sender is InsertClause) return false;

if (token.Parent != null && token.Parent.Sender is ValuesQuery) return false;
if (token.Sender is FunctionValue) return false;
if (token.Sender is FunctionTable) return false;
if (token.Sender is Interval) return false;
if (token.Text.IsEqualNoCase("filter")) return false;
if (token.Text.IsEqualNoCase("over")) return false;

return true;
}

/// <summary>
/// Determines whether the indent level should be decremented before writing the specified token.
/// </summary>
/// <param name="token">The token to evaluate.</param>
/// <returns>True if the indent level should be decremented before writing the token; otherwise, false.</returns>
public virtual bool IsDecrementIndentOnBeforeWriteToken(Token token)
{
if (token.Parent == null) return true;

if (token.Text.Equals(")") && token.IsReserved == false) return false;

if (token.Parent.Sender is ValuesQuery) return false;
if (token.Sender is FunctionValue) return false;
if (token.Sender is FunctionTable) return false;
if (token.Text.Equals(")") && token.Parent.Text.IsEqualNoCase("filter")) return true;
if (token.Text.Equals(")") && token.Parent.Text.IsEqualNoCase("over")) return true;

return true;
}
}
Loading

0 comments on commit 8982cf7

Please sign in to comment.