Skip to content

Commit

Permalink
Feature Add Settings Cache (#96)
Browse files Browse the repository at this point in the history
* Add Feature Settings Cache

* Update GetOrCreateObject

* Fix code warnings
  • Loading branch information
ChrisPulman authored Jul 12, 2022
1 parent a7a4782 commit b384814
Show file tree
Hide file tree
Showing 17 changed files with 786 additions and 8 deletions.
16 changes: 10 additions & 6 deletions src/ReactiveMarbles.CacheDatabase.Core/SerializerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,7 @@ blobCache is null
: blobCache.GetObject<T>(key).Catch<T?, Exception>(_ =>
{
var value = fetchFunc();
blobCache.InsertObject(key, value);
return Observable.Return(value);
return blobCache.InsertObject(key, value).Select(_ => value);
});

/// <summary>
Expand Down Expand Up @@ -337,7 +336,7 @@ blobCache is null
? Observable.Return(default(T))
: blobCache.InvalidateObject<T>(key).Select(__ => x))
.SelectMany(x =>
cacheValidationPredicate is not null && !cacheValidationPredicate(x)
cacheValidationPredicate is not null && !cacheValidationPredicate(x!)
? Observable.Return(default(T))
: blobCache.InsertObject(key, x, absoluteExpiration).Select(__ => x));
});
Expand All @@ -357,21 +356,26 @@ blobCache is null
}

/// <summary>
/// <para>
/// This method attempts to returned a cached value, while
/// simultaneously calling a Func to return the latest value. When the
/// latest data comes back, it replaces what was previously in the
/// cache.
///
/// </para>
/// <para>
/// This method is best suited for loading dynamic data from the
/// Internet, while still showing the user earlier data.
///
/// </para>
/// <para>
/// This method returns an IObservable that may return *two* results
/// (first the cached data, then the latest data). Therefore, it's
/// important for UI applications that in your Subscribe method, you
/// write the code to merge the second result when it comes in.
///
/// </para>
/// <para>
/// This also means that awaiting this method is a Bad Idea(tm), always
/// use Subscribe.
/// </para>
/// </summary>
/// <typeparam name="T">The type of item to get.</typeparam>
/// <param name="blobCache">The cache to get the item.</param>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<DefineConstants>ENCRYPTED</DefineConstants>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\ReactiveMarbles.CacheDatabase.Settings.Tests\Mocks\*.cs" LinkBase="Mocks" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.EncryptedSettings\ReactiveMarbles.CacheDatabase.EncryptedSettings.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using ReactiveMarbles.CacheDatabase.Settings.Tests;

namespace ReactiveMarbles.CacheDatabase.EncryptedSettings.Tests
{
/// <summary>
/// Settings Cache Tests.
/// </summary>
public class SettingsCacheTests
{
/// <summary>
/// Test1s this instance.
/// </summary>
[Fact]
public async void TestCreateAndInsert()
{
await AppInfo.DeleteSettingsStore<ViewSettings>();
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>("test1234");

Assert.NotNull(viewSettings);
Assert.True(viewSettings!.BoolTest);
Assert.Equal((short)16, viewSettings.ShortTest);
Assert.Equal(1, viewSettings.IntTest);
Assert.Equal(123456L, viewSettings.LongTest);
Assert.Equal("TestString", viewSettings.StringTest);
Assert.Equal(2.2f, viewSettings.FloatTest);
Assert.Equal(23.8d, viewSettings.DoubleTest);
Assert.Equal(EnumTestValue.Option1, viewSettings.EnumTest);
await viewSettings.DisposeAsync();
}

/// <summary>
/// Tests the update and read.
/// </summary>
[Fact]
public async void TestUpdateAndRead()
{
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>("test1234");
viewSettings!.EnumTest = EnumTestValue.Option2;
Assert.Equal(EnumTestValue.Option2, viewSettings.EnumTest);
await viewSettings.DisposeAsync();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

global using Xunit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>ReactiveMarbles.CacheDatabase.EncryptedSettings</RootNamespace>
<LangVersion>preview</LangVersion>
<DefineConstants>ENCRYPTED</DefineConstants>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\ReactiveMarbles.CacheDatabase.Settings\Core\*.cs" LinkBase="Core" />
<Compile Include="..\ReactiveMarbles.CacheDatabase.Settings\SettingsBase.cs" Link="SettingsBase.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.EncryptedSqlite3\ReactiveMarbles.CacheDatabase.EncryptedSqlite3.csproj" />
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.NewtonsoftJson\ReactiveMarbles.CacheDatabase.NewtonsoftJson.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

namespace ReactiveMarbles.CacheDatabase.Settings.Tests
{

/// <summary>
/// EnumTestValue.
/// </summary>
public enum EnumTestValue
{
/// <summary>
/// The default.
/// </summary>
Default,
/// <summary>
/// The option1.
/// </summary>
Option1,
/// <summary>
/// The option2.
/// </summary>
Option2,
/// <summary>
/// The option3.
/// </summary>
Option3,
/// <summary>
/// The option4.
/// </summary>
Option4,
}
}
120 changes: 120 additions & 0 deletions src/ReactiveMarbles.CacheDatabase.Settings.Tests/Mocks/ViewSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

namespace ReactiveMarbles.CacheDatabase.Settings.Tests
{
/// <summary>
/// View Settings.
/// </summary>
/// <seealso cref="ReactiveMarbles.CacheDatabase.Settings.SettingsBase" />
public class ViewSettings : SettingsBase
{
/// <summary>
/// Initializes a new instance of the <see cref="ViewSettings"/> class.
/// </summary>
public ViewSettings()
: base(nameof(ViewSettings))
{
}

/// <summary>
/// Gets or sets a value indicating whether [bool test].
/// </summary>
/// <value>
/// <c>true</c> if [bool test]; otherwise, <c>false</c>.
/// </value>
public bool BoolTest
{
get => GetOrCreate(true); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the byte test.
/// </summary>
/// <value>
/// The byte test.
/// </value>
public byte ByteTest
{
get => GetOrCreate((byte)123); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the short test.
/// </summary>
/// <value>
/// The short test.
/// </value>
public short ShortTest
{
get => GetOrCreate((short)16); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the int test.
/// </summary>
/// <value>
/// The int test.
/// </value>
public int IntTest
{
get => GetOrCreate(1); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the long test.
/// </summary>
/// <value>
/// The long test.
/// </value>
public long LongTest
{
get => GetOrCreate(123456); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the string test.
/// </summary>
/// <value>
/// The string test.
/// </value>
public string? StringTest
{
get => GetOrCreate("TestString"); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the float test.
/// </summary>
/// <value>
/// The float test.
/// </value>
public float FloatTest
{
get => GetOrCreate(2.2f); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the double test.
/// </summary>
/// <value>
/// The double test.
/// </value>
public double DoubleTest
{
get => GetOrCreate(23.8d); set => SetOrCreate(value);
}

/// <summary>
/// Gets or sets the enum test.
/// </summary>
/// <value>
/// The enum test.
/// </value>
public EnumTestValue EnumTest
{
get => GetOrCreate(EnumTestValue.Option1); set => SetOrCreate(value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.Reactive.Testing" Version="5.0.0" />
<PackageReference Include="ReactiveUI.Testing" Version="18.2.5" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveMarbles.CacheDatabase.Settings\ReactiveMarbles.CacheDatabase.Settings.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

namespace ReactiveMarbles.CacheDatabase.Settings.Tests
{
/// <summary>
/// Settings Cache Tests.
/// </summary>
public class SettingsCacheTests
{
/// <summary>
/// Test1s this instance.
/// </summary>
[Fact]
public async void TestCreateAndInsert()
{
await AppInfo.DeleteSettingsStore<ViewSettings>();
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>();

Assert.NotNull(viewSettings);
Assert.True(viewSettings!.BoolTest);
Assert.Equal((short)16, viewSettings.ShortTest);
Assert.Equal(1, viewSettings.IntTest);
Assert.Equal(123456L, viewSettings.LongTest);
Assert.Equal("TestString", viewSettings.StringTest);
Assert.Equal(2.2f, viewSettings.FloatTest);
Assert.Equal(23.8d, viewSettings.DoubleTest);
Assert.Equal(EnumTestValue.Option1, viewSettings.EnumTest);
await viewSettings.DisposeAsync();
}

/// <summary>
/// Tests the update and read.
/// </summary>
[Fact]
public async void TestUpdateAndRead()
{
var viewSettings = await AppInfo.SetupSettingsStore<ViewSettings>();
viewSettings!.EnumTest = EnumTestValue.Option2;
Assert.Equal(EnumTestValue.Option2, viewSettings.EnumTest);
await viewSettings.DisposeAsync();
}
}
}
5 changes: 5 additions & 0 deletions src/ReactiveMarbles.CacheDatabase.Settings.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2019-2022 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

global using Xunit;
Loading

0 comments on commit b384814

Please sign in to comment.