Skip to content

Commit 326a29e

Browse files
committed
.
1 parent 96d6389 commit 326a29e

3 files changed

Lines changed: 63 additions & 100 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
class FormattedScriptGenerator
2+
{
3+
readonly Sql170ScriptGenerator generator = new(
4+
new()
5+
{
6+
SqlVersion = SqlVersion.Sql170,
7+
KeywordCasing = KeywordCasing.Lowercase,
8+
IndentationSize = 2,
9+
AlignClauseBodies = true
10+
});
11+
12+
public string GenerateScript(TSqlFragment fragment)
13+
{
14+
generator.GenerateScript(fragment, out var script);
15+
16+
var collector = new OrderByCollector();
17+
fragment.Accept(collector);
18+
19+
foreach (var orderBy in collector.Clauses)
20+
{
21+
if (orderBy.OrderByElements.Count <= 1)
22+
{
23+
continue;
24+
}
25+
26+
var elements = new List<string>(orderBy.OrderByElements.Count);
27+
foreach (var element in orderBy.OrderByElements)
28+
{
29+
generator.GenerateScript(element, out var text);
30+
elements.Add(text);
31+
}
32+
33+
var singleLine = "order by " + string.Join(", ", elements);
34+
35+
var pos = script.IndexOf(singleLine, StringComparison.Ordinal);
36+
if (pos == -1)
37+
{
38+
continue;
39+
}
40+
41+
var lineStart = script.LastIndexOf('\n', pos) + 1;
42+
var indent = new string(' ', pos - lineStart + "order by ".Length);
43+
44+
var multiLine = "order by " + string.Join(",\n" + indent, elements);
45+
46+
script = string.Concat(script.AsSpan(0, pos), multiLine, script.AsSpan(pos + singleLine.Length));
47+
}
48+
49+
return script;
50+
}
51+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class OrderByCollector : TSqlFragmentVisitor
2+
{
3+
public List<OrderByClause> Clauses { get; } = [];
4+
5+
public override void Visit(OrderByClause node) =>
6+
Clauses.Add(node);
7+
}
Lines changed: 5 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
static class SqlFormatter
22
{
3+
static readonly FormattedScriptGenerator generator = new();
4+
35
public static StringBuilder Format(string input)
46
{
57
var parser = new TSql170Parser(false);
@@ -23,112 +25,15 @@ Failed to parse sql.
2325
var visitor = new RemoveSquareBracketVisitor();
2426
fragment.Accept(visitor);
2527

26-
var generator = new Sql170ScriptGenerator(
27-
new()
28-
{
29-
SqlVersion = SqlVersion.Sql170,
30-
KeywordCasing = KeywordCasing.Lowercase,
31-
IndentationSize = 2,
32-
AlignClauseBodies = true
33-
});
34-
35-
var builder = new StringBuilder();
36-
using (var writer = new StringWriter(builder, CultureInfo.InvariantCulture))
37-
{
38-
generator.GenerateScript(fragment, writer);
39-
}
28+
var script = generator.GenerateScript(fragment);
4029

30+
var builder = new StringBuilder(script);
4131
builder.TrimEnd();
4232
if (builder[^1] == ';')
4333
{
4434
builder.Length--;
4535
}
4636

47-
FormatOrderBy(builder);
48-
4937
return builder;
5038
}
51-
52-
static void FormatOrderBy(StringBuilder builder)
53-
{
54-
var text = builder.ToString();
55-
builder.Clear();
56-
57-
using var lineReader = new StringReader(text);
58-
string? line;
59-
var first = true;
60-
61-
while ((line = lineReader.ReadLine()) != null)
62-
{
63-
if (!first)
64-
{
65-
builder.Append('\n');
66-
}
67-
68-
first = false;
69-
70-
var trimmed = line.TrimStart();
71-
if (trimmed.StartsWith("order by ") && trimmed.Contains(','))
72-
{
73-
var leadingSpaces = line.Length - trimmed.Length;
74-
var prefix = new string(' ', leadingSpaces) + "order by ";
75-
var columns = trimmed["order by ".Length..];
76-
var items = SplitRespectingParens(columns);
77-
78-
if (items.Count > 1)
79-
{
80-
var pad = new string(' ', prefix.Length);
81-
for (var j = 0; j < items.Count; j++)
82-
{
83-
if (j > 0)
84-
{
85-
builder.Append('\n');
86-
builder.Append(pad);
87-
}
88-
else
89-
{
90-
builder.Append(prefix);
91-
}
92-
93-
builder.Append(items[j].Trim());
94-
if (j < items.Count - 1)
95-
{
96-
builder.Append(',');
97-
}
98-
}
99-
100-
continue;
101-
}
102-
}
103-
104-
builder.Append(line);
105-
}
106-
}
107-
108-
static List<string> SplitRespectingParens(string input)
109-
{
110-
var items = new List<string>();
111-
var depth = 0;
112-
var start = 0;
113-
114-
for (var i = 0; i < input.Length; i++)
115-
{
116-
switch (input[i])
117-
{
118-
case '(':
119-
depth++;
120-
break;
121-
case ')':
122-
depth--;
123-
break;
124-
case ',' when depth == 0:
125-
items.Add(input[start..i]);
126-
start = i + 1;
127-
break;
128-
}
129-
}
130-
131-
items.Add(input[start..]);
132-
return items;
133-
}
134-
}
39+
}

0 commit comments

Comments
 (0)