Skip to content

Commit bb63005

Browse files
committed
feat(countries): use HtCountriesInMemoryClient for countries data
- Replace the InMemoryHtCountriesClient with HtCountriesInMemoryClient - Update the countriesClientProvider to use the new client - Add ht_countries_inmemory package to dependencies
1 parent de189aa commit bb63005

File tree

2 files changed

+18
-155
lines changed

2 files changed

+18
-155
lines changed
Lines changed: 15 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,163 +1,23 @@
11
import 'package:dart_frog/dart_frog.dart';
22
import 'package:ht_countries_client/ht_countries_client.dart';
3-
import 'package:meta/meta.dart'; // For @visibleForTesting
3+
import 'package:ht_countries_inmemory/ht_countries_inmemory.dart';
44

55
/// Provides an instance of [HtCountriesClient] to the request context.
66
///
7-
/// This middleware is responsible for creating or obtaining the client instance
8-
/// (e.g., based on environment variables or configuration) and making it
9-
/// available via `context.read<HtCountriesClient>()` in subsequent handlers
10-
/// and middleware.
7+
/// This middleware uses the inmemory implementation
8+
/// [HtCountriesInMemoryClient].
119
Middleware countriesClientProvider() {
12-
return provider<HtCountriesClient>(
13-
(context) {
14-
// TODO(fulleni): Replace this with your actual HtCountriesClient
15-
// implementation.
16-
//
17-
// This could involve reading configuration, setting up database
18-
// connections, or initializing an HTTP client depending on your
19-
// chosen backend.
20-
//
21-
// Example:
22-
// final firestore = Firestore.instance; // If using Firestore
23-
// return FirestoreHtCountriesClient(firestore);
24-
//
25-
// final dio = Dio(); // If using an HTTP API
26-
// return ApiHtCountriesClient(dio);
27-
28-
// For development/testing purposes, we provide an in-memory mock.
29-
// DO NOT use this in production.
30-
print(
31-
'WARNING: Using InMemoryHtCountriesClient. Replace for production!',
32-
);
33-
return InMemoryHtCountriesClient();
34-
},
35-
);
36-
}
37-
38-
/// {@template in_memory_ht_countries_client}
39-
/// A simple in-memory implementation of [HtCountriesClient] for testing
40-
/// and development purposes.
41-
///
42-
/// **Do not use this in production.**
43-
/// {@endtemplate}
44-
@visibleForTesting
45-
class InMemoryHtCountriesClient implements HtCountriesClient {
46-
/// {@macro in_memory_ht_countries_client}
47-
InMemoryHtCountriesClient() {
48-
// Initialize with some sample data
49-
_countries = {
50-
'US': Country(
51-
isoCode: 'US',
52-
name: 'United States',
53-
flagUrl: 'https://example.com/flags/us.png',
54-
),
55-
'CA': Country(
56-
isoCode: 'CA',
57-
name: 'Canada',
58-
flagUrl: 'https://example.com/flags/ca.png',
59-
),
60-
'GB': Country(
61-
isoCode: 'GB',
62-
name: 'United Kingdom',
63-
flagUrl: 'https://example.com/flags/gb.png',
64-
),
65-
'DZ': Country(
66-
isoCode: 'DZ',
67-
name: 'Algeria',
68-
flagUrl: 'https://example.com/flags/dz.png',
69-
),
10+
// Create the client instance once when the middleware is initialized.
11+
// This assumes the in-memory client is cheap to create and can be reused
12+
// across requests.
13+
final HtCountriesClient client = HtCountriesInMemoryClient();
14+
15+
return (Handler innerHandler) {
16+
return (RequestContext context) {
17+
// Provide the existing client instance to this request's context.
18+
final updatedContext = context.provide<HtCountriesClient>(() => client);
19+
// Call the next handler in the chain with the updated context.
20+
return innerHandler(updatedContext);
7021
};
71-
}
72-
73-
/// Internal storage for countries, mapping ISO code to Country object.
74-
late final Map<String, Country> _countries;
75-
76-
@override
77-
Future<List<Country>> fetchCountries({
78-
required int limit,
79-
String? startAfterId,
80-
}) async {
81-
await _simulateDelay();
82-
final countryList = _countries.values.toList()
83-
..sort((a, b) => a.isoCode.compareTo(b.isoCode)); // Consistent order
84-
85-
var startIndex = 0;
86-
if (startAfterId != null) {
87-
final startAfterCountry = _countries.values.firstWhere(
88-
(c) => c.id == startAfterId,
89-
orElse: () => throw const CountryNotFound('StartAfterId not found'),
90-
);
91-
final index = countryList.indexWhere((c) => c.id == startAfterCountry.id);
92-
if (index != -1) {
93-
startIndex = index + 1;
94-
} else {
95-
// Should not happen if startAfterId was valid, but handle defensively
96-
throw const CountryNotFound('StartAfterId inconsistency');
97-
}
98-
}
99-
100-
if (startIndex >= countryList.length) {
101-
return []; // No more items after the specified ID
102-
}
103-
104-
final endIndex = (startIndex + limit).clamp(0, countryList.length);
105-
return countryList.sublist(startIndex, endIndex);
106-
}
107-
108-
@override
109-
Future<Country> fetchCountry(String isoCode) async {
110-
await _simulateDelay();
111-
final country = _countries[isoCode.toUpperCase()];
112-
if (country == null) {
113-
throw CountryNotFound('Country with ISO code $isoCode not found.');
114-
}
115-
return country;
116-
}
117-
118-
@override
119-
Future<void> createCountry(Country country) async {
120-
await _simulateDelay();
121-
final upperIsoCode = country.isoCode.toUpperCase();
122-
if (_countries.containsKey(upperIsoCode)) {
123-
throw CountryCreateFailure(
124-
'Country with ISO code $upperIsoCode already exists.',
125-
);
126-
}
127-
// Ensure ID is generated if not provided (though constructor handles this)
128-
final countryWithId = Country(
129-
id: country.id, // Use existing or generate new
130-
isoCode: upperIsoCode,
131-
name: country.name,
132-
flagUrl: country.flagUrl,
133-
);
134-
_countries[upperIsoCode] = countryWithId;
135-
}
136-
137-
@override
138-
Future<void> updateCountry(Country country) async {
139-
await _simulateDelay();
140-
final upperIsoCode = country.isoCode.toUpperCase();
141-
if (!_countries.containsKey(upperIsoCode)) {
142-
throw CountryNotFound('Country with ISO code $upperIsoCode not found.');
143-
}
144-
// Update using the provided country data, keeping the original ID if needed
145-
// or ensuring the provided one is used consistently.
146-
_countries[upperIsoCode] = country;
147-
}
148-
149-
@override
150-
Future<void> deleteCountry(String isoCode) async {
151-
await _simulateDelay();
152-
final upperIsoCode = isoCode.toUpperCase();
153-
if (!_countries.containsKey(upperIsoCode)) {
154-
throw CountryNotFound('Country with ISO code $upperIsoCode not found.');
155-
}
156-
_countries.remove(upperIsoCode);
157-
}
158-
159-
/// Helper to simulate network latency.
160-
Future<void> _simulateDelay() async {
161-
await Future<void>.delayed(const Duration(milliseconds: 50));
162-
}
22+
};
16323
}

pubspec.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ dependencies:
1111
ht_countries_client:
1212
git:
1313
url: https://github.com/headlines-toolkit/ht-countries-client.git
14+
ht_countries_inmemory:
15+
git:
16+
url: https://github.com/headlines-toolkit/ht-countries-inmemory.git
1417
meta: ^1.16.0
1518
uuid: ^4.5.1
1619

0 commit comments

Comments
 (0)