Skip to content

Commit c2aff30

Browse files
committed
fix(core): correct db connection and provide all repositories
- Fixes a critical error in `server.dart` where `Endpoint.uri` was called, which is not available in the current `postgres` package version. The `DATABASE_URL` is now parsed manually to create the `Endpoint`. - Initializes all data repositories (`User`, `UserAppSettings`, `UserContentPreferences`, `AppConfig`) in addition to the existing ones. - Wraps the main handler with `provider` middleware for all repositories and `Uuid`, making them available for dependency injection throughout the application.
1 parent 50f101e commit c2aff30

File tree

1 file changed

+128
-14
lines changed

1 file changed

+128
-14
lines changed

lib/src/config/server.dart

Lines changed: 128 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
1-
import 'dart:io';
1+
import 'dart:io';
22

33
import 'package:dart_frog/dart_frog.dart';
44
import 'package:ht_api/src/config/environment_config.dart';
5+
import 'package:ht_data_postgres/ht_data_postgres.dart';
6+
import 'package:ht_data_repository/ht_data_repository.dart';
7+
import 'package:ht_shared/ht_shared.dart';
58
import 'package:logging/logging.dart';
69
import 'package:postgres/postgres.dart';
10+
import 'package:uuid/uuid.dart';
711

812
/// Global logger instance.
9-
final _log = Logger('ht_api');
13+
final _log = Logger('ht_api');
1014

1115
/// Global PostgreSQL connection instance.
12-
late final Connection _connection;
16+
late final Connection _connection;
17+
18+
/// Creates a data repository for a given type [T].
19+
///
20+
/// This helper function centralizes the creation of repositories,
21+
/// ensuring they all use the same database connection and logger.
22+
HtDataRepository<T> _createRepository<T>({
23+
required String tableName,
24+
required FromJson<T> fromJson,
25+
required ToJson<T> toJson,
26+
}) {
27+
return HtDataRepository<T>(
28+
dataClient: HtDataPostgresClient<T>(
29+
connection: _connection,
30+
tableName: tableName,
31+
fromJson: fromJson,
32+
toJson: toJson,
33+
log: _log,
34+
),
35+
);
36+
}
1337

1438
/// The main entry point for the server.
1539
///
@@ -31,21 +55,111 @@ Future<HttpServer> run(Handler handler, InternetAddress ip, int port) async {
3155

3256
// 2. Establish Database Connection
3357
_log.info('Connecting to PostgreSQL database...');
58+
final dbUri = Uri.parse(EnvironmentConfig.databaseUrl);
59+
String? username;
60+
String? password;
61+
if (dbUri.userInfo.isNotEmpty) {
62+
final parts = dbUri.userInfo.split(':');
63+
username = Uri.decodeComponent(parts.first);
64+
if (parts.length > 1) {
65+
password = Uri.decodeComponent(parts.last);
66+
}
67+
}
68+
3469
_connection = await Connection.open(
35-
Endpoint.uri(Uri.parse(EnvironmentConfig.databaseUrl)),
36-
settings: const ConnectionSettings(sslMode: SslMode.prefer),
70+
Endpoint(
71+
host: dbUri.host,
72+
port: dbUri.port,
73+
database: dbUri.path.substring(1), // Remove leading '/'
74+
username: username,
75+
password: password,
76+
),
77+
// Using `require` is a more secure default. For local development against
78+
// a non-SSL database, this may need to be changed to `SslMode.disable`.
79+
settings: const ConnectionSettings(sslMode: SslMode.require),
3780
);
3881
_log.info('PostgreSQL database connection established.');
3982

40-
// 3. Start the server and set up shutdown logic
41-
return serve(
42-
handler,
83+
// 3. Initialize Repositories
84+
final headlineRepository = _createRepository<Headline>(
85+
tableName: 'headlines',
86+
fromJson: Headline.fromJson,
87+
toJson: (h) => h.toJson(),
88+
);
89+
final categoryRepository = _createRepository<Category>(
90+
tableName: 'categories',
91+
fromJson: Category.fromJson,
92+
toJson: (c) => c.toJson(),
93+
);
94+
final sourceRepository = _createRepository<Source>(
95+
tableName: 'sources',
96+
fromJson: Source.fromJson,
97+
toJson: (s) => s.toJson(),
98+
);
99+
final countryRepository = _createRepository<Country>(
100+
tableName: 'countries',
101+
fromJson: Country.fromJson,
102+
toJson: (c) => c.toJson(),
103+
);
104+
final userRepository = _createRepository<User>(
105+
tableName: 'users',
106+
fromJson: User.fromJson,
107+
toJson: (u) => u.toJson(),
108+
);
109+
final userAppSettingsRepository = _createRepository<UserAppSettings>(
110+
tableName: 'user_app_settings',
111+
fromJson: UserAppSettings.fromJson,
112+
toJson: (s) => s.toJson(),
113+
);
114+
final userContentPreferencesRepository =
115+
_createRepository<UserContentPreferences>(
116+
tableName: 'user_content_preferences',
117+
fromJson: UserContentPreferences.fromJson,
118+
toJson: (p) => p.toJson(),
119+
);
120+
final appConfigRepository = _createRepository<AppConfig>(
121+
tableName: 'app_config',
122+
fromJson: AppConfig.fromJson,
123+
toJson: (c) => c.toJson(),
124+
);
125+
126+
// 4. Create the main handler with all dependencies provided
127+
final finalHandler = handler
128+
.use(provider<Uuid>((_) => const Uuid()))
129+
.use(provider<HtDataRepository<Headline>>((_) => headlineRepository))
130+
.use(provider<HtDataRepository<Category>>((_) => categoryRepository))
131+
.use(provider<HtDataRepository<Source>>((_) => sourceRepository))
132+
.use(provider<HtDataRepository<Country>>((_) => countryRepository))
133+
.use(provider<HtDataRepository<User>>((_) => userRepository))
134+
.use(
135+
provider<HtDataRepository<UserAppSettings>>(
136+
(_) => userAppSettingsRepository,
137+
),
138+
)
139+
.use(
140+
provider<HtDataRepository<UserContentPreferences>>(
141+
(_) => userContentPreferencesRepository,
142+
),
143+
)
144+
.use(provider<HtDataRepository<AppConfig>>((_) => appConfigRepository));
145+
146+
// 5. Start the server
147+
final server = await serve(
148+
finalHandler,
43149
ip,
44150
port,
45-
onShutdown: () async {
46-
_log.info('Server shutting down. Closing database connection...');
47-
await _connection.close();
48-
_log.info('Database connection closed.');
49-
},
50151
);
51-
}
152+
_log.info('Server listening on port ${server.port}');
153+
154+
// 6. Handle graceful shutdown
155+
ProcessSignal.sigint.watch().listen((_) async {
156+
_log.info('Received SIGINT. Shutting down...');
157+
await _connection.close();
158+
_log.info('Database connection closed.');
159+
await server.close(force: true);
160+
_log.info('Server shut down.');
161+
exit(0);
162+
});
163+
164+
return server;
165+
}

0 commit comments

Comments
 (0)