import 'package:drift/drift.dart'; import 'package:hiddify/data/local/data_mappers.dart'; import 'package:hiddify/data/local/database.dart'; import 'package:hiddify/data/local/tables.dart'; import 'package:hiddify/domain/enums.dart'; import 'package:hiddify/domain/profiles/profiles.dart'; import 'package:hiddify/utils/utils.dart'; part 'profiles_dao.g.dart'; Map orderMap = { SortMode.ascending: OrderingMode.asc, SortMode.descending: OrderingMode.desc, }; @DriftAccessor(tables: [ProfileEntries]) class ProfilesDao extends DatabaseAccessor with _$ProfilesDaoMixin, InfraLogger { ProfilesDao(super.db); Future getById(String id) async { return (profileEntries.select()..where((tbl) => tbl.id.equals(id))) .map(ProfileMapper.fromEntry) .getSingleOrNull(); } Future getProfileByUrl(String url) async { return (select(profileEntries)..where((tbl) => tbl.url.like('%$url%'))) .map(ProfileMapper.fromEntry) .get() .then((value) => value.firstOrNull); } Stream watchActiveProfile() { return (profileEntries.select()..where((tbl) => tbl.active.equals(true))) .map(ProfileMapper.fromEntry) .watchSingleOrNull(); } Stream watchProfileCount() { final count = profileEntries.id.count(); return (profileEntries.selectOnly()..addColumns([count])) .map((exp) => exp.read(count)!) .watchSingle(); } Stream> watchAll({ ProfilesSort sort = ProfilesSort.lastUpdate, SortMode mode = SortMode.ascending, }) { return (profileEntries.select() ..orderBy( [ (tbl) { final trafficRatio = (tbl.download + tbl.upload) / tbl.total; final isExpired = tbl.expire.isSmallerOrEqualValue(DateTime.now()); return OrderingTerm( expression: (trafficRatio.isNull() | trafficRatio.isSmallerThanValue(1)) & (isExpired.isNull() | isExpired.equals(false)), mode: OrderingMode.desc, ); }, switch (sort) { ProfilesSort.name => (tbl) => OrderingTerm( expression: tbl.name, mode: orderMap[mode]!, ), ProfilesSort.lastUpdate => (tbl) => OrderingTerm( expression: tbl.lastUpdate, mode: orderMap[mode]!, ), }, ], )) .map(ProfileMapper.fromEntry) .watch(); } Future create(Profile profile) async { await transaction( () async { if (profile.active) { await (update(profileEntries) ..where((tbl) => tbl.id.isNotValue(profile.id))) .write(const ProfileEntriesCompanion(active: Value(false))); } await into(profileEntries).insert(profile.toCompanion()); }, ); } Future edit(Profile patch) async { await transaction( () async { if (patch.active) { await (update(profileEntries) ..where((tbl) => tbl.id.isNotValue(patch.id))) .write(const ProfileEntriesCompanion(active: Value(false))); } await (update(profileEntries)..where((tbl) => tbl.id.equals(patch.id))) .write(patch.toCompanion()); }, ); } Future setAsActive(String id) async { await transaction( () async { await (update(profileEntries)..where((tbl) => tbl.id.isNotValue(id))) .write(const ProfileEntriesCompanion(active: Value(false))); await (update(profileEntries)..where((tbl) => tbl.id.equals(id))) .write(const ProfileEntriesCompanion(active: Value(true))); }, ); } Future removeById(String id) async { await transaction( () async { await (delete(profileEntries)..where((tbl) => tbl.id.equals(id))).go(); }, ); } }