extract CachedKeyValueRepository

refactor/cached-key-value-repo
shenlong-tanwen 2026-06-03 12:15:19 +05:30
parent 932302c5ab
commit 19fbc11c33
2 changed files with 60 additions and 27 deletions

View File

@ -0,0 +1,37 @@
import 'package:collection/collection.dart';
import 'package:drift/drift.dart';
// ignore: depend_on_referenced_packages
import 'package:meta/meta.dart';
abstract class CachedKeyValueRepository<K extends Enum, S> {
CachedKeyValueRepository(this._snapshot);
S _snapshot;
S get snapshot => _snapshot;
@protected
set snapshot(S value) => _snapshot = value;
List<K> get keys;
Object decodeValue(K key, String raw);
S buildSnapshot(Map<K, Object> overrides);
Selectable<({String key, String value})> selectable();
Future<void> refresh() async => _snapshot = _build(await selectable().get());
Stream<S> watchSnapshot() => selectable().watch().map((rows) => _snapshot = _build(rows));
S _build(List<({String key, String value})> rows) {
final overrides = <K, Object>{};
for (final row in rows) {
final key = keys.firstWhereOrNull((k) => k.name == row.key);
if (key == null) {
continue;
}
overrides[key] = decodeValue(key, row.value);
}
return buildSnapshot(overrides);
}
}

View File

@ -1,14 +1,14 @@
import 'package:collection/collection.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/config/app_config.dart'; import 'package:immich_mobile/domain/models/config/app_config.dart';
import 'package:immich_mobile/domain/models/settings_key.dart'; import 'package:immich_mobile/domain/models/settings_key.dart';
import 'package:immich_mobile/infrastructure/entities/settings.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/settings.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/cached_key_value_repository.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
class SettingsRepository extends DriftDatabaseRepository { class SettingsRepository extends CachedKeyValueRepository<SettingsKey, AppConfig> {
final Drift _db; final Drift _db;
SettingsRepository._(this._db) : super(_db); SettingsRepository._(this._db) : super(const .new());
static SettingsRepository? _instance; static SettingsRepository? _instance;
@ -20,9 +20,6 @@ class SettingsRepository extends DriftDatabaseRepository {
return instance; return instance;
} }
AppConfig _appConfig = const .new();
AppConfig get appConfig => _appConfig;
static Future<SettingsRepository> ensureInitialized(Drift db) async { static Future<SettingsRepository> ensureInitialized(Drift db) async {
if (_instance == null) { if (_instance == null) {
final instance = SettingsRepository._(db); final instance = SettingsRepository._(db);
@ -32,7 +29,20 @@ class SettingsRepository extends DriftDatabaseRepository {
return _instance!; return _instance!;
} }
Future<void> refresh() async => _applyOverrides(await _db.select(_db.settingsEntity).get()); @override
List<SettingsKey> get keys => SettingsKey.values;
@override
Object decodeValue(SettingsKey key, String raw) => key.decode(raw);
@override
AppConfig buildSnapshot(Map<SettingsKey, Object> overrides) => AppConfig.fromEntries(overrides);
@override
Selectable<({String key, String value})> selectable() =>
_db.select(_db.settingsEntity).map((row) => (key: row.key, value: row.value));
AppConfig get appConfig => snapshot;
Future<void> clear(Iterable<SettingsKey> keys) async { Future<void> clear(Iterable<SettingsKey> keys) async {
if (keys.isEmpty) { if (keys.isEmpty) {
@ -42,13 +52,15 @@ class SettingsRepository extends DriftDatabaseRepository {
final names = keys.map((key) => key.name).toList(); final names = keys.map((key) => key.name).toList();
await (_db.delete(_db.settingsEntity)..where((row) => row.key.isIn(names))).go(); await (_db.delete(_db.settingsEntity)..where((row) => row.key.isIn(names))).go();
var config = snapshot;
for (final key in keys) { for (final key in keys) {
_appConfig = _appConfig.write(key, defaultConfig.read(key)); config = config.write(key, defaultConfig.read(key));
} }
snapshot = config;
} }
Future<void> write<T extends Object, U extends T>(SettingsKey<T> key, U value) async { Future<void> write<T extends Object, U extends T>(SettingsKey<T> key, U value) async {
if (value == _appConfig.read(key)) { if (value == snapshot.read(key)) {
return; return;
} }
@ -61,24 +73,8 @@ class SettingsRepository extends DriftDatabaseRepository {
.insertOnConflictUpdate( .insertOnConflictUpdate(
SettingsEntityCompanion.insert(key: key.name, value: key.encode(value), updatedAt: Value(DateTime.now())), SettingsEntityCompanion.insert(key: key.name, value: key.encode(value), updatedAt: Value(DateTime.now())),
); );
_appConfig = _appConfig.write(key, value); snapshot = snapshot.write(key, value);
} }
Stream<AppConfig> watchConfig() => _db.select(_db.settingsEntity).watch().map((rows) { Stream<AppConfig> watchConfig() => watchSnapshot();
_applyOverrides(rows);
return _appConfig;
});
void _applyOverrides(List<SettingsEntityData> rows) {
_appConfig = AppConfig.fromEntries(
rows.fold({}, (overrides, row) {
final metadataKey = SettingsKey.values.firstWhereOrNull((key) => key.name == row.key);
if (metadataKey == null) {
return overrides;
}
return {...overrides, metadataKey: metadataKey.decode(row.value)};
}),
);
}
} }