Skip to content

Commit c2e5964

Browse files
committed
feat(registry): implement data operation registry for CRUD functions
- Create DataOperationRegistry class to centralize data handling functions - Define typedefs for various data operations (fetch, read, create, update, delete) - Implement registration methods for different data models - Add support for headline, topic, source, country, language, user, and other models - Enable dependency injection for DataRepository and DashboardSummaryService - Include ownership check middleware for user-related operations
1 parent 62f0f50 commit c2e5964

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import 'package:core/core.dart';
2+
import 'package:dart_frog/dart_frog.dart';
3+
import 'package:data_repository/data_repository.dart';
4+
import 'package:flutter_news_app_api_server_full_source_code/src/services/dashboard_summary_service.dart';
5+
import 'package:flutter_news_app_api_server_full_source_code/src/middlewares/ownership_check_middleware.dart';
6+
7+
// --- Typedefs for Data Operations ---
8+
9+
/// A function that fetches a single item by its ID.
10+
typedef ItemFetcher = Future<dynamic> Function(
11+
RequestContext context,
12+
String id,
13+
);
14+
15+
/// A function that fetches a paginated list of items.
16+
typedef AllItemsReader = Future<PaginatedResponse<dynamic>> Function(
17+
RequestContext context,
18+
String? userId,
19+
Map<String, dynamic>? filter,
20+
List<SortOption>? sort,
21+
PaginationOptions? pagination,
22+
);
23+
24+
/// A function that creates a new item.
25+
typedef ItemCreator = Future<dynamic> Function(
26+
RequestContext context,
27+
dynamic item,
28+
String? userId,
29+
);
30+
31+
/// A function that updates an existing item.
32+
typedef ItemUpdater = Future<dynamic> Function(
33+
RequestContext context,
34+
String id,
35+
dynamic item,
36+
String? userId,
37+
);
38+
39+
/// A function that deletes an item by its ID.
40+
typedef ItemDeleter = Future<void> Function(
41+
RequestContext context,
42+
String id,
43+
String? userId,
44+
);
45+
46+
/// {@template data_operation_registry}
47+
/// A centralized registry for all data handling functions (CRUD operations).
48+
///
49+
/// This class uses a map-based strategy to associate model names (strings)
50+
/// with their corresponding data operation functions. This approach avoids
51+
/// large, repetitive `switch` statements in the route handlers, making the
52+
/// code more maintainable, scalable, and easier to read.
53+
///
54+
/// By centralizing these mappings, we create a single source of truth for how
55+
/// data operations are performed for each model, improving consistency across
56+
/// the API.
57+
/// {@endtemplate}
58+
class DataOperationRegistry {
59+
/// {@macro data_operation_registry}
60+
DataOperationRegistry() {
61+
_registerOperations();
62+
}
63+
64+
// --- Private Maps to Hold Operation Functions ---
65+
66+
final Map<String, ItemFetcher> _itemFetchers = {};
67+
final Map<String, AllItemsReader> _allItemsReaders = {};
68+
final Map<String, ItemCreator> _itemCreators = {};
69+
final Map<String, ItemUpdater> _itemUpdaters = {};
70+
final Map<String, ItemDeleter> _itemDeleters = {};
71+
72+
// --- Public Getters to Access Operation Maps ---
73+
74+
/// Provides access to the map of item fetcher functions.
75+
Map<String, ItemFetcher> get itemFetchers => _itemFetchers;
76+
77+
/// Provides access to the map of collection reader functions.
78+
Map<String, AllItemsReader> get allItemsReaders => _allItemsReaders;
79+
80+
/// Provides access to the map of item creator functions.
81+
Map<String, ItemCreator> get itemCreators => _itemCreators;
82+
83+
/// Provides access to the map of item updater functions.
84+
Map<String, ItemUpdater> get itemUpdaters => _itemUpdaters;
85+
86+
/// Provides access to the map of item deleter functions.
87+
Map<String, ItemDeleter> get itemDeleters => _itemDeleters;
88+
89+
/// Populates the operation maps with their respective functions.
90+
void _registerOperations() {
91+
// --- Register Item Fetchers ---
92+
_itemFetchers.addAll({
93+
'headline': (c, id) =>
94+
c.read<DataRepository<Headline>>().read(id: id, userId: null),
95+
'topic': (c, id) =>
96+
c.read<DataRepository<Topic>>().read(id: id, userId: null),
97+
'source': (c, id) =>
98+
c.read<DataRepository<Source>>().read(id: id, userId: null),
99+
'country': (c, id) =>
100+
c.read<DataRepository<Country>>().read(id: id, userId: null),
101+
'language': (c, id) =>
102+
c.read<DataRepository<Language>>().read(id: id, userId: null),
103+
'user': (c, id) =>
104+
c.read<DataRepository<User>>().read(id: id, userId: null),
105+
'user_app_settings': (c, id) => c
106+
.read<DataRepository<UserAppSettings>>()
107+
.read(id: id, userId: null),
108+
'user_content_preferences': (c, id) => c
109+
.read<DataRepository<UserContentPreferences>>()
110+
.read(id: id, userId: null),
111+
'remote_config': (c, id) =>
112+
c.read<DataRepository<RemoteConfig>>().read(id: id, userId: null),
113+
'dashboard_summary': (c, id) =>
114+
c.read<DashboardSummaryService>().getSummary(),
115+
});
116+
117+
// --- Register "Read All" Readers ---
118+
_allItemsReaders.addAll({
119+
'headline': (c, uid, f, s, p) => c
120+
.read<DataRepository<Headline>>()
121+
.readAll(userId: uid, filter: f, sort: s, pagination: p),
122+
'topic': (c, uid, f, s, p) => c
123+
.read<DataRepository<Topic>>()
124+
.readAll(userId: uid, filter: f, sort: s, pagination: p),
125+
'source': (c, uid, f, s, p) => c
126+
.read<DataRepository<Source>>()
127+
.readAll(userId: uid, filter: f, sort: s, pagination: p),
128+
'country': (c, uid, f, s, p) => c
129+
.read<DataRepository<Country>>()
130+
.readAll(userId: uid, filter: f, sort: s, pagination: p),
131+
'language': (c, uid, f, s, p) => c
132+
.read<DataRepository<Language>>()
133+
.readAll(userId: uid, filter: f, sort: s, pagination: p),
134+
'user': (c, uid, f, s, p) => c
135+
.read<DataRepository<User>>()
136+
.readAll(userId: uid, filter: f, sort: s, pagination: p),
137+
});
138+
139+
// --- Register Item Creators ---
140+
_itemCreators.addAll({
141+
'headline': (c, item, uid) => c
142+
.read<DataRepository<Headline>>()
143+
.create(item: item as Headline, userId: uid),
144+
'topic': (c, item, uid) => c
145+
.read<DataRepository<Topic>>()
146+
.create(item: item as Topic, userId: uid),
147+
'source': (c, item, uid) => c
148+
.read<DataRepository<Source>>()
149+
.create(item: item as Source, userId: uid),
150+
'country': (c, item, uid) => c
151+
.read<DataRepository<Country>>()
152+
.create(item: item as Country, userId: uid),
153+
'language': (c, item, uid) => c
154+
.read<DataRepository<Language>>()
155+
.create(item: item as Language, userId: uid),
156+
'remote_config': (c, item, uid) => c
157+
.read<DataRepository<RemoteConfig>>()
158+
.create(item: item as RemoteConfig, userId: uid),
159+
});
160+
161+
// --- Register Item Updaters ---
162+
_itemUpdaters.addAll({
163+
'headline': (c, id, item, uid) => c
164+
.read<DataRepository<Headline>>()
165+
.update(id: id, item: item as Headline, userId: uid),
166+
'topic': (c, id, item, uid) => c
167+
.read<DataRepository<Topic>>()
168+
.update(id: id, item: item as Topic, userId: uid),
169+
'source': (c, id, item, uid) => c
170+
.read<DataRepository<Source>>()
171+
.update(id: id, item: item as Source, userId: uid),
172+
'country': (c, id, item, uid) => c
173+
.read<DataRepository<Country>>()
174+
.update(id: id, item: item as Country, userId: uid),
175+
'language': (c, id, item, uid) => c
176+
.read<DataRepository<Language>>()
177+
.update(id: id, item: item as Language, userId: uid),
178+
'user': (c, id, item, uid) {
179+
final repo = c.read<DataRepository<User>>();
180+
final existingUser = c.read<FetchedItem<dynamic>>().data as User;
181+
final updatedUser = existingUser.copyWith(
182+
feedActionStatus: (item as User).feedActionStatus,
183+
);
184+
return repo.update(id: id, item: updatedUser, userId: uid);
185+
},
186+
'user_app_settings': (c, id, item, uid) => c
187+
.read<DataRepository<UserAppSettings>>()
188+
.update(id: id, item: item as UserAppSettings, userId: uid),
189+
'user_content_preferences': (c, id, item, uid) => c
190+
.read<DataRepository<UserContentPreferences>>()
191+
.update(id: id, item: item as UserContentPreferences, userId: uid),
192+
'remote_config': (c, id, item, uid) => c
193+
.read<DataRepository<RemoteConfig>>()
194+
.update(id: id, item: item as RemoteConfig, userId: uid),
195+
});
196+
197+
// --- Register Item Deleters ---
198+
_itemDeleters.addAll({
199+
'headline': (c, id, uid) =>
200+
c.read<DataRepository<Headline>>().delete(id: id, userId: uid),
201+
'topic': (c, id, uid) =>
202+
c.read<DataRepository<Topic>>().delete(id: id, userId: uid),
203+
'source': (c, id, uid) =>
204+
c.read<DataRepository<Source>>().delete(id: id, userId: uid),
205+
'country': (c, id, uid) =>
206+
c.read<DataRepository<Country>>().delete(id: id, userId: uid),
207+
'language': (c, id, uid) =>
208+
c.read<DataRepository<Language>>().delete(id: id, userId: uid),
209+
'user': (c, id, uid) =>
210+
c.read<DataRepository<User>>().delete(id: id, userId: uid),
211+
'user_app_settings': (c, id, uid) => c
212+
.read<DataRepository<UserAppSettings>>()
213+
.delete(id: id, userId: uid),
214+
'user_content_preferences': (c, id, uid) => c
215+
.read<DataRepository<UserContentPreferences>>()
216+
.delete(id: id, userId: uid),
217+
'remote_config': (c, id, uid) =>
218+
c.read<DataRepository<RemoteConfig>>().delete(id: id, userId: uid),
219+
});
220+
}
221+
}

0 commit comments

Comments
 (0)