From f4030f2ce71cf5a7cba9474fa7d73dd108180ad3 Mon Sep 17 00:00:00 2001 From: Glenn Watson <5834289+glennawatson@users.noreply.github.com> Date: Sat, 25 Jun 2022 21:01:26 +1000 Subject: [PATCH] housekeeping: further cleanup --- .gitattributes | 5 +- src/Akavache.Core/Akavache.Core.csproj | 1 - src/Akavache.Core/BlobCache/BlobCache.cs | 10 +-- src/Akavache.Core/BlobCache/CacheEntry.cs | 3 - .../BlobCache/InMemoryBlobCache.cs | 9 +-- src/Akavache.Core/BlobCache/ObjectWrapper.cs | 14 +++- src/Akavache.Core/BulkOperationsMixin.cs | 19 ++---- src/Akavache.Core/DependencyResolverMixin.cs | 9 +-- src/Akavache.Core/IsExternalInit.cs | 13 ++++ .../Json/JsonDateTimeOffsetTickConverter.cs | 7 +- .../Json/JsonDateTimeTickConverter.cs | 2 +- .../Json/JsonSerializationMixin.cs | 66 +++++-------------- .../KeyedOperations/KeyedOperation.cs | 4 +- .../KeyedOperations/KeyedOperationQueue.cs | 3 +- .../SimpleFilesystemProvider.cs | 7 +- src/Akavache.Core/Properties/AssemblyInfo.cs | 1 + src/Akavache.Core/ProtectedData.cs | 4 +- src/Akavache.Core/Providers/FileAccess.cs | 3 - src/Akavache.Core/Providers/FileShare.cs | 3 - src/Akavache.Core/RelativeTimeMixin.cs | 60 +++++------------ src/Akavache.Drawing/BitmapImageMixin.cs | 60 +++++------------ src/Akavache.Sqlite3/AsyncLock.cs | 9 +-- src/Akavache.Sqlite3/IsExternalInit.cs | 13 ++++ .../Operations/SqliteOperationMixin.cs | 2 + src/Akavache.Sqlite3/Queues/OperationQueue.cs | 5 +- .../Queues/OperationQueueCoalescing.cs | 26 ++++---- src/Akavache.Sqlite3/SQLite.cs | 8 +-- .../SqlLiteCache/ObjectWrapper.cs | 18 +++-- .../SqlLiteCache/SqlRawPersistentBlobCache.cs | 2 +- src/Akavache.Tests/API/ApiApprovalTests.cs | 5 +- .../FakeDateTimeHighPrecisionJsonConverter.cs | 2 +- .../Helpers/IntegrationTestHelper.cs | 2 +- .../TestBases/BlobCacheExtensionsTestBase.cs | 9 +-- .../TestBases/DateTimeTestBase.cs | 4 +- src/Akavache/Registrations.cs | 1 + 35 files changed, 152 insertions(+), 257 deletions(-) create mode 100644 src/Akavache.Core/IsExternalInit.cs create mode 100644 src/Akavache.Sqlite3/IsExternalInit.cs diff --git a/.gitattributes b/.gitattributes index 269bc192f..2dbab83b2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,7 +2,7 @@ * text=auto # Text files that should be normalized to LF in odb. -*.cs text eol=lf diff=csharp +*.cs text diff=csharp *.xaml text *.config text *.c text @@ -40,6 +40,3 @@ *.pdb binary *.sdf binary *.7z binary - -# Generated file should just use CRLF, it's fiiine -SolutionInfo.cs text eol=crlf diff=csharp diff --git a/src/Akavache.Core/Akavache.Core.csproj b/src/Akavache.Core/Akavache.Core.csproj index 9cc9e2f6a..4d81ae46e 100644 --- a/src/Akavache.Core/Akavache.Core.csproj +++ b/src/Akavache.Core/Akavache.Core.csproj @@ -15,7 +15,6 @@ - diff --git a/src/Akavache.Core/BlobCache/BlobCache.cs b/src/Akavache.Core/BlobCache/BlobCache.cs index 8f667a062..3687a9b34 100644 --- a/src/Akavache.Core/BlobCache/BlobCache.cs +++ b/src/Akavache.Core/BlobCache/BlobCache.cs @@ -56,15 +56,7 @@ static BlobCache() [SuppressMessage("Design", "CA1065: Properties should not fire exceptions.", Justification = "Extreme non standard case.")] public static string ApplicationName { - get - { - if (_applicationName is null) - { - throw new("Make sure to set BlobCache.ApplicationName on startup"); - } - - return _applicationName; - } + get => _applicationName ?? throw new("Make sure to set BlobCache.ApplicationName on startup"); set => _applicationName = value; } diff --git a/src/Akavache.Core/BlobCache/CacheEntry.cs b/src/Akavache.Core/BlobCache/CacheEntry.cs index 2a3392a4f..5477bbf73 100644 --- a/src/Akavache.Core/BlobCache/CacheEntry.cs +++ b/src/Akavache.Core/BlobCache/CacheEntry.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - namespace Akavache; /// @@ -45,6 +43,5 @@ public CacheEntry(string? typeName, byte[] value, DateTimeOffset createdAt, Date /// /// Gets or sets the value of the entry. /// - [SuppressMessage("FxCop.Style", "CA1819: Properties should not return arrays", Justification = "Legacy reasons.")] public byte[] Value { get; protected set; } } diff --git a/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs b/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs index 18bcc6a1f..834fc9b29 100644 --- a/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs +++ b/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs @@ -225,12 +225,9 @@ public IObservable Get(string key) } } - if (entry is null) - { - return ExceptionHelper.ObservableThrowKeyNotFoundException(key); - } - - return Observable.Return(entry.CreatedAt, Scheduler); + return entry is null + ? ExceptionHelper.ObservableThrowKeyNotFoundException(key) + : Observable.Return(entry.CreatedAt, Scheduler); } /// diff --git a/src/Akavache.Core/BlobCache/ObjectWrapper.cs b/src/Akavache.Core/BlobCache/ObjectWrapper.cs index 3bb74589b..946a552aa 100644 --- a/src/Akavache.Core/BlobCache/ObjectWrapper.cs +++ b/src/Akavache.Core/BlobCache/ObjectWrapper.cs @@ -5,4 +5,16 @@ namespace Akavache; -internal record ObjectWrapper(T Value) : IObjectWrapper; +internal class ObjectWrapper : IObjectWrapper +{ + public ObjectWrapper() + { + } + + public ObjectWrapper(T value) + { + Value = value; + } + + public T? Value { get; set; } +} diff --git a/src/Akavache.Core/BulkOperationsMixin.cs b/src/Akavache.Core/BulkOperationsMixin.cs index 3b8342031..5d639e08e 100644 --- a/src/Akavache.Core/BulkOperationsMixin.cs +++ b/src/Akavache.Core/BulkOperationsMixin.cs @@ -22,13 +22,10 @@ public static IObservable> Get(this IBlobCache blobC null => throw new ArgumentNullException(nameof(blobCache)), IBulkBlobCache bulkCache => bulkCache.Get(keys), _ => keys.ToObservable() - .SelectMany(x => - { - return blobCache.Get(x) + .SelectMany(x => blobCache.Get(x) .Select(y => new KeyValuePair(x, y)) .Catch, KeyNotFoundException>(_ => - Observable.Empty>()); - }) + Observable.Empty>())) .ToDictionary(k => k.Key, v => v.Value) }; @@ -87,20 +84,14 @@ public static IObservable Invalidate(this IBlobCache blobCache, IEnumerabl /// The blob cache to extract the values from. /// The keys to get the values for. /// A observable with the specified values. - public static IObservable> GetObjects(this IBlobCache blobCache, IEnumerable keys) - { - if (blobCache is IObjectBulkBlobCache bulkCache) - { - return bulkCache.GetObjects(keys); - } - - return keys.ToObservable() + public static IObservable> GetObjects(this IBlobCache blobCache, IEnumerable keys) => blobCache is IObjectBulkBlobCache bulkCache + ? bulkCache.GetObjects(keys) + : keys.ToObservable() .SelectMany(x => blobCache.GetObject(x) .Where(y => y is not null) .Select(y => new KeyValuePair(x, y!)) .Catch, KeyNotFoundException>(_ => Observable.Empty>())) .ToDictionary(k => k.Key, v => v.Value); - } /// /// Inserts the specified key/value pairs into the blob. diff --git a/src/Akavache.Core/DependencyResolverMixin.cs b/src/Akavache.Core/DependencyResolverMixin.cs index b6e156d0d..e6e1fbe8f 100644 --- a/src/Akavache.Core/DependencyResolverMixin.cs +++ b/src/Akavache.Core/DependencyResolverMixin.cs @@ -3,7 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; using System.Reflection; using Splat; @@ -13,7 +12,6 @@ namespace Akavache; /// /// A set of mix-in associated with the interface. /// -[SuppressMessage("FxCop.Analyzer", "CA1307: The behavior of 'string.Replace(string, string)' could vary based on the current user's locale settings", Justification = "Not all platforms allow locale.")] public static class DependencyResolverMixin { /// @@ -63,12 +61,7 @@ public static void InitializeAkavache(this IMutableDependencyResolver resolver, var registerer = (IWantsToRegisterStuff?)Activator.CreateInstance(registerTypeClass); - if (registerer is null) - { - continue; - } - - registerer.Register(resolver, readonlyDependencyResolver); + registerer?.Register(resolver, readonlyDependencyResolver); } } } diff --git a/src/Akavache.Core/IsExternalInit.cs b/src/Akavache.Core/IsExternalInit.cs new file mode 100644 index 000000000..046bad107 --- /dev/null +++ b/src/Akavache.Core/IsExternalInit.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.ComponentModel; + +namespace System.Runtime.CompilerServices; + +[EditorBrowsable(EditorBrowsableState.Never)] +internal class IsExternalInit +{ +} diff --git a/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs b/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs index 68e4314ae..b03597242 100644 --- a/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs +++ b/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs @@ -28,12 +28,7 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer var data = serializer.Deserialize(reader); - if (data is null) - { - return null; - } - - return (DateTimeOffset)data; + return data is null ? null : (DateTimeOffset)data; } public override bool CanConvert(Type objectType) => objectType == typeof(DateTimeOffset) || objectType == typeof(DateTimeOffset?); diff --git a/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs b/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs index d5993f106..eca652600 100644 --- a/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs +++ b/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs @@ -36,7 +36,7 @@ internal class JsonDateTimeTickConverter : JsonConverter throw new ArgumentNullException(nameof(reader)); } - if (reader.TokenType != JsonToken.Integer && reader.TokenType != JsonToken.Date) + if (reader.TokenType is not JsonToken.Integer and not JsonToken.Date) { return null; } diff --git a/src/Akavache.Core/Json/JsonSerializationMixin.cs b/src/Akavache.Core/Json/JsonSerializationMixin.cs index a4a962414..1c839aa72 100644 --- a/src/Akavache.Core/Json/JsonSerializationMixin.cs +++ b/src/Akavache.Core/Json/JsonSerializationMixin.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reactive.Threading.Tasks; @@ -55,15 +54,9 @@ public static IObservable InsertObject(this IBlobCache blobCache, strin /// The data to insert into the cache. /// An optional expiration date. /// A Future result representing the completion of the insert. - public static IObservable InsertAllObjects(this IBlobCache blobCache, IDictionary keyValuePairs, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is IObjectBlobCache objCache) - { - return objCache.InsertObjects(keyValuePairs, absoluteExpiration); - } - - throw new NotImplementedException(); - } + public static IObservable InsertAllObjects(this IBlobCache blobCache, IDictionary keyValuePairs, DateTimeOffset? absoluteExpiration = null) => blobCache is IObjectBlobCache objCache + ? objCache.InsertObjects(keyValuePairs, absoluteExpiration) + : throw new NotImplementedException(); /// /// Get an object from the cache and deserialize it via the JSON @@ -130,25 +123,19 @@ public static IObservable> GetAllObjects(this IBlobCache blobC /// The type of item to get. /// A Future result representing the deserialized object from /// the cache. - public static IObservable GetOrFetchObject(this IBlobCache blobCache, string key, Func> fetchFunc, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.GetObject(key).Catch(ex => + public static IObservable GetOrFetchObject(this IBlobCache blobCache, string key, Func> fetchFunc, DateTimeOffset? absoluteExpiration = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.GetObject(key).Catch(ex => { var prefixedKey = blobCache.GetHashCode().ToString(CultureInfo.InvariantCulture) + key; var result = Observable.Defer(fetchFunc) .Do(x => blobCache.InsertObject(key, x, absoluteExpiration)) - .Finally(() => _inflightFetchRequests.TryRemove(prefixedKey, out var _)) + .Finally(() => _inflightFetchRequests.TryRemove(prefixedKey, out _)) .Multicast(new AsyncSubject()).RefCount(); return (IObservable)_inflightFetchRequests.GetOrAdd(prefixedKey, result); }); - } /// /// @@ -170,15 +157,9 @@ public static IObservable> GetAllObjects(this IBlobCache blobC /// An optional expiration date. /// A Future result representing the deserialized object from /// the cache. - public static IObservable GetOrFetchObject(this IBlobCache blobCache, string key, Func> fetchFunc, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.GetOrFetchObject(key, () => fetchFunc().ToObservable(), absoluteExpiration); - } + public static IObservable GetOrFetchObject(this IBlobCache blobCache, string key, Func> fetchFunc, DateTimeOffset? absoluteExpiration = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.GetOrFetchObject(key, () => fetchFunc().ToObservable(), absoluteExpiration); /// /// @@ -199,15 +180,9 @@ public static IObservable> GetAllObjects(this IBlobCache blobC /// An optional expiration date. /// A Future result representing the deserialized object from /// the cache. - public static IObservable GetOrCreateObject(this IBlobCache blobCache, string key, Func fetchFunc, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.GetOrFetchObject(key, () => Observable.Return(fetchFunc()), absoluteExpiration); - } + public static IObservable GetOrCreateObject(this IBlobCache blobCache, string key, Func fetchFunc, DateTimeOffset? absoluteExpiration = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.GetOrFetchObject(key, () => Observable.Return(fetchFunc()), absoluteExpiration); /// /// Returns the time that the key was added to the cache, or returns @@ -261,7 +236,6 @@ public static IObservable> GetAllObjects(this IBlobCache blobC /// if the fetched value should be cached. /// An Observable stream containing either one or two /// results (possibly a cached version, then the latest version). - [SuppressMessage("Design", "CA2000: call dispose", Justification = "Disposed by member")] public static IObservable GetAndFetchLatest( this IBlobCache blobCache, string key, @@ -360,15 +334,9 @@ public static IObservable> GetAllObjects(this IBlobCache blobC Func? fetchPredicate = null, DateTimeOffset? absoluteExpiration = null, bool shouldInvalidateOnError = false, - Func? cacheValidationPredicate = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.GetAndFetchLatest(key, () => fetchFunc().ToObservable(), fetchPredicate, absoluteExpiration, shouldInvalidateOnError, cacheValidationPredicate); - } + Func? cacheValidationPredicate = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.GetAndFetchLatest(key, () => fetchFunc().ToObservable(), fetchPredicate, absoluteExpiration, shouldInvalidateOnError, cacheValidationPredicate); /// /// Invalidates a single object from the cache. It is important that the Type @@ -441,9 +409,7 @@ internal static byte[] SerializeObject(T value) var bytes = Encoding.UTF8.GetString(x, 0, x.Length); var ret = JsonConvert.DeserializeObject(bytes, settings); -#pragma warning disable CS8604 // Possible null reference argument. return Observable.Return(ret); -#pragma warning restore CS8604 // Possible null reference argument. } catch (Exception ex) { diff --git a/src/Akavache.Core/KeyedOperations/KeyedOperation.cs b/src/Akavache.Core/KeyedOperations/KeyedOperation.cs index 3ee2ffba5..14b7fe8bc 100644 --- a/src/Akavache.Core/KeyedOperations/KeyedOperation.cs +++ b/src/Akavache.Core/KeyedOperations/KeyedOperation.cs @@ -14,7 +14,7 @@ internal abstract class KeyedOperation /// /// The key of the operation. /// The ID of the operation. - public KeyedOperation(string key, int id) + protected KeyedOperation(string key, int id) { Key = key; Id = id; @@ -68,4 +68,4 @@ public override IObservable EvaluateFunc() return ret.Select(_ => Unit.Default); } -} \ No newline at end of file +} diff --git a/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs b/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs index 411845022..86b73068d 100644 --- a/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs +++ b/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs @@ -3,8 +3,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; using System.Globalization; + using Splat; namespace Akavache; @@ -24,7 +24,6 @@ public class KeyedOperationQueue : IKeyedOperationQueue, IEnableLogger, IDisposa /// Initializes a new instance of the class. /// /// The scheduler for Observable operations. - [SuppressMessage("Design", "CA2000: call dispose", Justification = "Disposed by member")] public KeyedOperationQueue(IScheduler? scheduler = null) { scheduler ??= BlobCache.TaskpoolScheduler; diff --git a/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs b/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs index 8bf7e9f38..4014a1a35 100644 --- a/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs +++ b/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs @@ -56,11 +56,6 @@ protected static string GetAssemblyDirectoryName() { var assemblyDirectoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - if (assemblyDirectoryName is null) - { - throw new InvalidOperationException("The directory name of the assembly location is null"); - } - - return assemblyDirectoryName; + return assemblyDirectoryName ?? throw new InvalidOperationException("The directory name of the assembly location is null"); } } \ No newline at end of file diff --git a/src/Akavache.Core/Properties/AssemblyInfo.cs b/src/Akavache.Core/Properties/AssemblyInfo.cs index 6ef496432..0a688b1cb 100644 --- a/src/Akavache.Core/Properties/AssemblyInfo.cs +++ b/src/Akavache.Core/Properties/AssemblyInfo.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using System.Runtime.CompilerServices; + using Akavache.Core; [assembly: InternalsVisibleTo("Akavache.Tests")] diff --git a/src/Akavache.Core/ProtectedData.cs b/src/Akavache.Core/ProtectedData.cs index 413d84a93..5e964d333 100644 --- a/src/Akavache.Core/ProtectedData.cs +++ b/src/Akavache.Core/ProtectedData.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -#pragma warning disable CA1801 // Non-used parameters - deliberate due to shim. - namespace Akavache; /// @@ -29,4 +27,4 @@ public static class ProtectedData /// The scope where to store the data. /// The original data. public static byte[] Unprotect(byte[] originalData, byte[]? entropy, DataProtectionScope scope = DataProtectionScope.CurrentUser) => originalData; -} \ No newline at end of file +} diff --git a/src/Akavache.Core/Providers/FileAccess.cs b/src/Akavache.Core/Providers/FileAccess.cs index c6ed10b5e..6a97e0836 100644 --- a/src/Akavache.Core/Providers/FileAccess.cs +++ b/src/Akavache.Core/Providers/FileAccess.cs @@ -3,14 +3,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - namespace Akavache.Internal; /// /// Gets a set of flags about the file access mode. /// -[SuppressMessage("FxCop.Style", "CA1714: Flags should use plural names", Justification = "Legacy reasons.")] [Flags] public enum FileAccess { diff --git a/src/Akavache.Core/Providers/FileShare.cs b/src/Akavache.Core/Providers/FileShare.cs index fbf0c6d58..6cb5e533a 100644 --- a/src/Akavache.Core/Providers/FileShare.cs +++ b/src/Akavache.Core/Providers/FileShare.cs @@ -3,14 +3,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - namespace Akavache.Internal; /// /// Flags about how the file should be shared on the file system. /// -[SuppressMessage("FxCop.Style", "CA1714: Flags should use plural names", Justification = "Legacy reasons.")] [Flags] public enum FileShare { diff --git a/src/Akavache.Core/RelativeTimeMixin.cs b/src/Akavache.Core/RelativeTimeMixin.cs index f2a387762..6bc8f1544 100644 --- a/src/Akavache.Core/RelativeTimeMixin.cs +++ b/src/Akavache.Core/RelativeTimeMixin.cs @@ -19,15 +19,9 @@ public static class RelativeTimeMixin /// The data for the entry. /// A timespan that will be added to the current DateTime. /// A observable which will signal when the item is added. - public static IObservable Insert(this IBlobCache blobCache, string key, byte[] data, TimeSpan expiration) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.Insert(key, data, blobCache.Scheduler.Now + expiration); - } + public static IObservable Insert(this IBlobCache blobCache, string key, byte[] data, TimeSpan expiration) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.Insert(key, data, blobCache.Scheduler.Now + expiration); /// /// Inserts a item into the cache. @@ -38,15 +32,9 @@ public static IObservable Insert(this IBlobCache blobCache, string key, by /// A timespan that will be added to the current DateTime. /// The type of item to insert. /// A observable which will signal when the item is added. - public static IObservable InsertObject(this IBlobCache blobCache, string key, T value, TimeSpan expiration) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.InsertObject(key, value, blobCache.Scheduler.Now + expiration); - } + public static IObservable InsertObject(this IBlobCache blobCache, string key, T value, TimeSpan expiration) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.InsertObject(key, value, blobCache.Scheduler.Now + expiration); /// /// Downloads the specified url if there is not already a entry in the cache. @@ -57,15 +45,9 @@ public static IObservable InsertObject(this IBlobCache blobCache, strin /// The headers to specify when getting the entry. /// If we should fetch always and not return the cache entry if available. /// A observable which will signal when the data is available. - public static IObservable DownloadUrl(this IBlobCache blobCache, string url, TimeSpan expiration, Dictionary? headers = null, bool fetchAlways = false) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.DownloadUrl(url, headers, fetchAlways, blobCache.Scheduler.Now + expiration); - } + public static IObservable DownloadUrl(this IBlobCache blobCache, string url, TimeSpan expiration, Dictionary? headers = null, bool fetchAlways = false) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.DownloadUrl(url, headers, fetchAlways, blobCache.Scheduler.Now + expiration); /// /// Downloads the specified url if there is not already a entry in the cache. @@ -76,15 +58,9 @@ public static IObservable DownloadUrl(this IBlobCache blobCache, string /// The headers to specify when getting the entry. /// If we should fetch always and not return the cache entry if available. /// A observable which will signal when the data is available. - public static IObservable DownloadUrl(this IBlobCache blobCache, Uri url, TimeSpan expiration, Dictionary? headers = null, bool fetchAlways = false) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.DownloadUrl(url, headers, fetchAlways, blobCache.Scheduler.Now + expiration); - } + public static IObservable DownloadUrl(this IBlobCache blobCache, Uri url, TimeSpan expiration, Dictionary? headers = null, bool fetchAlways = false) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.DownloadUrl(url, headers, fetchAlways, blobCache.Scheduler.Now + expiration); /// /// Saves a username and password. @@ -95,13 +71,7 @@ public static IObservable DownloadUrl(this IBlobCache blobCache, Uri url /// The host to store against. /// A timespan that will be added to the current DateTime. /// A observable which will signal when the item is added. - public static IObservable SaveLogin(this ISecureBlobCache blobCache, string user, string password, string host, TimeSpan expiration) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.SaveLogin(user, password, host, blobCache.Scheduler.Now + expiration); - } + public static IObservable SaveLogin(this ISecureBlobCache blobCache, string user, string password, string host, TimeSpan expiration) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.SaveLogin(user, password, host, blobCache.Scheduler.Now + expiration); } \ No newline at end of file diff --git a/src/Akavache.Drawing/BitmapImageMixin.cs b/src/Akavache.Drawing/BitmapImageMixin.cs index 05487ea55..1aa5cab01 100644 --- a/src/Akavache.Drawing/BitmapImageMixin.cs +++ b/src/Akavache.Drawing/BitmapImageMixin.cs @@ -23,17 +23,11 @@ public static class BitmapImageMixin /// Optional desired height, if not specified will be the default size. /// A Future result representing the bitmap image. blobCache /// Observable is guaranteed to be returned on the UI thread. - public static IObservable LoadImage(this IBlobCache blobCache, string key, float? desiredWidth = null, float? desiredHeight = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.Get(key) + public static IObservable LoadImage(this IBlobCache blobCache, string key, float? desiredWidth = null, float? desiredHeight = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.Get(key) .SelectMany(ThrowOnBadImageBuffer) .SelectMany(x => BytesToImage(x, desiredWidth, desiredHeight)); - } /// /// A combination of DownloadUrl and LoadImage, this method fetches an @@ -48,17 +42,11 @@ public static IObservable LoadImage(this IBlobCache blobCache, string k /// An optional expiration date. /// A Future result representing the bitmap image. blobCache /// Observable is guaranteed to be returned on the UI thread. - public static IObservable LoadImageFromUrl(this IBlobCache blobCache, string url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.DownloadUrl(url, null, fetchAlways, absoluteExpiration) + public static IObservable LoadImageFromUrl(this IBlobCache blobCache, string url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.DownloadUrl(url, null, fetchAlways, absoluteExpiration) .SelectMany(ThrowOnBadImageBuffer) .SelectMany(x => BytesToImage(x, desiredWidth, desiredHeight)); - } /// /// A combination of DownloadUrl and LoadImage, this method fetches an @@ -73,17 +61,11 @@ public static IObservable LoadImageFromUrl(this IBlobCache blobCache, s /// An optional expiration date. /// A Future result representing the bitmap image. blobCache /// Observable is guaranteed to be returned on the UI thread. - public static IObservable LoadImageFromUrl(this IBlobCache blobCache, Uri url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.DownloadUrl(url, null, fetchAlways, absoluteExpiration) + public static IObservable LoadImageFromUrl(this IBlobCache blobCache, Uri url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.DownloadUrl(url, null, fetchAlways, absoluteExpiration) .SelectMany(ThrowOnBadImageBuffer) .SelectMany(x => BytesToImage(x, desiredWidth, desiredHeight)); - } /// /// A combination of DownloadUrl and LoadImage, this method fetches an @@ -99,17 +81,11 @@ public static IObservable LoadImageFromUrl(this IBlobCache blobCache, U /// An optional expiration date. /// A Future result representing the bitmap image. blobCache /// Observable is guaranteed to be returned on the UI thread. - public static IObservable LoadImageFromUrl(this IBlobCache blobCache, string key, string url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.DownloadUrl(key, url, null, fetchAlways, absoluteExpiration) + public static IObservable LoadImageFromUrl(this IBlobCache blobCache, string key, string url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.DownloadUrl(key, url, null, fetchAlways, absoluteExpiration) .SelectMany(ThrowOnBadImageBuffer) .SelectMany(x => BytesToImage(x, desiredWidth, desiredHeight)); - } /// /// A combination of DownloadUrl and LoadImage, this method fetches an @@ -125,17 +101,11 @@ public static IObservable LoadImageFromUrl(this IBlobCache blobCache, s /// An optional expiration date. /// A Future result representing the bitmap image. blobCache /// Observable is guaranteed to be returned on the UI thread. - public static IObservable LoadImageFromUrl(this IBlobCache blobCache, string key, Uri url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) - { - if (blobCache is null) - { - throw new ArgumentNullException(nameof(blobCache)); - } - - return blobCache.DownloadUrl(key, url, null, fetchAlways, absoluteExpiration) + public static IObservable LoadImageFromUrl(this IBlobCache blobCache, string key, Uri url, bool fetchAlways = false, float? desiredWidth = null, float? desiredHeight = null, DateTimeOffset? absoluteExpiration = null) => blobCache is null + ? throw new ArgumentNullException(nameof(blobCache)) + : blobCache.DownloadUrl(key, url, null, fetchAlways, absoluteExpiration) .SelectMany(ThrowOnBadImageBuffer) .SelectMany(x => BytesToImage(x, desiredWidth, desiredHeight)); - } /// /// Converts bad image buffers into an exception. diff --git a/src/Akavache.Sqlite3/AsyncLock.cs b/src/Akavache.Sqlite3/AsyncLock.cs index 238e6142e..5af4bc00b 100644 --- a/src/Akavache.Sqlite3/AsyncLock.cs +++ b/src/Akavache.Sqlite3/AsyncLock.cs @@ -32,12 +32,9 @@ public sealed class AsyncLock : IDisposable var wait = _semaphore.WaitAsync(cancellationToken); // Happy path. We synchronously acquired the lock. - if (wait.IsCompleted && !wait.IsFaulted && !wait.IsCanceled) - { - return _releaser; - } - - return wait + return wait.IsCompleted && !wait.IsFaulted && !wait.IsCanceled + ? _releaser + : wait .ContinueWith( (task, state) => task.IsCanceled || state is null ? null : (IDisposable)state, _releaser.Result, diff --git a/src/Akavache.Sqlite3/IsExternalInit.cs b/src/Akavache.Sqlite3/IsExternalInit.cs new file mode 100644 index 000000000..046bad107 --- /dev/null +++ b/src/Akavache.Sqlite3/IsExternalInit.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.ComponentModel; + +namespace System.Runtime.CompilerServices; + +[EditorBrowsable(EditorBrowsableState.Never)] +internal class IsExternalInit +{ +} diff --git a/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs b/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs index 78f255fd0..09d59cc13 100644 --- a/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs +++ b/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs @@ -4,7 +4,9 @@ // See the LICENSE file in the project root for full license information. using Akavache.Sqlite3.Internal; + using Splat; + using SQLitePCL; namespace Akavache.Sqlite3; diff --git a/src/Akavache.Sqlite3/Queues/OperationQueue.cs b/src/Akavache.Sqlite3/Queues/OperationQueue.cs index 887aa0ef1..3e42b9205 100644 --- a/src/Akavache.Sqlite3/Queues/OperationQueue.cs +++ b/src/Akavache.Sqlite3/Queues/OperationQueue.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; using System.Reactive.Disposables; using System.Reactive.Threading.Tasks; @@ -38,7 +37,7 @@ internal partial class SqliteOperationQueue : IEnableLogger, IDisposable private BlockingCollection _operationQueue = new(); - [SuppressMessage("Design", "CA2213: dispose field", Justification = "Will be invalid")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA2213: dispose field", Justification = "Will be invalid")] private IDisposable? _start; private CancellationTokenSource? _shouldQuit; @@ -398,7 +397,6 @@ private static void MarshalCompletion(object completion, Action block, IObservab } // NB: Callers must hold flushLock to call this - [SuppressMessage("Design", "CA2000: dispose variable", Justification = "Swapped ownership.")] private void FlushInternal() { var newQueue = new BlockingCollection(); @@ -407,7 +405,6 @@ private void FlushInternal() ProcessItems(CoalesceOperations(existingItems)); } - [SuppressMessage("Design", "CA2000: Dispose variable", Justification = "Ownership transferred.")] private void ProcessItems(List toProcess) { var commitResult = new AsyncSubject(); diff --git a/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs b/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs index 9115e598d..e60b1fe51 100644 --- a/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs +++ b/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - namespace Akavache.Sqlite3; internal partial class SqliteOperationQueue @@ -125,13 +123,9 @@ private static IEnumerable MultipleOpsTurnIntoSingleOp(IEnum if (currentWrites is not null) { - if (currentWrites.Count == 1) - { - yield return currentWrites[0]; - } - else - { - yield return new( + yield return currentWrites.Count == 1 + ? currentWrites[0] + : new( CombineSubjectsByOperation( currentWrites[0].Completion, currentWrites.Skip(1).Select(x => x.Completion), @@ -140,7 +134,6 @@ private static IEnumerable MultipleOpsTurnIntoSingleOp(IEnum { OperationType = currentWrites[0].OperationType, }; - } currentWrites = null; } @@ -240,9 +233,20 @@ private static OperationQueueItem GroupUnrelatedInserts(IEnumerable unrelatedDeletes) + After: + } + + private static OperationQueueItem GroupUnrelatedDeletes(IEnumerable unrelatedDeletes) + */ } - [SuppressMessage("Design", "CA2000: Dispose variable", Justification = "Ownership transferred.")] private static OperationQueueItem GroupUnrelatedDeletes(IEnumerable unrelatedDeletes) { var subj = new AsyncSubject(); diff --git a/src/Akavache.Sqlite3/SQLite.cs b/src/Akavache.Sqlite3/SQLite.cs index 50fd394dd..fd0bde013 100644 --- a/src/Akavache.Sqlite3/SQLite.cs +++ b/src/Akavache.Sqlite3/SQLite.cs @@ -1374,7 +1374,7 @@ public int Update(object obj, Type objType) throw NotNullConstraintViolationException.New(ex, map, obj); } - throw ex; + throw; } if (rowsAffected > 0) @@ -2198,7 +2198,7 @@ Sqlite3Statement Prepare() return stmt; } - void Finalize(Sqlite3Statement stmt) => SQLite3.Finalize(stmt); + static void Finalize(Sqlite3Statement stmt) => SQLite3.Finalize(stmt); void BindAll(Sqlite3Statement stmt) { @@ -2907,7 +2907,7 @@ static object ConvertTo(object obj, Type t) /// /// The expression to compile. /// The non-null parameter - private string CompileNullBinaryExpression(Expression expression, CompileResult parameter) => + private static string CompileNullBinaryExpression(Expression expression, CompileResult parameter) => expression.NodeType switch { ExpressionType.Equal => "(" + parameter.CommandText + " is ?)", @@ -2916,7 +2916,7 @@ private string CompileNullBinaryExpression(Expression expression, CompileResult expression.NodeType.ToString()) }; - string GetSqlName(Expression expr) + static string GetSqlName(Expression expr) { var n = expr.NodeType; return n switch diff --git a/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs b/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs index d531955f5..e49cc59a5 100755 --- a/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs @@ -11,10 +11,14 @@ namespace Akavache.Sqlite3; /// The type of object wrapped. internal class ObjectWrapper : IObjectWrapper { - /// - /// Gets or sets the value. - /// -#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. - public T Value { get; set; } -#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. -} \ No newline at end of file + public ObjectWrapper() + { + } + + public ObjectWrapper(T value) + { + Value = value; + } + + public T? Value { get; set; } +} diff --git a/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs b/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs index 3b69eb094..24bab1ea4 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs @@ -761,7 +761,7 @@ private byte[] SerializeObject(T value) var serializer = GetSerializer(); using var ms = new MemoryStream(); using var writer = new BsonDataWriter(ms); - serializer.Serialize(writer, new ObjectWrapper { Value = value }); + serializer.Serialize(writer, new ObjectWrapper(value)); return ms.ToArray(); } diff --git a/src/Akavache.Tests/API/ApiApprovalTests.cs b/src/Akavache.Tests/API/ApiApprovalTests.cs index 51d68fc14..89e6b1e8d 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.cs +++ b/src/Akavache.Tests/API/ApiApprovalTests.cs @@ -45,10 +45,7 @@ public class ApiApprovalTests /// #if !NETSTANDARD [Fact] - public void AkavacheDrawing() - { - CheckApproval(typeof(Akavache.Drawing.Registrations).Assembly); - } + public void AkavacheDrawing() => CheckApproval(typeof(Akavache.Drawing.Registrations).Assembly); #endif private static void CheckApproval(Assembly assembly, [CallerMemberName] string memberName = null, [CallerFilePath] string filePath = null) diff --git a/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs b/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs index 555d0b2c9..c46de0eb0 100644 --- a/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs +++ b/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs @@ -18,7 +18,7 @@ public class FakeDateTimeHighPrecisionJsonConverter : JsonConverter /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - if (reader.TokenType != JsonToken.Integer && reader.TokenType != JsonToken.Date) + if (reader.TokenType is not JsonToken.Integer and not JsonToken.Date) { return null; } diff --git a/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs b/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs index 2f6997a73..dfea1f450 100644 --- a/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs +++ b/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs @@ -64,7 +64,7 @@ public static HttpResponseMessage GetResponse(params string[] paths) throw new("Couldn't find response body"); - foundIt: + foundIt: var headerText = Encoding.UTF8.GetString(bytes, 0, bodyIndex); var lines = headerText.Split('\n'); diff --git a/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs b/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs index c521ab779..d7c58d4eb 100644 --- a/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs +++ b/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs @@ -8,6 +8,7 @@ using FluentAssertions; using Microsoft.Reactive.Testing; + using ReactiveUI.Testing; using Xunit; @@ -29,7 +30,7 @@ public async Task DownloadUrlTest() using (Utility.WithEmptyDirectory(out var path)) using (var fixture = CreateBlobCache(path)) { - var bytes = await fixture.DownloadUrl(@"http://httpbin.org/html").FirstAsync(); + var bytes = await fixture.DownloadUrl("http://httpbin.org/html").FirstAsync(); Assert.True(bytes.Length > 0); } } @@ -509,12 +510,12 @@ public async Task GetAndFetchLatestCallsFetchPredicate() { var fetchPredicateCalled = false; - Func fetchPredicate = d => + bool FetchPredicate(DateTimeOffset d) { fetchPredicateCalled = true; return true; - }; + } var fetcher = new Func>(() => Observable.Return("baz")); @@ -531,7 +532,7 @@ public async Task GetAndFetchLatestCallsFetchPredicate() await fixture.InsertObject("foo", "bar").FirstAsync(); - await fixture.GetAndFetchLatest("foo", fetcher, fetchPredicate).LastAsync(); + await fixture.GetAndFetchLatest("foo", fetcher, FetchPredicate).LastAsync(); Assert.True(fetchPredicateCalled); } diff --git a/src/Akavache.Tests/TestBases/DateTimeTestBase.cs b/src/Akavache.Tests/TestBases/DateTimeTestBase.cs index ecbc7c174..6c73c97ed 100644 --- a/src/Akavache.Tests/TestBases/DateTimeTestBase.cs +++ b/src/Akavache.Tests/TestBases/DateTimeTestBase.cs @@ -149,7 +149,7 @@ public async Task DateTimeKindCanBeForced() /// The blob cache to perform the operation against. /// The data to grab. /// A task with the data found. - private async Task<(TData First, TData Second)> PerformTimeStampGrab(IBlobCache blobCache, TData data) + private static async Task<(TData First, TData Second)> PerformTimeStampGrab(IBlobCache blobCache, TData data) { const string key = "key"; @@ -160,4 +160,4 @@ public async Task DateTimeKindCanBeForced() return (firstResult, secondResult); } -} \ No newline at end of file +} diff --git a/src/Akavache/Registrations.cs b/src/Akavache/Registrations.cs index 35f9935ed..a99607727 100644 --- a/src/Akavache/Registrations.cs +++ b/src/Akavache/Registrations.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using Akavache.Core; + using Splat; namespace Akavache;