@@ -24,16 +24,19 @@ void registerPrimaryDatabase(PrimaryDatabase database) =>
2424 ss.register (#_primaryDatabase, database);
2525
2626/// The active primary database service.
27- PrimaryDatabase ? get primaryDatabase =>
27+ PrimaryDatabase ? get primaryDatabase => _lookupPrimaryDatabase ();
28+
29+ PrimaryDatabase ? _lookupPrimaryDatabase () =>
2830 ss.lookup (#_primaryDatabase) as PrimaryDatabase ? ;
2931
3032/// Access to the primary database connection and object mapping.
3133class PrimaryDatabase {
3234 final Pool _pg;
3335 final DatabaseAdapter _adapter;
3436 final Database <PrimarySchema > db;
37+ final Future <void > Function ()? _closeFn;
3538
36- PrimaryDatabase ._(this ._pg, this ._adapter, this .db);
39+ PrimaryDatabase ._(this ._pg, this ._adapter, this .db, this ._closeFn );
3740
3841 /// Gets the connection string either from the environment variable or from
3942 /// the secret backend, connects to it and registers the primary database
@@ -43,54 +46,71 @@ class PrimaryDatabase {
4346 // Production is not configured for postgresql yet.
4447 return ;
4548 }
46- var connectionString =
49+ if (_lookupPrimaryDatabase () != null ) {
50+ // Already initialized, must be in a local test environment.
51+ assert (activeConfiguration.isFakeOrTest);
52+ return ;
53+ }
54+ final connectionString =
4755 envConfig.pubPostgresUrl ??
4856 (await secretBackend.lookup (SecretKey .postgresConnectionString));
4957 if (connectionString == null && activeConfiguration.isStaging) {
5058 // Staging may not have the connection string set yet.
5159 return ;
5260 }
61+ final database = await createAndInit (url: connectionString);
62+ registerPrimaryDatabase (database);
63+ ss.registerScopeExitCallback (database.close);
64+ }
65+
66+ /// Creates and initializes a [PrimaryDatabase] instance.
67+ ///
68+ /// When [url] is not provided, it will start a new local postgresql instance, or
69+ /// if it detects an existing one, connects to it.
70+ ///
71+ /// When NOT running in the AppEngine environment (e.g. testing or local fake),
72+ /// the initilization will create a new database, which will be dropped when the
73+ /// [close] method is called.
74+ static Future <PrimaryDatabase > createAndInit ({String ? url}) async {
5375 // The scope-specific custom database. We are creating a custom database for
5476 // each test run, in order to provide full isolation, however, this must not
5577 // be used in Appengine.
5678 String ? customDb;
57- if (connectionString == null ) {
58- (connectionString , customDb) = await _startOrUseLocalPostgresInDocker ();
79+ if (url == null ) {
80+ (url , customDb) = await _startOrUseLocalPostgresInDocker ();
5981 }
6082 if (customDb == null && ! envConfig.isRunningInAppengine) {
61- customDb = await _createCustomDatabase (connectionString );
83+ customDb = await _createCustomDatabase (url );
6284 }
6385
86+ final originalUrl = url;
6487 if (customDb != null ) {
6588 if (envConfig.isRunningInAppengine) {
6689 throw StateError ('Should not use custom database inside AppEngine.' );
6790 }
6891
69- final originalUrl = connectionString;
70- connectionString = Uri .parse (
71- connectionString,
72- ).replace (path: customDb).toString ();
73- ss.registerScopeExitCallback (() async {
74- await _dropCustomDatabase (originalUrl, customDb! );
75- });
92+ url = Uri .parse (url).replace (path: customDb).toString ();
7693 }
7794
78- final database = await _fromConnectionString (connectionString);
79- registerPrimaryDatabase (database);
80- ss.registerScopeExitCallback (database.close);
81- }
95+ Future <void > closeFn () async {
96+ if (customDb != null ) {
97+ await _dropCustomDatabase (originalUrl, customDb);
98+ }
99+ }
82100
83- static Future <PrimaryDatabase > _fromConnectionString (String value) async {
84- final pg = Pool .withUrl (value);
101+ final pg = Pool .withUrl (url);
85102 final adapter = DatabaseAdapter .postgres (pg);
86103 final db = Database <PrimarySchema >(adapter, SqlDialect .postgres ());
87104 await db.createTables ();
88- return PrimaryDatabase ._(pg, adapter, db);
105+ return PrimaryDatabase ._(pg, adapter, db, closeFn );
89106 }
90107
91108 Future <void > close () async {
92109 await _adapter.close ();
93110 await _pg.close ();
111+ if (_closeFn != null ) {
112+ await _closeFn ();
113+ }
94114 }
95115
96116 @visibleForTesting
0 commit comments