1+ namespace SqlStreamStore . HAL . DevServer
2+ {
3+ using System ;
4+ using System . Collections . Generic ;
5+ using System . Data . SqlClient ;
6+ using System . Threading ;
7+ using System . Threading . Tasks ;
8+ using Npgsql ;
9+ using Serilog ;
10+ using SqlStreamStore . Infrastructure ;
11+
12+ internal static class SqlStreamStoreFactory
13+ {
14+ private delegate Task < IStreamStore > CreateStreamStore (
15+ string connectionString ,
16+ string schema ,
17+ CancellationToken cancellationToken ) ;
18+
19+ private const string SQLSTREAMSTORE_CONNECTION_STRING = nameof ( SQLSTREAMSTORE_CONNECTION_STRING ) ;
20+ private const string SQLSTREAMSTORE_SCHEMA = nameof ( SQLSTREAMSTORE_SCHEMA ) ;
21+ private const string SQLSTREAMSTORE_PROVIDER = nameof ( SQLSTREAMSTORE_PROVIDER ) ;
22+
23+ private const string postgres = nameof ( postgres ) ;
24+ private const string mssql = nameof ( mssql ) ;
25+ private const string inmemory = nameof ( inmemory ) ;
26+
27+ private static readonly IDictionary < string , CreateStreamStore > s_factories
28+ = new Dictionary < string , CreateStreamStore >
29+ {
30+ [ inmemory ] = CreateInMemoryStreamStore ,
31+ [ postgres ] = CreatePostgresStreamStore ,
32+ [ mssql ] = CreateMssqlStreamStore
33+ } ;
34+
35+ public static Task < IStreamStore > Create ( CancellationToken cancellationToken = default )
36+ {
37+ var provider = Environment . GetEnvironmentVariable ( SQLSTREAMSTORE_PROVIDER ) ? . ToLowerInvariant ( )
38+ ?? inmemory ;
39+
40+ Log . Information ( $ "Creating stream store for provider '{ provider } '") ;
41+
42+ if ( ! s_factories . TryGetValue ( provider , out var factory ) )
43+ {
44+ throw new InvalidOperationException ( $ "No provider factory for provider '{ provider } ' found.") ;
45+ }
46+
47+ var connectionString = Environment . GetEnvironmentVariable ( SQLSTREAMSTORE_CONNECTION_STRING ) ;
48+ var schema = Environment . GetEnvironmentVariable ( SQLSTREAMSTORE_SCHEMA ) ;
49+
50+ return factory ( connectionString , schema , cancellationToken ) ;
51+ }
52+
53+ private static Task < IStreamStore > CreateInMemoryStreamStore (
54+ string connectionString ,
55+ string schema ,
56+ CancellationToken cancellationToken )
57+ => Task . FromResult < IStreamStore > ( new InMemoryStreamStore ( ) ) ;
58+
59+ private static async Task < IStreamStore > CreateMssqlStreamStore (
60+ string connectionString ,
61+ string schema ,
62+ CancellationToken cancellationToken )
63+ {
64+ var connectionStringBuilder = new SqlConnectionStringBuilder ( connectionString ) ;
65+ using ( var connection = new SqlConnection ( new SqlConnectionStringBuilder ( connectionString )
66+ {
67+ InitialCatalog = "master"
68+ } . ConnectionString ) )
69+ {
70+ await connection . OpenAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
71+
72+ using ( var command = new SqlCommand (
73+ $@ "
74+ IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'{ connectionStringBuilder . InitialCatalog } ')
75+ BEGIN
76+ CREATE DATABASE [{ connectionStringBuilder . InitialCatalog } ]
77+ END;
78+ " ,
79+ connection ) )
80+ {
81+ await command . ExecuteNonQueryAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
82+ }
83+ }
84+
85+ var settings = new MsSqlStreamStoreV3Settings ( connectionString ) ;
86+
87+ if ( schema != null )
88+ {
89+ settings . Schema = schema ;
90+ }
91+
92+ var streamStore = new MsSqlStreamStoreV3 ( settings ) ;
93+
94+ await streamStore . CreateSchema ( cancellationToken ) ;
95+
96+ return streamStore ;
97+ }
98+
99+ private static async Task < IStreamStore > CreatePostgresStreamStore (
100+ string connectionString ,
101+ string schema ,
102+ CancellationToken cancellationToken )
103+ {
104+ var connectionStringBuilder = new NpgsqlConnectionStringBuilder ( connectionString ) ;
105+
106+ using ( var connection = new NpgsqlConnection ( new NpgsqlConnectionStringBuilder ( connectionString )
107+ {
108+ Database = null
109+ } . ConnectionString ) )
110+ {
111+ bool exists ;
112+ await connection . OpenAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
113+
114+ using ( var command = new NpgsqlCommand (
115+ $ "SELECT 1 FROM pg_database WHERE datname = '{ connectionStringBuilder . Database } '",
116+ connection ) )
117+ {
118+ exists = await command . ExecuteScalarAsync ( cancellationToken ) . NotOnCapturedContext ( )
119+ != null ;
120+ }
121+
122+ if ( ! exists )
123+ {
124+ using ( var command = new NpgsqlCommand (
125+ $ "CREATE DATABASE { connectionStringBuilder . Database } ",
126+ connection ) )
127+ {
128+ await command . ExecuteNonQueryAsync ( cancellationToken ) . NotOnCapturedContext ( ) ;
129+ }
130+ }
131+
132+ var settings = new PostgresStreamStoreSettings ( connectionString ) ;
133+
134+ if ( schema != null )
135+ {
136+ settings . Schema = schema ;
137+ }
138+
139+ var streamStore = new PostgresStreamStore ( settings ) ;
140+
141+ await streamStore . CreateSchema ( cancellationToken ) ;
142+
143+ return streamStore ;
144+ }
145+ }
146+ }
147+ }
0 commit comments