Skip to content

Commit ded84ad

Browse files
added history
1 parent 18caa43 commit ded84ad

4 files changed

Lines changed: 82 additions & 11 deletions

File tree

src/Config.SqlStreamStore.Tests/ConfigRepositoryTests.cs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using System.Threading;
34
using System.Threading.Tasks;
45
using SqlStreamStore;
@@ -7,10 +8,11 @@
78
namespace Config.SqlStreamStore.Tests
89
{
910

10-
// Optimistic concurrency checks
11+
// Max number of versions
1112
// Can roll back to a version
12-
// wait until sql is available
13-
// configure stream name
13+
// List versions
14+
// Hooks for encryption / decryption
15+
//
1416

1517
public class ConfigRepositoryTests
1618
{
@@ -109,10 +111,11 @@ Task<IConfigurationSettings> StartModification(string value)
109111
return _streamStoreConfigRepository.Modify(
110112
changeSettings: async (currentSettings, ct) =>
111113
{
112-
if (++count == 2)
114+
if (Interlocked.Increment(ref count) == 2)
113115
{
114116
waitUntilBothStarted.SetResult(true);
115117
}
118+
116119
await delayWriting.Task;
117120
return currentSettings.WithModifiedSettings(("setting1", value));
118121
},
@@ -142,6 +145,31 @@ Task<IConfigurationSettings> StartModification(string value)
142145
Assert.True(errorHandlerInvoked);
143146
}
144147

148+
[Fact]
149+
public async Task Can_get_history()
150+
{
151+
// write 100 modifications, 0 .. 99
152+
for (int i = 0; i < 100; i++)
153+
{
154+
await _streamStoreConfigRepository.Modify(CancellationToken.None,
155+
("setting", i.ToString()),
156+
("othersetting", "constant")
157+
);
158+
}
159+
160+
var history = await _streamStoreConfigRepository.GetSettingsHistory(CancellationToken.None);
161+
162+
Assert.Equal(Constants.DefaultMaxCount, history.Count);
163+
164+
// Check first and last entry
165+
Assert.Equal("90", history.First()["setting"]);
166+
Assert.Equal("constant", history.First()["othersetting"]);
167+
Assert.Equal(90, history.First().Version);
168+
Assert.Equal("99", history.Last()["setting"]);
169+
Assert.Equal(99, history.Last().Version);
170+
Assert.Equal("constant", history.Last()["othersetting"]);
171+
}
172+
145173
private static ModifiedConfigurationSettings BuildNewSettings()
146174
{
147175
var settings = new ModifiedConfigurationSettings(

src/Config.SqlStreamStore/ConfigRepository.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Threading;
45
using System.Threading.Tasks;
@@ -17,6 +18,9 @@ public interface IStreamStoreConfigRepository
1718
IDisposable SubscribeToChanges(int version,
1819
StreamStoreConfigRepository.OnSettingsChanged onSettingsChanged,
1920
CancellationToken ct);
21+
22+
Task<int?> GetMaxCount(CancellationToken ct);
23+
Task SetMaxCount(int maxCount, CancellationToken ct);
2024
}
2125

2226
public class StreamStoreConfigRepository : IStreamStoreConfigRepository
@@ -67,6 +71,21 @@ public async Task<IConfigurationSettings> Modify(CancellationToken ct,
6771
return await WriteChanges(modified, ct);
6872
}
6973

74+
public async Task<IReadOnlyList<IConfigurationSettings>> GetSettingsHistory(CancellationToken ct)
75+
{
76+
var maxCount = await GetMaxCount(ct) ?? Constants.DefaultMaxCount;
77+
var stream = await _streamStore.ReadStreamBackwards(_streamId, StreamVersion.End, maxCount, true, ct);
78+
79+
var result = new List<IConfigurationSettings> ();
80+
foreach (var message in stream.Messages.OrderBy(x => x.StreamVersion))
81+
{
82+
var setting = await BuildConfigurationSettingsFromMessage(message, ct);
83+
result.Add(setting);
84+
}
85+
86+
return result;
87+
}
88+
7089
public async Task<IConfigurationSettings> Modify(
7190
Func<IConfigurationSettings, CancellationToken, Task<ModifiedConfigurationSettings>> changeSettings,
7291
ErrorHandler errorHandler,
@@ -92,9 +111,25 @@ public async Task<IConfigurationSettings> Modify(
92111
throw new InvalidOperationException("Failed to write configuration settings");
93112
}
94113

114+
public async Task<int?> GetMaxCount(CancellationToken ct)
115+
{
116+
var metaData = await _streamStore.GetStreamMetadata(_streamId, ct);
117+
return metaData?.MaxCount;
118+
}
119+
120+
public async Task SetMaxCount(int maxCount, CancellationToken ct)
121+
{
122+
await _streamStore.SetStreamMetadata(_streamId, maxCount: maxCount, cancellationToken: ct);
123+
}
95124

96125
public async Task<IConfigurationSettings> WriteChanges(ModifiedConfigurationSettings settings, CancellationToken ct)
97126
{
127+
if (await GetMaxCount(ct) == null)
128+
{
129+
// Ensure default value is set
130+
await SetMaxCount(Constants.DefaultMaxCount, CancellationToken.None);
131+
}
132+
98133
var changes = settings.GetChanges();
99134

100135
if (changes == null)

src/Config.SqlStreamStore/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ public static class Constants
44
{
55
public const string DefaultStreamName = "Config.SqlStreamStore";
66
public const string ConfigChangedMessageName = "Config.SqlStreamStore.ConfigChanged";
7+
public const int DefaultMaxCount = 10;
78
}
89
}

src/Config.SqlStreamStore/StreamStoreConfigurationSource.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ public class StreamStoreConfigurationSource : IConfigurationSource
1616

1717
private readonly BuildStreamStoreFromConfig _buildStreamStoreFromConfig;
1818

19+
public string StreamId { get; set; } = Constants.DefaultStreamName;
20+
1921
public bool SubscribeToChanges { get; set; }
2022

2123
public ErrorHandler ErrorHandler { get; set; }
2224

2325
private readonly BuildConfigRepository _getConfigRepository;
2426

25-
2627
public StreamStoreConfigurationSource(BuildStreamStoreFromConfig buildStreamStoreFromConfig)
2728
{
2829
_buildStreamStoreFromConfig = buildStreamStoreFromConfig;
@@ -44,10 +45,9 @@ public StreamStoreConfigurationSource(string connectionStringKey, BuildStreamSto
4445
});
4546
}
4647

47-
public StreamStoreConfigurationSource(Func<IStreamStore> getStreamStore) :
48-
this(() => new StreamStoreConfigRepository(getStreamStore()))
48+
public StreamStoreConfigurationSource(Func<IStreamStore> getStreamStore)
4949
{
50-
50+
_getConfigRepository = () => BuildRepository(getStreamStore());
5151
}
5252

5353
public StreamStoreConfigurationSource(BuildConfigRepository getConfigRepository)
@@ -71,11 +71,18 @@ public IConfigurationProvider Build(IConfigurationBuilder builder)
7171
}
7272
}
7373

74-
var repo = new StreamStoreConfigRepository(_buildStreamStoreFromConfig(innerBuilder.Build()));
74+
var streamStore = _buildStreamStoreFromConfig(innerBuilder.Build());
75+
var streamStoreConfigRepository = BuildRepository(streamStore);
7576

76-
return new StreamStoreConfigurationProvider(this, repo);
77-
77+
return new StreamStoreConfigurationProvider(this, streamStoreConfigRepository);
7878
}
7979

80+
private StreamStoreConfigRepository BuildRepository(IStreamStore streamStore)
81+
{
82+
var repo = new StreamStoreConfigRepository(
83+
streamStore: streamStore,
84+
streamId: StreamId);
85+
return repo;
86+
}
8087
}
8188
}

0 commit comments

Comments
 (0)