Node.js用のシンプルなキーバリューストア「keyv」を試す（データの保持はメモリ・SQLite）

タイトル通りの内容です。Node.js でシンプルなキーバリューストアを使う場合、割とメンテナンスがされているものを選ぶとして選択肢に何があるだろうかと思い、少し調べてみました。

その時に出てきたものの 1つが、今回の記事で扱う [keyv](https://www.npmjs.com/package/keyv) です。
　●jaredwray/keyv: Simple key-value storage with support for multiple backends
　　https://github.com/jaredwray/keyv
![keyv](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a08ecb73-278f-99fc-8a0e-4f1642304f1b.png)

公式の説明で「Simple key-value storage with support for multiple backends」と書かれているように、自分の目的に合っていそうです。とりあえず、公式のページやドキュメント等を見ながら、軽いお試しをしてみることにします。

## keyv を試す
### インストールについて
インストールに関して、[公式の GitHubリポジトリの「Usage」](https://github.com/jaredwray/keyv#usage)を見てみると、以下のように書かれていました。
![インストール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ee8bdec4-a0ce-85d8-6763-ed254b7ac794.png)

`npm install` でシンプルにインストールすると、データをメモリに保持するやり方になるようですが、そのデータ保持の部分で MySQL や SQLite などに利用することもできるようです。

今回のお試しでは、メモリに保持するやり方と SQLite を使うやり方で試してみます（※ なお、この記事では SQLite自体の話は取り扱いません）。

### メモリに保持する方法
公式サンプルを参考にして、以下のプログラムを作成して実行してみました。こちらを実行する前に `keyv` を npmコマンドでインストールしておいてください。

```javascript
const Keyv = require("keyv");
const keyv = new Keyv();

keyv.on("error", (err) => console.log("Connection Error", err));

(async () => {
  await keyv.set("foo", "expires in 1 second", 1000);
  const temp = await keyv.get("foo");
  console.log(temp);
})();
```

このプログラムを実行した結果、「expires in 1 second」という出力が得られるのを確認できました。

### SQLite を利用する方法
今度はデータの保持に SQLite を利用するために、 `@keyv/sqlite` を npmコマンドを使って追加でインストールしてください。

そして、以下のプログラムを実行してみます。

```javascript
const Keyv = require("keyv");
const keyv = new Keyv('sqlite://test.db');

keyv.on("error", (err) => console.log("Connection Error", err));

(async () => {
  await keyv.set("foo", "expires in 1 second", 1000);
  const temp = await keyv.get("foo");
  console.log(temp);
})();
```

そうすると、 `Error: Cannot find module 'pify'` というエラーが発生しました。npmコマンドで、pify のインストールを行って、再度、プログラムを実行してみます。

そうすると先ほどと同様に、「expires in 1 second」という出力が得られるのを確認できました。ここから、先ほどとの違いとなる SQLite が関わる部分を確認していきます。

#### DB用のファイルの中身を確認する
先ほどと異なり、プログラムを置いた場所と同じ階層に「test.db」というファイルが作成されていました。そして、このファイルの中身を以下のコマンドで確認していきました。

```bash
$ sqlite3 test.db
sqlite> .table
keyv
sqlite> select * from keyv;
keyv:foo|{"value":"expires in 1 second","expires":1650874028402}
```

プログラムで書きこんだ内容が、ＤＢ内に書きこまれているのが分かります。

#### ネームスペースを試す
次は、[公式の GitHubリポジトリ　の「Namespaces」](https://github.com/jaredwray/keyv#namespaces)に書かれている内容を少し混ぜ込んでみます。

今度は、以下のプログラムを実行してみました。

```javascript
const Keyv = require("keyv");
const keyv = new Keyv("sqlite://test.db");
const keyvdb = new Keyv("sqlite://test.db", { table: "keyvdb" });

keyv.on("error", (err) => console.log("Connection Error", err));
keyvdb.on("error", (err) => console.log("Connection Error", err));

(async () => {
  await keyv.set("foo", "bar");
  const temp = await keyv.get("foo");
  console.log(temp);

  await keyvdb.set("foo2", "bar2");
})();
```

そして、先ほどと同様に「test.db」の中身を、コマンドを使って確認していきます。

```bash
$ sqlite3 test.db
sqlite> .table
keyv    keyvdb
sqlite> select * from keyv;
keyv:foo|{"value":"bar","expires":null}
sqlite> select * from keyvdb;
keyv:foo2|{"value":"bar2","expires":null}
```

今回は、2つのテーブルが作成されていることが分かります。あとは、先ほど作成したものとは別にプログラムを作成して、このデータを読み出してみようと思います。

実行するプログラムは以下です。

```javascript
const Keyv = require("keyv");
const keyv = new Keyv("sqlite://test.db");
const keyvdb = new Keyv("sqlite://test.db", { table: "keyvdb" });

keyv.on("error", (err) => console.log("Connection Error", err));
keyvdb.on("error", (err) => console.log("Connection Error", err));

(async () => {
  const temp1 = await keyv.get("foo");
  const temp2 = await keyv.get("foo2"); // 存在しないものを呼び出し
  const temp3 = await keyvdb.get("foo2");

  console.log(temp1, temp2, temp3);
})();
```

こちらを実行すると、「bar undefined bar2」という出力が得られました。先ほど test.db に書き込み済みのデータを、別のプログラムから読み出せているのを確認できました。