はじめに
エキサイト株式会社の髙野です。
今回はFlutterのライブラリであるDriftを使用しましたので紹介します。
そもそもDriftとは
DriftとはiOSではRealm, AndroidではRoomのようにオブジェクトをアプリがアンインストール等されない限り端末内に残しておくためのデータベースライブラリです。
Roomを参考にしているようでもともとはMoorという名前でした。それから名前が変更され、Driftという名前になったそうです。
環境
flutter: 3.3.8
drift: 2.4.2
sqlite3_flutter_libs: 0.5.0
path_provider: 2.0.0
path: 1.8.2
インストール
上記に環境としてライブラリのバージョンを記載しましたが、以下URLを参考に pubspec.yaml
に記述してください。
実装
今回僕が実装した方法としてはrepository→dataSource→dao→databaseという形にしました。
databaseから遡るように紹介します。
database
@DriftDatabase( tables: [ Users, ], daos: [ UserDao, ] ) class AppDatabase extends _$AppDatabase { AppDatabase() : super(_openConnection()); @override int get schemaVersion => 1; } LazyDatabase _openConnection() { return LazyDatabase(() async { final dbFolder = await getApplicationDocumentsDirectory(); final file = File(join(dbFolder.path, 'db.sqlite')); return NativeDatabase(file); }); }
まずは大元のデータベースを作成し、管理するクラスを作成します。
作成しましたら、 build_runner
を使用してコード生成を行います。
@DataClassName('UserTable') class Users extends Table { @override String? get tableName => 'Users'; @override List<Set<Column>> get uniqueKeys => [ {userCode} ]; IntColumn get id => integer().autoIncrement()(); TextColumn get userCode => text()(); TextColumn get name => text()(); IntColumn get age => integer()(); }
次にTableClassの作成をします。
@DataClassName
で設定した名前がModel名となります。
uniqueKey
を設定することもでき、これで重複しないようにすることができます。
dao
@DriftAccessor(tables: [Users]) class UserDao extends DatabaseAccessor<AppDatabase> with _$UserDaoMixin { UserDao(AppDatabase db) : super(db); Future<List<UserTable>> getAllUsers() { return select(users).get(); } Future<void> insertUser({ required Insertable<UserTable> user, }) async { await batch((batch) { batch.insert( users, user, onConflict: DoUpdate( (_) => user, target: [ user.name, user.age, ], ), ); }); } }
以上がDaoになります。今回記載したのは全件取得とInsertですがこちらを紹介します。
データを取得する時には select
を使用し、挿入したい時には batch.insert
を使用します。作成した後 build_runner
でコード生成をします。
dataSource
class UserDatabaseDataSource { const UserDatabaseDataSource(this._database); final AppDatabase _database; Future<List<User>> getAllUsers() async { final localUsers = await _database.userDao.getAllUsers(); return localUsers.map((e) => User( userCode: e.userCode, name: e.name, age: e.age, )).toList(); } Future<void> addUser(User user) async { final insertableUser = UsersCompanion( userCode: Value(user.userCode), name: Value(user.name), age: Value(user.age), ); return await _database.userDao.insertUser(user: insertableUser); } }
以上がDataSourceになります。ここでTableModelと実際に使用するModelの変換を行います。
insert時には生成された UsersCompanion
クラスを使用し、変換をします。そのマッピング時に各値に対してValueで括って上げる必要があるのでご注意ください。
repository
class UserRepository { const UserRepository(this._dataSource); final UserDatabaseDataSource _dataSource; Future<List<User>> getAllUsers() async { return await _dataSource.getAllUsers(); } Future<void> addUser({ required User user, }) async { return _dataSource.addUser(user); } }
特に変わった処理はしていませんが、dataSourceから必要な関数を呼び出しています。
最後に
エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。募集にはありませんが、長期インターンも歓迎していますので、興味があれば連絡いただければと思います。
カジュアル面談はこちらになります! meety.net
募集職種一覧はこちらになります!(カジュアルからもOK) www.wantedly.com