nc-photos/app/lib/use_case/sync_person.dart

85 lines
3 KiB
Dart
Raw Normal View History

2022-08-05 11:39:49 +02:00
import 'package:collection/collection.dart';
import 'package:drift/drift.dart' as sql;
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/person.dart';
2023-02-20 15:21:35 +01:00
import 'package:nc_photos/entity/sqlite/database.dart' as sql;
import 'package:nc_photos/entity/sqlite/type_converter.dart';
2022-08-05 11:39:49 +02:00
import 'package:nc_photos/exception.dart';
import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/list_util.dart' as list_util;
2022-12-16 16:01:04 +01:00
import 'package:np_codegen/np_codegen.dart';
2022-08-05 11:39:49 +02:00
2022-12-16 16:01:04 +01:00
part 'sync_person.g.dart';
@npLog
2022-08-05 11:39:49 +02:00
class SyncPerson {
SyncPerson(this._c) : assert(require(_c));
static bool require(DiContainer c) =>
DiContainer.has(c, DiType.personRepoRemote) &&
DiContainer.has(c, DiType.personRepoLocal);
/// Sync people in cache db with remote server
Future<void> call(Account account) async {
_log.info("[call] Sync people with remote");
late final List<Person> remote;
try {
remote = await _c.personRepoRemote.list(account);
} catch (e) {
if (e is ApiException && e.response.statusCode == 404) {
// face recognition app probably not installed, ignore
_log.info("[call] Face Recognition app not installed");
return;
}
rethrow;
}
final cache = await _c.personRepoLocal.list(account);
int personSorter(Person a, Person b) => a.name.compareTo(b.name);
final diff = list_util.diffWith<Person>(cache, remote, personSorter);
2023-02-14 16:40:30 +01:00
final inserts = diff.onlyInB;
2022-08-05 11:39:49 +02:00
_log.info("[call] New people: ${inserts.toReadableString()}");
2023-02-14 16:40:30 +01:00
final deletes = diff.onlyInA;
2022-08-05 11:39:49 +02:00
_log.info("[call] Removed people: ${deletes.toReadableString()}");
final updates = remote.where((r) {
final c = cache.firstWhereOrNull((c) => c.name == r.name);
return c != null && c != r;
}).toList();
_log.info("[call] Updated people: ${updates.toReadableString()}");
if (inserts.isNotEmpty || deletes.isNotEmpty || updates.isNotEmpty) {
await _c.sqliteDb.use((db) async {
final dbAccount = await db.accountOf(account);
await db.batch((batch) {
for (final d in deletes) {
batch.deleteWhere(
db.persons,
(sql.$PersonsTable p) =>
p.account.equals(dbAccount.rowId) & p.name.equals(d.name),
);
}
for (final u in updates) {
batch.update(
db.persons,
sql.PersonsCompanion(
name: sql.Value(u.name),
thumbFaceId: sql.Value(u.thumbFaceId),
count: sql.Value(u.count),
),
where: (sql.$PersonsTable p) =>
p.account.equals(dbAccount.rowId) & p.name.equals(u.name),
);
}
for (final i in inserts) {
batch.insert(db.persons, SqlitePersonConverter.toSql(dbAccount, i),
mode: sql.InsertMode.insertOrIgnore);
}
});
});
}
}
final DiContainer _c;
}