【BigQuery】standardSQLのフォーマッターを公開した（各種エディタ対応）

## 最新情報
- `version 0.2.27`
    - 2022/08/03までの[リリースノート](https://cloud.google.com/bigquery/docs/release-notes)に対応
    - qualify周りのサイレント修正に対応
- VSCode拡張機能を公開
    - このフォーマッターを組み込んだ[BigQuery Extension For VSCode](https://qiita.com/dr666m1/items/7a5737c472ce663cb300)という拡張機能を公開（まだα版）
    - ほとんどの機能はLanguage Serverとして実装したため、Vimなど他のエディタからも利用可能

## 概要
VimやVSCodeでも利用可能な **standardSQL** [^standardsql]のフォーマッター **[prettier-plugin-bq](https://github.com/dr666m1/prettier-plugin-bq)** を先日公開したため、開発した背景・特徴・使い方などを紹介する。開発初期に投稿した[記事](https://qiita.com/dr666m1/items/48af411bf02ca65662a1)もあるが、どう開発するかに重点を置いていたため、この記事では **どう使うか** に重点を置く。まだ開発中の部分もあるが、`version 0.1.0`で（おそらく）一通りの文法に対応したため、興味があれば使ってみてください。

[^standardsql]: BigQueryで利用するSQLの一つ。標準SQLと直訳する場合もあるらしい。

**▼Vimからの利用イメージ（詳細は[使い方](https://qiita.com/dr666m1/items/6bdac6f17d3530152bb9#%E4%BD%BF%E3%81%84%E6%96%B9)を参照）**
![ezgif-6-55c08dc04c9f.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540947/e17d4995-1aa2-737f-19f0-6dacdd15ac58.gif)

## 背景
SQLワークスペースの **【Format Query】** （日本語だと【クエリを書式設定】）を使ったことがあるだろうか。私は一度試して、 **それ以降使うのをやめた** 。理由は単純で、少なくとも2021年06月現在、まだ満足できる性能ではないと感じるから。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540947/5c378814-98d4-c120-fd9d-eeda23159d22.png)


例えば以下がこの機能を利用した結果だが、明らかにクエリの意味が変わってしまっている（また、`BETWEEN xxx AND yyy`の改行も気に入らない）。これが開発に着手した動機である。

```sql
-- フォーマット前
declare start_date default 1590;
declare end_date default 1600;
select
  corpus, -- comment
  word_count as love_count
from `bigquery-public-data`.samples.shakespeare
where corpus_date between start_date and end_date and word = "love"
order by love_count desc
;

-- フォーマット後
DECLARE
  start_date DEFAULT 1590;
DECLARE
  end_date DEFAULT 1600;
SELECT
  corpus,
  -- comment word_count AS love_count
FROM
  `bigquery-public-data`.samples.shakespeare
WHERE
  corpus_date BETWEEN start_date
  AND end_date
  AND word = "love"
ORDER BY
  love_count DESC ;
```

## 特徴
今回公開した**prettier-plugin-bq**には以下のような特徴がある。

### Prettierの拡張機能として実装
[Prettier](https://prettier.io/)というフォーマッターの拡張機能（plugin）として実装したため、Prettierが対応していればどのエディタからでも利用可能。チームでコーディングスタイルを統一するのも容易。

### standardSQLに特化
[リリースノート](https://cloud.google.com/bigquery/docs/release-notes)を見ての通り、BigQueryはかなり頻繁に新機能が追加される。今後個人でもメンテを続けられるよう、standardSQLのみを対象とした。逆に言えばPostgreSQL・MySQLなど他のRDBMSについては考えないし、同じBigQueryでもlegacySQLについては考えない。

### 後カンマ、予約語大文字、...
コーディングスタイルについても軽く言及しておく。

まずSELECT句などでは**後カンマを採用**する。standardSQLでは以下のような記法が許されており、後カンマでも列の追加・削除に不都合がないため。

```sql
SELECT
  col1,
  col2, -- この位置のカンマも許される
```

また、**予約語はデフォルトだと大文字に変換**される[^upper]。速く書けるから予約語も小文字推奨、というスタンスもあるようだが、フォーマッターを使って変換するなら関係ないため。
[^upper]: `version 0.2.0`で大文字に変換しないオプションも追加
その他のコーディングスタイルは **「可読性は担保」** しつつ **「複雑な実装にしない」** という方針で決めている。

## 使い方

動作確認はWSL2のUbuntu-20.04で実施した。`npm`は事前に使えるようにしておくこと。後段でコマンドライン・Vim・VSCodeからの利用方法を紹介するが、まずはフォーマッターを利用したいプロジェクト内で、以下の通りインストール[^npm]。

[^npm]: パッケージ管理のために`node_modules/` `package.json`, `package-lock.json`が作成される。Gitで管理する場合、`node_modules/`を`.gitignore`に追記しておくとよい。

```bash
npm init -y
npm install --save-dev --save-exact prettier @dr666m1/prettier-plugin-bq # prettier本体もインストール
```


### コマンドラインからの利用
拡張子が`.sql`または`.bq`のファイルを指定して、以下のコマンドを実行する。この方法だとファイルがフォーマットされた状態で上書きされる。`--write`を`--check`で置き換えて、フォーマット済みか確認するといった使い方もできる。詳細はPrettierのドキュメントを参照されたい。

```bash
npx prettier --write ./xxx.sql
```

![ezgif-6-d2fdaff080d4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540947/e4b787ef-e8ef-025d-3621-581052b6b79f.gif)

### Vim (Neovim) からの利用
[vim-prettier](https://github.com/prettier/vim-prettier)が便利。[vim-plug](https://github.com/junegunn/vim-plug)を利用しているなら、以下を`.vimrc` （または`init.vim`）に追記して`:PlugInstall`を実行する[^vimplug]。

[^vimplug]: vim-plugのREADME通りの手順。おそらく`yarn`を使えるようにしておく必要あり。

```vim:init.vim
call plug#begin('~/.vim/plugged')
" ... other plugins
Plug 'prettier/vim-prettier', { 'do': 'yarn install' }
" ... other plugins
call plug#end()
```

これにより、`:Prettier`というコマンドで編集中の`.sql`や`.bq`のファイルをフォーマット可能になる。デフォルトだと`<leader>p`に割り当てられるため、それでも実行可能。

![ezgif-6-55c08dc04c9f.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540947/e17d4995-1aa2-737f-19f0-6dacdd15ac58.gif)

### VSCodeからの利用
まずはWindowsの場合を、Remote-WSLを使う前提で解説する（Remote-WSLの導入は[こちら](https://qiita.com/nj_ryoo0/items/a42c47436b77310f5430)の記事が詳しい）。先ほど`npm install`を実行したディレクトリでVSCodeを起動（`code .`を実行）し、Extensionsを`Prettier - Code formatter`で検索。そして[prettier-vscode](https://github.com/prettier/prettier-vscode)をインストール。

macの場合はprettier-vscodeをインストールして、先ほど`npm init -y`したディレクトリをVSCodeから普通にopen folderすればよさそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540947/81443f19-8d27-a362-698e-679002986b60.png)
必要なら、Prettierを利用すると明示するため`setting.json`に以下を記入しておく。

```setting.json
{
    "editor.defaultFormatter": "esbenp.prettier-vscode"
}
```

ここまでで準備完了。`Ctrl + Shift + P`でコマンドパレットを開き、`Format Document`を選択すれば`.sql`や`.bq`のファイルをフォーマットできる。

## 今後の展望
今後は以下を進める予定。

- ~~コードのリファクタリング~~
- ~~テストコードの充実~~（[構文解析器](https://github.com/dr666m1/bq2cst)はテスト駆動開発したので、それ以外を重点的に）
- ~~エラーメッセージの充実~~
- Prettierのpluginとして不足している機能の開発

ほかにもバグがあれば随時直すので、何かあれば教えてください。