0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flutter on the WebでSQLiteを使う

Last updated at Posted at 2024-08-21

SQLite本家によるwasmサポートが開始されており、ブラウザ上でもSQLiteが使えるようになっています。

wasm版のSQLiteは1MBを切るという軽量具合なので、Webアプリで使うには嬉しいですね☺️

Flutter Webでももちろん使えるので、やり方メモを残します。

導入

Dart用のORMであるDriftを作られている方による、sqlite.wasmのビルド済みバイナリがあります。

ありがてぇ、ありがてぇ。

そのままDriftを使うという道もありますが、build_runnerを使う仕組みなので一定規模以下だとメンドクセェ_:(´ཀ`」 ∠):_

ちょろっとDB使いたいだけの時にORMは大袈裟なので、sqlite3パッケージで直接SQL叩く方が簡単だと思います(プレースホルダが使えます)

sqlite3パッケージはプロジェクトフォルダ内で次のコマンドで追加します。

> flutter pub add sqlite3

sqlite3.wasmはライブラリなのでlib下(のwebの下)に配置します。

image.png

利用方法

基本的な流れとしては

  1. sqlite3.wasmを読み込む
  2. ファイル置き場を決める(メモリ or ストレージ)
  3. ファイル名を決めてopen

となります。

インメモリDBで使用する

読み込みも保存もしなくて本当にちょっと使いたい時用です。

基本的には動作確認で使用することになると思います。

// sqlite3.wasmを読み込む
final sqlite3 = await WasmSqlite3.loadFromUrl(Uri.parse('sqlite3.wasm'));

// ファイル置き場を決める(メモリ)
sqlite3.registerVirtualFileSystem(InMemoryFileSystem(), makeDefault: true);

// ファイル名を決めてopen(":memory:"(SQLite規定値)。ラッパー関数が使える)
var db = sqlite3.openInMemory();

ブラウザのストレージに保存する

ユーザーデータなどを置くのはここになると思います。

// sqlite3.wasmを読み込む
final sqlite3 = await WasmSqlite3.loadFromUrl(Uri.parse('sqlite3.wasm'));

// ファイル置き場を決める(IndexedDB)
final fileSystem = await IndexedDbFileSystem.open(dbName: 'indexedDBの名前');
sqlite3.registerVirtualFileSystem(fileSystem, makeDefault: true);

// ファイル名を決めてopen
var db = sqlite3.open("ファイル名");

こんな感じで保存されます。

456115520_8839903346092574_8604917256199807913_n.jpg

Web上のファイルを読み込む

作成済みのデータを読み込む時はこのやり方になると思います。

メモリ上にファイルを作ってデータをコピーしてから使います。

// 作成済みデータの配置場所
var path = "assets/パス名/ファイル名";

// データファイルの読み込み
ByteData data = await rootBundle.load(path);
Uint8List bytes =
    data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

// InMemoryFileSystem上にファイルを作成して書き込む
var fileSystem = InMemoryFileSystem();
var file = fileSystem
    .xOpen(Sqlite3Filename(fileSystem.xFullPathName(path)),  // とりあえず同じpathで
        SqlFlag.SQLITE_OPEN_READWRITE | SqlFlag.SQLITE_OPEN_CREATE)
    .file;
file.xTruncate(0);
file.xWrite(bytes, 0);
file.xClose();

// sqlite3.wasmを読み込む
final sqlite3 = await WasmSqlite3.loadFromUrl(Uri.parse('sqlite3.wasm'));

// ファイル置き場を決める(メモリ)
sqlite3.registerVirtualFileSystem(fileSystem, makeDefault: true);

// ファイル名を決めてopen(InMemoryFileSystem上に作成したファイル)
return sqlite3.open(path);

※実際に使うときは例外処理等を忘れないように

クエリの発行

プレースホルダには?を使います。

文字列操作、ダメ、絶対。

戻り値が不要なクエリ

execute関数を使います。

db.execute("SQLを記述", ["置換する値"]);

// prepare版
var prepared = db.prepare("SQLを記述");
prepared.execute(["置換する値"]);

結果が必要なクエリ

どんなSQLだろうとselect関数を使います。

var result = db.select("SQLを記述", ["置換する値"]);
result.forEach(print);

// prepare版
var prepared = db.prepare("SQLを記述");
var result = prepared.select(["置換する値"]);

結果はResultSet型で、forやforEachでアクセスできます。

もう少し突っ込んで使ってみる

複数のDBをまとめる

データの管理の都合上sqliteのファイルを複数に分けたくなる場合があります。

同じFileSystem上に作成したファイルならattachで開けます。

// DBのロード
Future<void> loadDB(
     CommonDatabase db,
     InMemoryFileSystem fileSystem,
     String dbName,
     String path
   ) async {

  // assetからデータの読み込み
  ByteData data = await rootBundle.load(path);
  Uint8List bytes =
      data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

  // SQLite3のInMemoryFileSystemに書き込む
  var file = fileSystem
      .xOpen(Sqlite3Filename(fileSystem.xFullPathName(path)),
          SqlFlag.SQLITE_OPEN_READWRITE | SqlFlag.SQLITE_OPEN_CREATE)
      .file;
  file.xTruncate(0);
  file.xWrite(bytes, 0);
  file.xClose();

  // Attach Open
  db.execute("""attach database "$path" as $dbName""");
}

アクセス時にtable名の前にdb名を付けてdb名.table名のようにアクセスします。

テーブル作成用SQLを拾う

sqlite_masterにスキーマが格納されています。

IndexedDB上にDBを作るときとか、外部でテーブルを作っておけて便利です。

var schemas =
  memoryDB.select("SELECT * FROM user.sqlite_master WHERE type='table'");
for (var schema in schemas) {
  localStorageDB.execute((schema["sql"] as String)
      .replaceFirst("CREATE TABLE", "CREATE TABLE IF NOT EXISTS"));
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?