Skip to content

Commit 644ac68

Browse files
committed
refactor(country): optimize country query pipeline and cache management
- Reorganize match stages for better efficiency - Implement text search and standard filter handling in initial match stage - Simplify and reorder aggregation pipeline stages - Improve cache cleanup mechanism
1 parent 39eea59 commit 644ac68

File tree

1 file changed

+33
-32
lines changed

1 file changed

+33
-32
lines changed

lib/src/services/country_query_service.dart

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ class CountryQueryService {
2020
required DataRepository<Country> countryRepository,
2121
required Logger log,
2222
Duration cacheDuration = const Duration(minutes: 15),
23-
}) : _countryRepository = countryRepository,
24-
_log = log,
25-
_cacheDuration = cacheDuration {
23+
}) : _countryRepository = countryRepository,
24+
_log = log,
25+
_cacheDuration = cacheDuration {
2626
_cleanupTimer = Timer.periodic(const Duration(minutes: 5), (_) {
2727
_cleanupCache();
2828
});
@@ -35,7 +35,7 @@ class CountryQueryService {
3535
final Duration _cacheDuration;
3636

3737
final Map<String, ({PaginatedResponse<Country> data, DateTime expiry})>
38-
_cache = {};
38+
_cache = {};
3939
Timer? _cleanupTimer;
4040
bool _isDisposed = false;
4141

@@ -123,10 +123,34 @@ class CountryQueryService {
123123
final pipeline = <Map<String, dynamic>>[];
124124
final compoundMatchStages = <Map<String, dynamic>>[];
125125

126-
// --- Stage 1: Initial Match for active status (if applicable) ---
126+
// --- Stage 1: Initial Match for active status, text search, and other filters ---
127127
// All countries should be active by default for these queries
128128
compoundMatchStages.add({'status': ContentStatus.active.name});
129129

130+
// Handle `q` (text search) filter
131+
final qValue = filter['q'];
132+
if (qValue is String && qValue.isNotEmpty) {
133+
compoundMatchStages.add({
134+
r'$text': {r'$search': qValue},
135+
});
136+
}
137+
138+
// Handle other standard filters
139+
filter.forEach((key, value) {
140+
if (key != 'q' &&
141+
key != 'hasActiveSources' &&
142+
key != 'hasActiveHeadlines') {
143+
compoundMatchStages.add({key: value});
144+
}
145+
});
146+
147+
// Combine all compound match stages and add to pipeline first for efficiency
148+
if (compoundMatchStages.isNotEmpty) {
149+
pipeline.add({
150+
r'$match': {r'$and': compoundMatchStages},
151+
});
152+
}
153+
130154
// --- Stage 2: Handle `hasActiveSources` filter ---
131155
if (filter['hasActiveSources'] == true) {
132156
// This lookup uses a sub-pipeline to filter for active sources *before*
@@ -183,31 +207,7 @@ class CountryQueryService {
183207
});
184208
}
185209

186-
// --- Stage 4: Handle `q` (text search) filter ---
187-
final qValue = filter['q'];
188-
if (qValue is String && qValue.isNotEmpty) {
189-
compoundMatchStages.add({
190-
r'$text': {r'$search': qValue},
191-
});
192-
}
193-
194-
// --- Stage 5: Handle other standard filters ---
195-
filter.forEach((key, value) {
196-
if (key != 'q' &&
197-
key != 'hasActiveSources' &&
198-
key != 'hasActiveHeadlines') {
199-
compoundMatchStages.add({key: value});
200-
}
201-
});
202-
203-
// Combine all compound match stages
204-
if (compoundMatchStages.isNotEmpty) {
205-
pipeline.add({
206-
r'$match': {r'$and': compoundMatchStages},
207-
});
208-
}
209-
210-
// --- Stage 6: Project to original Country structure and ensure uniqueness ---
210+
// --- Stage 4: Project to original Country structure and ensure uniqueness ---
211211
// After lookups and matches, we might have duplicate countries if they
212212
// matched multiple sources/headlines. We need to group them back to unique countries.
213213
pipeline.add({
@@ -222,7 +222,7 @@ class CountryQueryService {
222222
},
223223
});
224224

225-
// --- Stage 7: Sorting ---
225+
// --- Stage 5: Sorting ---
226226
if (sort != null && sort.isNotEmpty) {
227227
final sortStage = <String, dynamic>{};
228228
for (final option in sort) {
@@ -231,7 +231,7 @@ class CountryQueryService {
231231
pipeline.add({r'$sort': sortStage});
232232
}
233233

234-
// --- Stage 8: Pagination (Skip and Limit) ---
234+
// --- Stage 6: Pagination (Skip and Limit) ---
235235
if (pagination?.cursor != null) {
236236
// For cursor-based pagination, we'd typically need a more complex
237237
// aggregation that sorts by the cursor field and then skips.
@@ -247,6 +247,7 @@ class CountryQueryService {
247247
pipeline.add({r'$limit': pagination!.limit! + 1});
248248
}
249249

250+
// --- Stage 7: Final Projection ---
250251
// Project to match the Country model's JSON structure if necessary
251252
// (e.g., if _id was used, map it back to id)
252253
pipeline.add({

0 commit comments

Comments
 (0)