Skip to content

Commit eb57c33

Browse files
authored
Placeholder for the database-related initialization + environment-based setup. (#9002)
1 parent 581dfcd commit eb57c33

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

app/lib/database/database.dart

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:gcloud/service_scope.dart' as ss;
6+
import 'package:meta/meta.dart';
7+
import 'package:postgres/postgres.dart';
8+
import 'package:pub_dev/service/secret/backend.dart';
9+
import 'package:pub_dev/shared/env_config.dart';
10+
11+
/// Sets the primary database service.
12+
void registerPrimaryDatabase(PrimaryDatabase database) =>
13+
ss.register(#_primaryDatabase, database);
14+
15+
/// The active primary database service.
16+
PrimaryDatabase? get primaryDatabase =>
17+
ss.lookup(#_primaryDatabase) as PrimaryDatabase?;
18+
19+
/// Access to the primary database connection and object mapping.
20+
class PrimaryDatabase {
21+
final Pool _pg;
22+
23+
PrimaryDatabase._(this._pg);
24+
25+
/// Gets the connection string either from the environment variable or from
26+
/// the secret backend, connects to it and registers the primary database
27+
/// service in the current scope.
28+
static Future<void> tryRegisterInScope() async {
29+
final connectionString =
30+
envConfig.pubPostgresUrl ??
31+
(await secretBackend.lookup(SecretKey.postgresConnectionString));
32+
if (connectionString == null) {
33+
// ignore for now, must throw once we have the environment setup ready
34+
return;
35+
}
36+
final database = await _fromConnectionString(connectionString);
37+
registerPrimaryDatabase(database);
38+
ss.registerScopeExitCallback(database.close);
39+
}
40+
41+
static Future<PrimaryDatabase> _fromConnectionString(String value) async {
42+
final pg = Pool.withUrl(value);
43+
return PrimaryDatabase._(pg);
44+
}
45+
46+
Future<void> close() async {
47+
await _pg.close();
48+
}
49+
50+
@visibleForTesting
51+
Future<void> verifyConnection() async {
52+
final rs = await _pg.execute('SELECT 1');
53+
if (rs.length != 1) {
54+
throw StateError('Connection is not returning expected rows.');
55+
}
56+
}
57+
}

app/lib/service/secret/models.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
/// Identifiers and secret keys.
66
abstract class SecretKey {
7+
/// Postgres connection string.
8+
static const String postgresConnectionString = 'postgres-connection-string';
9+
10+
/// Redis connection string.
711
static const String redisConnectionString = 'redis-connection-string';
812

913
/// OAuth client secret.
@@ -27,6 +31,7 @@ abstract class SecretKey {
2731

2832
/// List of all keys.
2933
static const values = [
34+
postgresConnectionString,
3035
redisConnectionString,
3136
oauthClientSecret,
3237
announcement,

app/lib/service/services.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:gcloud/service_scope.dart';
1414
import 'package:gcloud/storage.dart';
1515
import 'package:googleapis_auth/auth_io.dart' as auth;
1616
import 'package:logging/logging.dart';
17+
import 'package:pub_dev/database/database.dart';
1718
import 'package:pub_dev/package/api_export/api_exporter.dart';
1819
import 'package:pub_dev/search/handlers.dart';
1920
import 'package:pub_dev/service/async_queue/async_queue.dart';
@@ -250,6 +251,7 @@ Future<R> _withPubServices<R>(FutureOr<R> Function() fn) async {
250251
await storageService.verifyBucketExistenceAndAccess(bucketName);
251252
}
252253

254+
await PrimaryDatabase.tryRegisterInScope();
253255
registerAccountBackend(AccountBackend(dbService));
254256
registerAdminBackend(AdminBackend(dbService));
255257
registerAnnouncementBackend(AnnouncementBackend());

app/test/shared/postgresql_ci_test.dart renamed to app/test/database/postgresql_ci_test.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44

55
import 'package:clock/clock.dart';
66
import 'package:postgres/postgres.dart';
7+
import 'package:pub_dev/database/database.dart';
78
import 'package:pub_dev/shared/env_config.dart';
89
import 'package:test/test.dart';
910

11+
import '../shared/test_services.dart';
12+
1013
void main() {
1114
group('Postgresql connection on CI', () {
1215
test('connects to CI instance', () async {
@@ -32,5 +35,17 @@ void main() {
3235
await conn.execute('CREATE DATABASE $dbName');
3336
await conn.execute('DROP DATABASE $dbName');
3437
});
38+
39+
testWithProfile(
40+
'registered database scope',
41+
fn: () async {
42+
final pubPostgresUrl = envConfig.pubPostgresUrl;
43+
if (pubPostgresUrl == null) {
44+
markTestSkipped('PUB_POSTGRES_URL was not specified.');
45+
return;
46+
}
47+
await primaryDatabase!.verifyConnection();
48+
},
49+
);
3550
});
3651
}

0 commit comments

Comments
 (0)