tiberiusを使ってRustでMSSQLに接続する

## はじめに

RustからMSSQLを操作したいと思い、いい感じのcrateがないか探していました。
色々調べるとDB操作関連に関してはDieselというORMがよく使われているようでした。
https://github.com/diesel-rs/diesel

「情報もある程度ありそうだしこれを使ってみよう！」 
と思っていたら‥

```shell
Supported databases:

1. PostgreSQL
2. MySQL
3. SQLite
```

だめやん‥ 

というわけで他の方法を探すことにしました。

## tiberius

tiberiusというcrateがありました。
https://crates.io/crates/tiberius

スター数があまり多くないのは気になりますが、検証ということでとりあえずこちらを使ってみることにします。

### 注意

「rust tiberius」でググるとgithubのページが二つ出てくると思います。

- https://github.com/prisma/tiberius
- https://github.com/steffengy/tiberius

前者が最新のリポジトリのようなので気をつけてください。

## 確認環境

今回はそれぞれ以下のバージョンを使用しました。

- rustc
  - 1.45.0-nightly（dockerの「rustlang/rust:nightly」を使用）
- tiberius
  - 0.4.0-alpha.6
      - Crates.ioに公開されているバージョンを使いたかったのですが、いい感じのexampleが見つけられず現時点の最新版（2020/05/29 時点）を使っています。申し訳ありません‥

## 実装

### ディレクトリ構造

今回作成したプロジェクトは以下の構造になっています。

```shell
├── Dockerfile
├── app
│   ├── Cargo.lock
│   ├── Cargo.toml
│   └── target ※このディレクトリ配下は省略
│   └── src
│       └── main.rs
└── docker-compose.yaml
```

それでは一つづつみていきましょう！

### Dockerfile

今回はnightlyのバージョンを使います。

```dockerfile
FROM rustlang/rust:nightly
```

### docker-compose.yaml

docker-compose.yamlは以下の通りです。
接続するMSSQLは公式で配布されているdocker imageを使います。

また、あらかじめテスト用のデータを作成するためにアプリケーションとmssqlの他にmssqlのcliツールを使用するコンテナも作成します。

```yaml

version: '3.7'
services:
  app:
    build: .
    volumes:
      - ./app:/app
    working_dir: /app
    tty: true
    depends_on: 
      - db
  db:
    image: microsoft/mssql-server-linux:2017-GA
    environment:
      ACCEPT_EULA: Y
      SA_PASSWORD: "P@ssw0rd!"
    volumes:
      - rust-mssql-data:/var/opt/mssql/
    ports:
      - "1433:1433"
  mssql_cil_client:
    image: node:alpine
    tty: true
volumes:
  rust-mssql-data:
    driver: local
```

### Cargo.toml

「Cargo.toml」はdependenciesだけ抜粋しています。
サンプルを動かすにはtiberiusの他にも幾つか必要なcrateがあるので全て追加してください。

```toml
[dependencies]
tiberius = { git = "https://github.com/prisma/tiberius.git" }
tokio = { version = "0.2", features = ["macros"] }
anyhow = "1.0.31"
futures = "0.3.5"
```

tiberiusについては「動作確認環境」にも書きましたが最新版を使いたかったのでgithubから直接ダウンロードするようにしています。

### サンプル用確認用のテーブル

サンプルを実装する前にテスト用のデータベースを作成してサンプルデータを登録しておきます。

#### コンテナの起動

```
docker-compose up -d
```

MSSQLが起動するので、データベースやテーブルを作成します。

#### cli用のコンテナにログイン

```shell

docker-compose exec mssql_cil_client /bin/sh
```

#### sql-cliのinstall

```shell

npm install -g sql-cli
```

#### mssqlにログイン

```shell

mssql -s db -u sa -p P@ssw0rd!
```

#### データベースの作成

```shell

create database test;
use test;
```


#### テーブルの作成

```shell

create table users \
( \
    id int not null, \
    name nvarchar(128), \
    constraint pk_users primary key (id) \
);
```

#### テストデータの登録

```shell

insert into users(id,name) values(1,'Taro');
insert into users(id,name) values(2,'Jiro');
insert into users(id,name) values(3,'Hanako');
```

#### テストデータの確認

想定通りにデータが登録されているか確認しましょう！

```shell

select * from users;
```

以下ように表示されればOKです！

```shell

id  name
--  ------
1   Taro
2   Jiro
3   Hanako

3 row(s) returned

Executed in 1 ms
```

問題なければ、mssqlおよびコンテナからログアウトしましょう

```shell

.quit
exit
```

### main.rs

それでは先ほど作成したテストデータをRustから取得してみます！

以下にテーブルを作成するサンプルが格納されています。
今回はこれをベースにしました。
https://github.com/prisma/tiberius/blob/master/examples/new.rs

```rust

use tiberius::{AuthMethod, Client};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut builder = Client::builder();
    builder.host("db");
    builder.port(1433);
    builder.database("test");
    builder.authentication(AuthMethod::sql_server("SA", "P@ssw0rd!"));
    builder.trust_cert();

    let mut conn = builder.build().await?;
    let results = conn
        .simple_query("select id, name from Users;")
        .await?
        .into_results()
        .await?;

    for val in results.iter() {
        // 取得した件数分ループする
        for inner in val.iter() {
            // id列の情報を取得
            if let Some(id) = inner.get::<i32, _>("id") {
                print!("id = {} ", id);
            }
            // name列の情報を取得
            if let Some(name) = inner.get::<&str, _>("name") {
                println!("name = {}", name);
            }
        }
    }
    Ok(())
}
```

とりあえず使ってみるだけであれば、特に難しい点はなさそうです。
resultsが2次元配列になっている理由が今ひとつわからず気になりました。


細かいことは一旦気にせず上記コードを実行してみましょう！

```shell

docker-compose exec app cargo run
```

結果

```
id = 1 name = Taro
id = 2 name = Jiro
id = 3 name = Hanako
```

いい感じですね！

今回作ったサンプルは以下で公開しています。
https://github.com/shushutochako/tiberius_sample

## さいごに

Rustでmssqlを操作するサンプルがあまり多くない印象で少し手こずってしまいました。
これから色々と実装例が増えてくることを切に願います(´·ω·`)

他にもRustからMSSQLを操作する場合はODBCのWrapperライブラリを使う方法などもあるようです。
ODBCクレートを使用する場合はこちらの記事が非常に参考になりました。
https://setsuna-no-matataki.hateblo.jp/entry/2020/04/30/182305


----


ZEROBILLBANKでは一緒に働く仲間を募集中です。
[ZEROBILLBANK JAPAN Inc.](https://zerobillbank.com/%e3%81%8a%e5%95%8f%e3%81%84%e5%90%88%e3%82%8f%e3%81%9b/)