見出し画像

[開発者日記] タスクメモアプリ開発 9日目

9日目の投稿がだいぶ遅れました。
最近、やりたいことが多すぎてあれもこれもしていたらあっという間に時間がなくなりました。高速道路の仕組みやナンバリングについて調査したり、ポケモンではらだいこマリルリを育成したり、彼女とお出かけしたりすると日記おろか開発がままならない状況が続いています。
優先順位として、彼女 > 開発 > 資格取得でいかないといけないですね。
平日にいらんことすると自分が本来やりたいことができずに後悔だけが残るので納得できる時間を作れるように調整できたらなと思います。

さて、8日目はGithubとVSCODEの連携と永続化の調査でSQLiteを使用するということになりました。
今日はメモアプリのプロジェクトにSQLiteを実装していきたいと思います。

SQLiteをインストールする

SQLiteを使用するために関連モジュールをインストールします。
モジュールをインストールする際にpubspec.yamlに記述する必要がありますが、ここでpubspec.yamlは何ぞやとなりました。

そもそもYAMLファイルとは?(ザックリ)

YAMLファイルとはファイルの書き方の一つのことで、読み方はヤムルになります。正式名称はYAML Ain’t Markup Languageで、直訳すると「YAML はマークアップ言語ではない」という意味ですね。おもしろい(笑)
改行とインデントで意味を持つみたいです。

じゃあ、pubspec.yamlは?

ここでYAMLファイルはザックリ理解したけれど、Flutterプロジェクトにおけるyamlファイルの役割はなんだろうとなりました。
公式サイトでは、

The pubspec file specifies dependencies that the project requires, such as particular packages (and their versions), fonts, or image files. It also specifies other requirements, such as dependencies on developer packages (like testing or mocking packages), or particular constraints on the version of the Flutter SDK.

# 訳
pubspec ファイルは、特定のパッケージ (およびそのバージョン)、フォント、またはイメージ ファイルなど、プロジェクトが必要とする依存関係を指定します。また、開発者パッケージ (テストやモック パッケージなど) への依存関係や、Flutter SDK のバージョンに対する特定の制約など、その他の要件も指定します。

Flutter公式より
https://docs.flutter.dev/development/tools/pubspec

とありましたので、どうやらpubspec.yamlは必要なパッケージを指定するだけではなく、使用するフォントや画像なども指定できるみたいですね🤔
つまり、プロジェクトで必要なデータやパッケージを管理できる場所という位置づけでしょうか。。

pubspec.yamlにモジュールを追加する

pubspec.yamlがなんとなくわかりましたので、pubspec.yamlにSQLiteに関連するモジュールを追加してあげます。公式を見てみますとSQLiteを使用したかったらsqfliteとpathモジュールを入れてねと書いてありますのでsqfliteとpathをdependenciesの下に追加します。

dependenciesはプロジェクトで使用するパッケージを管理する場所であり、モジュール名を記述する際は半角スペースが2つ必要なことに注意が必要です。

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  
  # 追加
  sqflite:
  path

保存すると勝手にインストールしてくれます。

[memo_app] flutter pub get
Running "flutter pub get" in memo_app...                            5.9s
exit code 0

exit code 0 なのでどうやら成功したみたいですね☺
あえてモジュール名を間違えて、失敗したときの挙動を見たいと思います。
sqfliteをsqfliteeeeeeでインストールしてみます。

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  
  # 追加
  # あえて間違える
  sqfliteeeeee:
  path:

編集して保存してみますと、

[memo_app] flutter pub get
Running "flutter pub get" in memo_app...                        
Because memo_app depends on sqfliteeeeee any which doesn't exist (could not find package sqfliteeeeee at https://pub.dartlang.org), version solving failed.
pub get failed (server unavailable) -- attempting retry 1 in 1 second...
Because memo_app depends on sqfliteeeeee any which doesn't exist (could not find package sqfliteeeeee at https://pub.dartlang.org), version solving failed.

省略

こんな感じでsqfliteeeeeeというパッケージが見つからんよとひたすら怒られ続けることが確認できました👍

SQLiteを実装する

よし!SQLiteが使用できる環境が整ったから後は書くだけ!
と思いましたが、どこに何を書くのだろうと思い手が止まってしまいました。公式も特に一つのファイルに書き出すって感じなのでとりあえず1ファイルにドカドカっと記述していきます。

Modelを作成する

DBのTableからデータを使用するためにModelを作成します。
Tableにデータを挿入・更新するためにModelからMapに変換する必要があるため、ToMapメソッドを定義します。

class Task {
  final int id;
  final String task;

  const Task({required this.id, required this.task});

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'task': task,
    };
  }
}

DB・Tableを作成する

Modelを作成したらDB・Tableを作成します。記述コードは、

final database = openDatabase(
  # DBのパス
  join(await getDatabasesPath(), 'Task_database.db'), 
  
 # Table作成 DBを開く前にDBのパスがなければ実行される
  onCreate: (db, version) {
     return db.execute(
      'CREATE TABLE tasks(id INTEGER PRIMARY KEY, task TEXT)',
     );
   },
   # DBのバージョン
   version: 1,
);

こんな感じです。
DB名は"task_database.db"で、Table名は"tasks"で作成します。
openDatabase(path, onCreate, version)メソッドを実行させることでデータベースを参照することができます。
openDatabaseをもっと詳しく知りたい場合は公式を参考にしてください。

openDatabaseの第一引数(DBパス)を作成する際に、getDtabasesPath()を使用しています。
どこに作成されるかは公式で記述されていました。

Future<String> getDatabasesPath()
Get the default databases location.

On Android, it is typically data/data/

On iOS and MacOS, it is the Documents directory.

Note for iOS: Using path_provider is recommended to get the databases directory. The most appropriate location on iOS would be the Library directory that you could get from the `path_provider` package (https://pub.dev/documentation/path_provider/latest/path_provider/getLibraryDirectory.html).

sqflite公式より(バージョン2.2.2)

今回はiOS専用で作成しますので、iOSではDocumentsフォルダにDBが保存されるようです。今回のメモアプリではDocumentsフォルダをユーザが参照できる想定がありませんので別にここに保存されても問題ないかと思います。最初、Documentsフォルダは何だっけとなりましたが、

こちらが大変参考になりました。

CRUDを作成する

テーブルのデータを操作するためにCRUDを作成します。
データを挿入・更新では定義したModelをMapに変換させて処理をします。
一方、テーブルからデータを取得する際にはMapからModelに変換させてUI側で利用できる形に変換します。

// データ挿入
 Future<void> insertTask(Task task) async {
   final db = await database;
   await db.insert(
     'tasks',
     task.toMap(),
     conflictAlgorithm: ConflictAlgorithm.replace,
   );
 }

// データを更新
 Future<void> updateTask(Task task) async {
   final db = await database;
   await db.update(
     'tasks',
     task.toMap(),
     where: 'id = ?',
     whereArgs: [task.id],
   );
 }

// データ全取得
 Future<List<Task>> tasks() async {
   final db = await database;
   final List<Map<String, dynamic>> maps = await db.query('tasks');
   return List.generate(maps.length, (i) {
     return Task(
       id: maps[i]['id'],
       task: maps[i]['task'],
     );
   });
 }

 // データを削除
 Future<void> deleteTask(int id) async {
   final db = await database;
   await db.delete(
     'tasks',
     where: 'id = ?',
     whereArgs: [id],
   );
 }

ファイルの配置が気になる

ちょっとしたコードですがやはりコード数が長くなり見にくいかなと思ったので、どうやって配置するとか調べるとGithubにsqfliteのサンプルが公開されていました。しかし、ちょっとめんどくさいので次回にやろうかなと思います。一応忘れないために参考URLを貼っておきます。

まとめ

今回はSQLiteを使用するために、パッケージをインストールしてCRUDを定義しました。次回は他の人が実装しているファイル配置を真似しようかなと思います。
(できればテーブルから取得したデータを表示できたら尚良し)

ここまで読んでいただきありがとうございました🥹

溢れた参考URLたち

日記に盛り込めなかった参考URLたちです。日記を更新するときに盛り込みます。


この記事が気に入ったらサポートをしてみませんか?