React を使って SQLite からデータを取得する

Uncategorized
807 words

ちょっとニッチな使い方をしてみたいと思います。

初めに

ブラウザの JavaScript で SQLite の wasm版 を動かして、ネットワーク上の SQLite をダウンロード・SELECT実行をします。

探したところ、空のDBに新規でテーブルを作って、データを入れて、そのデータを取得するって記事がほとんどでした。

今回のポイントは、ネットワーク上の SQLite をダウンロードするってのがミソになるかと思っています。

DBは使いたいけど、バックエンドサーバはいらないって人に、うってつけなんじゃないでしょうか。

React はオマケですね。

GitHub Page にデプロイしても、DBが使えるのはいいですね。

環境

  • Windows 11 Home 22H2

  • create-react-app 5.0.1

事前に React のプロジェクトを作成しておきます。

1
npx create-react-app --template typescript my-react-app

ネットワーク上に配置する「mydb.sqlite3」も作成しておきます。

1
2
3
4
5
CREATE TABLE Test(id TEXT PRIMARY KEY, name TEXT, create_at TEXT);
INSERT INTO Test VALUES ('1','test', DATETIME('now', 'localtime'));
INSERT INTO Test VALUES ('2','テスト', DATETIME('now', 'localtime'));
INSERT INTO Test VALUES ('3','テスト3', DATETIME('now', 'localtime'));
INSERT INTO Test VALUES ('4','テスト4', DATETIME('now', 'localtime'));

作ったら、プロジェクトフォルダーの「public」フォルダー内に置いておきます。このフォルダーにあるファイルは、無条件でウェブに配置されるためです。

手順

モジュール

モジュール「SQLite Wasm」を使います。

https://github.com/tomayac/sqlite-wasm

コマンドプロンプトで次のコマンドを実行します。

1
npm install @sqlite.org/sqlite-wasm

Windows PowerShell の場合次のエラーが発生する。

1
2
3
4
5
6
7
8
PS D:\React\my-react-app> npm install @sqlite.org/sqlite-wasm
発生場所 行:1 文字:13
+ npm install @sqlite.org/sqlite-wasm
+ ~~~~~~~
分配演算子 '@' を使用して式で変数を参照することはできません。コマンドの引数として使用できるのは '@sqlite' だけです。式
で変数を参照するには、'$sqlite' を使用してください。
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : SplattingNotPermitted

mydb.sqlite3 をダウンロードしてデータ取得

次のコードを「App.tsx」に貼り付けます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import React from 'react';
import logo from './logo.svg';
import './App.css';
import sqlite3InitModule from '@sqlite.org/sqlite-wasm';

const log = (...args: any[]) => console.log(...args);
const error = (...args: any[]) => console.error(...args);

const start = function (sqlite3: any) {
log('Running SQLite3 version', sqlite3.version.libVersion);

const readDatabase = (arrayBuffer: any) => {
const bytes = new Uint8Array(arrayBuffer);
const p = sqlite3.wasm.allocFromTypedArray(bytes);
const db = new sqlite3.oo1.DB();
sqlite3.capi.sqlite3_deserialize(db.pointer, "main", p, bytes.length, bytes.length, sqlite3.capi.SQLITE_DESERIALIZE_FREEONCLOSE | sqlite3.capi.SQLITE_DESERIALIZE_RESIZEABLE);
return db;
};
(async function () {
const dataPromise = await fetch('mydb.sqlite3').then(res => res.arrayBuffer());
const u8array = new Uint8Array(dataPromise);
const db = readDatabase(u8array);

// Your SQLite code here.
db.exec({
sql: 'SELECT * FROM Test ORDER BY id LIMIT 3', callback: (row: any) => {
log(row);
},
});

})();
};

function App() {

const didLogRef = React.useRef(false);
React.useEffect(() => {
if (didLogRef.current == false) {
didLogRef.current = true;

log('Loading and initializing SQLite3 module...');
sqlite3InitModule({ print: log, printErr: error, }).then((sqlite3: any) => {
try {
log('Done initializing. Running demo...');
start(sqlite3);
} catch (err: any) {
error(err.name, err.message);
}
});
}
}, []);

return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}

export default App;

4~32行目 と 36~51行目 が追加したコードです。

確認

開発者ツールを開いて画面更新をおこなうと、コンソールにSELECT結果が出力されます。

ネットワークタブを見ると「mydb.sqlite3」をダウンロードしていることが分かるかと思います。

終わりに

デモ

デモページを公開しました。

https://noitaro.github.io/react-sqlite-select-web/

参考

https://github.com/tomayac/sqlite-wasm

https://javascript.plainenglish.io/sqlite-3-in-action-how-to-open-a-local-database-with-javascript-and-webassembly-d766d0743a79

https://zenn.dev/knaka0209/books/96eca53ecdb2cd/viewer/d8ca93

https://qiita.com/kaikusakari/items/f30c97385e6b0118f4f0