Open5
【Flutter】内部ストレージ Drift
参考
依存パッケージ
dependencies
- drift
- sqlite3_flutter_libs
- path_provider
- path
dev_dependencies
- build_runner
- drift_dev
path_provider
を使っていることからも分かるように内部的にはデバイスにファイルを作成し、それをデータベースとして取り扱っている様子。
導入
- パッケージのインポート
- テーブルクラスを定義
- データベースクラスを定義
- データベースクラスをインスタンス化
0. パッケージのインポート
dependencies:
drift: ^2.18.0
sqlite3_flutter_libs: ^0.5.0
path_provider: ^2.0.0
path: ^1.9.0
dev_dependencies:
drift_dev: ^2.18.0
build_runner: ^2.4.9
1. テーブルクラスの定義
Table
クラスを継承したクラスを生成。
「カラムのデータ型」+「get」+「カラム名」+「Dartによるマッパー」の形で定義。
class TodoItems 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()();
}
2. データベースクラスの定義
-
_$[クラス名]
を継承したクラスに -
@DriftDatabase(tables:[テーブルの配列])
のアノテーションを付け- テーブルが複数ある場合は
tables:[]
の配列内に記述 ref
- テーブルが複数ある場合は
-
schemaVersion
のgetterを定義し -
LazyDatabase
クラスを返す処理を定義し(現時点では呪いに近い...) - コンストラクタで実行
- 生成ファイルをpart importし
- build runnerで生成
database.dart
part 'database.g.dart';
(tables: [TodoItems])
class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection());
int get schemaVersion => 1;
}
LazyDatabase _openConnection() {
// the LazyDatabase util lets us find the right location for the file async.
return LazyDatabase(() async {
// put the database file, called db.sqlite here, into the documents folder
// for your app.
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));
// Also work around limitations on old Android versions
if (Platform.isAndroid) {
await applyWorkaroundToOpenSqlite3OnOldAndroidVersions();
}
// Make sqlite3 pick a more suitable location for temporary files - the
// one from the system may be inaccessible due to sandboxing.
final cachebase = (await getTemporaryDirectory()).path;
// We can't access /tmp on Android, which sqlite3 would try by default.
// Explicitly tell it about the correct temporary directory.
sqlite3.tempDirectory = cachebase;
return NativeDatabase.createInBackground(file);
});
}
3. データベースクラスのインスタンス化
あとはfinal database = AppDatabase();
でインスタンス化し、インスタンスに対してクエリを実行して操作
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final database = AppDatabase();
await database.into(database.todoItems).insert(TodoItemsCompanion.insert(
title: 'todo: finish drift setup',
content: 'We can now write queries and define our own tables.',
));
List<TodoItem> allItems = await database.select(database.todoItems).get();
print('items in database: $allItems');
}
テーブル定義
基本のデータ型
大体以下で対応できるはず。
Dart type | 対応クラス | 対応するSQL liteのデータ型 |
---|---|---|
int | integer() | INTEGER |
BigInt | int64() | INTEGER (useful for large values on the web) |
double | real() | REAL |
boolean | boolean() | INTEGER, which a CHECK to only allow 0 or 1 |
String | text() | TEXT |
DateTime | dateTime() | INTEGER (default) or TEXT depending on options |
Uint8List | blob() | BLOB |
Enum | intEnum() | INTEGER (more information available here) |
Enum | textEnum() | TEXT (more information available here) |
nullable
nullableのカラムについてはnullable()()
でカラムクラスを作成する
class Items extends Table {
IntColumn get category => integer().nullable()();
// ...
}
外部キー参照
外部キー参照をするカラムはreference(テーブル名、#フィールド名)
でカラムクラスを作成する
class TodoItems extends Table {
// ...
IntColumn get category =>
integer().nullable().references(TodoCategories, #id)();
}
("Category")
class TodoCategories extends Table {
IntColumn get id => integer().autoIncrement()();
// and more columns...
}
デフォルト値
カラムにデフォルト値を持たせたい場合は.withDefault(const Constant(デフォルト値))()
でカラムクラスを作成
BoolColumn get enabled => boolean().withDefault(const Constant(false))();
ユニーク値
カラムをユニーク値にしたい場合はunique()()
でカラムクラスを作成
IntColumn get unique => integer().unique()();
プライマリ・キー
クエリ
Select
- Databaseクラスに生えている
select()
メソッドでテーブルを指定 -
get()
メソッドでテーブル内のデータのFutureを取得
Future<List<TodoItem>> get allTodoItems => database.select(todoItems).get();
-
watch()
メソッドでテーブル内データのStreamを取得
Stream<List<TodoItem>> watchEntriesInCategory(Category c) {
return (database.select(todos)..where((t) => t.category.equals(c.id))).watch();
}
-
select()
メソッドに続く形でDatabaseクラスに生えているwhere()
メソッドでフィルタリング -
where()
メソッド内ではレコードのフィールドに対しequals()
、not()
、isNull()
などでクエリを掛けてフィルタリングする
OrderBy
Join
Update / Delete