refactor(apps): 重构数据层目录结构并新增启动预热编排器

This commit is contained in:
zl-q
2026-03-29 20:26:30 +08:00
parent 33340de8f9
commit 4db9a13bfe
108 changed files with 1653 additions and 1320 deletions
@@ -1,4 +1,4 @@
import 'package:social_app/core/network/i_api_client.dart';
import 'package:social_app/data/network/i_api_client.dart';
class TodoApi {
final IApiClient _client;
@@ -0,0 +1,104 @@
import 'dart:async';
import '../../../../data/cache/cache_store.dart';
import '../../../../data/cache/cache_policy.dart';
import '../../../../data/cache/cached_repository.dart';
import '../apis/todo_api.dart';
class TodoRepository extends CachedRepository<List<TodoResponse>> {
static const String pendingListKey = 'todo:list:pending';
final TodoApi api;
final CacheInvalidator invalidator;
TodoRepository({
required this.api,
required super.store,
required this.invalidator,
super.now,
}) : super(
policy: const CachePolicy(
softTtl: Duration(seconds: 30),
hardTtl: Duration(minutes: 10),
minRefreshInterval: Duration(seconds: 15),
),
encodeValue: _encodeTodoList,
decodeValue: _decodeTodoList,
);
Future<List<TodoResponse>> getPendingTodos({
bool forceRefresh = false,
}) async {
return getOrLoad(
key: pendingListKey,
forceRefresh: forceRefresh,
loadFromRemote: api.getPendingTodos,
);
}
Future<void> completeTodo(String id) async {
final CacheEntry<List<TodoResponse>>? cached = await readCacheEntry(
pendingListKey,
);
if (cached != null) {
final next = cached.value
.where((todo) => todo.id != id)
.toList(growable: false);
await writeCacheEntry(pendingListKey, next);
}
try {
await api.completeTodo(id);
invalidator.invalidate(pendingListKey);
} catch (error) {
if (cached != null) {
await writeCacheEntry(pendingListKey, cached.value);
}
rethrow;
}
}
Future<void> invalidatePending() {
invalidator.invalidate(pendingListKey);
return Future<void>.value();
}
static Object? _encodeTodoList(List<TodoResponse> todos) {
return todos.map(_encodeTodo).toList(growable: false);
}
static List<TodoResponse> _decodeTodoList(Object? raw) {
if (raw is! List) {
throw const FormatException('Invalid cached todo list payload');
}
return raw
.whereType<Map>()
.map((item) => TodoResponse.fromJson(Map<String, dynamic>.from(item)))
.toList(growable: false);
}
static Map<String, Object?> _encodeTodo(TodoResponse todo) {
return <String, Object?>{
'id': todo.id,
'owner_id': todo.ownerId,
'title': todo.title,
'description': todo.description,
'order': todo.order,
'priority': todo.priority,
'status': todo.status,
'completed_at': todo.completedAt?.toIso8601String(),
'created_at': todo.createdAt.toIso8601String(),
'updated_at': todo.updatedAt.toIso8601String(),
'schedule_items': todo.scheduleItems.map(_encodeScheduleItem).toList(),
};
}
static Map<String, Object?> _encodeScheduleItem(ScheduleItemBasic item) {
return <String, Object?>{
'id': item.id,
'title': item.title,
'start_at': item.startAt.toIso8601String(),
'end_at': item.endAt?.toIso8601String(),
};
}
}
@@ -1,67 +0,0 @@
import 'dart:async';
import '../../../data/cache/cache_entry.dart';
import '../../../data/cache/cache_invalidator.dart';
import '../../../data/cache/cache_policy.dart';
import '../../../data/cache/cached_repository.dart';
import 'todo_api.dart';
class TodoRepository extends CachedRepository<List<TodoResponse>> {
static const String pendingListKey = 'todo:list:pending';
final TodoApi api;
final CacheInvalidator invalidator;
TodoRepository({
required this.api,
required super.store,
required this.invalidator,
super.now,
}) : super(
policy: const CachePolicy(
softTtl: Duration(days: 3650),
hardTtl: Duration(days: 3650),
minRefreshInterval: Duration(days: 3650),
),
);
Future<List<TodoResponse>> getPendingTodos({
bool forceRefresh = false,
}) async {
return getOrLoad(
key: pendingListKey,
forceRefresh: forceRefresh,
loadFromRemote: api.getPendingTodos,
);
}
Future<void> completeTodo(String id) async {
final CacheEntry<List<TodoResponse>>? cached = await readCacheEntry(
pendingListKey,
);
if (cached != null) {
final next = cached.value
.where((todo) => todo.id != id)
.toList(growable: false);
await writeCacheEntry(pendingListKey, next);
}
try {
await api.completeTodo(id);
invalidator.invalidate(pendingListKey);
} catch (error) {
if (cached != null) {
await store.write<CacheEntry<List<TodoResponse>>>(
pendingListKey,
cached,
);
}
rethrow;
}
}
Future<void> invalidatePending() {
invalidator.invalidate(pendingListKey);
return Future<void>.value();
}
}