Skip to content

Commit b384814

Browse files
authored
Feature Add Settings Cache (#96)
* Add Feature Settings Cache * Update GetOrCreateObject * Fix code warnings
1 parent a7a4782 commit b384814

File tree

17 files changed

+786
-8
lines changed

17 files changed

+786
-8
lines changed

src/ReactiveMarbles.CacheDatabase.Core/SerializerExtensions.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,7 @@ blobCache is null
269269
: blobCache.GetObject<T>(key).Catch<T?, Exception>(_ =>
270270
{
271271
var value = fetchFunc();
272-
blobCache.InsertObject(key, value);
273-
return Observable.Return(value);
272+
return blobCache.InsertObject(key, value).Select(_ => value);
274273
});
275274

276275
/// <summary>
@@ -337,7 +336,7 @@ blobCache is null
337336
? Observable.Return(default(T))
338337
: blobCache.InvalidateObject<T>(key).Select(__ => x))
339338
.SelectMany(x =>
340-
cacheValidationPredicate is not null && !cacheValidationPredicate(x)
339+
cacheValidationPredicate is not null && !cacheValidationPredicate(x!)
341340
? Observable.Return(default(T))
342341
: blobCache.InsertObject(key, x, absoluteExpiration).Select(__ => x));
343342
});
@@ -357,21 +356,26 @@ blobCache is null
357356
}
358357

359358
/// <summary>
359+
/// <para>
360360
/// This method attempts to returned a cached value, while
361361
/// simultaneously calling a Func to return the latest value. When the
362362
/// latest data comes back, it replaces what was previously in the
363363
/// cache.
364-
///
364+
/// </para>
365+
/// <para>
365366
/// This method is best suited for loading dynamic data from the
366367
/// Internet, while still showing the user earlier data.
367-
///
368+
/// </para>
369+
/// <para>
368370
/// This method returns an IObservable that may return *two* results
369371
/// (first the cached data, then the latest data). Therefore, it's
370372
/// important for UI applications that in your Subscribe method, you
371373
/// write the code to merge the second result when it comes in.
372-
///
374+
/// </para>
375+
/// <para>
373376
/// This also means that awaiting this method is a Bad Idea(tm), always
374377
/// use Subscribe.
378+
/// </para>
375379
/// </summary>
376380
/// <typeparam name="T">The type of item to get.</typeparam>
377381
/// <param name="blobCache">The cache to get the item.</param>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<IsPackable>false</IsPackable>
8+
<DefineConstants>ENCRYPTED</DefineConstants>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<Compile Include="..\ReactiveMarbles.CacheDatabase.Settings.Tests\Mocks\*.cs" LinkBase="Mocks" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
17+
<PackageReference Include="xunit" Version="2.4.1" />
18+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
19+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
20+
<PrivateAssets>all</PrivateAssets>
21+
</PackageReference>
22+
<PackageReference Include="coverlet.collector" Version="3.1.2">
23+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
24+
<PrivateAssets>all</PrivateAssets>
25+
</PackageReference>
26+
</ItemGroup>
27+
28+
<ItemGroup>
29+
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.EncryptedSettings\ReactiveMarbles.CacheDatabase.EncryptedSettings.csproj" />
30+
</ItemGroup>
31+
32+
</Project>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
2+
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
using ReactiveMarbles.CacheDatabase.Settings.Tests;
6+
7+
namespace ReactiveMarbles.CacheDatabase.EncryptedSettings.Tests
8+
{
9+
/// <summary>
10+
/// Settings Cache Tests.
11+
/// </summary>
12+
public class SettingsCacheTests
13+
{
14+
/// <summary>
15+
/// Test1s this instance.
16+
/// </summary>
17+
[Fact]
18+
public async void TestCreateAndInsert()
19+
{
20+
await AppInfo.DeleteSettingsStore<ViewSettings>();
21+
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>("test1234");
22+
23+
Assert.NotNull(viewSettings);
24+
Assert.True(viewSettings!.BoolTest);
25+
Assert.Equal((short)16, viewSettings.ShortTest);
26+
Assert.Equal(1, viewSettings.IntTest);
27+
Assert.Equal(123456L, viewSettings.LongTest);
28+
Assert.Equal("TestString", viewSettings.StringTest);
29+
Assert.Equal(2.2f, viewSettings.FloatTest);
30+
Assert.Equal(23.8d, viewSettings.DoubleTest);
31+
Assert.Equal(EnumTestValue.Option1, viewSettings.EnumTest);
32+
await viewSettings.DisposeAsync();
33+
}
34+
35+
/// <summary>
36+
/// Tests the update and read.
37+
/// </summary>
38+
[Fact]
39+
public async void TestUpdateAndRead()
40+
{
41+
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>("test1234");
42+
viewSettings!.EnumTest = EnumTestValue.Option2;
43+
Assert.Equal(EnumTestValue.Option2, viewSettings.EnumTest);
44+
await viewSettings.DisposeAsync();
45+
}
46+
}
47+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
2+
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
global using Xunit;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<RootNamespace>ReactiveMarbles.CacheDatabase.EncryptedSettings</RootNamespace>
8+
<LangVersion>preview</LangVersion>
9+
<DefineConstants>ENCRYPTED</DefineConstants>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<Compile Include="..\ReactiveMarbles.CacheDatabase.Settings\Core\*.cs" LinkBase="Core" />
14+
<Compile Include="..\ReactiveMarbles.CacheDatabase.Settings\SettingsBase.cs" Link="SettingsBase.cs" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.EncryptedSqlite3\ReactiveMarbles.CacheDatabase.EncryptedSqlite3.csproj" />
19+
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.NewtonsoftJson\ReactiveMarbles.CacheDatabase.NewtonsoftJson.csproj" />
20+
</ItemGroup>
21+
22+
</Project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
2+
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
namespace ReactiveMarbles.CacheDatabase.Settings.Tests
6+
{
7+
8+
/// <summary>
9+
/// EnumTestValue.
10+
/// </summary>
11+
public enum EnumTestValue
12+
{
13+
/// <summary>
14+
/// The default.
15+
/// </summary>
16+
Default,
17+
/// <summary>
18+
/// The option1.
19+
/// </summary>
20+
Option1,
21+
/// <summary>
22+
/// The option2.
23+
/// </summary>
24+
Option2,
25+
/// <summary>
26+
/// The option3.
27+
/// </summary>
28+
Option3,
29+
/// <summary>
30+
/// The option4.
31+
/// </summary>
32+
Option4,
33+
}
34+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
2+
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
namespace ReactiveMarbles.CacheDatabase.Settings.Tests
6+
{
7+
/// <summary>
8+
/// View Settings.
9+
/// </summary>
10+
/// <seealso cref="ReactiveMarbles.CacheDatabase.Settings.SettingsBase" />
11+
public class ViewSettings : SettingsBase
12+
{
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="ViewSettings"/> class.
15+
/// </summary>
16+
public ViewSettings()
17+
: base(nameof(ViewSettings))
18+
{
19+
}
20+
21+
/// <summary>
22+
/// Gets or sets a value indicating whether [bool test].
23+
/// </summary>
24+
/// <value>
25+
/// <c>true</c> if [bool test]; otherwise, <c>false</c>.
26+
/// </value>
27+
public bool BoolTest
28+
{
29+
get => GetOrCreate(true); set => SetOrCreate(value);
30+
}
31+
32+
/// <summary>
33+
/// Gets or sets the byte test.
34+
/// </summary>
35+
/// <value>
36+
/// The byte test.
37+
/// </value>
38+
public byte ByteTest
39+
{
40+
get => GetOrCreate((byte)123); set => SetOrCreate(value);
41+
}
42+
43+
/// <summary>
44+
/// Gets or sets the short test.
45+
/// </summary>
46+
/// <value>
47+
/// The short test.
48+
/// </value>
49+
public short ShortTest
50+
{
51+
get => GetOrCreate((short)16); set => SetOrCreate(value);
52+
}
53+
54+
/// <summary>
55+
/// Gets or sets the int test.
56+
/// </summary>
57+
/// <value>
58+
/// The int test.
59+
/// </value>
60+
public int IntTest
61+
{
62+
get => GetOrCreate(1); set => SetOrCreate(value);
63+
}
64+
65+
/// <summary>
66+
/// Gets or sets the long test.
67+
/// </summary>
68+
/// <value>
69+
/// The long test.
70+
/// </value>
71+
public long LongTest
72+
{
73+
get => GetOrCreate(123456); set => SetOrCreate(value);
74+
}
75+
76+
/// <summary>
77+
/// Gets or sets the string test.
78+
/// </summary>
79+
/// <value>
80+
/// The string test.
81+
/// </value>
82+
public string? StringTest
83+
{
84+
get => GetOrCreate("TestString"); set => SetOrCreate(value);
85+
}
86+
87+
/// <summary>
88+
/// Gets or sets the float test.
89+
/// </summary>
90+
/// <value>
91+
/// The float test.
92+
/// </value>
93+
public float FloatTest
94+
{
95+
get => GetOrCreate(2.2f); set => SetOrCreate(value);
96+
}
97+
98+
/// <summary>
99+
/// Gets or sets the double test.
100+
/// </summary>
101+
/// <value>
102+
/// The double test.
103+
/// </value>
104+
public double DoubleTest
105+
{
106+
get => GetOrCreate(23.8d); set => SetOrCreate(value);
107+
}
108+
109+
/// <summary>
110+
/// Gets or sets the enum test.
111+
/// </summary>
112+
/// <value>
113+
/// The enum test.
114+
/// </value>
115+
public EnumTestValue EnumTest
116+
{
117+
get => GetOrCreate(EnumTestValue.Option1); set => SetOrCreate(value);
118+
}
119+
}
120+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<IsPackable>false</IsPackable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
12+
<PackageReference Include="xunit" Version="2.4.1" />
13+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
14+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
15+
<PrivateAssets>all</PrivateAssets>
16+
</PackageReference>
17+
<PackageReference Include="coverlet.collector" Version="3.1.2">
18+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
19+
<PrivateAssets>all</PrivateAssets>
20+
</PackageReference>
21+
<PackageReference Include="FluentAssertions" Version="6.7.0" />
22+
<PackageReference Include="Microsoft.Reactive.Testing" Version="5.0.0" />
23+
<PackageReference Include="ReactiveUI.Testing" Version="18.2.5" />
24+
</ItemGroup>
25+
26+
<ItemGroup>
27+
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.Settings\ReactiveMarbles.CacheDatabase.Settings.csproj" />
28+
</ItemGroup>
29+
30+
</Project>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
2+
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
namespace ReactiveMarbles.CacheDatabase.Settings.Tests
6+
{
7+
/// <summary>
8+
/// Settings Cache Tests.
9+
/// </summary>
10+
public class SettingsCacheTests
11+
{
12+
/// <summary>
13+
/// Test1s this instance.
14+
/// </summary>
15+
[Fact]
16+
public async void TestCreateAndInsert()
17+
{
18+
await AppInfo.DeleteSettingsStore<ViewSettings>();
19+
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>();
20+
21+
Assert.NotNull(viewSettings);
22+
Assert.True(viewSettings!.BoolTest);
23+
Assert.Equal((short)16, viewSettings.ShortTest);
24+
Assert.Equal(1, viewSettings.IntTest);
25+
Assert.Equal(123456L, viewSettings.LongTest);
26+
Assert.Equal("TestString", viewSettings.StringTest);
27+
Assert.Equal(2.2f, viewSettings.FloatTest);
28+
Assert.Equal(23.8d, viewSettings.DoubleTest);
29+
Assert.Equal(EnumTestValue.Option1, viewSettings.EnumTest);
30+
await viewSettings.DisposeAsync();
31+
}
32+
33+
/// <summary>
34+
/// Tests the update and read.
35+
/// </summary>
36+
[Fact]
37+
public async void TestUpdateAndRead()
38+
{
39+
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>();
40+
viewSettings!.EnumTest = EnumTestValue.Option2;
41+
Assert.Equal(EnumTestValue.Option2, viewSettings.EnumTest);
42+
await viewSettings.DisposeAsync();
43+
}
44+
}
45+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
2+
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
global using Xunit;

0 commit comments

Comments
 (0)