【Flutter】SQLiteデータベースの扱い方

`sqflite` パッケージを使って `SQLite` データベースとやり取りできる

# 事前準備
`sqflite` パッケージを利用するため `pubspec.yaml` に
```yaml
dependencies:
  flutter:
    sdk: flutter
  path_provider: ^2.0.14
  sqflite: ^2.2.8+1
```
と `sqflite` を追記する
(`path_provider` も使用するのでついでに追記する)

# テーブル作成

```dart
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

void create() async {
  final directory = await getLibraryDirectory();
  final path = join(directory.path, 'my_db.db');

  // テーブル作成
  await openDatabase(
    path,
    version: 1,
    onCreate: (newDb, version) async {
      await newDb.execute('''
        CREATE TABLE sample(
          id INTEGER PRIMARY KEY,
          name TEXT
        )
      ''');
    },
  );
}
```
[openDatabase()](https://pub.dev/documentation/sqflite_common/latest/sqflite/openDatabase.html) には `onCreate` というパラメータがあり、 `path` で指定したデータベースが存在しなかった場合、呼び出される。
ここを利用してテーブルを作成やレコード登録など初期処理を行うことができる。

また、2番目のパラメータとして `version` を指定でき、ここが上がったときに呼び出される `onUpgrade` や、下がった時に呼び出される `onDowngrade` を利用して、スキーマ変更などを行うこともできる。

# レコード登録
```dart
void insert() async {
  final directory = await getLibraryDirectory();
  final path = join(directory.path, 'my_db.db');

  final db = await openDatabase(path);

  await db.transaction((txn) async {
    await txn.insert('sample', {'id': 1, 'name': 'サンプルレコード1'});
    await txn.insert('sample', {'id': 2, 'name': 'サンプルレコード2'});
    await txn.insert('sample', {'id': 3, 'name': 'サンプルレコード3'});
    await txn.insert('sample', {'id': 4, 'name': 'サンプルレコード4'});
  });
}
```
`openDatabase()`はDBが存在するときはDB情報を返してくれるので、それを介して処理を行う。
[transaction()](https://pub.dev/documentation/sqflite_common/latest/sqlite_api/Transaction-class.html) でトランザクションを張り、実際の登録は [insert()](https://pub.dev/documentation/sqflite_common/latest/sqlite_api/DatabaseExecutor/insert.html) を使用して行う。1番目の引数でテーブル名を指定して、実際に登録する値を2番目の引数としてMap型で指定する。

# レコード更新
```dart
void update() async {
  final directory = await getLibraryDirectory();
  final path = join(directory.path, 'my_db.db');

  final db = await openDatabase(path);

  await db.transaction((txn) async {
    await txn.update('sample', {'name': '【更新】サンプルレコード2'}, where: 'id = ?', whereArgs: [2]);
    await txn.update('sample', {'name': '【更新】サンプルレコード3'}, where: 'id = ?', whereArgs: [3]);
    await txn.update('sample', {'name': '【更新】サンプルレコード4'}, where: 'id = ?', whereArgs: [4]);
  });
}
```
[update()](https://pub.dev/documentation/sqflite_common/latest/sqlite_api/DatabaseExecutor/update.html) を使用して行う。insertとほぼ同じ。

# レコード削除
```dart
void delete() async {
  final directory = await getLibraryDirectory();
  final path = join(directory.path, 'my_db.db');

  final db = await openDatabase(path);

  await db.transaction((txn) async {
    await txn.delete('sample', where: 'id = ?', whereArgs: [3]);
    await txn.delete('sample', where: 'id = ?', whereArgs: [4]);
  });
}
```
[delete()](https://pub.dev/documentation/sqflite_common/latest/sqlite_api/DatabaseExecutor/delete.html) を使用する。

# レコード取得
```
void select() async {
  final directory = await getLibraryDirectory();
  final path = join(directory.path, 'my_db.db');

  final db = await openDatabase(path);

  final List<Map<String, dynamic>> result = await db.query(
    'sample',
    where: 'id in (?,?,?,?)',
    whereArgs: [1,2,3,4],
  );

  print(result);
}
```
[query()](https://pub.dev/documentation/sqflite_common/latest/sqlite_api/DatabaseExecutor/query.html) を使用する。例としてWHERE句しか指定していないが、 `ORDER BY` や `GROUP BY` なども指定可能。