Skip to content

Commit 0074b39

Browse files
implemented connection string loader
1 parent 86a1e09 commit 0074b39

5 files changed

Lines changed: 159 additions & 107 deletions

File tree

src/Config.SqlStreamStore.Tests/ConfigRepositoryTests.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using System.Collections;
2-
using System.Collections.ObjectModel;
31
using System.Threading;
42
using System.Threading.Tasks;
53
using SqlStreamStore;
Lines changed: 22 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
1+
using System.Collections.Generic;
42
using System.Threading;
53
using System.Threading.Tasks;
64
using Microsoft.Extensions.Configuration;
7-
using Microsoft.Extensions.Primitives;
85
using SqlStreamStore;
96
using Xunit;
107

@@ -29,127 +26,52 @@ public async Task Can_build_config_source_with_instance_from_lambda()
2926
.Build();
3027

3128

32-
SqlStreamStoreInstance = new InMemoryStreamStore();
33-
34-
var repo = new ConfigRepository(SqlStreamStoreInstance);
35-
await repo.WriteChanges(new ModifiedConfigurationSettings(
36-
("setting1", "value1")), CancellationToken.None);
29+
SqlStreamStoreInstance = await BuildSteamStoreWithSettings(("setting1", "value1"));
3730

3831
Assert.Equal("value1", config.GetValue<string>("setting1"));
3932
}
4033

4134
[Fact]
4235
public async Task Can_build_config_source_with_connection_string()
4336
{
44-
const string key = "Config.SqlStreamStore.ConnectionString";
37+
const string connectionStringKey = "Config.SqlStreamStore.ConnectionString";
38+
const string expectedConnectionString = "not really a conection string, but as good as it gets";
4539

4640
string usedConnectionString = null;
4741

48-
Func<string, IStreamStore> factory = (s) =>
42+
var instance = await BuildSteamStoreWithSettings(("setting1", "value1"));
43+
44+
IStreamStore BuildStreamStore(string s)
4945
{
5046
usedConnectionString = s;
51-
return new InMemoryStreamStore();
52-
};
47+
return instance;
48+
}
49+
5350

5451
var config = new ConfigurationBuilder()
55-
.AddInMemoryCollection(new Dictionary<string, string>()
52+
.AddInMemoryCollection(new Dictionary<string, string>
5653
{
57-
{ key , "sql server"}
54+
{ connectionStringKey , expectedConnectionString}
5855
})
59-
.Add(new StreamStoreConfigurationSource(connectionStringKey: key, streamStoreFactory: factory))
56+
.Add(new StreamStoreConfigurationSource(connectionStringKey: connectionStringKey, streamStoreFactory: BuildStreamStore))
6057
.Build();
6158

62-
SqlStreamStoreInstance = new InMemoryStreamStore();
63-
64-
var repo = new ConfigRepository(SqlStreamStoreInstance);
65-
await repo.WriteChanges(new ModifiedConfigurationSettings(
66-
("setting1", "value1")), CancellationToken.None);
59+
// Ensure the factory actually used the configured connection string key
60+
Assert.Equal(expectedConnectionString, usedConnectionString);
6761

62+
// Ensure setting 1was read from stream store
6863
Assert.Equal("value1", config.GetValue<string>("setting1"));
69-
70-
}
71-
}
72-
73-
public class StreamStoreConfigurationSource : IConfigurationSource
74-
{
75-
private readonly string _connectionStringKey;
76-
private readonly Func<IConfigRepository> _getConfigRepository;
77-
private Func<string, IStreamStore> _streamStoreFactory;
78-
79-
public StreamStoreConfigurationSource(string connectionStringKey, Func<string, IStreamStore> streamStoreFactory)
80-
{
81-
_connectionStringKey = connectionStringKey;
82-
_streamStoreFactory = streamStoreFactory;
83-
}
84-
85-
public StreamStoreConfigurationSource(Func<IStreamStore> getStreamStore) :
86-
this(() => new ConfigRepository(getStreamStore()))
87-
{
88-
89-
}
90-
91-
public StreamStoreConfigurationSource(Func<IConfigRepository> getConfigRepository)
92-
{
93-
_getConfigRepository = getConfigRepository;
94-
}
95-
96-
public IConfigurationProvider Build(IConfigurationBuilder builder)
97-
{
98-
var getConfigRepository = _getConfigRepository;
99-
if (getConfigRepository == null)
100-
{
101-
getConfigRepository = () =>
102-
{
103-
var connectionString = GetConnectionString(builder);
104-
return new ConfigRepository(_streamStoreFactory(connectionString));
105-
};
106-
}
107-
108-
return new StreamStoreConfigurationProvider(_getConfigRepository);
10964
}
11065

111-
}
112-
113-
public class StreamStoreConfigurationProvider : IConfigurationProvider
114-
{
115-
private readonly Func<IConfigRepository> _getConfigRepository;
116-
117-
private IConfigurationSettings _settings;
118-
119-
public StreamStoreConfigurationProvider(Func<IConfigRepository> getConfigRepository)
66+
private static async Task<InMemoryStreamStore> BuildSteamStoreWithSettings(params (string key, string value)[] settings)
12067
{
121-
_getConfigRepository = getConfigRepository;
122-
}
123-
124-
public bool TryGet(string key, out string value)
125-
{
126-
if (_settings == null)
127-
{
128-
_settings = _getConfigRepository().GetLatest(CancellationToken.None).GetAwaiter().GetResult();
129-
}
68+
var instance = new InMemoryStreamStore();
13069

131-
return _settings.TryGetValue(key, out value);
132-
}
133-
134-
public void Set(string key, string value)
135-
{
136-
// Not going to write to SSS this way..
137-
}
138-
139-
public IChangeToken GetReloadToken()
140-
{
141-
return new ConfigurationReloadToken();
142-
}
143-
144-
public void Load()
145-
{
146-
147-
//_settings = _getConfigRepository()?.GetLatest(CancellationToken.None).GetAwaiter().GetResult();
148-
}
70+
var repo = new ConfigRepository(instance);
71+
await repo.WriteChanges(new ModifiedConfigurationSettings(
72+
settings), CancellationToken.None);
14973

150-
public IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath)
151-
{
152-
throw new NotImplementedException();
74+
return instance;
15375
}
15476
}
15577
}

src/Config.SqlStreamStore/ModifiedConfigurationSettings.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public ModifiedConfigurationSettings(ConfigurationSettings originalSettings, IRe
2828

2929
public IConfigurationSettings Modify(params (string Key, string Value)[] modifications)
3030
{
31-
var modified = this.Changes.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
31+
var modified = Changes.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
3232
foreach (var modification in modifications)
3333
{
3434
modified[modification.Key] = modification.Value;
@@ -44,7 +44,7 @@ public IConfigurationSettings Set(IReadOnlyDictionary<string, string> replacemen
4444

4545
public IConfigurationSettings Delete(params string[] deletions)
4646
{
47-
var modified = this.Changes.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
47+
var modified = Changes.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
4848
foreach (var deletion in deletions)
4949
{
5050
modified.Remove(deletion);
@@ -55,11 +55,11 @@ public IConfigurationSettings Delete(params string[] deletions)
5555
public ConfigChanged GetChanges()
5656
{
5757
var deleted = new HashSet<string>(
58-
collection: this.OriginalSettings.Settings.Keys.Where(x => !this.Changes.ContainsKey(x)),
58+
collection: OriginalSettings.Settings.Keys.Where(x => !Changes.ContainsKey(x)),
5959
comparer: StringComparer.InvariantCultureIgnoreCase);
6060

6161
var modified = new HashSet<string>(
62-
collection: this.Changes.Where(IsModified).Select(x => x.Key),
62+
collection: Changes.Where(IsModified).Select(x => x.Key),
6363
comparer: StringComparer.InvariantCultureIgnoreCase);
6464

6565
if (!deleted.Any() && !modified.Any())
@@ -68,7 +68,7 @@ public ConfigChanged GetChanges()
6868
return null;
6969
}
7070
return new ConfigChanged(
71-
allSettings: this.Changes.ToDictionary(x => x.Key, x => x.Value),
71+
allSettings: Changes.ToDictionary(x => x.Key, x => x.Value),
7272
modifiedSettings: modified,
7373
deletedSettings: deleted);
7474
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading;
5+
using Microsoft.Extensions.Configuration;
6+
using Microsoft.Extensions.Primitives;
7+
8+
namespace Config.SqlStreamStore
9+
{
10+
public class StreamStoreConfigurationProvider : ConfigurationProvider
11+
{
12+
private bool _loaded = false;
13+
private readonly Func<IConfigRepository> _getConfigRepository;
14+
private IConfigRepository _configRepository;
15+
16+
public StreamStoreConfigurationProvider(Func<IConfigRepository> getConfigRepository)
17+
{
18+
_getConfigRepository = getConfigRepository;
19+
}
20+
21+
public override bool TryGet(string key, out string value)
22+
{
23+
if (!_loaded)
24+
{
25+
LoadSettings();
26+
}
27+
28+
return Data.TryGetValue(key, out value);
29+
}
30+
31+
private void LoadSettings()
32+
{
33+
if (GetConfigRepository() == null)
34+
{
35+
throw new InvalidOperationException("The configuration repository has not yet been initialized.");
36+
}
37+
38+
var settings = GetConfigRepository()
39+
.GetLatest(CancellationToken.None).GetAwaiter().GetResult();
40+
41+
Data = settings.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
42+
43+
_loaded = true;
44+
}
45+
46+
47+
IConfigRepository GetConfigRepository()
48+
{
49+
if (_configRepository == null)
50+
{
51+
_configRepository = _getConfigRepository();
52+
}
53+
54+
return _configRepository;
55+
}
56+
57+
public override void Load()
58+
{
59+
if (GetConfigRepository() != null)
60+
{
61+
LoadSettings();
62+
}
63+
64+
}
65+
}
66+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using Microsoft.Extensions.Configuration;
3+
using SqlStreamStore;
4+
5+
namespace Config.SqlStreamStore
6+
{
7+
public class StreamStoreConfigurationSource : IConfigurationSource
8+
{
9+
private readonly string _connectionStringKey;
10+
private readonly Func<IConfigRepository> _getConfigRepository;
11+
private Func<string, IStreamStore> _streamStoreFactory;
12+
13+
public StreamStoreConfigurationSource(string connectionStringKey, Func<string, IStreamStore> streamStoreFactory)
14+
{
15+
_connectionStringKey = connectionStringKey;
16+
_streamStoreFactory = streamStoreFactory;
17+
}
18+
19+
public StreamStoreConfigurationSource(Func<IStreamStore> getStreamStore) :
20+
this(() =>
21+
{
22+
var streamStore = getStreamStore();
23+
if (streamStore == null) return null;
24+
25+
return new ConfigRepository(streamStore);
26+
})
27+
{
28+
29+
}
30+
31+
public StreamStoreConfigurationSource(Func<IConfigRepository> getConfigRepository)
32+
{
33+
_getConfigRepository = getConfigRepository;
34+
}
35+
36+
public IConfigurationProvider Build(IConfigurationBuilder builder)
37+
{
38+
if (_getConfigRepository == null)
39+
{
40+
var innerBuilder = new ConfigurationBuilder();
41+
foreach (var source in builder.Sources)
42+
{
43+
if (source != this)
44+
{
45+
innerBuilder.Add(source);
46+
}
47+
}
48+
49+
var connectionString = innerBuilder.Build()[_connectionStringKey];
50+
51+
if (string.IsNullOrEmpty(connectionString))
52+
{
53+
throw new InvalidOperationException($"Cannot create SqlStreamStore repository, becuase connection string (key: '{_connectionStringKey}') has not been configured.");
54+
}
55+
56+
var repo = new ConfigRepository(_streamStoreFactory(connectionString));
57+
58+
return new StreamStoreConfigurationProvider(() => repo);
59+
}
60+
61+
return new StreamStoreConfigurationProvider(_getConfigRepository);
62+
}
63+
64+
65+
}
66+
}

0 commit comments

Comments
 (0)