대부분의 IDE 에서는 언어별로 포맷팅 프로파일을 설정해서 배포할 수 있는 확장들이 있는데 Code 에서 SQL 용으로 쓸만한 포맷터는 없는 것 같다. 그나마 있는게 Poor Man's T-SQL
스타일에서 keyword uppercase 옵션이나 comma 위치 정도 선택할 수 있는 기능 정도 뿐인듯.
내가 하는 업무에서는 1~200 줄은 가볍게 넘어가는 SQL 코드를 많이 만들어내는데, 키워드 마다 개행을 하고 서브쿼리 타입이 식별이 잘 안되는 Poor Man 스타일로는 감당이 안된다. 그래서, VSCode를 애용하고 1인으로서, 이참에 사내에서 구전으로 이어져오는 SQL 스타일을 정의도 할 겸 포맷터를 직접 만들어보기로 했다.
VSCode extension 생태계
VSCode 가 대성한 이유중 하나로 강력한 커뮤니티의 지원이 꼽히는데 그 명성에 맞게 역시나 매뉴얼과 코드 예제들이 잘 관리되고 있었다.
이 중에서 포맷터 구현에 필요한 에디터 API는 단순히 선택된 텍스트들을 포맷된 텍스트로 바꿔줄 수 있는 기능이면 충분한데, 예제 중 document-editing-sample
에서 사용하는 API 들이면 충분해보였고 typescript 에 익숙하지 않은 입장에서 빌드하기 수월한 helloworld-minimal-sample
를 참고했다.
SQL Styler 개발
위 두 샘플 코드를 참고해서 이제 텍스트를 바꿔주는 기능만 javascript 로 구현하면 되는데 괄호검사 알고리즘을 기반으로, 입력된 sql text 를 keyword 들로 분할한 뒤에 하나씩 꺼내면서 정돈해나가는 형태로 구현했다.
스타일의 기본적인 원칙은 다음과 같다.
- keyword 오른쪽 정렬
- comma는 identifier 앞에
- 서브쿼리는 개행하지않고 괄호가 시작된 column 위치에서부터 정렬
- SELECT, WHERE, CASE WHEN 의 첫번째 expression 은 개행하지 않음
Sample Style
내가 선호하는 SQL 스타일은 다음과 같은 형태를 갖고있는데, 이렇게 배우기도 했고 나한테 잘 맞는듯.
select a.a /* double-dashed comments will be replaced like C-style comments. */
, max(a.b) as max_b /* * * multi * line * comments * will be compressed into single-line. */
, max(a.c) as max_c
, sum(b.cnt) as sum_cnt
, nvl(cast(max(case when a.cnt > 0 and b.max_v > 0 then 'A'
when a.cnt > 0 and b.max_v < 0 then 'B'
when a.cnt < 0 and b.max_v > 0 then 'C'
when a.cnt < 0 and b.max_v < 0 then 'D'
else (select a.k_1
, case when a.k_1 is null then 'A'
when a.k_1 > 'V' then 'A'
else 'B'
end as v
from (select a.k_1
, a.k_2
, max(a.col) as max_col
from tab_d a inner join
tab_f b on (a.k_1 = b.k_1
and a.k_2 = b.k_2
and a.k_3 = b.k_3
and a.k_4 = b.k_4)
group by a.k_1, a.k_2
) a
where a.max_col > 120
)
end) as STRING) ,'') as some_case
from (select a.k /* SELECT , FROM , WHERE , ... , JOIN: Reserved words in comments are treated as comments. */
, b.v
, c.max_v
, c.avg_v
, c.min_v
, c.cnt
from tab_a a inner join
tab_b b on (a.k = b.k
and b.d = 'dd') left outer join
(select a.k
, max(b.v) as max_v
, avg(c.v) as avg_v
, min(d.v) as min_v
, count(e.v) as cnt
from tab_e a inner join
tab_f b on a.k = b.k left outer join
tab_g c on a.k = c.k left outer join
tab_h d on a.k = d.k left outer join
tab_i e on a.k = e.k
group by a
) c on (a.c = c.a)
where a.col_1 >= 'filter' /* comment */
and b.col_2 between 'fil'
and 'ter'
) a left outer join
(select a.k
, max(v) as max_v
from tab_c a
where a.d >= 'filter'
group by a.k
having count(1) > 0
) b on (a.k = b.k)
order by 1, 2
;
sqlstyle.guide
추후에는 위 가이드를 기본으로 하고 몇가지 다른 점들은 옵션으로 제공할 수 있으면 좋을 것 같다.
빌드 및 배포
vsce
라는 npm 패키지를 설치해서 빌드할 수 있고, 로컬에서 ms marketplace 에 바로 배포할 수도 있다. access 토큰을 발급 받아서 하는 부분에서 조금 버벅이긴 했지만 간단히 설정할 수 있고 다음 링크에 자세히 나와있다.
https://code.visualstudio.com/api/working-with-extensions/publishing-extension
별거 아닌 유틸이지만 ms marketplace 에 내 이름으로 올라가 있는걸 보니 신기하다. 샘플 참고해서 DB 메타정보들 조회해오는 플러그인도 만들어보면 재미있을 것 같다.
SQL Styler
- vscode marketplace
- github repository