1616/// </summary>
1717public static class PostgresqlExtensions
1818{
19- private static readonly string pattern = @"(?i)Search\s?Path=([^;]+)" ;
19+ private static readonly string pattern = @"(?i)Search\s?Path=([^;]+)" ;
2020 /// <summary>
2121 /// Creates an upgrader for PostgreSQL databases.
2222 /// </summary>
@@ -165,21 +165,55 @@ public static void PostgresqlDatabase(this SupportedDatabasesForEnsureDatabase s
165165 PostgresqlDatabase ( supported , connectionString , logger , new PostgresqlConnectionOptions ( ) ) ;
166166 }
167167
168+ /// <summary>
169+ /// Ensures that the database specified in the connection string exists.
170+ /// </summary>
171+ /// <param name="supported">Fluent helper type.</param>
172+ /// <param name="connectionString">The connection string.</param>
173+ /// <param name="logger">The <see cref="DbUp.Engine.Output.IUpgradeLog"/> used to record actions.</param>
174+ /// <param name="certificate">Certificate for securing connection.</param>
175+ /// <returns></returns>
168176 public static void PostgresqlDatabase ( this SupportedDatabasesForEnsureDatabase supported , string connectionString , IUpgradeLog logger , X509Certificate2 certificate )
169177 {
170178 var options = new PostgresqlConnectionOptions
171- {
179+ {
172180 ClientCertificate = certificate
173181 } ;
174182 PostgresqlDatabase ( supported , connectionString , logger , options ) ;
175183 }
176184
185+ /// <summary>
186+ /// Ensures that the database specified in the connection string exists.
187+ /// </summary>
188+ /// <param name="supported">Fluent helper type.</param>
189+ /// <param name="connectionString">The connection string.</param>
190+ /// <param name="logger">The <see cref="DbUp.Engine.Output.IUpgradeLog"/> used to record actions.</param>
191+ /// <param name="connectionOptions">Connection SSL to customize SSL behaviour</param>
177192 public static void PostgresqlDatabase (
178- this SupportedDatabasesForEnsureDatabase supported ,
179- string connectionString ,
180- IUpgradeLog logger ,
193+ this SupportedDatabasesForEnsureDatabase supported ,
194+ string connectionString ,
195+ IUpgradeLog logger ,
181196 PostgresqlConnectionOptions connectionOptions
182197 )
198+ {
199+ PostgresqlDatabase ( supported , connectionString , logger , connectionOptions , null ) ;
200+ }
201+
202+ /// <summary>
203+ /// Ensures that the database specified in the connection string exists, assigning an owner at creation time.
204+ /// </summary>
205+ /// <param name="supported">Fluent helper type.</param>
206+ /// <param name="connectionString">The connection string.</param>
207+ /// <param name="logger">The <see cref="DbUp.Engine.Output.IUpgradeLog"/> used to record actions.</param>
208+ /// <param name="connectionOptions">Connection SSL to customize SSL behaviour</param>
209+ /// <param name="owner">Role to own the new database during creation (adds 'WITH OWNER = "role"').</param>
210+ public static void PostgresqlDatabase (
211+ this SupportedDatabasesForEnsureDatabase supported ,
212+ string connectionString ,
213+ IUpgradeLog logger ,
214+ PostgresqlConnectionOptions connectionOptions ,
215+ string owner
216+ )
183217 {
184218 if ( supported == null ) throw new ArgumentNullException ( "supported" ) ;
185219
@@ -191,14 +225,16 @@ PostgresqlConnectionOptions connectionOptions
191225 if ( logger == null ) throw new ArgumentNullException ( "logger" ) ;
192226
193227 var masterConnectionStringBuilder = new NpgsqlConnectionStringBuilder ( connectionString ) ;
194-
228+
195229 var databaseName = masterConnectionStringBuilder . Database ;
196230
197231 if ( string . IsNullOrEmpty ( databaseName ) || databaseName . Trim ( ) == string . Empty )
198232 {
199233 throw new InvalidOperationException ( "The connection string does not specify a database name." ) ;
200234 }
201235
236+ owner = string . IsNullOrWhiteSpace ( owner ) ? masterConnectionStringBuilder . Username : owner ;
237+
202238 masterConnectionStringBuilder . Database = connectionOptions . MasterDatabaseName ;
203239
204240 var logMasterConnectionStringBuilder = new NpgsqlConnectionStringBuilder ( masterConnectionStringBuilder . ConnectionString ) ;
@@ -218,9 +254,9 @@ PostgresqlConnectionOptions connectionOptions
218254
219255 // check to see if the database already exists..
220256 using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
221- {
222- CommandType = CommandType . Text
223- } )
257+ {
258+ CommandType = CommandType . Text
259+ } )
224260 {
225261 var results = Convert . ToInt32 ( command . ExecuteScalar ( ) ) ;
226262
@@ -231,13 +267,29 @@ PostgresqlConnectionOptions connectionOptions
231267 }
232268 }
233269
234- sqlCommandText = $ "create database \" { databaseName } \" ;";
270+ sqlCommandText = $ "select 1 from pg_roles where rolname = \' { owner } \' limit 1;";
271+ // check to see if the owner exists..
272+ using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
273+ {
274+ CommandType = CommandType . Text
275+ } )
276+ {
277+ var results = Convert . ToInt32 ( command . ExecuteScalar ( ) ) ;
278+
279+ // if the owner role does not exist, we throw an exception.
280+ if ( results == 0 )
281+ {
282+ throw new InvalidOperationException ( $ "PostgreSQL role '{ owner } ' does not exist.") ;
283+ }
284+ }
285+
286+ sqlCommandText = $ "create database \" { databaseName } \" with owner = \" { owner } \" ;";
235287
236288 // Create the database...
237289 using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
238- {
239- CommandType = CommandType . Text
240- } )
290+ {
291+ CommandType = CommandType . Text
292+ } )
241293 {
242294 command . ExecuteNonQuery ( ) ;
243295 }
@@ -319,7 +371,7 @@ PostgresqlConnectionOptions connectionOptions
319371
320372 var masterConnectionStringBuilder = new NpgsqlConnectionStringBuilder ( connectionString ) ;
321373
322- var databaseName = masterConnectionStringBuilder . Database ;
374+ var databaseName = masterConnectionStringBuilder . Database ;
323375
324376 if ( string . IsNullOrEmpty ( databaseName ) || databaseName . Trim ( ) == string . Empty )
325377 {
@@ -351,9 +403,9 @@ PostgresqlConnectionOptions connectionOptions
351403
352404 // check to see if the database already exists..
353405 using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
354- {
355- CommandType = CommandType . Text
356- } )
406+ {
407+ CommandType = CommandType . Text
408+ } )
357409 {
358410 var results = Convert . ToInt32 ( command . ExecuteScalar ( ) ) ;
359411
@@ -368,9 +420,9 @@ PostgresqlConnectionOptions connectionOptions
368420 // prevent new connections to the database
369421 sqlCommandText = $ "alter database \" { databaseName } \" with ALLOW_CONNECTIONS false;";
370422 using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
371- {
372- CommandType = CommandType . Text
373- } )
423+ {
424+ CommandType = CommandType . Text
425+ } )
374426 {
375427 command . ExecuteNonQuery ( ) ;
376428 }
@@ -380,9 +432,9 @@ PostgresqlConnectionOptions connectionOptions
380432 // terminate all existing connections to the database
381433 sqlCommandText = $ "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where pg_stat_activity.datname = \' { databaseName } \' ;";
382434 using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
383- {
384- CommandType = CommandType . Text
385- } )
435+ {
436+ CommandType = CommandType . Text
437+ } )
386438 {
387439 command . ExecuteNonQuery ( ) ;
388440 }
@@ -393,9 +445,9 @@ PostgresqlConnectionOptions connectionOptions
393445
394446 // drop the database
395447 using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
396- {
397- CommandType = CommandType . Text
398- } )
448+ {
449+ CommandType = CommandType . Text
450+ } )
399451 {
400452 command . ExecuteNonQuery ( ) ;
401453 }
0 commit comments