Skip to content

Commit bf74d8b

Browse files
committed
Add compact option to force a more compact formatting (fixes #783).
1 parent 8b03427 commit bf74d8b

File tree

6 files changed

+45
-7
lines changed

6 files changed

+45
-7
lines changed

CHANGELOG

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Development Version
22
-------------------
33

4+
Enhancements
5+
6+
* New "compact" option for formatter. If set, the formatter tries to produce
7+
a more compact output by avoiding some line breaks (issue783).
8+
49
Bug Fixes
510

611
* The strip comments filter was a bit greedy and removed too much
@@ -23,7 +28,7 @@ Notable Changes
2328
https://github.com/andialbrecht/sqlparse/security/advisories/GHSA-2m57-hf25-phgg
2429
The vulnerability was discovered by @uriyay-jfrog. Thanks for reporting!
2530

26-
Enhancements:
31+
Enhancements
2732

2833
* Splitting statements now allows to remove the semicolon at the end.
2934
Some database backends love statements without semicolon (issue742).

docs/source/api.rst

+3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ The :meth:`~sqlparse.format` function accepts the following keyword arguments.
6262
The column limit (in characters) for wrapping comma-separated lists. If unspecified, it
6363
puts every item in the list on its own line.
6464

65+
``compact```
66+
If ``True`` the formatter tries to produce more compact output.
67+
6568
``output_format``
6669
If given the output is additionally formatted to be used as a variable
6770
in a programming language. Allowed values are "python" and "php".

sqlparse/cli.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,14 @@ def create_parser():
138138
default=False,
139139
type=bool,
140140
help='Insert linebreak before comma (default False)')
141-
141+
142+
group.add_argument(
143+
'--compact',
144+
dest='compact',
145+
default=False,
146+
type=bool,
147+
help='Try to produce more compact output (default False)')
148+
142149
group.add_argument(
143150
'--encoding',
144151
dest='encoding',

sqlparse/filters/reindent.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class ReindentFilter:
1313
def __init__(self, width=2, char=' ', wrap_after=0, n='\n',
1414
comma_first=False, indent_after_first=False,
15-
indent_columns=False):
15+
indent_columns=False, compact=False):
1616
self.n = n
1717
self.width = width
1818
self.char = char
@@ -21,6 +21,7 @@ def __init__(self, width=2, char=' ', wrap_after=0, n='\n',
2121
self.wrap_after = wrap_after
2222
self.comma_first = comma_first
2323
self.indent_columns = indent_columns
24+
self.compact = compact
2425
self._curr_stmt = None
2526
self._last_stmt = None
2627
self._last_func = None
@@ -196,15 +197,20 @@ def _process_case(self, tlist):
196197
with offset(self, self._get_offset(tlist[0])):
197198
with offset(self, self._get_offset(first)):
198199
for cond, value in iterable:
199-
token = value[0] if cond is None else cond[0]
200-
tlist.insert_before(token, self.nl())
200+
str_cond = ''.join(str(x) for x in cond or [])
201+
str_value = ''.join(str(x) for x in value)
202+
end_pos = self.offset + 1 + len(str_cond) + len(str_value)
203+
if (not self.compact
204+
and end_pos > self.wrap_after):
205+
token = value[0] if cond is None else cond[0]
206+
tlist.insert_before(token, self.nl())
201207

202208
# Line breaks on group level are done. let's add an offset of
203209
# len "when ", "then ", "else "
204210
with offset(self, len("WHEN ")):
205211
self._process_default(tlist)
206212
end_idx, end = tlist.token_next_by(m=sql.Case.M_CLOSE)
207-
if end_idx is not None:
213+
if end_idx is not None and not self.compact:
208214
tlist.insert_before(end_idx, self.nl())
209215

210216
def _process_values(self, tlist):

sqlparse/formatter.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ def validate_options(options):
115115
if comma_first not in [True, False]:
116116
raise SQLParseError('comma_first requires a boolean value')
117117
options['comma_first'] = comma_first
118+
119+
compact = options.get('compact', False)
120+
if compact not in [True, False]:
121+
raise SQLParseError('compact requires a boolean value')
122+
options['compact'] = compact
118123

119124
right_margin = options.get('right_margin')
120125
if right_margin is not None:
@@ -171,7 +176,8 @@ def build_filter_stack(stack, options):
171176
indent_after_first=options['indent_after_first'],
172177
indent_columns=options['indent_columns'],
173178
wrap_after=options['wrap_after'],
174-
comma_first=options['comma_first']))
179+
comma_first=options['comma_first'],
180+
compact=options['compact'],))
175181

176182
if options.get('reindent_aligned', False):
177183
stack.enable_grouping()

tests/test_format.py

+11
Original file line numberDiff line numberDiff line change
@@ -734,3 +734,14 @@ def test_format_json_ops(): # issue542
734734
"select foo->'bar', foo->'bar';", reindent=True)
735735
expected = "select foo->'bar',\n foo->'bar';"
736736
assert formatted == expected
737+
738+
739+
@pytest.mark.parametrize('sql, expected_normal, expected_compact', [
740+
('case when foo then 1 else bar end',
741+
'case\n when foo then 1\n else bar\nend',
742+
'case when foo then 1 else bar end')])
743+
def test_compact(sql, expected_normal, expected_compact): # issue783
744+
formatted_normal = sqlparse.format(sql, reindent=True)
745+
formatted_compact = sqlparse.format(sql, reindent=True, compact=True)
746+
assert formatted_normal == expected_normal
747+
assert formatted_compact == expected_compact

0 commit comments

Comments
 (0)