@@ -2,11 +2,9 @@ import 'dart:async';
22import 'dart:collection' ; // Added for SplayTreeMap
33import 'dart:convert' ;
44
5- import 'package:collection/collection.dart' ;
65import 'package:core/core.dart' ;
76import 'package:data_repository/data_repository.dart' ;
87import 'package:logging/logging.dart' ;
9- import 'package:mongo_dart/mongo_dart.dart' ;
108
119/// {@template country_query_service}
1210/// A service responsible for executing complex queries on country data,
@@ -19,30 +17,25 @@ import 'package:mongo_dart/mongo_dart.dart';
1917class CountryQueryService {
2018 /// {@macro country_query_service}
2119 CountryQueryService ({
22- required DataRepository <Headline > headlineRepository,
23- required DataRepository <Source > sourceRepository,
2420 required DataRepository <Country > countryRepository,
2521 required Logger log,
2622 Duration cacheDuration = const Duration (minutes: 15 ),
27- }) : _headlineRepository = headlineRepository,
28- _sourceRepository = sourceRepository,
29- _countryRepository = countryRepository,
30- _log = log,
31- _cacheDuration = cacheDuration {
23+ }) : _countryRepository = countryRepository,
24+ _log = log,
25+ _cacheDuration = cacheDuration {
3226 _cleanupTimer = Timer .periodic (const Duration (minutes: 5 ), (_) {
3327 _cleanupCache ();
3428 });
35- _log.info ('CountryQueryService initialized with cache duration: $cacheDuration ' );
29+ _log.info (
30+ 'CountryQueryService initialized with cache duration: $cacheDuration ' ,
31+ );
3632 }
37-
38- final DataRepository <Headline > _headlineRepository;
39- final DataRepository <Source > _sourceRepository;
4033 final DataRepository <Country > _countryRepository;
4134 final Logger _log;
4235 final Duration _cacheDuration;
4336
4437 final Map <String , ({PaginatedResponse <Country > data, DateTime expiry})>
45- _cache = {};
38+ _cache = {};
4639 Timer ? _cleanupTimer;
4740 bool _isDisposed = false ;
4841
@@ -88,26 +81,26 @@ class CountryQueryService {
8881
8982 // MongoDB aggregation returns a list of maps. We need to convert these
9083 // back into Country objects.
91- final List <Country > countries = aggregationResult
92- .map ((json) => Country .fromJson (json))
93- .toList ();
84+ final countries = aggregationResult.map (Country .fromJson).toList ();
9485
9586 // For aggregation queries, pagination and hasMore need to be handled
9687 // manually if not directly supported by the aggregation stages.
9788 // For simplicity, we'll assume the aggregation pipeline handles limit/skip
9889 // and we'll determine hasMore based on if we fetched more than the limit.
99- final int limit = pagination? .limit ?? countries.length;
100- final bool hasMore = countries.length > limit;
101- final List <Country > paginatedCountries =
102- countries.take (limit).toList ();
90+ final limit = pagination? .limit ?? countries.length;
91+ final hasMore = countries.length > limit;
92+ final paginatedCountries = countries.take (limit).toList ();
10393
10494 final response = PaginatedResponse <Country >(
10595 items: paginatedCountries,
10696 cursor: null , // Aggregation doesn't typically return a cursor directly
10797 hasMore: hasMore,
10898 );
10999
110- _cache[cacheKey] = (data: response, expiry: DateTime .now ().add (_cacheDuration));
100+ _cache[cacheKey] = (
101+ data: response,
102+ expiry: DateTime .now ().add (_cacheDuration),
103+ );
111104 _log.finer ('Cached new result for key: $cacheKey ' );
112105
113106 return response;
@@ -132,9 +125,7 @@ class CountryQueryService {
132125
133126 // --- Stage 1: Initial Match for active status (if applicable) ---
134127 // All countries should be active by default for these queries
135- compoundMatchStages.add ({
136- 'status' : ContentStatus .active.name,
137- });
128+ compoundMatchStages.add ({'status' : ContentStatus .active.name});
138129
139130 // --- Stage 2: Handle `hasActiveSources` filter ---
140131 if (filter['hasActiveSources' ] == true ) {
@@ -148,7 +139,9 @@ class CountryQueryService {
148139 });
149140 pipeline.add ({
150141 r'$match' : {
151- 'matchingSources' : {r'$ne' : []}, // Ensure there's at least one source
142+ 'matchingSources' : {
143+ r'$ne' : < dynamic > [],
144+ }, // Ensure there's at least one source
152145 'matchingSources.status' : ContentStatus .active.name,
153146 },
154147 });
@@ -159,14 +152,16 @@ class CountryQueryService {
159152 pipeline.add ({
160153 r'$lookup' : {
161154 'from' : 'headlines' ,
162- 'localField' : r '_id' ,
163- 'foreignField' : r 'eventCountry._id' ,
155+ 'localField' : '_id' ,
156+ 'foreignField' : 'eventCountry._id' ,
164157 'as' : 'matchingHeadlines' ,
165158 },
166159 });
167160 pipeline.add ({
168161 r'$match' : {
169- 'matchingHeadlines' : {r'$ne' : []}, // Ensure there's at least one headline
162+ 'matchingHeadlines' : {
163+ r'$ne' : < dynamic > [],
164+ }, // Ensure there's at least one headline
170165 'matchingHeadlines.status' : ContentStatus .active.name,
171166 },
172167 });
@@ -182,22 +177,26 @@ class CountryQueryService {
182177
183178 // --- Stage 5: Handle other standard filters ---
184179 filter.forEach ((key, value) {
185- if (key != 'q' && key != 'hasActiveSources' && key != 'hasActiveHeadlines' ) {
180+ if (key != 'q' &&
181+ key != 'hasActiveSources' &&
182+ key != 'hasActiveHeadlines' ) {
186183 compoundMatchStages.add ({key: value});
187184 }
188185 });
189186
190187 // Combine all compound match stages
191188 if (compoundMatchStages.isNotEmpty) {
192- pipeline.add ({r'$match' : {r'$and' : compoundMatchStages}});
189+ pipeline.add ({
190+ r'$match' : {r'$and' : compoundMatchStages},
191+ });
193192 }
194193
195194 // --- Stage 6: Project to original Country structure and ensure uniqueness ---
196195 // After lookups and matches, we might have duplicate countries if they
197196 // matched multiple sources/headlines. We need to group them back to unique countries.
198197 pipeline.add ({
199198 r'$group' : {
200- r '_id': r'$_id' , // Group by the original country ID
199+ '_id' : r'$_id' , // Group by the original country ID
201200 'doc' : {r'$first' : r'$$ROOT' }, // Take the first full document
202201 },
203202 });
@@ -236,7 +235,7 @@ class CountryQueryService {
236235 // (e.g., if _id was used, map it back to id)
237236 pipeline.add ({
238237 r'$project' : {
239- r '_id': 0 , // Exclude _id
238+ '_id' : 0 , // Exclude _id
240239 'id' : {r'$toString' : r'$_id' }, // Map _id back to id
241240 'isoCode' : r'$isoCode' ,
242241 'name' : r'$name' ,
@@ -268,10 +267,7 @@ class CountryQueryService {
268267
269268 final keyData = {
270269 'filter' : sortedFilter,
271- 'pagination' : {
272- 'cursor' : pagination? .cursor,
273- 'limit' : pagination? .limit,
274- },
270+ 'pagination' : {'cursor' : pagination? .cursor, 'limit' : pagination? .limit},
275271 'sort' : sortedSort? .map ((s) => '${s .field }:${s .order .name }' ).toList (),
276272 };
277273 return json.encode (keyData);
0 commit comments