LoginSignup
1
1

FlutterでDriftを使用してみた~初期構築編~

Last updated at Posted at 2023-05-01

はじめに

FlutterにDriftを導入したときの手順を残しておきます。

本記事は以下の公式ドキュメントを参考にしています。
詳しいことが知りたい方はこちらを参照してください。

Flutterのインストール方法は説明しません。

環境

Dart-2.19.6Flutter-3.7.12Drift-2.7.0

1.インストール

Driftと依存関係のあるパッケージをpubspec.yamlに定義します。

pubspec.yamlでバージョンを指定してインストールする場合

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
+  drift: ^2.7.0
+  sqlite3_flutter_libs: ^0.5.0
+  path_provider: ^2.0.0
+  path: ^1.8.2

dev_dependencies:
  flutter_test:
    sdk: flutter
+  drift_dev: ^2.7.0
+  build_runner: ^2.3.3
各パッケージの用途

公式ドキュメントをそのまま翻訳しただけのものですが、載せておきます。

パッケージ名 用途
drift ほとんどのAPIを定義するコアパッケージ
sqlite3_flutter_libs AndroidまたはiOSアプリに最新のsqlite3バージョンを含めるためのパッケージ。Flutterを使用していない場合は必要ありませんが、その場合は自分でsqlite3を含める必要があります。他のプラットフォームの概要については、プラットフォームを参照してください。
path_providerとpath データベースを格納するのに適した場所を見つけるためのパッケージ。FlutterとDartチームによって維持されています。
drift_dev テーブルに基づいたクエリコードを生成するための開発時の依存関係。最終的なアプリには含まれません。
build_runner コード生成のための一般的なツールで、Dartチームによって維持されています。

以下のコマンドを実行してパッケージをインストールします。

flutter pub get

コマンドから最新のパッケージをインストールする場合

以下のコマンドを実行してください。

dart pub add drift sqlite3_flutter_libs path_provider path dev:drift_dev dev:build_runner

2.テーブル定義を作成

2.1 データベース関連の定義を置くためのフォルダ/ファイルを作成する

フォルダ構成
lib
│  main.dart
└─database <- ここに作成
   └─  database.dart

2.2 定義ファイルを作成

database.dart
import 'package:drift/drift.dart';

// このファイルの名前が"database.dart"の場合は以下の名前で定義しておく。
// このタイミングだとファイルが存在しないためエラーが出るが、後の工程で自動作成される。
part 'database.g.dart';

// 以下の定義の場合だと"todos"というテーブルが作成される。
// 行単位のデータは"Todoクラス"になる。
//  ※Todoクラスはこの後の工程で自動で作成される。
class Todos extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().withLength(min: 6, max: 32)();
  TextColumn get content => text().named('body')();
  IntColumn get category => integer().nullable()();
}

// Driftでは行単位のデータを扱うクラスを作成するときはテーブルクラスから"s"を除いたものを作成するため、
// 単数形と複数形で形が異なる場合は"DataClassName"で単数形の名称を定義する必要がある。
// DataNameClassを定義しない場合は"Categorie"になってしまう。
@DataClassName('Category')
class Categories extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get description => text()();
}

// DriftDatabaseに上記の2テーブルを指定して、Driftで扱えるよう設定する。
// 今のタイミングではMyDatabeseクラスは空で良い。
// "_$MyDatabase"が存在しないと怒られるが気にしない。
@DriftDatabase(tables: [Todos, Categories])
class MyDatabase extends _$MyDatabase {
}

3.ビルドする

3.1 ビルド

以下のコマンドを実行すると2で書いたテーブル定義をもとに"database.g.dart"を作成してくれます。
テーブル定義に手を加えたときは、毎回このコマンドを実行して"database.g.dart"を更新する必要があります。

筆者は公式ドキュメントをよく読んでなくてここでちょっとつまづきました...。反省...。

flutter pub run build_runner build

テーブル定義を何回か修正する場合は、以下のコマンドを使用することで変更を追跡して勝手にビルドしてくれます

flutter pub run build_runner watch

3.2 ビルド後の初期設定

"database.dart"内で定義した"MyDatabase"を以下のように変更します。

database.dart
// 初期設定を定義するために以下のインポートを追加
import 'dart:io';

import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

@DriftDatabase(tables: [Todos, Categories])
class MyDatabase extends _$MyDatabase {
  // コンストラクタでDBの保存先を定義する
  MyDatabase() : super(_openConnection());

  // マイグレーションを行う場合に使用ため、テーブルを追加/変更/削除する場合はこの値をインクリメントする
  @override
  int get schemaVersion => 1;
}

LazyDatabase _openConnection() {
  // the LazyDatabase util lets us find the right location for the file async.
  return LazyDatabase(() async {
    // PCの場合はドキュメントフォルダに"db.sqlite"が作成される
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File(p.join(dbFolder.path, 'db.sqlite'));
    return NativeDatabase.createInBackground(file);
  });
}

4.実際に使用する

お試しでDBにデータを登録して取得する処理を作りたいので、main.dartのincrementボタンを流用します。
main.dart を以下のように変更します。
アプリ立ち上げ後に、incrementボタンを押したらコンソール上に
Categories in database: [Category(id: 1, description: my first category)]
みたいな文章がprintされればOKです。

main.dart
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

+  Future<void> _testDrift() async {
+    final database = MyDatabase();
+
+    // Simple insert:
+    await database
+        .into(database.categories)
+        .insert(CategoriesCompanion.insert(description: 'my first category'));
+
+    // Simple select:
+    final allCategories = await database.select(database.categories).get();
+    print('Categories in database: $allCategories');
+  }

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      floatingActionButton: FloatingActionButton(
-        onPressed: _incrementCounter,
+        onPressed: _testDrift,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
}

おまけ(TodosとCategoriesをForeignKeyでつなぐ)

今のままだとTodosとCategoriesの関係がわかりにくいのと、SQLiteのForeignKey機能を利用したい場合は以下のコードのように変更すればよいです。

database.dart
class Todos extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().withLength(min: 6, max: 32)();
  TextColumn get content => text().named('body')();
- IntColumn get category => integer().nullable()();
+ // categoyにForeignKeyを設定
+ IntColumn get category => integer().nullable().references(Categories, #id)();
}

@DriftDatabase(tables: [Movies, WatchLists], daos: [MoviesDao, WatchListsDao])
class MyDatabase extends _$MyDatabase {

+@override
+  MigrationStrategy get migration {
+    return MigrationStrategy(
+        onCreate: (Migrator m) async {
+          await m.createAll();
+        },
+        onUpgrade: (Migrator m, int from, int to) async {},
+        beforeOpen: (details) async {
+          if (details.wasCreated) {
+            // ...
+          }
+          // デフォルトではForeignKeyの設定がOFFになっているためONにする
+          await customStatement('PRAGMA foreign_keys = ON');
+        });
+  }
}

Driftを使って見たメモ

Driftを使ってみたときのメモです。よかったらこちらも参考にしてください。

テスト編

1
1
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
1
1