refactor(apps): 重构数据层目录结构并新增启动预热编排器
This commit is contained in:
+1
-1
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user