Tauri アプリで SQLite データベースを利用するためのプラグイン導入から、テーブル作成、データの追加・参照・更新・削除 (CRUD) までの基本操作をまとめて解説します。
1. セットアップ
インストール手順
Rust 側と JavaScript 側の両方に依存関係を追加し、プラグインを初期化します。
1. コマンドで追加
Tauri CLI を使用して、プラグインをプロジェクトに追加します。
このコマンドを実行すると、Rust 側の依存関係(cargo)と JavaScript 側の依存関係(npm)の両方が自動的にインストールされます。
npm run tauri add sql
補足: Rust 側を個別にインストールしたい場合は、src-tauriディレクトリでcargo add tauri-plugin-sql --features sqliteを実行してください。
2. Cargo.toml の確認 (Rust)
src-tauri/Cargo.toml を確認し、features に sqlite が含まれていることを確認してください。
[dependencies]
tauri-plugin-sql = { version = "2", features = ["sqlite"] }
3. プラグインの初期化 (Rust)
src-tauri/src/lib.rs ファイルを開き、plugin メソッドを使用してプラグインを登録します。
// src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_sql::Builder::default().build()) // ここに追加
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
権限設定 (Capabilities)
src-tauri/capabilities/default.json でデータベースへのアクセスを許可します。
{
"permissions": [
...,
"sql:default",
"sql:allow-load",
"sql:allow-execute",
"sql:allow-select"
]
}
注意:sql.execute not allowedなどのエラーが出る場合は、上記のように個別の権限(allow-executeやallow-select)を明示的に追加してください。セキュリティ向上のため、本番環境では必要な権限のみに絞ることが推奨されます。
2. データベースへの接続
フロントエンドからデータベースファイルを作成・接続します。
SQLite の場合、指定したパスにファイルがなければ自動的に作成されます。
import Database from '@tauri-apps/plugin-sql';
// データベースを開く(なければ作成)
// ファイル名 "myapp.db" の場合、OSごとの標準的なアプリデータフォルダに保存されます
const db = await Database.load('sqlite:myapp.db');
console.log('Database connected');
3. テーブルの作成
初期化時などに CREATE TABLE を実行します。IF NOT EXISTS を使うと安全です。
// テーブル作成
await db.execute(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
4. データの操作 (CRUD)
追加 (INSERT)
SQL インジェクションを防ぐため、必ずプレースホルダー($1, $2...)を使用してください。
async function addUser(name: string, email: string) {
// 戻り値は { rowsAffected: number, lastInsertId: number }
const result = await db.execute(
'INSERT INTO users (name, email) VALUES ($1, $2)',
[name, email]
);
console.log(`Inserted ID: ${result.lastInsertId}`);
}
検索 (SELECT)
戻り値を型指定して受け取ることができます。
interface User {
id: number;
name: string;
email: string | null;
}
async function searchUser(keyword: string): Promise<User[]> {
// 部分一致検索
const users = await db.select<User[]>(
'SELECT * FROM users WHERE name LIKE $1 ORDER BY id DESC',
[`%${keyword}%`]
);
return users;
}
更新 (UPDATE)
async function updateUserName(id: number, newName: string) {
const result = await db.execute(
'UPDATE users SET name = $1 WHERE id = $2',
[newName, id]
);
console.log(`Updated ${result.rowsAffected} row(s).`);
}
削除 (DELETE)
async function deleteUser(id: number) {
const result = await db.execute(
'DELETE FROM users WHERE id = $1',
[id]
);
console.log(`Deleted ${result.rowsAffected} user(s).`);
}
5. トランザクション
複数の操作をまとめて行う場合は、トランザクションを使用します。
await db.execute('BEGIN TRANSACTION');
try {
// 複数の処理...
await db.execute('INSERT INTO users (name) VALUES ($1)', ['Alice']);
await db.execute('INSERT INTO users (name) VALUES ($1)', ['Bob']);
await db.execute('COMMIT');
} catch (e) {
await db.execute('ROLLBACK');
throw e;
}