Spigot(Paper)+Kotlin+Exposedでなんかやってみる

# Exposed
`Kotlin`で`sql`をやるライブラリだそうです

https://github.com/JetBrains/Exposed
# 動機
こちらの記事を拝見し、ぼくも`Exposed`を使ってみようと思った

https://qiita.com/ReyADayer/items/269febe921ee9461e60d
# ライブラリを追加する
## Gradle
```build.gradle
repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.jetbrains.exposed:exposed-core:0.35.1'
    implementation 'org.jetbrains.exposed:exposed-dao:0.35.1'
    implementation 'org.jetbrains.exposed:exposed-jdbc:0.35.1'
    // カラムの型に日付、時間を使いたい場合これがいる
    implementation 'org.jetbrains.exposed:exposed-java-time:0.35.1'
    // ドライバー（今回はmysqlを使う）
    implementation 'mysql:mysql-connector-java:8.0.26'
}
```

# 使ってみる
## テーブルを定義
今回はプレイヤーのmcid,uuid,最終ログイン日時を記録するプラグインを作ってみます

```User.kt
object User : Table() {
    val mcid = varchar("mcid", 16)
    val uuid = uuid("uuid").primaryKey()
    val login = datetime("login")
}
```
## データベースの作成
ターミナルから`Mysql`に接続してデータベースを作成します。

```shell
mysql> create database exposed_sample;
```
## テーブルの作成
プラグインが起動したとき、`Mysql`に接続して`User`テーブルを作成します。

```Kotlin
override fun onEnable() {

        Database.connect("jdbc:mysql://localhost/exposed_sample", driver = "com.mysql.jdbc.Driver", user = "user", password = "password")
        transaction {
            // データを作成
            SchemaUtils.create(User)
        }       

    }
```
起動すると、テーブルが自動で作成されてるのが分かります。

```shell
mysql> use exposed_sample;
mysql> show tables;
+--------------------------+
| Tables_in_exposed_sample |
+--------------------------+
| user                     |
+--------------------------+
1 row in set (0.00 sec)
```
### もう一度起動したらどうなる？
どうやら実行されるSQL文には、自動的に`IF NOT EXISTS`が付くので気にしなくてもいいようです。テーブルを削除する時も同様です。

## プレイヤーデータの追加
プレイヤーがサーバーに参加した時、プレイヤーの情報をデータベースに書き込みます。

```Kotlin
@EventHandler
fun onJoin(event: PlayerJoinEvent) {

    val player = event.player

    transaction {

        User.insert {
            it[mcid] = player.name
            it[uuid] = player.uniqueId
            it[login] = LocalDateTime.now()
        }

    }
}
```
## データの取得
プレイヤーがサーバーに入って来た時、前回のログイン日時をチャットで送信する仕組みを作ってみます。
先ほどの`onJoin`を書き換えて...

```Kotlin
@EventHandler
fun onJoin(event: PlayerJoinEvent) {

    val player = event.player

    transaction {

        val user = User.select { User.uuid eq player.uniqueId }
        // ユーザーデータがあればアップデート＆前回のログインを通知
        if (user.count() > 0L) {
            player.sendMessage("ようこそ！前回のログインは${user.single()[User.login].format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"))}です！")
            User.update({ User.uuid eq player.uniqueId }) { it[login] = LocalDateTime.now() }
            return@transaction
        }

        // なければ追加＆初めまして      
        User.insert {
            it[mcid] = player.name
            it[uuid] = player.uniqueId
            it[login] = LocalDateTime.now()
        }
        player.sendMessage("初めまして${player.name}さん！")

    }
}
```

## 実際の動きはこんな感じ
### 初めてサーバーに参加したとき
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758030/43be2c13-258e-4a32-03f8-6d7485d3975a.png)
### 二回目以降
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758030/85d1c86c-6377-25aa-84da-8e2e88ea48bb.png)

# 最後に
## Javaはどうすればいいんですか
えっと`Java`の場合は、`Kotlin`を使ってみるといいです。
## 感想
`Exposed`の使い方が分かりました（小並感）
ユーザーデータがあるかどうかを確かめるとき、返ってくる`Query`のカウントが０かどうか見てるんですが`isEmpty`みたいなのないんですかね。まだまだ調査が必要です。

ぼく`sql`はまだ完全に理解すらしていないので、間違ってることがあれば遠慮なくコメントなりSNSなりで指摘してください。
あとTwitterフォローお願いします。
https://twitter.com/Gorayan_kun
# 参考
https://qiita.com/gumimin/items/e8cc7783546e2047331c