Skip to content

Commit 4d05b44

Browse files
committed
Add formatter option for comma first notation (fixes andialbrecht#141).
1 parent 4430c5c commit 4d05b44

File tree

5 files changed

+50
-2
lines changed

5 files changed

+50
-2
lines changed

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Development Version
22
-------------------
33

4+
Enhancements
5+
6+
* Add comma_first option: When splitting list "comma first" notation
7+
is used (issue141).
8+
49
Bug Fixes
510

611
* Fix parsing of incomplete AS (issue284, by vmuriart).

sqlparse/cli.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ def create_parser():
118118
type=int,
119119
help='Column after which lists should be wrapped')
120120

121+
group.add_argument(
122+
'--comma_first',
123+
dest='comma_first',
124+
default=False,
125+
type=bool,
126+
help='Insert linebreak before comma (default False)')
127+
121128
return parser
122129

123130

sqlparse/filters/reindent.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111

1212

1313
class ReindentFilter(object):
14-
def __init__(self, width=2, char=' ', wrap_after=0, n='\n'):
14+
def __init__(self, width=2, char=' ', wrap_after=0, n='\n',
15+
comma_first=False):
1516
self.n = n
1617
self.width = width
1718
self.char = char
1819
self.indent = 0
1920
self.offset = 0
2021
self.wrap_after = wrap_after
22+
self.comma_first = comma_first
2123
self._curr_stmt = None
2224
self._last_stmt = None
2325

@@ -123,7 +125,20 @@ def _process_identifierlist(self, tlist):
123125
# Add 1 for the "," separator
124126
position += len(token.value) + 1
125127
if position > (self.wrap_after - self.offset):
128+
if self.comma_first:
129+
_, comma = tlist.token_prev(
130+
tlist.token_index(token))
131+
if comma is None:
132+
continue
133+
token = comma
126134
tlist.insert_before(token, self.nl())
135+
if self.comma_first:
136+
_, ws = tlist.token_next(
137+
tlist.token_index(token), skip_ws=False)
138+
if (ws is not None
139+
and not ws.ttype is T.Text.Whitespace):
140+
tlist.insert_after(
141+
token, sql.Token(T.Whitespace, ' '))
127142
position = 0
128143
self._process_default(tlist)
129144

sqlparse/formatter.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ def validate_options(options):
9797
raise SQLParseError('wrap_after requires a positive integer')
9898
options['wrap_after'] = wrap_after
9999

100+
comma_first = options.get('comma_first', False)
101+
if comma_first not in [True, False]:
102+
raise SQLParseError('comma_first requires a boolean value')
103+
options['comma_first'] = comma_first
104+
100105
right_margin = options.get('right_margin')
101106
if right_margin is not None:
102107
try:
@@ -148,7 +153,8 @@ def build_filter_stack(stack, options):
148153
stack.stmtprocess.append(
149154
filters.ReindentFilter(char=options['indent_char'],
150155
width=options['indent_width'],
151-
wrap_after=options['wrap_after']))
156+
wrap_after=options['wrap_after'],
157+
comma_first=options['comma_first']))
152158

153159
if options.get('reindent_aligned', False):
154160
stack.enable_grouping()

tests/test_format.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@ def test_option(self):
322322
sqlparse.format('foo', reindent=True, wrap_after='foo')
323323
with pytest.raises(SQLParseError):
324324
sqlparse.format('foo', reindent=True, wrap_after=-12)
325+
with pytest.raises(SQLParseError):
326+
sqlparse.format('foo', reindent=True, comma_first='foo')
325327

326328
def test_stmts(self):
327329
f = lambda sql: sqlparse.format(sql, reindent=True)
@@ -428,6 +430,19 @@ def test_identifier_list_with_wrap_after(self):
428430
'from table1, table2',
429431
'where 1 = 2'])
430432

433+
def test_identifier_list_comment_first(self):
434+
f = lambda sql: sqlparse.format(sql, reindent=True, comma_first=True)
435+
# not the 3: It cleans up whitespace too!
436+
s = 'select foo, bar, baz from table where foo in (1, 2,3)'
437+
assert f(s) == '\n'.join([
438+
'select foo',
439+
' , bar',
440+
' , baz',
441+
'from table',
442+
'where foo in (1',
443+
' , 2',
444+
' , 3)'])
445+
431446
def test_identifier_list_with_functions(self):
432447
f = lambda sql: sqlparse.format(sql, reindent=True)
433448
s = ("select 'abc' as foo, coalesce(col1, col2)||col3 as bar,"

0 commit comments

Comments
 (0)