DenoでSQL Serverに接続して問合せするだけ

# この記事は何か
denoでローカルネットワーク上のSQL Serverに接続して問合せする、
ただそれだけのために結構つまづきました。
あまり需要が無いかもしれませんが、成功した実装を紹介します。

# 結論
以下のコードで接続と問い合わせができました。
コメント内の(1)などは、後述の解説と対応します。
```typescript:main.ts
import "https://deno.land/std@0.193.0/dotenv/load.ts"; //(2)
import {
  Disposable,
  using,
} from "https://deno.land/x/disposable@v1.1.1/mod.ts"; //(4)
//@deno-types="npm:@types/mssql" //(1)
import mssql from "npm:mssql@9.1.1";  //(1)

//(2)
const conPool = new mssql.ConnectionPool({
  user: Deno.env.get("DB_USER"),
  password: Deno.env.get("DB_PASSWORD"),
  server: Deno.env.get("DB_SERVER") as string,
  database: Deno.env.get("DB_DATABASE"),

//(3)
  options: {
    //denoの場合、npmのtlsが使えないため false にする必要あり。
    encrypt: false,

    //これをfalseにしないと、問合せ結果の日時がUTCになってしまう。
    useUTC: false,
  },
});

//(4)
await using(
  (await conPool.connect()) as mssql.ConnectionPool & Disposable,
  async (con) => {
    con.dispose = con.close;

    const dbReq = con.request();
    const query = `SELECT GETDATE() AS DBDATE;`;
    const rs = await dbReq.query(query);

    console.log(rs.recordset[0]["DBDATE"].constructor.name); //→　Date
    console.log(rs.recordset[0]["DBDATE"]); //ex→ Fri Aug 11 2023 22:42:27 GMT+0900 (日本標準時)
  }
);
```
```.env
DB_USER=(接続ユーザー)
DB_PASSWORD=(接続パスワード)
DB_SERVER=(接続先IPアドレスかホスト名)
DB_DATABASE=(使用DB名)
```
以降、解説です。

# (1)npmのmssqlを使用する
```typescript:
//@deno-types="npm:@types/mssql" //(1)
import mssql from "npm:mssql@9.1.1";  //(1)
```

denoのライブラリに`https://deno.land/x/mssql@v.0.0.2`がありますが、
これはどうやら　Implementation in progress　・・・実装中とのことです。（2023/8/11時点情報）

代わりにnpmの`mssql@9.1.1`を使用します。
@typesパッケージを`import`の１行上で`//@deno-types=`のコメントで指定することにより、型チェックが効くようになります。
VSCode + Deno の環境なら、コード補完もされる様になります。


# (2)接続先を.envで指定する
```typescript
import "https://deno.land/std@0.193.0/dotenv/load.ts"; //(2)

//・・・

//(2)
const conPool = new mssql.ConnectionPool({
  user: Deno.env.get("DB_USER"),
  password: Deno.env.get("DB_PASSWORD"),
  server: Deno.env.get("DB_SERVER") as string,
  database: Deno.env.get("DB_DATABASE"),
```
Denoの`dotenv`による`.env`や環境変数の読込方法はいろいろな情報がある様子ですが、
標準ライブラリを使用するとこのような感じです。

Nodeとは異なり、標準ライブラリでできるのが良いですね。


# (3)一部のオプション指定が必要
```typescript
//(3)
  options: {
    //denoの場合、npmのtlsが使えないため false にする必要あり。
    encrypt: false,

    //これをfalseにしないと、問合せ結果の日時がUTCになってしまう。
    useUTC: false,
  },
```

https://github.com/denoland/deno/issues/17842 によると、
Denoはnpmのtlsを使用できないとのことです。（2023/8/11時点）
そのため、tlsを用いた暗号化ができません。

ローカルネットワーク上の SQL Server に接続することが目的のため、本件では暗号化不要です。
そのため、`encrypt: false`で暗号化を無効にします。


また、DB側が返す日時がUTCやGMTでない場合（例えば日本標準時の場合）、`useUTC: false`が必要です。
これをしないと、DB側が返した日時をUTCと認識してしまい、日本だと9時間のズレが発生します。
（例　DBからの返し：日本標準時2023/8/11 20:00:00　→　Denoの認識：UTCで2023/8/11 20:00:00、日本標準時で2023/8/12 5:00:00）



# (4)using構文で確実に切断する
```typescript
import {
  Disposable,
  using,
} from "https://deno.land/x/disposable@v1.1.1/mod.ts"; //(4)

//・・・

//(4)
await using(
  (await conPool.connect()) as mssql.ConnectionPool & Disposable,
  async (con) => {
    con.dispose = con.close;

    const dbReq = con.request();
    const query = `SELECT GETDATE() AS DBDATE;`;
    const rs = await dbReq.query(query);

    console.log(rs.recordset[0]["DBDATE"].constructor.name); //→　Date
    console.log(rs.recordset[0]["DBDATE"]); //ex→ Fri Aug 11 2023 22:42:27 GMT+0900 (日本標準時)
  }
);
```

Denoはどうやら接続後にちゃんと切断しなくても、接続用変数が何処からも参照できなくなれば
ガベージコレクタか何かが自動的に切断してくれる様子です。

しかし、環境次第ですが私の検証では自動切断まで約20秒かかっていました。
c#などにあるusing構文で、不要になったら確実に切断させたいです。

using構文はTypeScript5.2で予告されていますが、現時点（2023/8/11時点）ではまだないので、
サードパーティ製ライブラリ https://deno.land/x/disposable@v1.1.1/mod.ts で実現します。

要点は以下2点です。
・`(await conPool.connect()) as mssql.ConnectionPool & Disposable,`のダウンキャストにより、
　using構文対象の変数は本来の型`mssql.ConnectionPool`であることと
　using構文対象の条件である型`Disposable`であることを示す。
↓
・しかし、実際は型`Disposable`であることを満たすメソッド`dispose`が実装されていない。
　`con.dispose = con.close;`により`dispose`を実装する。

これにより、`await using`を抜けた時点で接続が切断されます。



# 
以上です。