1+ using System ;
2+ using System . Data . SqlClient ;
3+ using System . Threading ;
4+ using System . Threading . Tasks ;
5+ using MySql . Data . MySqlClient ;
6+ using Npgsql ;
7+ using Serilog ;
8+ using SqlStreamStore . Infrastructure ;
9+
10+ namespace SqlStreamStore . Server
11+ {
12+ internal class DatabaseInitializer
13+ {
14+ private readonly SqlStreamStoreServerConfiguration _configuration ;
15+
16+ public DatabaseInitializer ( SqlStreamStoreServerConfiguration configuration )
17+ {
18+ if ( configuration == null )
19+ {
20+ throw new ArgumentNullException ( nameof ( configuration ) ) ;
21+ }
22+
23+ _configuration = configuration ;
24+ }
25+
26+ public Task Initialize ( CancellationToken cancellationToken = default )
27+ {
28+ switch ( _configuration . Provider )
29+ {
30+ case Constants . mssql :
31+ return InitializeMsSql ( cancellationToken ) ;
32+ case Constants . mysql :
33+ return InitializeMySql ( cancellationToken ) ;
34+ case Constants . postgres :
35+ return InitializePostgres ( cancellationToken ) ;
36+ default :
37+ Log . Warning ( "Provider {provider} has no database initializer." , _configuration . Provider ) ;
38+ return Task . CompletedTask ;
39+ }
40+ }
41+
42+ private async Task InitializeMySql ( CancellationToken cancellationToken )
43+ {
44+ var connectionStringBuilder = new MySqlConnectionStringBuilder ( _configuration . ConnectionString ) ;
45+
46+ var cmdText = $ "CREATE DATABASE IF NOT EXISTS `{ connectionStringBuilder . Database } `";
47+
48+ Log . Information (
49+ "Creating database '{database}' at server '{server}' with the statement: {cmdText}" ,
50+ connectionStringBuilder . Database ,
51+ connectionStringBuilder . Server ,
52+ cmdText ) ;
53+
54+ using ( var connection = new MySqlConnection (
55+ new MySqlConnectionStringBuilder ( _configuration . ConnectionString )
56+ {
57+ Database = null
58+ } . ConnectionString ) )
59+ {
60+ await connection . OpenAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
61+
62+ using ( var command = new MySqlCommand (
63+ cmdText ,
64+ connection ) )
65+ {
66+ await command . ExecuteNonQueryAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
67+ }
68+ }
69+ }
70+
71+ private async Task InitializeMsSql ( CancellationToken cancellationToken )
72+ {
73+ var connectionStringBuilder = new SqlConnectionStringBuilder ( _configuration . ConnectionString ) ;
74+
75+ var cmdText = $@ "
76+ IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'{ connectionStringBuilder . InitialCatalog } ')
77+ BEGIN
78+ CREATE DATABASE [{ connectionStringBuilder . InitialCatalog } ]
79+ END;
80+ " ;
81+ Log . Information (
82+ "Creating database '{database}' at server '{server}' with the statement: {cmdText}" ,
83+ connectionStringBuilder . InitialCatalog ,
84+ connectionStringBuilder . DataSource ,
85+ cmdText ) ;
86+
87+ using ( var connection = new SqlConnection (
88+ new SqlConnectionStringBuilder ( _configuration . ConnectionString )
89+ {
90+ InitialCatalog = "master"
91+ } . ConnectionString ) )
92+ {
93+ await connection . OpenAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
94+
95+ using ( var command = new SqlCommand (
96+ cmdText ,
97+ connection ) )
98+ {
99+ await command . ExecuteNonQueryAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
100+ }
101+ }
102+ }
103+
104+ private async Task InitializePostgres ( CancellationToken cancellationToken )
105+ {
106+ var connectionStringBuilder = new NpgsqlConnectionStringBuilder ( _configuration . ConnectionString ) ;
107+
108+ var cmdText = $ "CREATE DATABASE { connectionStringBuilder . Database } ";
109+
110+ Log . Information (
111+ "Creating database '{database}' at server '{server}' with the statement: {cmdText}" ,
112+ connectionStringBuilder . Database ,
113+ connectionStringBuilder . Host ,
114+ cmdText ) ;
115+
116+ using ( var connection = new NpgsqlConnection (
117+ new NpgsqlConnectionStringBuilder ( _configuration . ConnectionString )
118+ {
119+ Database = null
120+ } . ConnectionString ) )
121+ {
122+ await connection . OpenAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
123+
124+ async Task < bool > DatabaseExists ( )
125+ {
126+ using ( var command = new NpgsqlCommand (
127+ $ "SELECT 1 FROM pg_database WHERE datname = '{ connectionStringBuilder . Database } '",
128+ connection ) )
129+ {
130+ return await command . ExecuteScalarAsync ( cancellationToken ) . NotOnCapturedContext ( )
131+ != null ;
132+ }
133+ }
134+
135+ if ( ! await DatabaseExists ( ) )
136+ {
137+ using ( var command = new NpgsqlCommand (
138+ cmdText ,
139+ connection ) )
140+ {
141+ await command . ExecuteNonQueryAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
142+ }
143+ }
144+ }
145+ }
146+ }
147+ }
0 commit comments