Skip to content

Commit ef5ee16

Browse files
committed
refactor(dependencies): simplify repository configurations
- Extract timestamp conversion to shared function - Simplify foreign key handling in serializers - Rename category to topic for better clarity - Update repository names and configurations - Refactor user and content preferences handling - Rename and expand remote config functionality
1 parent 33cab08 commit ef5ee16

File tree

1 file changed

+63
-123
lines changed

1 file changed

+63
-123
lines changed

lib/src/config/app_dependencies.dart

Lines changed: 63 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ class AppDependencies {
3939

4040
// --- Repositories ---
4141
late final HtDataRepository<Headline> headlineRepository;
42-
late final HtDataRepository<Category> categoryRepository;
42+
late final HtDataRepository<Topic> topicRepository;
4343
late final HtDataRepository<Source> sourceRepository;
4444
late final HtDataRepository<Country> countryRepository;
4545
late final HtDataRepository<User> userRepository;
4646
late final HtDataRepository<UserAppSettings> userAppSettingsRepository;
4747
late final HtDataRepository<UserContentPreferences>
48-
userContentPreferencesRepository;
49-
late final HtDataRepository<AppConfig> appConfigRepository;
48+
userContentPreferencesRepository;
49+
late final HtDataRepository<RemoteConfig> remoteConfigRepository;
5050

5151
// --- Services ---
5252
late final HtEmailRepository emailRepository;
@@ -100,178 +100,102 @@ class AppDependencies {
100100
headlineRepository = _createRepository(
101101
connection,
102102
'headlines',
103-
(json) {
104-
if (json['created_at'] is DateTime) {
105-
json['created_at'] =
106-
(json['created_at'] as DateTime).toIso8601String();
107-
}
108-
if (json['updated_at'] is DateTime) {
109-
json['updated_at'] =
110-
(json['updated_at'] as DateTime).toIso8601String();
111-
}
112-
if (json['published_at'] is DateTime) {
113-
json['published_at'] =
114-
(json['published_at'] as DateTime).toIso8601String();
115-
}
116-
return Headline.fromJson(json);
117-
},
103+
// The HtDataPostgresClient returns DateTime objects from TIMESTAMPTZ
104+
// columns. The Headline.fromJson factory expects ISO 8601 strings.
105+
// This handler converts them before deserialization.
106+
(json) => Headline.fromJson(_convertTimestampsToString(json)),
118107
(headline) {
119108
final json = headline.toJson();
120-
// The database expects source_id and category_id, not nested objects.
121-
// We extract the IDs and remove the original objects to match the
122-
// schema.
123-
if (headline.source != null) {
124-
json['source_id'] = headline.source!.id;
125-
}
126-
if (headline.category != null) {
127-
json['category_id'] = headline.category!.id;
128-
}
109+
// The database expects foreign key IDs, not nested objects.
110+
// We extract the IDs and remove the original objects.
111+
json['source_id'] = headline.source.id;
112+
json['topic_id'] = headline.topic.id;
113+
json['event_country_id'] = headline.eventCountry.id;
129114
json.remove('source');
130-
json.remove('category');
115+
json.remove('topic');
116+
json.remove('eventCountry');
131117
return json;
132118
},
133119
);
134-
categoryRepository = _createRepository(
120+
topicRepository = _createRepository(
135121
connection,
136-
'categories',
137-
(json) {
138-
if (json['created_at'] is DateTime) {
139-
json['created_at'] =
140-
(json['created_at'] as DateTime).toIso8601String();
141-
}
142-
if (json['updated_at'] is DateTime) {
143-
json['updated_at'] =
144-
(json['updated_at'] as DateTime).toIso8601String();
145-
}
146-
return Category.fromJson(json);
147-
},
148-
(c) => c.toJson(),
122+
'topics',
123+
(json) => Topic.fromJson(_convertTimestampsToString(json)),
124+
(topic) => topic.toJson(),
149125
);
150126
sourceRepository = _createRepository(
151127
connection,
152128
'sources',
153-
(json) {
154-
if (json['created_at'] is DateTime) {
155-
json['created_at'] =
156-
(json['created_at'] as DateTime).toIso8601String();
157-
}
158-
if (json['updated_at'] is DateTime) {
159-
json['updated_at'] =
160-
(json['updated_at'] as DateTime).toIso8601String();
161-
}
162-
return Source.fromJson(json);
163-
},
129+
(json) => Source.fromJson(_convertTimestampsToString(json)),
164130
(source) {
165131
final json = source.toJson();
166132
// The database expects headquarters_country_id, not a nested object.
167-
// We extract the ID and remove the original object to match the
168-
// schema.
169-
json['headquarters_country_id'] = source.headquarters?.id;
133+
json['headquarters_country_id'] = source.headquarters.id;
170134
json.remove('headquarters');
171135
return json;
172136
},
173137
);
174138
countryRepository = _createRepository(
175139
connection,
176140
'countries',
177-
(json) {
178-
if (json['created_at'] is DateTime) {
179-
json['created_at'] =
180-
(json['created_at'] as DateTime).toIso8601String();
181-
}
182-
if (json['updated_at'] is DateTime) {
183-
json['updated_at'] =
184-
(json['updated_at'] as DateTime).toIso8601String();
185-
}
186-
return Country.fromJson(json);
187-
},
188-
(c) => c.toJson(),
141+
(json) => Country.fromJson(_convertTimestampsToString(json)),
142+
(country) => country.toJson(),
189143
);
190144
userRepository = _createRepository(
191145
connection,
192146
'users',
193-
(json) {
194-
// The postgres driver returns DateTime objects, but the model's
195-
// fromJson expects ISO 8601 strings. We must convert them first.
196-
if (json['created_at'] is DateTime) {
197-
json['created_at'] = (json['created_at'] as DateTime).toIso8601String();
198-
}
199-
if (json['last_engagement_shown_at'] is DateTime) {
200-
json['last_engagement_shown_at'] =
201-
(json['last_engagement_shown_at'] as DateTime).toIso8601String();
202-
}
203-
return User.fromJson(json);
204-
},
147+
(json) => User.fromJson(_convertTimestampsToString(json)),
205148
(user) {
206-
// The `roles` field is a List<String>, but the database expects a
207-
// JSONB array. We must explicitly encode it.
208149
final json = user.toJson();
209-
json['roles'] = jsonEncode(json['roles']);
150+
// Convert enums to their string names for the database.
151+
json['app_role'] = user.appRole.name;
152+
json['dashboard_role'] = user.dashboardRole.name;
153+
// The `feed_action_status` map must be JSON encoded for the JSONB column.
154+
json['feed_action_status'] = jsonEncode(json['feed_action_status']);
210155
return json;
211156
},
212157
);
213158
userAppSettingsRepository = _createRepository(
214159
connection,
215160
'user_app_settings',
216-
(json) {
217-
// The DB has created_at/updated_at, but the model doesn't.
218-
// Remove them before deserialization to avoid CheckedFromJsonException.
219-
json.remove('created_at');
220-
json.remove('updated_at');
221-
return UserAppSettings.fromJson(json);
222-
},
161+
(json) => UserAppSettings.fromJson(json),
223162
(settings) {
224163
final json = settings.toJson();
225164
// These fields are complex objects and must be JSON encoded for the DB.
226165
json['display_settings'] = jsonEncode(json['display_settings']);
227166
json['feed_preferences'] = jsonEncode(json['feed_preferences']);
228-
json['engagement_shown_counts'] =
229-
jsonEncode(json['engagement_shown_counts']);
230-
json['engagement_last_shown_timestamps'] =
231-
jsonEncode(json['engagement_last_shown_timestamps']);
232167
return json;
233168
},
234169
);
235170
userContentPreferencesRepository = _createRepository(
236171
connection,
237172
'user_content_preferences',
238-
(json) {
239-
// The postgres driver returns DateTime objects, but the model's
240-
// fromJson expects ISO 8601 strings. We must convert them first.
241-
if (json['created_at'] is DateTime) {
242-
json['created_at'] =
243-
(json['created_at'] as DateTime).toIso8601String();
244-
}
245-
if (json['updated_at'] is DateTime) {
246-
json['updated_at'] =
247-
(json['updated_at'] as DateTime).toIso8601String();
248-
}
249-
return UserContentPreferences.fromJson(json);
250-
},
173+
(json) => UserContentPreferences.fromJson(json),
251174
(preferences) {
252175
final json = preferences.toJson();
253-
json['followed_categories'] = jsonEncode(json['followed_categories']);
176+
// These fields are lists of complex objects and must be JSON encoded.
177+
json['followed_topics'] = jsonEncode(json['followed_topics']);
254178
json['followed_sources'] = jsonEncode(json['followed_sources']);
255179
json['followed_countries'] = jsonEncode(json['followed_countries']);
256180
json['saved_headlines'] = jsonEncode(json['saved_headlines']);
257181
return json;
258182
},
259183
);
260-
appConfigRepository = _createRepository(
184+
remoteConfigRepository = _createRepository(
261185
connection,
262-
'app_config',
263-
(json) {
264-
if (json['created_at'] is DateTime) {
265-
json['created_at'] =
266-
(json['created_at'] as DateTime).toIso8601String();
267-
}
268-
if (json['updated_at'] is DateTime) {
269-
json['updated_at'] =
270-
(json['updated_at'] as DateTime).toIso8601String();
271-
}
272-
return AppConfig.fromJson(json);
186+
'remote_config',
187+
(json) => RemoteConfig.fromJson(_convertTimestampsToString(json)),
188+
(config) {
189+
final json = config.toJson();
190+
// All nested config objects must be JSON encoded for JSONB columns.
191+
json['user_preference_limits'] =
192+
jsonEncode(json['user_preference_limits']);
193+
json['ad_config'] = jsonEncode(json['ad_config']);
194+
json['account_action_config'] =
195+
jsonEncode(json['account_action_config']);
196+
json['app_status'] = jsonEncode(json['app_status']);
197+
return json;
273198
},
274-
(c) => c.toJson(),
275199
);
276200

277201
// 4. Initialize Services.
@@ -296,12 +220,12 @@ class AppDependencies {
296220
);
297221
dashboardSummaryService = DashboardSummaryService(
298222
headlineRepository: headlineRepository,
299-
categoryRepository: categoryRepository,
223+
topicRepository: topicRepository,
300224
sourceRepository: sourceRepository,
301225
);
302226
permissionService = const PermissionService();
303227
userPreferenceLimitService = DefaultUserPreferenceLimitService(
304-
appConfigRepository: appConfigRepository,
228+
remoteConfigRepository: remoteConfigRepository,
305229
);
306230
}
307231

@@ -321,4 +245,20 @@ class AppDependencies {
321245
),
322246
);
323247
}
248+
249+
/// Converts DateTime values in a JSON map to ISO 8601 strings.
250+
///
251+
/// The postgres driver returns DateTime objects for TIMESTAMPTZ columns,
252+
/// but our models' `fromJson` factories expect ISO 8601 strings. This
253+
/// utility function performs the conversion for known timestamp fields.
254+
Map<String, dynamic> _convertTimestampsToString(Map<String, dynamic> json) {
255+
const timestampKeys = {'created_at', 'updated_at'};
256+
final newJson = Map<String, dynamic>.from(json);
257+
for (final key in timestampKeys) {
258+
if (newJson[key] is DateTime) {
259+
newJson[key] = (newJson[key] as DateTime).toIso8601String();
260+
}
261+
}
262+
return newJson;
263+
}
324264
}

0 commit comments

Comments
 (0)