アプリのバージョンアップに伴い、データベース定義(カラム追加など)を変更するためのマイグレーションロジックの管理パターンを紹介します。
前提条件
Permissions (権限) の設定
src-tauri/capabilities/default.json に以下の権限を追加します。
{
"permissions": [
...,
"sql:default"
]
}
簡易マイグレーション関数の実装
専用のテーブル作成やスキーマ変更を順番に適用する関数を作成します。
import Database from '@tauri-apps/plugin-sql';
const MIGRATIONS = [
// Version 1: 初期テーブル作成
`CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT);`,
// Version 2: users テーブル追加
`CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT);`,
// Version 3: email カラム追加
`ALTER TABLE users ADD COLUMN email TEXT;`
];
async function migrate(db: Database) {
// 現在のバージョンを取得(PRAGMA user_version は SQLite 固有のバージョン管理領域)
const result = await db.select<[{user_version: number}]>('PRAGMA user_version');
let currentVersion = result[0].user_version;
console.log(`Current DB Version: ${currentVersion}`);
// 未適用のマイグレーションを実行
for (let i = currentVersion; i < MIGRATIONS.length; i++) {
console.log(`Applying migration version ${i + 1}...`);
try {
await db.execute('BEGIN TRANSACTION');
await db.execute(MIGRATIONS[i]);
// バージョン番号更新
await db.execute(`PRAGMA user_version = ${i + 1}`);
await db.execute('COMMIT');
} catch (e) {
await db.execute('ROLLBACK');
console.error(`Migration failed at version ${i + 1}`, e);
throw e;
}
}
}
// 実行例: DB接続とマイグレーションをまとめて実行
export async function initDatabase() {
try {
// データベースに接続
const db = await Database.load('sqlite:myapp.db');
// マイグレーション実行
await migrate(db);
console.log('Database initialized successfully');
return db;
} catch (error) {
console.error('Database initialization failed:', error);
throw error;
}
}
この migrate 関数を、Database.load 直後に呼び出すことで、常に最新のスキーマ状態を保つことができます。
SQL ファイルを分割して管理したい場合は、Vite の import.meta.glob (?raw) 機能を使って文字列として読み込むなどの工夫が可能です。