[プラグイン]kyselyのマイグレーションを拡張した

## kysely とは

Typescript のクエリビルダーです。
手前味噌ですが去年紹介記事を書いています。

https://qiita.com/mont_blanc/items/0564a946b0d6919ad3a0

上の記事の時点では`PostgreSQL`, `MySQL`, `SQLite`が使えてましたが`SQLServer`も増えているみたいです。

本家のドキュメント(トップページ)はこちら

https://kysely.dev/docs/intro

## kysely におけるマイグレーション

マイグレーションファイルの書き方は knex とよく似ていますが、「マイグレーションの実行」部分を自分で書く必要があります。
その分、自由度が高いともいえますが、少し面倒です。

https://kysely.dev/docs/migrations

## マイグレーションでほしい機能を自作する

手前味噌その2ですが、 kysely 系 npm パッケージをつくっています。
主に PostgreSQL に特化した追加機能を実装しています。
現在の最新バージョンは 0.2.4 です。

https://qiita.com/mont_blanc/items/7982bceddf58a0e9ab61

上の記事の時点では 0.1台でしたが、マイグレーション関係の機能を追加して 0.2 にしてみました。(バージョンのつけかた合ってる？)
また、 Node.js と Deno で一部ソースを共有できなさそうだったので、 Node.js オンリーの対応です。

### マイグレーション実行

個々のプロジェクトでマイグレーション実行を書かなくて済むよう、コマンド化しました。
まず、接続先の情報などを記載する設定ファイルを作成します。

```ts:config.ts
import type { UtilConfig } from 'kysely-extends-pg-query';

const config: UtilConfig = {
  database: 'test01',
  host: 'localhost',
  port: 5432,
  ssl: undefined,
  owner: {
    user: 'test_01',
    password: 'pwd',
  },
  migrate: 'migrate',
  dryMigrateOutput: undefined,
  superUser: {
    user: 'postgres',
    password: 'postgres',
    database: 'postgres',
  },
  verbose: true,
  createDbOptions: undefined,
};

export default config;
```

下の表に、それぞれのフィールドの概要を記載しておきます。

|フィールド|記載内容|
|---|---|
|database|接続先データベース名|
|host|接続先ホスト名/IPアドレス(未指定時`localhost`)|
|port|接続先ポート番号(未指定時`5432`)|
|ssl|SSLモード(未指定時`undefined`=暗号化なし)|
|owner.user|データベース所有者ロール名|
|owner.password|データベース所有者パスワード|
|migrate|マイグレーションファイルのあるフォルダパス|
|dryMigrateOutput|dry runしたときの出力先ファイル(未指定時`undefined`=コンソールに出力)|
|superUser.xxx|データベース作成時に利用するスーパーユーザー(DB・role作成権のあるユーザー)の情報(未指定時`undefined`=DB作成できない)|
|verbose|true=たくさんログを出力する(未指定時`false`)|
|createDbOptions|データベース作成時のオプション、`encoding`や`locale`等|

package.json で `scripts` 内に以下を書けば `npm run migrate:latest` で最新に、 `npm run migrate:down` でひとつ前に戻ります。
また、データベースの作成も`npm run migrate:init`で可能です。(設定ファイルにて`superUser`の項目を指定する必要がある)

```json
    "migrate:init": "kysely-extends-pg-query --mode migrate-init --config config.ts",
    "migrate:latest": "kysely-extends-pg-query --mode migrate-latest --config config.ts",
    "migrate:down": "kysely-extends-pg-query --mode migrate-down --config config.ts"
```

また、これらに追加してマイグレーションの`dry run`、すなわち実行するSQLを表示するだけで発行はしないモードも追加しました。
仕組みとしては`PgPool`互換のクラスを作成して、「マイグレーション実部のSQL発行」だけしないようにしています。
今後 kysely 本体の更新次第で正常に動作しなくなる可能性があるので注意してください。(気づいたら追従します)
package.json への記載は以下のようになります。
設定ファイルのフィールド`dryMigrateOutput`が未指定のときはコンソールに出力、指定ありのときは指定されたファイルに出力します。

```json
    "migrate:latest-dry": "kysely-extends-pg-query --mode migrate-latest --config config.ts --dry",
```

### マイグレーション内容のユーティリティ

`PostgreSQL`固有の機能(じゃないのもあるかもしれませんが)のユーティリティ関数群も作成しました。
引数に指定できる型は、 PostgreSQL 自体が受け付けるものより少ないです。(バージョンが古すぎる PostgreSQL だと逆に使えないものがあるかもしれません)
追加した関数の利用例は以下です。

```ts
  await commentOn(db, "table", "person", "test comment for table");
  await commentOn(db, "table", "person", null);
  await grantDBObj(db, "table", "select", { all: true, schema: "public" }, "target_role_name");
  await updateRowLevelSecurity(db, "person", "enable");
  await createPolicy(db, "person", { using: "true" });
  await dropPolicy(db, "person");
```

これらの利用例が発行するSQLを、下に表でまとめます。

|関数|SQL例|
|---|---|
|commentOn|comment on table "person" is 'test comment for table'<br>comment on table "person" is null|
|grantDBObj|grant select on all tables in schema "public" to "target_role_name"|
|updateRowLevelSecurity|alter table "person" enable row level security|
|createPolicy|create policy "person_policy" on "person" using(true)|
|dropPolicy|drop policy "person_policy" on "person"|

## おわりに

今回の記事はここまでになります。
みなさまもよき kysely ライフを！