Chapter 07

7. DriftでローカルDBを構築しよう

antman
antman
2021.12.06に更新

modelを担当するフォルダを作る

値を格納するDBやクラスを記述していくdartファイルを作ります。
それでは、プロジェクトのlibディレクトリ直下にmodelというディレクトリを作成し、以下のようなDartファイルを作成します。

  • model/
    • db/
      • todo_db.dart
    • freezed/
      • todo
        • todo_model.dart
    • sp/
      • notify_setting_sp.dart
        それぞれのdartファイルの役割は下記の通りです
  1. todo_db.dart
    • todoを記録するためのDBを構築する
  2. todo_model.dart
    • todo画面で使うプロバイダのためのクラスを記述。
  3. notidy_setting_sp.dart
    • 何時間前に通知するかを保存する

DBを構築

DBを構築するまえにどのような値がTodoを入力する画面では求められていたのか一度振り返って見ましょう。
まずタイトル(文字列)、説明文(文字列)、期限(DateTime)。この3つが入力を求められていたとおもいます。
今回はそれに追加して、主キーとなるID(整数)、通知を行うかどうか(真理値)の2つの値を追加したテーブルを作っていきます。

todo_db.dart
// For more information on using drift, please see https://drift.simonbinder.eu/docs/getting-started/

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

part 'todo_db.g.dart';

class TodoItem extends Table {
  IntColumn get id => integer().autoIncrement()(); //primary key
  //Enables auto-increment for this column, which will also make this column the primary key of the table.
  //For this reason, you can't use an [autoIncrement] column and also set a custom [Table.primaryKey] on the same table
  //要するに、autoIncrementを使うと、このカラムはテーブルのプライマリキーになるので、他のカラムにautoIncrementを使うことはできない。
  TextColumn get title =>
      text().withDefault(const Constant('')).withLength(min: 1)();
  TextColumn get description => text().withDefault(const Constant(''))();
  //nullable()でnullを許容する
  DateTimeColumn get limitDate => dateTime().nullable()();
  //DateTimeではなく,dateTimeであることに注意
  BoolColumn get isNotify => boolean().withDefault(const Constant(true))();
  //通知するかどうかを真理値で表す
}

記事にして書くのがめんどくさくてコメント欄に解説を書いちゃいました。
今はエラーだらけかもしれませんが下記のコマンドを実行してみてください。

flutter packages pub run build_runner build

どうでしょうか? todo_db.g.dartが生成されたのがわかると思います。
これでテーブルの作成は終わりです。
次はdbを開いてくれる関数とDBに追加や削除などの操作をしてくれるクラスの2つを追記していきます。

LazyDatabase _openConnection() {
  // the LazyDatabase util lets us find the right location for the file async.
  // これは、ファイルのロケーションを探すのに使えるLazyDatabase utilを許可します。
  return LazyDatabase(() async {
    // put the database file, called db.sqlite here, into the documents folder
    // for your app.
    // ここに、db.sqliteというファイルを、あなたのアプリのドキュメントフォルダに置きます。
    final dbFolder = await getApplicationDocumentsDirectory();
    //Path to a directory where the application may place data that is user-generated, or that cannot otherwise be recreated by your application.
    //データを配置することができるディレクトリのパス。
    final file = File(p.join(dbFolder.path, 'db.sqlite'));
    return NativeDatabase(file);
  });
}

(tables: [TodoItem])
class MyDatabase extends _$MyDatabase {
  MyDatabase() : super(_openConnection());

  
  int get schemaVersion => 1;

  //全てのデータ取得
  Future<List<TodoItemData>> readAllTodoData() => select(todoItem).get();
  //SELECT * FROM ToDoItemTable

  //追加
  Future writeTodo(TodoItemCompanion data) => into(todoItem).insert(data);
  //INSERT INTO ToDoItemTable VALUES(id, 'title', 'description', 'limitDate')

  //更新
  Future updateTodo(TodoItemData data) => update(todoItem).replace(data);
  //UPDATE ToDoItemTable SET title = 'title', description = 'description', limitDate = 'limitDate'

  //削除
  Future deleteTodo(int id) =>
      (delete(todoItem)..where((it) => it.id.equals(id))).go();
  //DELETE FROM ToDoItemTable WHERE id = id
}
//細かい使用方法はこの記事を参考に
//https://drift.simonbinder.eu/docs/getting-started/ (公式ドキュメント)
//https://qiita.com/niusounds/items/e4d731af58201ad5fe6f (ちょい古い)

こちらもコメント文に解説を書いてあります。

まとめ

そろそろ期限ががちでやばいのでこの章はこれで終わりです。聡明な弊大の学生ならなんとなくわかったと思います。
次の章ではtodo画面で使うproviderのためのクラスを作成していきます。具体的に言えばtodo_dbの状態(ロード中かどうかなど)とtodo_dbのデータを格納するためのクラス、入力中のtodoを格納しておくためのクラスの2つです。