From 46a4835de4cd18952a7289ebe4a61b783001cd08 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sat, 25 Nov 2023 06:04:59 +0000 Subject: [PATCH] Feature : Add Net 8.0 (#876) * Feature : Add Net 8.0 * Use Primary Constructors * Update code to fix code warnings * Further code warning fixes * Update AsyncLock.cs * Update API tests * use sqlite-net-pcl package instead of code from project --- src/Akavache.Core/Akavache.Core.csproj | 53 +- src/Akavache.Core/BlobCache/BlobCache.cs | 4 +- src/Akavache.Core/BlobCache/CacheEntry.cs | 33 +- src/Akavache.Core/BlobCache/IBlobCache.cs | 2 +- src/Akavache.Core/BlobCache/IBulkBlobCache.cs | 2 +- .../BlobCache/IObjectBlobCache.cs | 2 +- .../BlobCache/IObjectBulkBlobCache.cs | 2 +- src/Akavache.Core/BlobCache/IObjectWrapper.cs | 2 +- .../BlobCache/ISecureBlobCache.cs | 2 +- .../BlobCache/InMemoryBlobCache.cs | 8 +- src/Akavache.Core/BlobCache/ObjectWrapper.cs | 7 +- src/Akavache.Core/BulkOperationsMixin.cs | 2 +- src/Akavache.Core/DataProtectionScope.cs | 2 +- src/Akavache.Core/DependencyResolverMixin.cs | 2 +- src/Akavache.Core/ExceptionHelper.cs | 2 +- src/Akavache.Core/HttpMixinExtensions.cs | 2 +- .../IAkavacheHttpClientFactory.cs | 2 +- src/Akavache.Core/IAkavacheHttpMixin.cs | 2 +- src/Akavache.Core/IWantsToRegisterStuff.cs | 2 +- src/Akavache.Core/IsExternalInit.cs | 2 +- .../Json/JsonDateTimeContractResolver.cs | 24 +- .../Json/JsonDateTimeOffsetTickConverter.cs | 14 +- .../Json/JsonDateTimeTickConverter.cs | 8 +- .../Json/JsonSerializationMixin.cs | 10 +- .../KeyedOperations/IKeyedOperationQueue.cs | 2 +- .../KeyedOperations/KeyedOperation.cs | 21 +- .../KeyedOperations/KeyedOperationQueue.cs | 7 +- src/Akavache.Core/LoginInfo.cs | 23 +- src/Akavache.Core/LoginMixin.cs | 5 +- .../android/AndroidFilesystemProvider.cs | 8 +- .../apple-common/MacFilesystemProvider.cs | 18 +- .../SimpleFilesystemProvider.cs | 7 +- .../Platforms/shared/AkavacheHttpMixin.cs | 36 +- .../DefaultAkavacheHttpClientFactory.cs | 2 +- .../Platforms/shared/EncryptionProvider.cs | 8 +- .../Platforms/shared/MD5Managed.cs | 11 +- .../Platforms/shared/Registrations.cs | 12 +- .../Platforms/shared/StreamMixins.cs | 14 +- src/Akavache.Core/Platforms/shared/Utility.cs | 59 +- .../tizen/TizenFilesystemProvider.cs | 6 +- .../uap/Shims/IsolatedStorageException.cs | 31 - .../uap/Shims/MicrosoftStreamExtensions.cs | 28 - .../Platforms/uap/Shims/RandomStream.cs | 90 - .../Platforms/uap/WinRTEncryptionProvider.cs | 33 - .../Platforms/uap/WinRTFilesystemProvider.cs | 99 - .../xamarin-mobile/IsolatedStorageProvider.cs | 6 +- src/Akavache.Core/PortableExtensions.cs | 2 +- src/Akavache.Core/PreserveAttribute.cs | 2 +- src/Akavache.Core/Properties/AssemblyInfo.cs | 3 +- src/Akavache.Core/ProtectedData.cs | 2 +- src/Akavache.Core/Providers/FileAccess.cs | 2 +- src/Akavache.Core/Providers/FileMode.cs | 2 +- src/Akavache.Core/Providers/FileShare.cs | 2 +- .../Providers/IEncryptionProvider.cs | 2 +- .../Providers/IFilesystemProvider.cs | 2 +- src/Akavache.Core/RelativeTimeMixin.cs | 2 +- src/Akavache.Drawing/Akavache.Drawing.csproj | 7 +- src/Akavache.Drawing/BitmapImageMixin.cs | 2 +- src/Akavache.Drawing/Registrations.cs | 3 +- src/Akavache.Mobile/Akavache.Mobile.csproj | 7 +- src/Akavache.Mobile/AkavacheDriver.cs | 2 +- src/Akavache.Mobile/Registrations.cs | 11 +- src/Akavache.Sqlite3/Akavache.Sqlite3.csproj | 16 +- src/Akavache.Sqlite3/AsyncLock.cs | 6 +- src/Akavache.Sqlite3/EnumerableEx.cs | 4 +- src/Akavache.Sqlite3/IsExternalInit.cs | 2 +- .../BeginTransactionSqliteOperation.cs | 10 +- .../Operations/BulkInsertSqliteOperation.cs | 8 +- .../BulkInvalidateByTypeSqliteOperation.cs | 12 +- .../BulkInvalidateSqliteOperation.cs | 8 +- .../BulkSelectByTypeSqliteOperation.cs | 12 +- .../Operations/BulkSelectSqliteOperation.cs | 8 +- .../CommitTransactionSqliteOperation.cs | 10 +- src/Akavache.Sqlite3/Operations/Constants.cs | 2 +- .../DeleteExpiredSqliteOperation.cs | 10 +- .../Operations/GetKeysSqliteOperation.cs | 10 +- .../Operations/IPreparedSqliteOperation.cs | 7 +- .../InvalidateAllSqliteOperation.cs | 36 +- .../Operations/OperationType.cs | 2 +- .../Operations/SqliteOperationMixin.cs | 10 +- .../Operations/VacuumSqliteOperation.cs | 10 +- .../Properties/AssemblyInfo.cs | 2 +- src/Akavache.Sqlite3/Queues/OperationQueue.cs | 10 +- .../Queues/OperationQueueCoalescing.cs | 2 +- .../Queues/OperationQueueItem.cs | 14 +- src/Akavache.Sqlite3/Registrations.cs | 9 +- src/Akavache.Sqlite3/SQLite.cs | 3337 ----------------- .../SqlLiteCache/CacheElement.cs | 8 +- .../SqlLiteCache/IObjectWrapper.cs | 2 +- .../SqlLiteCache/ObjectWrapper.cs | 2 +- .../SqlLiteCache/SQLiteEncryptedBlobCache.cs | 2 +- .../SqlLiteCache/SchemaInfo.cs | 2 +- src/Akavache.Sqlite3/SqlLiteCache/SqlLite.cs | 2 +- .../SqlLiteCache/SqlRawPersistentBlobCache.cs | 15 +- src/Akavache.Sqlite3/sqlite3-hint.txt | 15 - ...Tests.AkavacheCore.DotNet6_0.verified.txt} | 3 +- ...valTests.AkavacheCore.Net4_8.verified.txt} | 5 +- ...ts.AkavacheDrawing.DotNet6_0.verified.txt} | 3 +- ...Tests.AkavacheDrawing.Net4_8.verified.txt} | 3 +- ...ts.AkavacheProject.DotNet6_0.verified.txt} | 3 +- ...Tests.AkavacheProject.Net4_8.verified.txt} | 3 +- src/Akavache.Tests/API/ApiApprovalTests.cs | 76 +- src/Akavache.Tests/API/ApiExtensions.cs | 39 + src/Akavache.Tests/Akavache.Tests.csproj | 17 +- src/Akavache.Tests/AsyncLockTests.cs | 4 +- src/Akavache.Tests/BasicEncryptionTests.cs | 12 +- .../BlockingDisposeBulkCache.cs | 9 +- .../BlockingDispose/BlockingDisposeCache.cs | 2 +- .../BlockingDisposeObjectCache.cs | 9 +- src/Akavache.Tests/CoalescerTests.cs | 8 +- src/Akavache.Tests/DateTimeResolverTests.cs | 4 +- .../EncryptedSqliteBlobBulkExtensionsTest.cs | 2 +- ...yptedSqliteBlobCacheBulkOperationsTests.cs | 2 +- .../EncryptedSqliteBlobCacheDateTimeTests.cs | 2 +- ...cryptedSqliteBlobCacheExtensionsFixture.cs | 2 +- ...qliteBlobCacheObjectBulkOperationsTests.cs | 2 +- .../Fixtures/DummyRoutedViewModel.cs | 16 +- ...keDateTimeHighPrecisionContractResolver.cs | 2 +- .../FakeDateTimeHighPrecisionJsonConverter.cs | 2 +- .../Fixtures/ServiceProvider.cs | 2 +- .../Fixtures/TestObjectDateTime.cs | 2 +- .../Fixtures/TestObjectDateTimeOffset.cs | 2 +- src/Akavache.Tests/Fixtures/UserModel.cs | 16 +- src/Akavache.Tests/Fixtures/UserObject.cs | 2 +- .../Helpers/IntegrationTestHelper.cs | 13 +- src/Akavache.Tests/Helpers/Utility.cs | 2 +- .../InMemoryBlobCacheBulkOperationsTests.cs | 2 +- .../InMemoryBlobCacheDateTimeTests.cs | 2 +- .../InMemoryBlobCacheInterfaceTests.cs | 2 +- ...emoryBlobCacheObjectBulkOperationsTests.cs | 2 +- src/Akavache.Tests/InMemoryBlobCacheTests.cs | 2 +- src/Akavache.Tests/Performance/PerfHelper.cs | 2 +- src/Akavache.Tests/Performance/ReadTests.cs | 4 +- .../Performance/Sqlite3ReadTests.cs | 2 +- .../Performance/Sqlite3WriteTests.cs | 2 +- src/Akavache.Tests/Performance/WriteTests.cs | 4 +- .../SqliteBlobCacheBulkExtensionsTest.cs | 2 +- .../SqliteBlobCacheBulkOperationsTests.cs | 2 +- .../SqliteBlobCacheDateTimeTests.cs | 2 +- .../SqliteBlobCacheExtensionsTests.cs | 4 +- .../SqliteBlobCacheInterfaceTests.cs | 2 +- ...qliteBlobCacheObjectBulkOperationsTests.cs | 2 +- .../TestBases/BlobCacheExtensionsTestBase.cs | 9 +- .../TestBases/BlobCacheInterfaceTestBase.cs | 65 +- .../TestBases/BulkOperationsTestBase.cs | 6 +- .../TestBases/DateTimeTestBase.cs | 16 +- .../TestBases/ObjectBulkOperationsTestBase.cs | 12 +- src/Akavache.Tests/UtilityTests.cs | 4 +- src/Akavache.sln | 2 + src/Akavache/Akavache.csproj | 13 +- src/Akavache/LinkerPreserve.cs | 4 +- src/Akavache/Properties/AssemblyInfo.cs | 6 +- src/Akavache/Registrations.cs | 3 +- src/Akavache/SQLitePersistentBlobCache.cs | 18 +- src/Directory.build.props | 9 +- src/Directory.build.targets | 11 +- src/global.json | 2 +- src/stylecop.json | 2 +- 158 files changed, 524 insertions(+), 4340 deletions(-) delete mode 100644 src/Akavache.Core/Platforms/uap/Shims/IsolatedStorageException.cs delete mode 100644 src/Akavache.Core/Platforms/uap/Shims/MicrosoftStreamExtensions.cs delete mode 100644 src/Akavache.Core/Platforms/uap/Shims/RandomStream.cs delete mode 100644 src/Akavache.Core/Platforms/uap/WinRTEncryptionProvider.cs delete mode 100644 src/Akavache.Core/Platforms/uap/WinRTFilesystemProvider.cs delete mode 100644 src/Akavache.Sqlite3/SQLite.cs delete mode 100644 src/Akavache.Sqlite3/sqlite3-hint.txt rename src/Akavache.Tests/API/{ApiApprovalTests.AkavacheCore.net6.0.approved.txt => ApiApprovalTests.AkavacheCore.DotNet6_0.verified.txt} (99%) rename src/Akavache.Tests/API/{ApiApprovalTests.AkavacheCore.net48.approved.txt => ApiApprovalTests.AkavacheCore.Net4_8.verified.txt} (98%) rename src/Akavache.Tests/API/{ApiApprovalTests.AkavacheDrawing.net6.0.approved.txt => ApiApprovalTests.AkavacheDrawing.DotNet6_0.verified.txt} (88%) rename src/Akavache.Tests/API/{ApiApprovalTests.AkavacheDrawing.net48.approved.txt => ApiApprovalTests.AkavacheDrawing.Net4_8.verified.txt} (87%) rename src/Akavache.Tests/API/{ApiApprovalTests.AkavacheProject.net6.0.approved.txt => ApiApprovalTests.AkavacheProject.DotNet6_0.verified.txt} (72%) rename src/Akavache.Tests/API/{ApiApprovalTests.AkavacheProject.net48.approved.txt => ApiApprovalTests.AkavacheProject.Net4_8.verified.txt} (71%) create mode 100644 src/Akavache.Tests/API/ApiExtensions.cs diff --git a/src/Akavache.Core/Akavache.Core.csproj b/src/Akavache.Core/Akavache.Core.csproj index 62f8926a7..30f095330 100644 --- a/src/Akavache.Core/Akavache.Core.csproj +++ b/src/Akavache.Core/Akavache.Core.csproj @@ -1,74 +1,68 @@  - netstandard2.0;netstandard2.1;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10;MonoAndroid12.0;MonoAndroid12.1;MonoAndroid13.0;tizen40;net6.0;net7.0;net7.0-android;net7.0-ios;net7.0-tvos;net7.0-macos;net7.0-maccatalyst - $(TargetFrameworks);net462;net6.0-windows10.0.17763.0;net7.0-windows10.0.17763.0 + $(AkavacheTargetFrameworks) Akavache.Core Akavache An asynchronous, persistent key-value store for desktop and mobile applications on .NET akavache.core - latest + + + - - - - - - + - - - - - - - - + - + + - + - + + + + + + - + - + - + - - + - + @@ -78,16 +72,11 @@ - + - - - - - diff --git a/src/Akavache.Core/BlobCache/BlobCache.cs b/src/Akavache.Core/BlobCache/BlobCache.cs index 3687a9b34..168ae51fe 100644 --- a/src/Akavache.Core/BlobCache/BlobCache.cs +++ b/src/Akavache.Core/BlobCache/BlobCache.cs @@ -1,13 +1,11 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics.CodeAnalysis; using System.Reactive.Threading.Tasks; - using Newtonsoft.Json.Bson; - using Splat; namespace Akavache; diff --git a/src/Akavache.Core/BlobCache/CacheEntry.cs b/src/Akavache.Core/BlobCache/CacheEntry.cs index 5477bbf73..bdc23933f 100644 --- a/src/Akavache.Core/BlobCache/CacheEntry.cs +++ b/src/Akavache.Core/BlobCache/CacheEntry.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -8,40 +8,33 @@ namespace Akavache; /// /// A entry in a memory cache. /// -public class CacheEntry +/// +/// Initializes a new instance of the class. +/// +/// The name of the type being stored. +/// The value being stored. +/// The date and time the entry was created. +/// The date and time when the entry expires. +public class CacheEntry(string? typeName, byte[] value, DateTimeOffset createdAt, DateTimeOffset? expiresAt) { - /// - /// Initializes a new instance of the class. - /// - /// The name of the type being stored. - /// The value being stored. - /// The date and time the entry was created. - /// The date and time when the entry expires. - public CacheEntry(string? typeName, byte[] value, DateTimeOffset createdAt, DateTimeOffset? expiresAt) - { - TypeName = typeName; - Value = value; - CreatedAt = createdAt; - ExpiresAt = expiresAt; - } /// /// Gets or sets the date and time when the entry was created. /// - public DateTimeOffset CreatedAt { get; protected set; } + public DateTimeOffset CreatedAt { get; protected set; } = createdAt; /// /// Gets or sets the date and time when the entry will expire. /// - public DateTimeOffset? ExpiresAt { get; protected set; } + public DateTimeOffset? ExpiresAt { get; protected set; } = expiresAt; /// /// Gets or sets the type name of the entry. /// - public string? TypeName { get; protected set; } + public string? TypeName { get; protected set; } = typeName; /// /// Gets or sets the value of the entry. /// - public byte[] Value { get; protected set; } + public byte[] Value { get; protected set; } = value; } diff --git a/src/Akavache.Core/BlobCache/IBlobCache.cs b/src/Akavache.Core/BlobCache/IBlobCache.cs index 4c0737259..c340833c9 100644 --- a/src/Akavache.Core/BlobCache/IBlobCache.cs +++ b/src/Akavache.Core/BlobCache/IBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/BlobCache/IBulkBlobCache.cs b/src/Akavache.Core/BlobCache/IBulkBlobCache.cs index a17924d10..1242608eb 100644 --- a/src/Akavache.Core/BlobCache/IBulkBlobCache.cs +++ b/src/Akavache.Core/BlobCache/IBulkBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/BlobCache/IObjectBlobCache.cs b/src/Akavache.Core/BlobCache/IObjectBlobCache.cs index 0f70c1219..d83d6044f 100644 --- a/src/Akavache.Core/BlobCache/IObjectBlobCache.cs +++ b/src/Akavache.Core/BlobCache/IObjectBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/BlobCache/IObjectBulkBlobCache.cs b/src/Akavache.Core/BlobCache/IObjectBulkBlobCache.cs index 3c559a6df..e172f1cbf 100644 --- a/src/Akavache.Core/BlobCache/IObjectBulkBlobCache.cs +++ b/src/Akavache.Core/BlobCache/IObjectBulkBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/BlobCache/IObjectWrapper.cs b/src/Akavache.Core/BlobCache/IObjectWrapper.cs index 83b7bad44..fa8a40019 100644 --- a/src/Akavache.Core/BlobCache/IObjectWrapper.cs +++ b/src/Akavache.Core/BlobCache/IObjectWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/BlobCache/ISecureBlobCache.cs b/src/Akavache.Core/BlobCache/ISecureBlobCache.cs index 53e30c65f..9a3b508c8 100644 --- a/src/Akavache.Core/BlobCache/ISecureBlobCache.cs +++ b/src/Akavache.Core/BlobCache/ISecureBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs b/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs index 834fc9b29..9c7dd27cd 100644 --- a/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs +++ b/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs @@ -1,14 +1,12 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics.CodeAnalysis; using System.Reactive.Disposables; - using Newtonsoft.Json; using Newtonsoft.Json.Bson; - using Splat; namespace Akavache; @@ -22,7 +20,7 @@ public class InMemoryBlobCache : ISecureBlobCache, IObjectBlobCache, IEnableLogg [SuppressMessage("Design", "CA2213: non-disposed field.", Justification = "Used for notification of dispose.")] private readonly AsyncSubject _shutdown = new(); private readonly IDisposable? _inner; - private readonly Dictionary _cache = new(); + private readonly Dictionary _cache = []; private readonly JsonDateTimeContractResolver _jsonDateTimeContractResolver = new(); // This will make us use ticks instead of json ticks for DateTime. private bool _disposed; private DateTimeKind? _dateTimeKind; @@ -135,7 +133,7 @@ public static InMemoryBlobCache OverrideGlobals(IScheduler? scheduler = null, pa /// The default inner contents to use. /// The default scheduler to use. /// A generated cache. - public static InMemoryBlobCache OverrideGlobals(IDictionary initialContents, IScheduler? scheduler = null) => OverrideGlobals(scheduler, initialContents.ToArray()); + public static InMemoryBlobCache OverrideGlobals(IDictionary initialContents, IScheduler? scheduler = null) => OverrideGlobals(scheduler, [.. initialContents]); /// /// Overrides the global registrations with specified values. diff --git a/src/Akavache.Core/BlobCache/ObjectWrapper.cs b/src/Akavache.Core/BlobCache/ObjectWrapper.cs index 946a552aa..67894f129 100644 --- a/src/Akavache.Core/BlobCache/ObjectWrapper.cs +++ b/src/Akavache.Core/BlobCache/ObjectWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -11,10 +11,7 @@ public ObjectWrapper() { } - public ObjectWrapper(T value) - { - Value = value; - } + 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 5d639e08e..5e3f20dd0 100644 --- a/src/Akavache.Core/BulkOperationsMixin.cs +++ b/src/Akavache.Core/BulkOperationsMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/DataProtectionScope.cs b/src/Akavache.Core/DataProtectionScope.cs index dc64d0cec..29bc51d9c 100644 --- a/src/Akavache.Core/DataProtectionScope.cs +++ b/src/Akavache.Core/DataProtectionScope.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/DependencyResolverMixin.cs b/src/Akavache.Core/DependencyResolverMixin.cs index c4ee225cf..0de5a8e42 100644 --- a/src/Akavache.Core/DependencyResolverMixin.cs +++ b/src/Akavache.Core/DependencyResolverMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/ExceptionHelper.cs b/src/Akavache.Core/ExceptionHelper.cs index 2559df3b0..3aa9578b2 100644 --- a/src/Akavache.Core/ExceptionHelper.cs +++ b/src/Akavache.Core/ExceptionHelper.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/HttpMixinExtensions.cs b/src/Akavache.Core/HttpMixinExtensions.cs index 17a768a50..81c676ca0 100644 --- a/src/Akavache.Core/HttpMixinExtensions.cs +++ b/src/Akavache.Core/HttpMixinExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/IAkavacheHttpClientFactory.cs b/src/Akavache.Core/IAkavacheHttpClientFactory.cs index a0492963c..f001c37c8 100644 --- a/src/Akavache.Core/IAkavacheHttpClientFactory.cs +++ b/src/Akavache.Core/IAkavacheHttpClientFactory.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/IAkavacheHttpMixin.cs b/src/Akavache.Core/IAkavacheHttpMixin.cs index 887c98ee2..2ae3976b0 100644 --- a/src/Akavache.Core/IAkavacheHttpMixin.cs +++ b/src/Akavache.Core/IAkavacheHttpMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/IWantsToRegisterStuff.cs b/src/Akavache.Core/IWantsToRegisterStuff.cs index 4a99f38fe..46647e9b0 100644 --- a/src/Akavache.Core/IWantsToRegisterStuff.cs +++ b/src/Akavache.Core/IWantsToRegisterStuff.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/IsExternalInit.cs b/src/Akavache.Core/IsExternalInit.cs index 046bad107..f37a2f144 100644 --- a/src/Akavache.Core/IsExternalInit.cs +++ b/src/Akavache.Core/IsExternalInit.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs b/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs index 57c3516ce..111fcf196 100644 --- a/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs +++ b/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -11,7 +11,12 @@ namespace Akavache; /// Resolver which will handle DateTime and DateTimeOffset with our own internal resolver. /// It will also be able to use, if set, a external provider that a user has set. /// -internal class JsonDateTimeContractResolver : DefaultContractResolver +/// +/// Initializes a new instance of the class. +/// +/// A inherited contract resolver. +/// If we should override the . +internal class JsonDateTimeContractResolver(IContractResolver? contractResolver, DateTimeKind? forceDateTimeKindOverride) : DefaultContractResolver { /// /// Initializes a new instance of the class. @@ -21,20 +26,9 @@ public JsonDateTimeContractResolver() { } - /// - /// Initializes a new instance of the class. - /// - /// A inherited contract resolver. - /// If we should override the . - public JsonDateTimeContractResolver(IContractResolver? contractResolver, DateTimeKind? forceDateTimeKindOverride) - { - ExistingContractResolver = contractResolver; - ForceDateTimeKindOverride = forceDateTimeKindOverride; - } - - public IContractResolver? ExistingContractResolver { get; set; } + public IContractResolver? ExistingContractResolver { get; set; } = contractResolver; - public DateTimeKind? ForceDateTimeKindOverride { get; set; } + public DateTimeKind? ForceDateTimeKindOverride { get; set; } = forceDateTimeKindOverride; /// public override JsonContract ResolveContract(Type type) diff --git a/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs b/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs index b03597242..d60e35b74 100644 --- a/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs +++ b/src/Akavache.Core/Json/JsonDateTimeOffsetTickConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -33,17 +33,11 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer public override bool CanConvert(Type objectType) => objectType == typeof(DateTimeOffset) || objectType == typeof(DateTimeOffset?); - internal class DateTimeOffsetData + internal class DateTimeOffsetData(DateTimeOffset offset) { - public DateTimeOffsetData(DateTimeOffset offset) - { - Ticks = offset.Ticks; - OffsetTicks = offset.Offset.Ticks; - } - - public long Ticks { get; set; } + public long Ticks { get; set; } = offset.Ticks; - public long OffsetTicks { get; set; } + public long OffsetTicks { get; set; } = offset.Offset.Ticks; public static explicit operator DateTimeOffset(DateTimeOffsetData value) // explicit byte to digit conversion operator => diff --git a/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs b/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs index eca652600..34ce0507a 100644 --- a/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs +++ b/src/Akavache.Core/Json/JsonDateTimeTickConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -11,11 +11,9 @@ namespace Akavache; /// Since we use BSON at places, we want to just store ticks to avoid loosing precision. /// By default BSON will use JSON ticks. /// -internal class JsonDateTimeTickConverter : JsonConverter +internal class JsonDateTimeTickConverter(DateTimeKind? forceDateTimeKindOverride = null) : JsonConverter { - private readonly DateTimeKind? _forceDateTimeKindOverride; - - public JsonDateTimeTickConverter(DateTimeKind? forceDateTimeKindOverride = null) => _forceDateTimeKindOverride = forceDateTimeKindOverride; + private readonly DateTimeKind? _forceDateTimeKindOverride = forceDateTimeKindOverride; /// /// Gets a instance of the DateTimeConverter that handles the DateTime in UTC mode. diff --git a/src/Akavache.Core/Json/JsonSerializationMixin.cs b/src/Akavache.Core/Json/JsonSerializationMixin.cs index 5f3b6df86..c1406619a 100644 --- a/src/Akavache.Core/Json/JsonSerializationMixin.cs +++ b/src/Akavache.Core/Json/JsonSerializationMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -6,9 +6,7 @@ using System.Collections.Concurrent; using System.Globalization; using System.Reactive.Threading.Tasks; - using Newtonsoft.Json; - using Splat; namespace Akavache; @@ -125,7 +123,7 @@ public static IObservable> GetAllObjects(this IBlobCache blobC /// the cache. 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 => + : blobCache.GetObject(key).Catch(__ => { var prefixedKey = blobCache.GetHashCode().ToString(CultureInfo.InvariantCulture) + key; @@ -245,10 +243,14 @@ public static IObservable> GetAllObjects(this IBlobCache blobC bool shouldInvalidateOnError = false, Func? cacheValidationPredicate = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); +#endif #pragma warning disable CS8604 // Possible null reference argument. var fetch = Observable.Defer(() => blobCache.GetObjectCreatedAt(key)) diff --git a/src/Akavache.Core/KeyedOperations/IKeyedOperationQueue.cs b/src/Akavache.Core/KeyedOperations/IKeyedOperationQueue.cs index 43dc1e2b0..8ecf99d38 100644 --- a/src/Akavache.Core/KeyedOperations/IKeyedOperationQueue.cs +++ b/src/Akavache.Core/KeyedOperations/IKeyedOperationQueue.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/KeyedOperations/KeyedOperation.cs b/src/Akavache.Core/KeyedOperations/KeyedOperation.cs index 14b7fe8bc..3e985053f 100644 --- a/src/Akavache.Core/KeyedOperations/KeyedOperation.cs +++ b/src/Akavache.Core/KeyedOperations/KeyedOperation.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -37,23 +37,20 @@ protected KeyedOperation(string key, int id) public abstract IObservable EvaluateFunc(); } +/// +/// Initializes a new instance of the class. +/// +/// The function to produce a value. +/// The key of the operation. +/// The ID of the operation. [SuppressMessage("StyleCop.Maintainability.CSharp", "SA1402: One type per file", Justification = "Same class name.")] -internal class KeyedOperation : KeyedOperation +internal class KeyedOperation(Func> func, string key, int id) : KeyedOperation(key, id) { - /// - /// Initializes a new instance of the class. - /// - /// The function to produce a value. - /// The key of the operation. - /// The ID of the operation. - public KeyedOperation(Func> func, string key, int id) - : base(key, id) => - Func = func; /// /// Gets the function which returns the observable. /// - public Func> Func { get; } + public Func> Func { get; } = func; /// /// Gets the result subject. diff --git a/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs b/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs index 86b73068d..592cc4f1d 100644 --- a/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs +++ b/src/Akavache.Core/KeyedOperations/KeyedOperationQueue.cs @@ -1,10 +1,9 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Globalization; - using Splat; namespace Akavache; @@ -137,7 +136,7 @@ private static IObservable ProcessOperation(KeyedOperation opera .Select(_ => operation) .Catch(Observable.Return(operation)); - private IObservable SafeStart(Func calculationFunc) + private AsyncSubject SafeStart(Func calculationFunc) { var ret = new AsyncSubject(); Observable.Start( @@ -159,4 +158,4 @@ private IObservable SafeStart(Func calculationFunc) return ret; } -} \ No newline at end of file +} diff --git a/src/Akavache.Core/LoginInfo.cs b/src/Akavache.Core/LoginInfo.cs index 8763b9da6..65cca1c4d 100644 --- a/src/Akavache.Core/LoginInfo.cs +++ b/src/Akavache.Core/LoginInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -8,18 +8,13 @@ namespace Akavache; /// /// Stored login information for a user. /// -public class LoginInfo +/// +/// Initializes a new instance of the class. +/// +/// The username for the entry. +/// The password for the user. +public class LoginInfo(string username, string password) { - /// - /// Initializes a new instance of the class. - /// - /// The username for the entry. - /// The password for the user. - public LoginInfo(string username, string password) - { - UserName = username; - Password = password; - } /// /// Initializes a new instance of the class. @@ -33,10 +28,10 @@ internal LoginInfo((string UserName, string Password) usernameAndLogin) /// /// Gets the username. /// - public string UserName { get; } + public string UserName { get; } = username; /// /// Gets the password. /// - public string Password { get; } + public string Password { get; } = password; } \ No newline at end of file diff --git a/src/Akavache.Core/LoginMixin.cs b/src/Akavache.Core/LoginMixin.cs index 949b2cfaa..43f84161d 100644 --- a/src/Akavache.Core/LoginMixin.cs +++ b/src/Akavache.Core/LoginMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -31,6 +31,7 @@ public static class LoginMixin /// The blob cache where to get the data. /// The host associated with the data. /// A Future result representing the user/password Tuple. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public static IObservable GetLoginAsync(this ISecureBlobCache blobCache, string host = "default") => blobCache.GetObject<(string, string)>("login:" + host).Select(x => new LoginInfo(x)); /// @@ -40,4 +41,4 @@ public static class LoginMixin /// The host associated with the data. /// A observable which signals when the erase is completed. public static IObservable EraseLogin(this ISecureBlobCache blobCache, string host = "default") => blobCache.InvalidateObject<(string, string)>("login:" + host); -} \ No newline at end of file +} diff --git a/src/Akavache.Core/Platforms/android/AndroidFilesystemProvider.cs b/src/Akavache.Core/Platforms/android/AndroidFilesystemProvider.cs index 98cf7ee95..8f31a7cc6 100644 --- a/src/Akavache.Core/Platforms/android/AndroidFilesystemProvider.cs +++ b/src/Akavache.Core/Platforms/android/AndroidFilesystemProvider.cs @@ -1,9 +1,11 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. +#if MONOANDROID13_0 using Android.App; +#endif namespace Akavache; @@ -15,9 +17,11 @@ public class AndroidFilesystemProvider : IFilesystemProvider private readonly SimpleFilesystemProvider _inner = new(); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForReadAsync(string path, IScheduler scheduler) => _inner.OpenFileForReadAsync(path, scheduler); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForWriteAsync(string path, IScheduler scheduler) => _inner.OpenFileForWriteAsync(path, scheduler); /// @@ -50,4 +54,4 @@ public class AndroidFilesystemProvider : IFilesystemProvider return di.FullName; } -} \ No newline at end of file +} diff --git a/src/Akavache.Core/Platforms/apple-common/MacFilesystemProvider.cs b/src/Akavache.Core/Platforms/apple-common/MacFilesystemProvider.cs index f0efd8d49..361a57fb7 100644 --- a/src/Akavache.Core/Platforms/apple-common/MacFilesystemProvider.cs +++ b/src/Akavache.Core/Platforms/apple-common/MacFilesystemProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -15,9 +15,11 @@ public class MacFilesystemProvider : IFilesystemProvider private readonly SimpleFilesystemProvider _inner = new(); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForReadAsync(string path, IScheduler scheduler) => _inner.OpenFileForReadAsync(path, scheduler); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForWriteAsync(string path, IScheduler scheduler) => _inner.OpenFileForWriteAsync(path, scheduler); /// @@ -38,18 +40,8 @@ public class MacFilesystemProvider : IFilesystemProvider private string CreateAppDirectory(NSSearchPathDirectory targetDir, string subDir = "BlobCache") { using var fm = new NSFileManager(); - var url = fm.GetUrl(targetDir, NSSearchPathDomain.All, null, true, out _); - if (url == null) - { - throw new DirectoryNotFoundException(); - } - - var rp = url.RelativePath; - if (rp == null) - { - throw new DirectoryNotFoundException(); - } - + var url = fm.GetUrl(targetDir, NSSearchPathDomain.All, null, true, out _) ?? throw new DirectoryNotFoundException(); + var rp = url.RelativePath ?? throw new DirectoryNotFoundException(); var ret = Path.Combine(rp, BlobCache.ApplicationName, subDir); if (!Directory.Exists(ret)) { diff --git a/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs b/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs index 4014a1a35..2c228ee56 100644 --- a/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs +++ b/src/Akavache.Core/Platforms/shared-not-uwp/SimpleFilesystemProvider.cs @@ -1,10 +1,9 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reflection; - using Splat; namespace Akavache; @@ -15,9 +14,11 @@ namespace Akavache; public class SimpleFilesystemProvider : IFilesystemProvider { /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForReadAsync(string path, IScheduler scheduler) => Utility.SafeOpenFileAsync(path, FileMode.Open, FileAccess.Read, FileShare.Read, scheduler); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForWriteAsync(string path, IScheduler scheduler) => Utility.SafeOpenFileAsync(path, FileMode.Create, FileAccess.Write, FileShare.None, scheduler); /// @@ -58,4 +59,4 @@ protected static string GetAssemblyDirectoryName() 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/Platforms/shared/AkavacheHttpMixin.cs b/src/Akavache.Core/Platforms/shared/AkavacheHttpMixin.cs index 6bca52d68..2a53c5bad 100644 --- a/src/Akavache.Core/Platforms/shared/AkavacheHttpMixin.cs +++ b/src/Akavache.Core/Platforms/shared/AkavacheHttpMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -17,10 +17,14 @@ public class AkavacheHttpMixin : IAkavacheHttpMixin /// public IObservable DownloadUrl(IBlobCache blobCache, string url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); +#endif return blobCache.DownloadUrl(url, url, headers, fetchAlways, absoluteExpiration); } @@ -28,6 +32,7 @@ public IObservable DownloadUrl(IBlobCache blobCache, string url, IDictio /// public IObservable DownloadUrl(IBlobCache blobCache, Uri url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); @@ -37,6 +42,10 @@ public IObservable DownloadUrl(IBlobCache blobCache, Uri url, IDictionar { throw new ArgumentNullException(nameof(url)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); + ArgumentNullException.ThrowIfNull(url); +#endif return blobCache.DownloadUrl(url.ToString(), url, headers, fetchAlways, absoluteExpiration); } @@ -44,10 +53,14 @@ public IObservable DownloadUrl(IBlobCache blobCache, Uri url, IDictionar /// public IObservable DownloadUrl(IBlobCache blobCache, string key, string url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); +#endif var doFetch = MakeWebRequest(HttpMethod.Get, new Uri(url), headers).SelectMany(x => ProcessWebResponse(x, url, absoluteExpiration)); var fetchAndCache = doFetch.SelectMany(x => blobCache.Insert(key, x, absoluteExpiration).Select(_ => x)); @@ -70,10 +83,14 @@ public IObservable DownloadUrl(IBlobCache blobCache, string key, string /// public IObservable DownloadUrl(IBlobCache blobCache, string key, Uri url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); +#endif var doFetch = MakeWebRequest(HttpMethod.Get, url, headers).SelectMany(x => ProcessWebResponse(x, url, absoluteExpiration)); var fetchAndCache = doFetch.SelectMany(x => blobCache.Insert(key, x, absoluteExpiration).Select(_ => x)); @@ -96,10 +113,14 @@ public IObservable DownloadUrl(IBlobCache blobCache, string key, Uri url /// public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, string url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); +#endif return blobCache.DownloadUrl(method, url, url, headers, fetchAlways, absoluteExpiration); } @@ -107,6 +128,7 @@ public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, /// public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, Uri url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); @@ -116,6 +138,10 @@ public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, { throw new ArgumentNullException(nameof(url)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); + ArgumentNullException.ThrowIfNull(url); +#endif return blobCache.DownloadUrl(method, url.ToString(), url, headers, fetchAlways, absoluteExpiration); } @@ -123,10 +149,14 @@ public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, /// public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, string key, string url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); +#endif var doFetch = MakeWebRequest(method, new Uri(url), headers).SelectMany(x => ProcessWebResponse(x, url, absoluteExpiration)); var fetchAndCache = doFetch.SelectMany(x => blobCache.Insert(key, x, absoluteExpiration).Select(_ => x)); @@ -149,10 +179,14 @@ public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, /// public IObservable DownloadUrl(IBlobCache blobCache, HttpMethod method, string key, Uri url, IDictionary? headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } +#else + ArgumentNullException.ThrowIfNull(blobCache); +#endif var doFetch = MakeWebRequest(method, url, headers).SelectMany(x => ProcessWebResponse(x, url, absoluteExpiration)); var fetchAndCache = doFetch.SelectMany(x => blobCache.Insert(key, x, absoluteExpiration).Select(_ => x)); diff --git a/src/Akavache.Core/Platforms/shared/DefaultAkavacheHttpClientFactory.cs b/src/Akavache.Core/Platforms/shared/DefaultAkavacheHttpClientFactory.cs index ba9506b8f..e7e3efdca 100644 --- a/src/Akavache.Core/Platforms/shared/DefaultAkavacheHttpClientFactory.cs +++ b/src/Akavache.Core/Platforms/shared/DefaultAkavacheHttpClientFactory.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Platforms/shared/EncryptionProvider.cs b/src/Akavache.Core/Platforms/shared/EncryptionProvider.cs index 17ae7824a..aff5a62b0 100644 --- a/src/Akavache.Core/Platforms/shared/EncryptionProvider.cs +++ b/src/Akavache.Core/Platforms/shared/EncryptionProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -12,10 +12,10 @@ public class EncryptionProvider : IEncryptionProvider { /// public IObservable EncryptBlock(byte[] block) => - Observable.Return( - ProtectedData.Protect(block, null, DataProtectionScope.CurrentUser)); + Observable.Return(ProtectedData.Protect(block, null, DataProtectionScope.CurrentUser)); /// - public IObservable DecryptBlock(byte[] block) => Observable.Return(ProtectedData.Unprotect(block, null, DataProtectionScope.CurrentUser)); + public IObservable DecryptBlock(byte[] block) => + Observable.Return(ProtectedData.Unprotect(block, null, DataProtectionScope.CurrentUser)); } } diff --git a/src/Akavache.Core/Platforms/shared/MD5Managed.cs b/src/Akavache.Core/Platforms/shared/MD5Managed.cs index 77f591404..3914bb2a5 100644 --- a/src/Akavache.Core/Platforms/shared/MD5Managed.cs +++ b/src/Akavache.Core/Platforms/shared/MD5Managed.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -26,10 +26,6 @@ internal class MD5Managed : MD5 public MD5Managed() { - // TODO SHANE is this ok for UWP? -#if !WINDOWS_UWP - HashSizeValue = 0x80; -#endif _data = new byte[64]; _abcd = default; } @@ -80,14 +76,9 @@ protected override void HashCore(byte[] array, int ibStart, int cbSize) _totalLength += cbSize; } - // TODO SHANE is this ok for UWP? -#if !WINDOWS_UWP protected override byte[] HashFinal() { HashValue = MD5Core.GetHashFinalBlock(_data, 0, _dataSize, _abcd, _totalLength * 8); return HashValue; } -#else - protected override byte[] HashFinal() => MD5Core.GetHashFinalBlock(_data, 0, _dataSize, _abcd, _totalLength * 8); -#endif } diff --git a/src/Akavache.Core/Platforms/shared/Registrations.cs b/src/Akavache.Core/Platforms/shared/Registrations.cs index f56cf09db..08078d81f 100644 --- a/src/Akavache.Core/Platforms/shared/Registrations.cs +++ b/src/Akavache.Core/Platforms/shared/Registrations.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -30,25 +30,23 @@ public class Registrations : IWantsToRegisterStuff #endif public void Register(IMutableDependencyResolver resolver, IReadonlyDependencyResolver readonlyDependencyResolver) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (resolver is null) { throw new ArgumentNullException(nameof(resolver)); } +#else + ArgumentNullException.ThrowIfNull(resolver); +#endif #if XAMARIN_MOBILE var fs = new IsolatedStorageProvider(); -#elif WINDOWS_UWP - var fs = new WinRTFilesystemProvider(); #else var fs = new SimpleFilesystemProvider(); #endif resolver.Register(() => fs, typeof(IFilesystemProvider), null); -#if WINDOWS_UWP - var enc = new WinRTEncryptionProvider(); -#else var enc = new EncryptionProvider(); -#endif resolver.Register(() => enc, typeof(IEncryptionProvider), null); var localCache = new Lazy(() => new InMemoryBlobCache()); diff --git a/src/Akavache.Core/Platforms/shared/StreamMixins.cs b/src/Akavache.Core/Platforms/shared/StreamMixins.cs index a03407227..05366eed7 100644 --- a/src/Akavache.Core/Platforms/shared/StreamMixins.cs +++ b/src/Akavache.Core/Platforms/shared/StreamMixins.cs @@ -1,12 +1,8 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. -#if WINDOWS_UWP -using System.Reactive.Threading.Tasks; -#endif - namespace System { /// @@ -24,14 +20,15 @@ public static class StreamMixins /// An observable that signals when the write operation has completed. public static IObservable WriteAsyncRx(this Stream blobCache, byte[] data, int start, int length) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } - -#if WINDOWS_UWP - return blobCache.WriteAsync(data, start, length).ToObservable(); #else + ArgumentNullException.ThrowIfNull(blobCache); +#endif + var ret = new AsyncSubject(); try @@ -61,7 +58,6 @@ public static IObservable WriteAsyncRx(this Stream blobCache, byte[] data, } return ret; -#endif } } } diff --git a/src/Akavache.Core/Platforms/shared/Utility.cs b/src/Akavache.Core/Platforms/shared/Utility.cs index d5b5c2707..799e7bea8 100644 --- a/src/Akavache.Core/Platforms/shared/Utility.cs +++ b/src/Akavache.Core/Platforms/shared/Utility.cs @@ -1,19 +1,12 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics.CodeAnalysis; using System.Globalization; - using Splat; -#if WINDOWS_UWP -using System.Reactive.Threading.Tasks; -using System.Reactive.Windows.Foundation; -using Windows.Storage; -#endif - namespace Akavache; [SuppressMessage("FxCop.Style", "CA5351: GetMd5Hash uses a broken cryptographic algorithm MD5", Justification = "Not used for encryption.")] @@ -21,12 +14,6 @@ internal static partial class Utility { public static string GetMd5Hash(string input) { -#if WINDOWS_UWP - // NB: Technically, we could do this everywhere, but if we did this - // upgrade, we may return different strings than we used to (i.e. - // formatting-wise), which would break old caches. - return MD5Core.GetHashString(input, Encoding.UTF8); -#else using var md5Hasher = new MD5Managed(); // Convert the input string to a byte array and compute the hash. @@ -38,10 +25,9 @@ public static string GetMd5Hash(string input) } return sBuilder.ToString(); -#endif } -#if !WINDOWS_UWP + [SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public static IObservable SafeOpenFileAsync(string path, FileMode mode, FileAccess access, FileShare share, IScheduler? scheduler = null) { scheduler ??= BlobCache.TaskpoolScheduler; @@ -117,7 +103,6 @@ public static IEnumerable SplitFullPath(this DirectoryInfo directoryInfo components.Reverse(); return components; } -#endif /// /// Logs the errors of the observable. @@ -127,9 +112,7 @@ public static IEnumerable SplitFullPath(this DirectoryInfo directoryInfo /// The message to log. /// An observable. public static IObservable LogErrors(this IObservable observable, string? message = null) => - Observable.Create(subj => - { - return observable.Subscribe( + Observable.Create(subj => observable.Subscribe( subj.OnNext, ex => { @@ -137,18 +120,8 @@ public static IObservable LogErrors(this IObservable observable, string LogHost.Default.Info(ex, "{0} failed", msg); subj.OnError(ex); }, - subj.OnCompleted); - }); + subj.OnCompleted)); -#if WINDOWS_UWP - /// - /// Copies a stream using async. - /// - /// The stream to copy from. - /// The stream to copy to. - /// An observable that signals when the operation has finished. - public static IObservable CopyToAsync(this Stream stream, Stream destination) -#else /// /// Copies a stream using async. /// @@ -156,26 +129,8 @@ public static IObservable CopyToAsync(this Stream stream, Stream destinati /// The stream to copy to. /// The scheduler to schedule on. /// An observable that signals when the operation has finished. - public static IObservable CopyToAsync(this Stream stream, Stream destination, IScheduler? scheduler = null) -#endif - { -#if WINDOWS_UWP - return stream.CopyToAsync(destination).ToObservable() - .Do( - x => - { - try - { - stream.Dispose(); - destination.Dispose(); - } - catch (Exception ex) - { - LogHost.Default.Warn(ex, "CopyToAsync failed"); - } - }); -#else - return Observable.Start( + [SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] + public static IObservable CopyToAsync(this Stream stream, Stream destination, IScheduler? scheduler = null) => Observable.Start( () => { try @@ -193,6 +148,4 @@ public static IObservable CopyToAsync(this Stream stream, Stream destinati } }, scheduler ?? BlobCache.TaskpoolScheduler); -#endif - } } diff --git a/src/Akavache.Core/Platforms/tizen/TizenFilesystemProvider.cs b/src/Akavache.Core/Platforms/tizen/TizenFilesystemProvider.cs index 8657ac4cf..87d1df411 100644 --- a/src/Akavache.Core/Platforms/tizen/TizenFilesystemProvider.cs +++ b/src/Akavache.Core/Platforms/tizen/TizenFilesystemProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -15,9 +15,11 @@ public class TizenFilesystemProvider : IFilesystemProvider private readonly SimpleFilesystemProvider _inner = new(); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForReadAsync(string path, IScheduler scheduler) => _inner.OpenFileForReadAsync(path, scheduler); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForWriteAsync(string path, IScheduler scheduler) => _inner.OpenFileForWriteAsync(path, scheduler); /// @@ -44,4 +46,4 @@ public string GetDefaultSecretCacheDirectory() return di.FullName; } -} \ No newline at end of file +} diff --git a/src/Akavache.Core/Platforms/uap/Shims/IsolatedStorageException.cs b/src/Akavache.Core/Platforms/uap/Shims/IsolatedStorageException.cs deleted file mode 100644 index 86e29bb95..000000000 --- a/src/Akavache.Core/Platforms/uap/Shims/IsolatedStorageException.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -namespace System.IO.IsolatedStorage; - -/// -/// An exception that happens when there is a isolated storage issue. -/// -public class IsolatedStorageException : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The message about the exception. - public IsolatedStorageException(string message) - : base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message about the exception. - /// An inner exception with further details. - public IsolatedStorageException(string message, Exception innerException) - : base(message, innerException) - { - } -} \ No newline at end of file diff --git a/src/Akavache.Core/Platforms/uap/Shims/MicrosoftStreamExtensions.cs b/src/Akavache.Core/Platforms/uap/Shims/MicrosoftStreamExtensions.cs deleted file mode 100644 index bf8a6b69b..000000000 --- a/src/Akavache.Core/Platforms/uap/Shims/MicrosoftStreamExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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 Windows.Storage.Streams; - -namespace System.IO; - -/// -/// A set of extension methods associated with streams. -/// -public static class MicrosoftStreamExtensions -{ - /// - /// Gets a random access stream from a stream. - /// - /// The stream to convert. - /// The random access stream. - public static IRandomAccessStream AsRandomAccessStream(this Stream stream) => new RandomStream(stream); - - /// - /// Converts a byte array into a random access stream. - /// - /// The bytes to convert. - /// The random access stream. - public static IRandomAccessStream AsRandomAccessStream(this byte[] bytes) => new RandomStream(bytes); -} \ No newline at end of file diff --git a/src/Akavache.Core/Platforms/uap/Shims/RandomStream.cs b/src/Akavache.Core/Platforms/uap/Shims/RandomStream.cs deleted file mode 100644 index 5f4e291cd..000000000 --- a/src/Akavache.Core/Platforms/uap/Shims/RandomStream.cs +++ /dev/null @@ -1,90 +0,0 @@ -// 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 Windows.Foundation; -using Windows.Storage.Streams; - -namespace System.IO; - -/// -/// A implementation of the random access stream. -/// -public sealed class RandomStream : IRandomAccessStream -{ - private readonly Stream _streamValue; - - /// - /// Initializes a new instance of the class. - /// - /// The stream to wrap. - public RandomStream(Stream stream) => _streamValue = stream; - - /// - /// Initializes a new instance of the class. - /// - /// The byte array to wrap. - public RandomStream(byte[] bytes) => _streamValue = new MemoryStream(bytes); - - /// - public ulong Size - { - get => (ulong)_streamValue.Length; - - set => _streamValue.SetLength((long)value); - } - - /// - public bool CanRead => true; - - /// - public bool CanWrite => true; - - /// - public ulong Position => (ulong)_streamValue.Position; - - /// - public IInputStream GetInputStreamAt(ulong position) - { - if ((long)position > _streamValue.Length) - { - throw new IndexOutOfRangeException(); - } - - _streamValue.Position = (long)position; - - return _streamValue.AsInputStream(); - } - - /// - public IOutputStream GetOutputStreamAt(ulong position) - { - if ((long)position > _streamValue.Length) - { - throw new IndexOutOfRangeException(); - } - - _streamValue.Position = (long)position; - - return _streamValue.AsOutputStream(); - } - - /// - public IRandomAccessStream CloneStream() => throw new NotSupportedException(); - - /// - public void Seek(ulong position) => _streamValue.Seek((long)position, 0); - - /// - public void Dispose() => _streamValue.Dispose(); - - /// - public IAsyncOperationWithProgress ReadAsync(IBuffer buffer, uint count, InputStreamOptions options) => throw new NotSupportedException(); - - /// - public IAsyncOperation FlushAsync() => throw new NotImplementedException(); - - /// - public IAsyncOperationWithProgress WriteAsync(IBuffer buffer) => throw new NotImplementedException(); -} \ No newline at end of file diff --git a/src/Akavache.Core/Platforms/uap/WinRTEncryptionProvider.cs b/src/Akavache.Core/Platforms/uap/WinRTEncryptionProvider.cs deleted file mode 100644 index 21055a5dc..000000000 --- a/src/Akavache.Core/Platforms/uap/WinRTEncryptionProvider.cs +++ /dev/null @@ -1,33 +0,0 @@ -// 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.Reactive.Windows.Foundation; -using System.Runtime.InteropServices.WindowsRuntime; - -using Windows.Security.Cryptography.DataProtection; - -namespace Akavache; - -/// -/// A encryption provider for the WinRT system. -/// -public class WinRTEncryptionProvider : IEncryptionProvider -{ - /// - public IObservable EncryptBlock(byte[] block) - { - var dpapi = new DataProtectionProvider("LOCAL=user"); - return dpapi.ProtectAsync(block.AsBuffer()).ToObservable().Select(b => b.ToArray()); - } - - /// - public IObservable DecryptBlock(byte[] block) - { - // Do not include a protectionDescriptor - // http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.cryptography.dataprotection.dataprotectionprovider.unprotectasync.aspx - var dpapi = new DataProtectionProvider(); - return dpapi.UnprotectAsync(block.AsBuffer()).ToObservable().Select(b => b.ToArray()); - } -} \ No newline at end of file diff --git a/src/Akavache.Core/Platforms/uap/WinRTFilesystemProvider.cs b/src/Akavache.Core/Platforms/uap/WinRTFilesystemProvider.cs deleted file mode 100644 index 09b43de06..000000000 --- a/src/Akavache.Core/Platforms/uap/WinRTFilesystemProvider.cs +++ /dev/null @@ -1,99 +0,0 @@ -// 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.Diagnostics.CodeAnalysis; -using System.Reactive.Threading.Tasks; -using System.Reactive.Windows.Foundation; - -using Splat; - -using Windows.Storage; - -namespace Akavache; - -/// -/// A file system provider for the WinRT system. -/// -[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 class WinRTFilesystemProvider : IFilesystemProvider, IEnableLogger -{ - /// - public IObservable OpenFileForReadAsync(string path, IScheduler scheduler) - { - var folder = Path.GetDirectoryName(path); - var name = Path.GetFileName(path); - - return StorageFolder.GetFolderFromPathAsync(folder).ToObservable() - .SelectMany(x => x.GetFileAsync(name).ToObservable()) - .SelectMany(x => x.OpenStreamForReadAsync().ToObservable()); - } - - /// - public IObservable OpenFileForWriteAsync(string path, IScheduler scheduler) - { - var folder = Path.GetDirectoryName(path); - var name = Path.GetFileName(path); - - return StorageFolder.GetFolderFromPathAsync(folder).ToObservable() - .SelectMany(x => x.CreateFileAsync(name, CreationCollisionOption.ReplaceExisting).ToObservable()) - .SelectMany(x => x.OpenStreamForWriteAsync().ToObservable()); - } - - /// - public IObservable CreateRecursive(string path) - { - if (string.IsNullOrWhiteSpace(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - var paths = path.Split('\\'); - - var firstFolderThatExists = Observable.Range(0, paths.Length - 1) - .Select(x => - StorageFolder.GetFolderFromPathAsync(string.Join("\\", paths.Take(paths.Length - x))) - .ToObservable() - .Catch(Observable.Empty())) - .Concat() - .Take(1); - - return firstFolderThatExists - .Select(x => - { - if (x.Path == path) - { - return null; - } - - return new { Root = x, Paths = path.Replace(x.Path + "\\", string.Empty).Split('\\') }; - }) - .SelectMany(x => - { - if (x is null) - { - return Observable.Return(default(StorageFolder)); - } - -#pragma warning disable CS0618 // Observable.First(IObservable)' is obsolete -- need to find a better solution - return x.Paths.ToObservable().Aggregate(x.Root, (acc, y) => acc.CreateFolderAsync(y).ToObservable().First()); -#pragma warning restore CS0618 - }) - .Select(_ => Unit.Default); - } - - /// - public IObservable Delete(string path) => - StorageFile.GetFileFromPathAsync(path).ToObservable() - .SelectMany(x => x.DeleteAsync().ToObservable()); - - /// - public string GetDefaultRoamingCacheDirectory() => Path.Combine(ApplicationData.Current.RoamingFolder.Path, "BlobCache"); - - /// - public string GetDefaultLocalMachineCacheDirectory() => Path.Combine(ApplicationData.Current.LocalFolder.Path, "BlobCache"); - - /// - public string GetDefaultSecretCacheDirectory() => Path.Combine(ApplicationData.Current.RoamingFolder.Path, "SecretCache"); -} \ No newline at end of file diff --git a/src/Akavache.Core/Platforms/xamarin-mobile/IsolatedStorageProvider.cs b/src/Akavache.Core/Platforms/xamarin-mobile/IsolatedStorageProvider.cs index bacc083a0..5e748a510 100644 --- a/src/Akavache.Core/Platforms/xamarin-mobile/IsolatedStorageProvider.cs +++ b/src/Akavache.Core/Platforms/xamarin-mobile/IsolatedStorageProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -14,6 +14,7 @@ namespace Akavache; public class IsolatedStorageProvider : IFilesystemProvider { /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForReadAsync(string path, IScheduler scheduler) => Observable.Create(subj => { @@ -34,6 +35,7 @@ public IObservable OpenFileForReadAsync(string path, IScheduler schedule }); /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design")] public IObservable OpenFileForWriteAsync(string path, IScheduler scheduler) => Observable.Create(subj => { @@ -111,4 +113,4 @@ public IObservable Delete(string path) => /// public string GetDefaultLocalMachineCacheDirectory() => "LocalBlobCache"; -} \ No newline at end of file +} diff --git a/src/Akavache.Core/PortableExtensions.cs b/src/Akavache.Core/PortableExtensions.cs index 1c2fd981e..e3b63f912 100644 --- a/src/Akavache.Core/PortableExtensions.cs +++ b/src/Akavache.Core/PortableExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/PreserveAttribute.cs b/src/Akavache.Core/PreserveAttribute.cs index f1b423f2e..c1898acee 100644 --- a/src/Akavache.Core/PreserveAttribute.cs +++ b/src/Akavache.Core/PreserveAttribute.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Properties/AssemblyInfo.cs b/src/Akavache.Core/Properties/AssemblyInfo.cs index 0a688b1cb..26e7ebd78 100644 --- a/src/Akavache.Core/Properties/AssemblyInfo.cs +++ b/src/Akavache.Core/Properties/AssemblyInfo.cs @@ -1,10 +1,9 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Runtime.CompilerServices; - using Akavache.Core; [assembly: InternalsVisibleTo("Akavache.Tests")] diff --git a/src/Akavache.Core/ProtectedData.cs b/src/Akavache.Core/ProtectedData.cs index 5e964d333..deef6ae36 100644 --- a/src/Akavache.Core/ProtectedData.cs +++ b/src/Akavache.Core/ProtectedData.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Providers/FileAccess.cs b/src/Akavache.Core/Providers/FileAccess.cs index 6a97e0836..95830e952 100644 --- a/src/Akavache.Core/Providers/FileAccess.cs +++ b/src/Akavache.Core/Providers/FileAccess.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Providers/FileMode.cs b/src/Akavache.Core/Providers/FileMode.cs index 958660bfc..e0bd308ad 100644 --- a/src/Akavache.Core/Providers/FileMode.cs +++ b/src/Akavache.Core/Providers/FileMode.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Providers/FileShare.cs b/src/Akavache.Core/Providers/FileShare.cs index 6cb5e533a..f06c5690f 100644 --- a/src/Akavache.Core/Providers/FileShare.cs +++ b/src/Akavache.Core/Providers/FileShare.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Providers/IEncryptionProvider.cs b/src/Akavache.Core/Providers/IEncryptionProvider.cs index ddc6ea100..d4d0f29ce 100644 --- a/src/Akavache.Core/Providers/IEncryptionProvider.cs +++ b/src/Akavache.Core/Providers/IEncryptionProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/Providers/IFilesystemProvider.cs b/src/Akavache.Core/Providers/IFilesystemProvider.cs index 3551a3a65..eceb41679 100644 --- a/src/Akavache.Core/Providers/IFilesystemProvider.cs +++ b/src/Akavache.Core/Providers/IFilesystemProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Core/RelativeTimeMixin.cs b/src/Akavache.Core/RelativeTimeMixin.cs index 6bc8f1544..0430f09a4 100644 --- a/src/Akavache.Core/RelativeTimeMixin.cs +++ b/src/Akavache.Core/RelativeTimeMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Drawing/Akavache.Drawing.csproj b/src/Akavache.Drawing/Akavache.Drawing.csproj index 3ef954f4b..46bd97917 100644 --- a/src/Akavache.Drawing/Akavache.Drawing.csproj +++ b/src/Akavache.Drawing/Akavache.Drawing.csproj @@ -1,19 +1,14 @@  - netstandard2.0;netstandard2.1;MonoAndroid12.0;MonoAndroid12.1;MonoAndroid13.0;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10;Xamarin.WatchOS10;tizen40;net6.0;net7.0;net7.0-android;net7.0-ios;net7.0-tvos;net7.0-macos;net7.0-maccatalyst - $(TargetFrameworks);net462;net6.0-windows10.0.17763.0;net7.0-windows10.0.17763.0 + $(AkavacheTargetFrameworks) Akavache.Drawing Akavache An asynchronous, persistent key-value store for desktop and mobile applications on .NET Akavache.Drawing - latest - enable - - diff --git a/src/Akavache.Drawing/BitmapImageMixin.cs b/src/Akavache.Drawing/BitmapImageMixin.cs index fbf8462ea..2d911c5f0 100644 --- a/src/Akavache.Drawing/BitmapImageMixin.cs +++ b/src/Akavache.Drawing/BitmapImageMixin.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Drawing/Registrations.cs b/src/Akavache.Drawing/Registrations.cs index 809337974..559312b59 100644 --- a/src/Akavache.Drawing/Registrations.cs +++ b/src/Akavache.Drawing/Registrations.cs @@ -1,10 +1,9 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Core; - using Splat; namespace Akavache.Drawing; diff --git a/src/Akavache.Mobile/Akavache.Mobile.csproj b/src/Akavache.Mobile/Akavache.Mobile.csproj index 93989e116..e1d534dc4 100644 --- a/src/Akavache.Mobile/Akavache.Mobile.csproj +++ b/src/Akavache.Mobile/Akavache.Mobile.csproj @@ -1,20 +1,15 @@  - netstandard2.0;netstandard2.1;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10;MonoAndroid12.0;MonoAndroid12.1;MonoAndroid13.0;tizen40;net6.0;net7.0;net7.0-android;net7.0-ios;net7.0-tvos;net7.0-macos;net7.0-maccatalyst - $(TargetFrameworks);net462 + $(AkavacheTargetFrameworks) Akavache.Mobile Akavache.Mobile An asynchronous, persistent key-value store for desktop and mobile applications on .NET akavache.mobile - latest - enable - - diff --git a/src/Akavache.Mobile/AkavacheDriver.cs b/src/Akavache.Mobile/AkavacheDriver.cs index 0cd9af185..3dbabb702 100644 --- a/src/Akavache.Mobile/AkavacheDriver.cs +++ b/src/Akavache.Mobile/AkavacheDriver.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Mobile/Registrations.cs b/src/Akavache.Mobile/Registrations.cs index b8e1d9c05..2a926a647 100644 --- a/src/Akavache.Mobile/Registrations.cs +++ b/src/Akavache.Mobile/Registrations.cs @@ -1,14 +1,11 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Core; - using Newtonsoft.Json; - using ReactiveUI; - using Splat; namespace Akavache.Mobile; @@ -22,10 +19,14 @@ public class Registrations : IWantsToRegisterStuff /// public void Register(IMutableDependencyResolver resolver, IReadonlyDependencyResolver readonlyDependencyResolver) { +#if NETSTANDARD || XAMARINIOS || XAMARINMAC || XAMARINTVOS || TIZEN || MONOANDROID13_0 if (resolver is null) { throw new ArgumentNullException(nameof(resolver)); } +#else + ArgumentNullException.ThrowIfNull(resolver); +#endif resolver.Register( () => new JsonSerializerSettings @@ -53,4 +54,4 @@ public void Register(IMutableDependencyResolver resolver, IReadonlyDependencyRes resolver.Register(() => RxApp.TaskpoolScheduler, typeof(IScheduler), "Taskpool"); } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Akavache.Sqlite3.csproj b/src/Akavache.Sqlite3/Akavache.Sqlite3.csproj index 054aaf1e7..7f6275117 100644 --- a/src/Akavache.Sqlite3/Akavache.Sqlite3.csproj +++ b/src/Akavache.Sqlite3/Akavache.Sqlite3.csproj @@ -1,26 +1,19 @@ - + - netstandard2.0;netstandard2.1;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10;MonoAndroid12.0;MonoAndroid12.1;MonoAndroid13.0;tizen40;net6.0;net7.0;net7.0-android;net7.0-ios;net7.0-tvos;net7.0-macos;net7.0-maccatalyst - $(TargetFrameworks);net462 + $(AkavacheTargetFrameworks) Akavache.Sqlite3 Akavache.Sqlite3 Akavache Sqlite3 akavache.sqlite3 $(NoWarn);CS1591 - $(DefineConstants);USE_SQLITEPCL_RAW;USE_NEW_REFLECTION_API - latest - enable + $(DefineConstants) - - - - - + @@ -30,7 +23,6 @@ - diff --git a/src/Akavache.Sqlite3/AsyncLock.cs b/src/Akavache.Sqlite3/AsyncLock.cs index 5af4bc00b..39a11657e 100644 --- a/src/Akavache.Sqlite3/AsyncLock.cs +++ b/src/Akavache.Sqlite3/AsyncLock.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -27,7 +27,11 @@ public sealed class AsyncLock : IDisposable /// /// A cancellation token which allows for release of the lock. /// A disposable which when Disposed will release the lock. +#if NETSTANDARD2_0 || XAMARINIOS || XAMARINMAC || XAMARINTVOS || MONOANDROID13_0 || TIZEN public Task LockAsync(CancellationToken cancellationToken = default) +#else + public Task LockAsync(in CancellationToken cancellationToken = default) +#endif { var wait = _semaphore.WaitAsync(cancellationToken); diff --git a/src/Akavache.Sqlite3/EnumerableEx.cs b/src/Akavache.Sqlite3/EnumerableEx.cs index 98d5098ac..162363a46 100644 --- a/src/Akavache.Sqlite3/EnumerableEx.cs +++ b/src/Akavache.Sqlite3/EnumerableEx.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -11,4 +11,4 @@ public static IEnumerable Return(T value) { yield return value; } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/IsExternalInit.cs b/src/Akavache.Sqlite3/IsExternalInit.cs index 046bad107..f37a2f144 100644 --- a/src/Akavache.Sqlite3/IsExternalInit.cs +++ b/src/Akavache.Sqlite3/IsExternalInit.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/Operations/BeginTransactionSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/BeginTransactionSqliteOperation.cs index 5c650b8dd..abbe08fde 100644 --- a/src/Akavache.Sqlite3/Operations/BeginTransactionSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/BeginTransactionSqliteOperation.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -23,7 +21,7 @@ public BeginTransactionSqliteOperation(SQLiteConnection conn) if (result != SQLite3.Result.OK) { - throw new SQLiteException(result, "Couldn't prepare statement"); + throw SQLiteException.New(result, "Couldn't prepare statement"); } _inner = _beginOp; @@ -45,4 +43,4 @@ public Action PrepareToExecute() => }; public void Dispose() => Interlocked.Exchange(ref _inner, Disposable.Empty).Dispose(); -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/BulkInsertSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/BulkInsertSqliteOperation.cs index 26f7cd691..91124b284 100644 --- a/src/Akavache.Sqlite3/Operations/BulkInsertSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/BulkInsertSqliteOperation.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -23,7 +21,7 @@ public BulkInsertSqliteOperation(SQLiteConnection conn) if (result != SQLite3.Result.OK) { - throw new SQLiteException(result, "Couldn't prepare statement"); + throw SQLiteException.New(result, "Couldn't prepare statement"); } _inner = _insertOp; diff --git a/src/Akavache.Sqlite3/Operations/BulkInvalidateByTypeSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/BulkInvalidateByTypeSqliteOperation.cs index 995978efd..fc9e0e38e 100644 --- a/src/Akavache.Sqlite3/Operations/BulkInvalidateByTypeSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/BulkInvalidateByTypeSqliteOperation.cs @@ -1,18 +1,14 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Sqlite3.Internal; +using SQLite; namespace Akavache.Sqlite3; // NB: This just makes OperationQueue's life easier by giving it a type // name. -internal class BulkInvalidateByTypeSqliteOperation : BulkInvalidateSqliteOperation +internal class BulkInvalidateByTypeSqliteOperation(SQLiteConnection conn) : BulkInvalidateSqliteOperation(conn, true) { - public BulkInvalidateByTypeSqliteOperation(SQLiteConnection conn) - : base(conn, true) - { - } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/BulkInvalidateSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/BulkInvalidateSqliteOperation.cs index 5be3bd969..d57c83618 100644 --- a/src/Akavache.Sqlite3/Operations/BulkInvalidateSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/BulkInvalidateSqliteOperation.cs @@ -1,13 +1,11 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics.CodeAnalysis; using System.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -34,7 +32,7 @@ public BulkInvalidateSqliteOperation(SQLiteConnection conn, bool useTypeInsteadO if (result != SQLite3.Result.OK) { - throw new SQLiteException(result, "Couldn't prepare statement"); + throw SQLiteException.New(result, "Couldn't prepare statement"); } qs.Append(",?"); diff --git a/src/Akavache.Sqlite3/Operations/BulkSelectByTypeSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/BulkSelectByTypeSqliteOperation.cs index ad33e6579..3283cfcab 100644 --- a/src/Akavache.Sqlite3/Operations/BulkSelectByTypeSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/BulkSelectByTypeSqliteOperation.cs @@ -1,16 +1,12 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Sqlite3.Internal; +using SQLite; namespace Akavache.Sqlite3; -internal class BulkSelectByTypeSqliteOperation : BulkSelectSqliteOperation +internal class BulkSelectByTypeSqliteOperation(SQLiteConnection conn, IScheduler scheduler) : BulkSelectSqliteOperation(conn, true, scheduler) { - public BulkSelectByTypeSqliteOperation(SQLiteConnection conn, IScheduler scheduler) - : base(conn, true, scheduler) - { - } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/BulkSelectSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/BulkSelectSqliteOperation.cs index 2a46820c9..befd4fd4d 100644 --- a/src/Akavache.Sqlite3/Operations/BulkSelectSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/BulkSelectSqliteOperation.cs @@ -1,13 +1,11 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics.CodeAnalysis; using System.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -37,7 +35,7 @@ public BulkSelectSqliteOperation(SQLiteConnection conn, bool useTypeInsteadOfKey var error = raw.sqlite3_errmsg(conn.Handle).utf8_to_string(); if (result != SQLite3.Result.OK) { - throw new SQLiteException(result, "Couldn't prepare statement: " + error); + throw SQLiteException.New(result, "Couldn't prepare statement: " + error); } qs.Append(",?"); diff --git a/src/Akavache.Sqlite3/Operations/CommitTransactionSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/CommitTransactionSqliteOperation.cs index 6ad58eecd..2df2abb16 100644 --- a/src/Akavache.Sqlite3/Operations/CommitTransactionSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/CommitTransactionSqliteOperation.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -23,7 +21,7 @@ public CommitTransactionSqliteOperation(SQLiteConnection conn) if (result != SQLite3.Result.OK) { - throw new SQLiteException(result, "Couldn't prepare statement"); + throw SQLiteException.New(result, "Couldn't prepare statement"); } _inner = _commitOp; @@ -45,4 +43,4 @@ public Action PrepareToExecute() => }; public void Dispose() => Interlocked.Exchange(ref _inner, Disposable.Empty).Dispose(); -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/Constants.cs b/src/Akavache.Sqlite3/Operations/Constants.cs index b9f58bc5d..5cf901998 100644 --- a/src/Akavache.Sqlite3/Operations/Constants.cs +++ b/src/Akavache.Sqlite3/Operations/Constants.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/Operations/DeleteExpiredSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/DeleteExpiredSqliteOperation.cs index 47f9b4b93..5564ea4d3 100644 --- a/src/Akavache.Sqlite3/Operations/DeleteExpiredSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/DeleteExpiredSqliteOperation.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -24,7 +22,7 @@ public DeleteExpiredSqliteOperation(SQLiteConnection conn, IScheduler scheduler) if (deleteResult != SQLite3.Result.OK) { - throw new SQLiteException(deleteResult, "Couldn't prepare delete statement"); + throw SQLiteException.New(deleteResult, "Couldn't prepare delete statement"); } _scheduler = scheduler; @@ -52,4 +50,4 @@ public Action PrepareToExecute() } public void Dispose() => Interlocked.Exchange(ref _inner, Disposable.Empty).Dispose(); -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/GetKeysSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/GetKeysSqliteOperation.cs index e11336d4d..f775d4bba 100644 --- a/src/Akavache.Sqlite3/Operations/GetKeysSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/GetKeysSqliteOperation.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -24,7 +22,7 @@ public GetKeysSqliteOperation(SQLiteConnection conn, IScheduler scheduler) if (result != SQLite3.Result.OK) { - throw new SQLiteException(result, "Couldn't prepare statement"); + throw SQLiteException.New(result, "Couldn't prepare statement"); } _inner = _selectOp; @@ -55,4 +53,4 @@ public Func> PrepareToExecute() => }; public void Dispose() => Interlocked.Exchange(ref _inner, Disposable.Empty).Dispose(); -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/IPreparedSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/IPreparedSqliteOperation.cs index 1916a7338..59562b865 100644 --- a/src/Akavache.Sqlite3/Operations/IPreparedSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/IPreparedSqliteOperation.cs @@ -1,11 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Sqlite3.Internal; - using Splat; +using SQLite; namespace Akavache.Sqlite3; @@ -18,4 +17,4 @@ internal interface IPreparedSqliteOperation : IEnableLogger, IDisposable /// Gets the connection to the SQLite database. /// SQLiteConnection Connection { get; } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/InvalidateAllSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/InvalidateAllSqliteOperation.cs index a7d37d7b0..689ea575a 100644 --- a/src/Akavache.Sqlite3/Operations/InvalidateAllSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/InvalidateAllSqliteOperation.cs @@ -1,29 +1,39 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; -internal class InvalidateAllSqliteOperation : IPreparedSqliteOperation +internal class InvalidateAllSqliteOperation(SQLiteConnection connection) : IPreparedSqliteOperation { - private readonly SQLiteConnection _connection; - - public InvalidateAllSqliteOperation(SQLiteConnection connection) - { - _connection = connection; - Connection = connection; - } + private readonly SQLiteConnection _connection = connection; + private bool _disposedValue; - public SQLiteConnection Connection { get; protected set; } + public SQLiteConnection Connection { get; protected set; } = connection; public Action PrepareToExecute() => () => this.Checked(raw.sqlite3_exec(_connection.Handle, "DELETE FROM CacheElement")); public void Dispose() { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + _connection.Dispose(); + } + + _disposedValue = true; + } } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/OperationType.cs b/src/Akavache.Sqlite3/Operations/OperationType.cs index 2f7ec3f8b..3f13ba465 100644 --- a/src/Akavache.Sqlite3/Operations/OperationType.cs +++ b/src/Akavache.Sqlite3/Operations/OperationType.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs b/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs index 09d59cc13..7b2d6eb3a 100644 --- a/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs +++ b/src/Akavache.Sqlite3/Operations/SqliteOperationMixin.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Sqlite3.Internal; - using Splat; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -22,9 +20,9 @@ public static SQLite3.Result Checked(this IPreparedSqliteOperation connection, i } var err = raw.sqlite3_errmsg(connection.Connection.Handle).utf8_to_string(); - var ex = new SQLiteException(result, (message ?? string.Empty) + ": " + err); + var ex = SQLiteException.New(result, (message ?? string.Empty) + ": " + err); connection.Log().Warn(ex, message); throw ex; } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Operations/VacuumSqliteOperation.cs b/src/Akavache.Sqlite3/Operations/VacuumSqliteOperation.cs index b5407ff1c..5aa98f777 100644 --- a/src/Akavache.Sqlite3/Operations/VacuumSqliteOperation.cs +++ b/src/Akavache.Sqlite3/Operations/VacuumSqliteOperation.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reactive.Disposables; - -using Akavache.Sqlite3.Internal; - +using SQLite; using SQLitePCL; namespace Akavache.Sqlite3; @@ -24,7 +22,7 @@ public VacuumSqliteOperation(SQLiteConnection conn, IScheduler scheduler) if (vacuumResult != SQLite3.Result.OK) { - throw new SQLiteException(vacuumResult, "Couldn't prepare vacuum statement"); + throw SQLiteException.New(vacuumResult, "Couldn't prepare vacuum statement"); } _scheduler = scheduler; @@ -51,4 +49,4 @@ public Action PrepareToExecute() } public void Dispose() => Interlocked.Exchange(ref _inner, Disposable.Empty).Dispose(); -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Properties/AssemblyInfo.cs b/src/Akavache.Sqlite3/Properties/AssemblyInfo.cs index b65f64488..5f67cc443 100644 --- a/src/Akavache.Sqlite3/Properties/AssemblyInfo.cs +++ b/src/Akavache.Sqlite3/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/Queues/OperationQueue.cs b/src/Akavache.Sqlite3/Queues/OperationQueue.cs index 3e42b9205..f1cb16b6e 100644 --- a/src/Akavache.Sqlite3/Queues/OperationQueue.cs +++ b/src/Akavache.Sqlite3/Queues/OperationQueue.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -7,10 +7,8 @@ using System.Reactive.Disposables; using System.Reactive.Threading.Tasks; -using Akavache.Sqlite3.Internal; - using Splat; - +using SQLite; using AsyncLock = Akavache.Sqlite3.Internal.AsyncLock; namespace Akavache.Sqlite3; @@ -35,7 +33,7 @@ internal partial class SqliteOperationQueue : IEnableLogger, IDisposable private readonly Lazy _begin; private readonly Lazy _commit; - private BlockingCollection _operationQueue = new(); + private BlockingCollection _operationQueue = []; [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA2213: dispose field", Justification = "Will be invalid")] private IDisposable? _start; @@ -486,4 +484,4 @@ private void MarshalCompletion(object completion, Func block, IObservable< _scheduler.Schedule(() => subj.OnError(ex)); } } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs b/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs index e60b1fe51..396f55046 100644 --- a/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs +++ b/src/Akavache.Sqlite3/Queues/OperationQueueCoalescing.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/Queues/OperationQueueItem.cs b/src/Akavache.Sqlite3/Queues/OperationQueueItem.cs index ea476634b..f20c79f74 100644 --- a/src/Akavache.Sqlite3/Queues/OperationQueueItem.cs +++ b/src/Akavache.Sqlite3/Queues/OperationQueueItem.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -7,19 +7,13 @@ namespace Akavache.Sqlite3; -internal class OperationQueueItem +internal class OperationQueueItem(object completion, IEnumerable? parameters) { - public OperationQueueItem(object completion, IEnumerable? parameters) - { - Completion = completion; - Parameters = parameters; - } - public OperationType OperationType { get; set; } - public IEnumerable? Parameters { get; set; } + public IEnumerable? Parameters { get; set; } = parameters; - public object Completion { get; set; } + public object Completion { get; set; } = completion; public IEnumerable? ParametersAsElements => (IEnumerable?)Parameters; diff --git a/src/Akavache.Sqlite3/Registrations.cs b/src/Akavache.Sqlite3/Registrations.cs index 3cd75360f..d469a9e81 100644 --- a/src/Akavache.Sqlite3/Registrations.cs +++ b/src/Akavache.Sqlite3/Registrations.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -36,12 +36,7 @@ public void Register(IMutableDependencyResolver resolver, IReadonlyDependencyRes // NB: We want the most recently registered fs, since there really // only should be one - var fs = Locator.Current.GetService(); - if (fs is null) - { - throw new InvalidOperationException("Failed to initialize Akavache properly. Do you have a reference to Akavache.dll?"); - } - + var fs = Locator.Current.GetService() ?? throw new InvalidOperationException("Failed to initialize Akavache properly. Do you have a reference to Akavache.dll?"); var localCache = new Lazy(() => { var directory = fs.GetDefaultLocalMachineCacheDirectory(); diff --git a/src/Akavache.Sqlite3/SQLite.cs b/src/Akavache.Sqlite3/SQLite.cs deleted file mode 100644 index 2518affa1..000000000 --- a/src/Akavache.Sqlite3/SQLite.cs +++ /dev/null @@ -1,3337 +0,0 @@ -// - -// Copyright (c) 2009-2012 Krueger Systems, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -#if WINDOWS_PHONE && !USE_WP8_NATIVE_SQLITE && !USE_SQLITEPCL_RAW -#define USE_CSHARP_SQLITE -#endif - -#if NETFX_CORE -#define USE_NEW_REFLECTION_API -#endif - -using System.Diagnostics; -#if !USE_SQLITEPCL_RAW -using System.Runtime.InteropServices; -#endif -using System.Reflection; -using System.Linq.Expressions; - -#if USE_CSHARP_SQLITE -using Sqlite3 = Community.CsharpSqlite.Sqlite3; -using Sqlite3DatabaseHandle = Community.CsharpSqlite.Sqlite3.sqlite3; -using Sqlite3Statement = Community.CsharpSqlite.Sqlite3.Vdbe; -#elif USE_WP8_NATIVE_SQLITE -using Sqlite3 = Sqlite.Sqlite3; -using Sqlite3DatabaseHandle = Sqlite.Database; -using Sqlite3Statement = Sqlite.Statement; -#elif USE_SQLITEPCL_RAW -using Sqlite3DatabaseHandle = SQLitePCL.sqlite3; -using Sqlite3Statement = SQLitePCL.sqlite3_stmt; -using Sqlite3Raw = SQLitePCL.raw; -#else -using Sqlite3DatabaseHandle = System.IntPtr; -using Sqlite3Statement = System.IntPtr; -#endif - -namespace Akavache.Sqlite3.Internal -{ - public class SQLiteException : Exception - { - public SQLite3.Result Result { get; private set; } - - public SQLiteException(SQLite3.Result r, string message) : base(message) => Result = r; - - public static SQLiteException New(SQLite3.Result r, string message) => new(r, message); - } - - public class NotNullConstraintViolationException : SQLiteException - { - public IEnumerable Columns { get; protected set; } - - protected NotNullConstraintViolationException(SQLite3.Result r, string message) - : this(r, message, null, null) - { - - } - - protected NotNullConstraintViolationException(SQLite3.Result r, string message, TableMapping mapping, object obj) - : base(r, message) - { - if (mapping is not null && obj is not null) - { - Columns = mapping.Columns.Where(c => c.IsNullable == false && c.GetValue(obj) is null); - } - } - - public static new NotNullConstraintViolationException New(SQLite3.Result r, string message) => new(r, message); - - public static NotNullConstraintViolationException New(SQLite3.Result r, string message, TableMapping mapping, object obj) => new(r, message, mapping, obj); - - public static NotNullConstraintViolationException New(SQLiteException exception, TableMapping mapping, object obj) => new(exception.Result, exception.Message, mapping, obj); - } - - [Flags] - public enum SQLiteOpenFlags - { - ReadOnly = 1, ReadWrite = 2, Create = 4, - NoMutex = 0x8000, FullMutex = 0x10000, - SharedCache = 0x20000, PrivateCache = 0x40000, - ProtectionComplete = 0x00100000, - ProtectionCompleteUnlessOpen = 0x00200000, - ProtectionCompleteUntilFirstUserAuthentication = 0x00300000, - ProtectionNone = 0x00400000 - } - - [Flags] - public enum CreateFlags - { - None = 0, - ImplicitPK = 1, // create a primary key for field called 'Id' (Orm.ImplicitPkName) - ImplicitIndex = 2, // create an index for fields ending in 'Id' (Orm.ImplicitIndexSuffix) - AllImplicit = 3, // do both above - - AutoIncPK = 4 // force PK field to be auto inc - } - - /// - /// Represents an open connection to a SQLite database. - /// - public partial class SQLiteConnection : IDisposable - { - /// - /// Used to list some code that we want the MonoTouch linker - /// to see, but that we never want to actually execute. - /// -#pragma warning disable CS0649 // Field 'SQLiteConnection._preserveDuringLinkMagic' is never assigned to, and will always have its default value false - private static bool _preserveDuringLinkMagic; -#pragma warning restore CS0649 - - private bool _open; - private TimeSpan _busyTimeout; - private Dictionary _mappings = null; - private Dictionary _tables = null; - private Stopwatch _sw; - private long _elapsedMilliseconds = 0; - - private int _transactionDepth = 0; - private readonly Random _rand = new(); - - public Sqlite3DatabaseHandle Handle { get; private set; } - internal static readonly Sqlite3DatabaseHandle NullHandle = default; - - public string DatabasePath { get; private set; } - - public bool TimeExecution { get; set; } - - public bool Trace { get; set; } - - public bool StoreDateTimeAsTicks { get; private set; } - - /// - /// Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath. - /// - /// - /// Specifies the path to the database file. - /// - /// - /// Specifies whether to store DateTime properties as ticks (true) or strings (false). You - /// absolutely do want to store them as Ticks in all new projects. The default of false is - /// only here for backwards compatibility. There is a *significant* speed advantage, with no - /// down sides, when setting storeDateTimeAsTicks = true. - /// - public SQLiteConnection(string databasePath, bool storeDateTimeAsTicks = false) - : this(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks) - { - } - - /// - /// Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath. - /// - /// - /// Specifies the path to the database file. - /// - /// The flags to use to open the database. - /// - /// Specifies whether to store DateTime properties as ticks (true) or strings (false). You - /// absolutely do want to store them as Ticks in all new projects. The default of false is - /// only here for backwards compatibility. There is a *significant* speed advantage, with no - /// down sides, when setting storeDateTimeAsTicks = true. - /// - public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false) - { - if (string.IsNullOrEmpty(databasePath)) - throw new ArgumentException("Must be specified", nameof(databasePath)); - - DatabasePath = databasePath; - -#if NETFX_CORE && !USE_SQLITEPCL_RAW - SQLite3.SetDirectory(/*temp directory type*/2, Windows.Storage.ApplicationData.Current.TemporaryFolder.Path); -#endif - -#if USE_CSHARP_SQLITE || USE_SQLITEPCL_RAW - var r = SQLite3.Open(databasePath, out var handle, (int)openFlags, IntPtr.Zero); -#else - // open using the byte[] - // in the case where the path may include Unicode - // force open to using UTF-8 using sqlite3_open_v2 - var databasePathAsBytes = GetNullTerminatedUtf8 (DatabasePath); - var r = SQLite3.Open (databasePathAsBytes, out handle, (int) openFlags, IntPtr.Zero); -#endif - - Handle = handle; - if (r != SQLite3.Result.OK) - { - throw SQLiteException.New(r, $"Could not open database file: {DatabasePath} ({r})"); - } - _open = true; - - StoreDateTimeAsTicks = storeDateTimeAsTicks; - - BusyTimeout = TimeSpan.FromSeconds(0.1); - } - - static SQLiteConnection() - { - if (_preserveDuringLinkMagic) - { - var ti = new ColumnInfo(); - ti.Name = "magic"; - } - } - -#if !USE_SQLITEPCL_RAW - public void EnableLoadExtension(int onoff) - { - SQLite3.Result r = SQLite3.EnableLoadExtension(Handle, onoff); - if (r != SQLite3.Result.OK) { - string msg = SQLite3.GetErrmsg (Handle); - throw SQLiteException.New (r, msg); - } - } -#endif - -#if !USE_SQLITEPCL_RAW - static byte[] GetNullTerminatedUtf8 (string s) - { - var utf8Length = System.Text.Encoding.UTF8.GetByteCount (s); - var bytes = new byte [utf8Length + 1]; - utf8Length = System.Text.Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0); - return bytes; - } -#endif - - /// - /// Sets a busy handler to sleep the specified amount of time when a table is locked. - /// The handler will sleep multiple times until a total time of has accumulated. - /// - public TimeSpan BusyTimeout - { - get => _busyTimeout; - set - { - _busyTimeout = value; - if (Handle == NullHandle) - { - SQLite3.BusyTimeout(Handle, (int)_busyTimeout.TotalMilliseconds); - } - } - } - - /// - /// Returns the mappings from types to tables that the connection - /// currently understands. - /// - public IEnumerable TableMappings => _tables is not null ? _tables.Values : Enumerable.Empty(); - - /// - /// Retrieves the mapping that is automatically generated for the given type. - /// - /// - /// The type whose mapping to the database is returned. - /// - /// - /// Optional flags allowing implicit PK and indexes based on naming conventions - /// - /// - /// The mapping represents the schema of the columns of the database and contains - /// methods to set and get properties of objects. - /// - public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None) - { - _mappings ??= new(); - - if (!_mappings.TryGetValue(type.FullName, out var map)) - { - map = new(type, createFlags); - _mappings[type.FullName] = map; - } - return map; - } - - /// - /// Retrieves the mapping that is automatically generated for the given type. - /// - /// - /// The mapping represents the schema of the columns of the database and contains - /// methods to set and get properties of objects. - /// - public TableMapping GetMapping() => GetMapping(typeof(T)); - - private struct IndexedColumn - { - public int Order; - public string ColumnName; - } - - private struct IndexInfo - { - public string IndexName; - public string TableName; - public bool Unique; - public List Columns; - } - - /// - /// Executes a "drop table" on the database. This is non-recoverable. - /// - public int DropTable() - { - var map = GetMapping(typeof(T)); - - var query = $"drop table if exists \"{map.TableName}\""; - - return Execute(query); - } - - /// - /// Executes a "create table if not exists" on the database. It also - /// creates any specified indexes on the columns of the table. It uses - /// a schema automatically generated from the specified type. You can - /// later access this schema by calling GetMapping. - /// - /// - /// The number of entries added to the database schema. - /// - public int CreateTable(CreateFlags createFlags = CreateFlags.None) => CreateTable(typeof(T), createFlags); - - /// - /// Executes a "create table if not exists" on the database. It also - /// creates any specified indexes on the columns of the table. It uses - /// a schema automatically generated from the specified type. You can - /// later access this schema by calling GetMapping. - /// - /// Type to reflect to a database table. - /// Optional flags allowing implicit PK and indexes based on naming conventions. - /// - /// The number of entries added to the database schema. - /// - public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None) - { - _tables ??= new(); - - if (!_tables.TryGetValue(ty.FullName, out var map)) - { - map = GetMapping(ty, createFlags); - _tables.Add(ty.FullName, map); - } - var query = "create table if not exists \"" + map.TableName + "\"(\n"; - - var decls = map.Columns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks)); - var decl = string.Join(",\n", decls.ToArray()); - query += decl; - query += ")"; - - var count = Execute(query); - - if (count == 0) - { //Possible bug: This always seems to return 0? - // Table already exists, migrate it - MigrateTable(map); - } - - var indexes = new Dictionary(); - foreach (var c in map.Columns) - { - foreach (var i in c.Indices) - { - var iname = i.Name ?? map.TableName + "_" + c.Name; - if (!indexes.TryGetValue(iname, out var iinfo)) - { - iinfo = new() - { - IndexName = iname, - TableName = map.TableName, - Unique = i.Unique, - Columns = new() - }; - indexes.Add(iname, iinfo); - } - - if (i.Unique != iinfo.Unique) - throw new("All the columns in an index must have the same value for their Unique property"); - - iinfo.Columns.Add(new() - { - Order = i.Order, - ColumnName = c.Name - }); - } - } - - foreach (var indexName in indexes.Keys) - { - var index = indexes[indexName]; - var columns = index.Columns.OrderBy(i => i.Order).Select(i => i.ColumnName).ToArray(); - count += CreateIndex(indexName, index.TableName, columns, index.Unique); - } - - return count; - } - - /// - /// Creates an index for the specified table and columns. - /// - /// Name of the index to create - /// Name of the database table - /// An array of column names to index - /// Whether the index should be unique - public int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false) - { - const string sqlFormat = "create {2} index if not exists \"{3}\" on \"{0}\"(\"{1}\")"; - var sql = string.Format(sqlFormat, tableName, string.Join("\", \"", columnNames), unique ? "unique" : "", indexName); - return Execute(sql); - } - - /// - /// Creates an index for the specified table and column. - /// - /// Name of the index to create - /// Name of the database table - /// Name of the column to index - /// Whether the index should be unique - public int CreateIndex(string indexName, string tableName, string columnName, bool unique = false) => CreateIndex(indexName, tableName, new[] { columnName }, unique); - - /// - /// Creates an index for the specified table and column. - /// - /// Name of the database table - /// Name of the column to index - /// Whether the index should be unique - public int CreateIndex(string tableName, string columnName, bool unique = false) => CreateIndex(tableName + "_" + columnName, tableName, columnName, unique); - - /// - /// Creates an index for the specified table and columns. - /// - /// Name of the database table - /// An array of column names to index - /// Whether the index should be unique - public int CreateIndex(string tableName, string[] columnNames, bool unique = false) => CreateIndex(tableName + "_" + string.Join("_", columnNames), tableName, columnNames, unique); - - /// - /// Creates an index for the specified object property. - /// e.g. CreateIndex(c => c.Name); - /// - /// Type to reflect to a database table. - /// Property to index - /// Whether the index should be unique - public void CreateIndex(Expression> property, bool unique = false) - { - MemberExpression mx; - if (property.Body.NodeType == ExpressionType.Convert) - { - mx = ((UnaryExpression)property.Body).Operand as MemberExpression; - } - else - { - mx = (property.Body as MemberExpression); - } - - if (mx?.Member is not PropertyInfo propertyInfo) - { - throw new ArgumentException("The lambda expression 'property' should point to a valid Property"); - } - - var propName = propertyInfo.Name; - - var map = GetMapping(); - var colName = map.FindColumnWithPropertyName(propName).Name; - - CreateIndex(map.TableName, colName, unique); - } - - /// - /// Information about a column in the sql lite schema. - /// - public class ColumnInfo - { - // public int cid { get; set; } - - /// - /// Gets or sets the name of the column. - /// - [Column("name")] - public string Name { get; set; } - - // [Column ("type")] - // public string ColumnType { get; set; } - - public int notnull { get; set; } - - // public string dflt_value { get; set; } - - // public int pk { get; set; } - - public override string ToString() => Name; - } - - public List GetTableInfo(string tableName) - { - var query = "pragma table_info(\"" + tableName + "\")"; - return Query(query); - } - - void MigrateTable(TableMapping map) - { - var existingCols = GetTableInfo(map.TableName); - - var toBeAdded = new List(); - - foreach (var p in map.Columns) - { - var found = false; - foreach (var c in existingCols) - { - found = (string.Compare(p.Name, c.Name, StringComparison.OrdinalIgnoreCase) == 0); - if (found) - break; - } - if (!found) - { - toBeAdded.Add(p); - } - } - - foreach (var p in toBeAdded) - { - var addCol = "alter table \"" + map.TableName + "\" add column " + Orm.SqlDecl(p, StoreDateTimeAsTicks); - Execute(addCol); - } - } - - /// - /// Creates a new SQLiteCommand. Can be overridden to provide a sub-class. - /// - /// - protected virtual SQLiteCommand NewCommand() => new(this); - - /// - /// Creates a new SQLiteCommand given the command text with arguments. Place a '?' - /// in the command text for each of the arguments. - /// - /// - /// The fully escaped SQL. - /// - /// - /// Arguments to substitute for the occurrences of '?' in the command text. - /// - /// - /// A - /// - public SQLiteCommand CreateCommand(string cmdText, params object[] ps) - { - if (!_open) - throw SQLiteException.New(SQLite3.Result.Error, "Cannot create commands from unopened database"); - - var cmd = NewCommand(); - cmd.CommandText = cmdText; - foreach (var o in ps) - { - cmd.Bind(o); - } - return cmd; - } - - /// - /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?' - /// in the command text for each of the arguments and then executes that command. - /// Use this method instead of Query when you don't expect rows back. Such cases include - /// INSERTs, UPDATEs, and DELETEs. - /// You can set the Trace or TimeExecution properties of the connection - /// to profile execution. - /// - /// - /// The fully escaped SQL. - /// - /// - /// Arguments to substitute for the occurrences of '?' in the query. - /// - /// - /// The number of rows modified in the database as a result of this execution. - /// - public int Execute(string query, params object[] args) - { - var cmd = CreateCommand(query, args); - - if (TimeExecution) - { - _sw ??= new(); - _sw.Reset(); - _sw.Start(); - } - - var r = cmd.ExecuteNonQuery(); - - if (TimeExecution) - { - _sw.Stop(); - _elapsedMilliseconds += _sw.ElapsedMilliseconds; - Debug.WriteLine($"Finished in {_sw.ElapsedMilliseconds} ms ({_elapsedMilliseconds / 1000.0:0.0} s total)"); - } - - return r; - } - - public T ExecuteScalar(string query, params object[] args) - { - var cmd = CreateCommand(query, args); - - if (TimeExecution) - { - _sw ??= new(); - _sw.Reset(); - _sw.Start(); - } - - var r = cmd.ExecuteScalar(); - - if (TimeExecution) - { - _sw.Stop(); - _elapsedMilliseconds += _sw.ElapsedMilliseconds; - Debug.WriteLine($"Finished in {_sw.ElapsedMilliseconds} ms ({_elapsedMilliseconds / 1000.0:0.0} s total)"); - } - - return r; - } - - /// - /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?' - /// in the command text for each of the arguments and then executes that command. - /// It returns each row of the result using the mapping automatically generated for - /// the given type. - /// - /// - /// The fully escaped SQL. - /// - /// - /// Arguments to substitute for the occurences of '?' in the query. - /// - /// - /// An enumerable with one result for each row returned by the query. - /// - public List Query(string query, params object[] args) where T : new() - { - var cmd = CreateCommand(query, args); - return cmd.ExecuteQuery(); - } - - /// - /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?' - /// in the command text for each of the arguments and then executes that command. - /// It returns each row of the result using the mapping automatically generated for - /// the given type. - /// - /// - /// The fully escaped SQL. - /// - /// - /// Arguments to substitute for the occurences of '?' in the query. - /// - /// - /// An enumerable with one result for each row returned by the query. - /// The enumerator will call sqlite3_step on each call to MoveNext, so the database - /// connection must remain open for the lifetime of the enumerator. - /// - public IEnumerable DeferredQuery(string query, params object[] args) where T : new() - { - var cmd = CreateCommand(query, args); - return cmd.ExecuteDeferredQuery(); - } - - /// - /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?' - /// in the command text for each of the arguments and then executes that command. - /// It returns each row of the result using the specified mapping. This function is - /// only used by libraries in order to query the database via introspection. It is - /// normally not used. - /// - /// - /// A to use to convert the resulting rows - /// into objects. - /// - /// - /// The fully escaped SQL. - /// - /// - /// Arguments to substitute for the occurrences of '?' in the query. - /// - /// - /// An enumerable with one result for each row returned by the query. - /// - public List Query(TableMapping map, string query, params object[] args) - { - var cmd = CreateCommand(query, args); - return cmd.ExecuteQuery(map); - } - - /// - /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?' - /// in the command text for each of the arguments and then executes that command. - /// It returns each row of the result using the specified mapping. This function is - /// only used by libraries in order to query the database via introspection. It is - /// normally not used. - /// - /// - /// A to use to convert the resulting rows - /// into objects. - /// - /// - /// The fully escaped SQL. - /// - /// - /// Arguments to substitute for the occurrences of '?' in the query. - /// - /// - /// An enumerable with one result for each row returned by the query. - /// The enumerator will call sqlite3_step on each call to MoveNext, so the database - /// connection must remain open for the lifetime of the enumerator. - /// - public IEnumerable DeferredQuery(TableMapping map, string query, params object[] args) - { - var cmd = CreateCommand(query, args); - return cmd.ExecuteDeferredQuery(map); - } - - /// - /// Returns a queryable interface to the table represented by the given type. - /// - /// - /// A queryable object that is able to translate Where, OrderBy, and Take - /// queries into native SQL. - /// - public TableQuery Table() where T : new() => new(this); - - /// - /// Attempts to retrieve an object with the given primary key from the table - /// associated with the specified type. Use of this method requires that - /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute). - /// - /// - /// The primary key. - /// - /// - /// The object with the given primary key. Throws a not found exception - /// if the object is not found. - /// - public T Get(object pk) where T : new() - { - var map = GetMapping(typeof(T)); - return Query(map.GetByPrimaryKeySql, pk).First(); - } - - /// - /// Attempts to retrieve the first object that matches the predicate from the table - /// associated with the specified type. - /// - /// - /// A predicate for which object to find. - /// - /// - /// The object that matches the given predicate. Throws a not found exception - /// if the object is not found. - /// - public T Get(Expression> predicate) where T : new() => Table().Where(predicate).First(); - - /// - /// Attempts to retrieve an object with the given primary key from the table - /// associated with the specified type. Use of this method requires that - /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute). - /// - /// - /// The primary key. - /// - /// - /// The object with the given primary key or null - /// if the object is not found. - /// - public T Find(object pk) where T : new() - { - var map = GetMapping(typeof(T)); - return Query(map.GetByPrimaryKeySql, pk).FirstOrDefault(); - } - - /// - /// Attempts to retrieve an object with the given primary key from the table - /// associated with the specified type. Use of this method requires that - /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute). - /// - /// - /// The primary key. - /// - /// - /// The TableMapping used to identify the object type. - /// - /// - /// The object with the given primary key or null - /// if the object is not found. - /// - public object Find(object pk, TableMapping map) => Query(map, map.GetByPrimaryKeySql, pk).FirstOrDefault(); - - /// - /// Attempts to retrieve the first object that matches the predicate from the table - /// associated with the specified type. - /// - /// - /// A predicate for which object to find. - /// - /// - /// The object that matches the given predicate or null - /// if the object is not found. - /// - public T Find(Expression> predicate) where T : new() => Table().Where(predicate).FirstOrDefault(); - - /// - /// Whether has been called and the database is waiting for a . - /// - public bool IsInTransaction => _transactionDepth > 0; - - /// - /// Begins a new transaction. Call to end the transaction. - /// - /// Throws if a transaction has already begun. - public void BeginTransaction() - { - // The BEGIN command only works if the transaction stack is empty, - // or in other words if there are no pending transactions. - // If the transaction stack is not empty when the BEGIN command is invoked, - // then the command fails with an error. - // Rather than crash with an error, we will just ignore calls to BeginTransaction - // that would result in an error. - if (Interlocked.CompareExchange(ref _transactionDepth, 1, 0) == 0) - { - try - { - Execute("begin transaction"); - } - catch (Exception ex) - { - if (ex is SQLiteException sqlExp) - { - // It is recommended that applications respond to the errors listed below - // by explicitly issuing a ROLLBACK command. - // TODO: This rollback failsafe should be localized to all throw sites. - switch (sqlExp.Result) - { - case SQLite3.Result.IOError: - case SQLite3.Result.Full: - case SQLite3.Result.Busy: - case SQLite3.Result.NoMem: - case SQLite3.Result.Interrupt: - RollbackTo(null, true); - break; - } - } - else - { - // Call decrement and not VolatileWrite in case we've already - // created a transaction point in SaveTransactionPoint since the catch. - Interlocked.Decrement(ref _transactionDepth); - } - - throw; - } - } - else - { - // Calling BeginTransaction on an already open transaction is invalid - throw new InvalidOperationException("Cannot begin a transaction while already in a transaction."); - } - } - - /// - /// Creates a savepoint in the database at the current point in the transaction timeline. - /// Begins a new transaction if one is not in progress. - /// - /// Call to undo transactions since the returned savepoint. - /// Call to commit transactions after the savepoint returned here. - /// Call to end the transaction, committing all changes. - /// - /// A string naming the savepoint. - public string SaveTransactionPoint() - { - int depth = Interlocked.Increment(ref _transactionDepth) - 1; - string retVal = "S" + _rand.Next(short.MaxValue) + "D" + depth; - - try - { - Execute("savepoint " + retVal); - } - catch (Exception ex) - { - if (ex is SQLiteException sqlExp) - { - // It is recommended that applications respond to the errors listed below - // by explicitly issuing a ROLLBACK command. - // TODO: This rollback failsafe should be localized to all throw sites. - switch (sqlExp.Result) - { - case SQLite3.Result.IOError: - case SQLite3.Result.Full: - case SQLite3.Result.Busy: - case SQLite3.Result.NoMem: - case SQLite3.Result.Interrupt: - RollbackTo(null, true); - break; - } - } - else - { - Interlocked.Decrement(ref _transactionDepth); - } - - throw; - } - - return retVal; - } - - /// - /// Rolls back the transaction that was begun by or . - /// - public void Rollback() => RollbackTo(null, false); - - /// - /// Rolls back the savepoint created by or SaveTransactionPoint. - /// - /// The name of the savepoint to roll back to, as returned by . If savepoint is null or empty, this method is equivalent to a call to - public void RollbackTo(string savepoint) => RollbackTo(savepoint, false); - - /// - /// Rolls back the transaction that was begun by . - /// - /// The name of the save point. - /// true to avoid throwing exceptions, false otherwise - void RollbackTo(string savePoint, bool noThrow) - { - // Rolling back without a TO clause rolls backs all transactions - // and leaves the transaction stack empty. - try - { - if (string.IsNullOrEmpty(savePoint)) - { - if (Interlocked.Exchange(ref _transactionDepth, 0) > 0) - { - Execute("rollback"); - } - } - else - { - DoSavePointExecute(savePoint, "rollback to "); - } - } - catch (SQLiteException) - { - if (!noThrow) - throw; - - } - // No need to rollback if there are no transactions open. - } - - /// - /// Releases a savepoint returned from . Releasing a savepoint - /// makes changes since that savepoint permanent if the savepoint began the transaction, - /// or otherwise the changes are permanent pending a call to . - /// - /// The RELEASE command is like a COMMIT for a SAVEPOINT. - /// - /// The name of the savepoint to release. The string should be the result of a call to - public void Release(string savepoint) => DoSavePointExecute(savepoint, "release "); - - void DoSavePointExecute(string savepoint, string cmd) - { - // Validate the savepoint - int firstLen = savepoint.IndexOf('D'); - if (firstLen >= 2 && savepoint.Length > firstLen + 1) - { - if (int.TryParse(savepoint.Substring(firstLen + 1), out var depth)) - { - // TODO: Mild race here, but inescapable without locking almost everywhere. - if (0 <= depth && depth < _transactionDepth) - { -#if NETFX_CORE || USE_SQLITEPCL_RAW - Volatile.Write(ref _transactionDepth, depth); -#else - Thread.VolatileWrite (ref _transactionDepth, depth); -#endif - Execute(cmd + savepoint); - return; - } - } - } - - throw new ArgumentException("savePoint is not valid, and should be the result of a call to SaveTransactionPoint.", "savePoint"); - } - - /// - /// Commits the transaction that was begun by . - /// - public void Commit() - { - if (Interlocked.Exchange(ref _transactionDepth, 0) != 0) - { - Execute("commit"); - } - // Do nothing on a commit with no open transaction - } - - /// - /// Executes the action within a (possibly nested) transaction by wrapping it in a SAVEPOINT. If an - /// exception occurs the whole transaction is rolled back, not just the current savepoint. The exception - /// is rethrown. - /// - /// - /// The to perform within a transaction. This parameter can contain any number - /// of operations on the connection but should never call or - /// . - /// - public void RunInTransaction(Action action) - { - try - { - var savePoint = SaveTransactionPoint(); - action(); - Release(savePoint); - } - catch (Exception) - { - Rollback(); - throw; - } - } - - /// - /// Inserts all specified objects. - /// - /// - /// An of the objects to insert. - /// - /// - /// The number of rows added to the table. - /// - public int InsertAll(System.Collections.IEnumerable objects) - { - var c = 0; - RunInTransaction(() => - { - foreach (var r in objects) - { - c += Insert(r); - } - }); - return c; - } - - /// - /// Inserts all specified objects. - /// - /// - /// An of the objects to insert. - /// - /// - /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ... - /// - /// - /// The number of rows added to the table. - /// - public int InsertAll(System.Collections.IEnumerable objects, string extra) - { - var c = 0; - RunInTransaction(() => - { - foreach (var r in objects) - { - c += Insert(r, extra); - } - }); - return c; - } - - /// - /// Inserts all specified objects. - /// - /// - /// An of the objects to insert. - /// - /// - /// The type of object to insert. - /// - /// - /// The number of rows added to the table. - /// - public int InsertAll(System.Collections.IEnumerable objects, Type objType) - { - var c = 0; - RunInTransaction(() => - { - foreach (var r in objects) - { - c += Insert(r, objType); - } - }); - return c; - } - - /// - /// Inserts the given object and retrieves its - /// auto incremented primary key if it has one. - /// - /// - /// The object to insert. - /// - /// - /// The number of rows added to the table. - /// - public int Insert(object obj) - { - if (obj is null) - { - return 0; - } - return Insert(obj, "", obj.GetType()); - } - - /// - /// Inserts the given object and retrieves its - /// auto incremented primary key if it has one. - /// If a UNIQUE constraint violation occurs with - /// some pre-existing object, this function deletes - /// the old object. - /// - /// - /// The object to insert. - /// - /// - /// The number of rows modified. - /// - public int InsertOrReplace(object obj) - { - if (obj is null) - { - return 0; - } - return Insert(obj, "OR REPLACE", obj.GetType()); - } - - /// - /// Inserts the given object and retrieves its - /// auto incremented primary key if it has one. - /// - /// - /// The object to insert. - /// - /// - /// The type of object to insert. - /// - /// - /// The number of rows added to the table. - /// - public int Insert(object obj, Type objType) => Insert(obj, "", objType); - - /// - /// Inserts the given object and retrieves its - /// auto incremented primary key if it has one. - /// If a UNIQUE constraint violation occurs with - /// some pre-existing object, this function deletes - /// the old object. - /// - /// - /// The object to insert. - /// - /// - /// The type of object to insert. - /// - /// - /// The number of rows modified. - /// - public int InsertOrReplace(object obj, Type objType) => Insert(obj, "OR REPLACE", objType); - - /// - /// Inserts the given object and retrieves its - /// auto incremented primary key if it has one. - /// - /// - /// The object to insert. - /// - /// - /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ... - /// - /// - /// The number of rows added to the table. - /// - public int Insert(object obj, string extra) - { - if (obj is null) - { - return 0; - } - return Insert(obj, extra, obj.GetType()); - } - - /// - /// Inserts the given object and retrieves its - /// auto incremented primary key if it has one. - /// - /// - /// The object to insert. - /// - /// - /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ... - /// - /// - /// The type of object to insert. - /// - /// - /// The number of rows added to the table. - /// - public int Insert(object obj, string extra, Type objType) - { - if (obj is null || objType is null) - { - return 0; - } - - - var map = GetMapping(objType); - -#if USE_NEW_REFLECTION_API - if (map.PK is not null && map.PK.IsAutoGuid) - { - // no GetProperty so search our way up the inheritance chain till we find it - PropertyInfo prop; - while (objType is not null) - { - var info = objType.GetTypeInfo(); - prop = info.GetDeclaredProperty(map.PK.PropertyName); - if (prop is not null) - { - if (prop.GetValue(obj, null).Equals(Guid.Empty)) - { - prop.SetValue(obj, Guid.NewGuid(), null); - } - break; - } - - objType = info.BaseType; - } - } -#else - if (map.PK is not null && map.PK.IsAutoGuid) { - var prop = objType.GetProperty(map.PK.PropertyName); - if (prop is not null) { - if (prop.GetValue(obj, null).Equals(Guid.Empty)) { - prop.SetValue(obj, Guid.NewGuid(), null); - } - } - } -#endif - - - var replacing = string.Compare(extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0; - - var cols = replacing ? map.InsertOrReplaceColumns : map.InsertColumns; - var vals = new object[cols.Length]; - for (var i = 0; i < vals.Length; i++) - { - vals[i] = cols[i].GetValue(obj); - } - - var insertCmd = map.GetInsertCommand(this, extra); - int count; - - try - { - count = insertCmd.ExecuteNonQuery(vals); - } - catch (SQLiteException ex) - { - - if (SQLite3.ExtendedErrCode(Handle) == SQLite3.ExtendedResult.ConstraintNotNull) - { - throw NotNullConstraintViolationException.New(ex.Result, ex.Message, map, obj); - } - throw; - } - - if (map.HasAutoIncPK) - { - var id = SQLite3.LastInsertRowid(Handle); - map.SetAutoIncPK(obj, id); - } - - if (count > 0) - OnTableChanged(map, NotifyTableChangedAction.Insert); - - return count; - } - - /// - /// Updates all of the columns of a table using the specified object - /// except for its primary key. - /// The object is required to have a primary key. - /// - /// - /// The object to update. It must have a primary key designated using the PrimaryKeyAttribute. - /// - /// - /// The number of rows updated. - /// - public int Update(object obj) - { - if (obj is null) - { - return 0; - } - return Update(obj, obj.GetType()); - } - - /// - /// Updates all of the columns of a table using the specified object - /// except for its primary key. - /// The object is required to have a primary key. - /// - /// - /// The object to update. It must have a primary key designated using the PrimaryKeyAttribute. - /// - /// - /// The type of object to insert. - /// - /// - /// The number of rows updated. - /// - public int Update(object obj, Type objType) - { - int rowsAffected = 0; - if (obj is null || objType is null) - { - return 0; - } - - var map = GetMapping(objType); - - var pk = map.PK; - - if (pk is null) - { - throw new NotSupportedException("Cannot update " + map.TableName + ": it has no PK"); - } - - var cols = map.Columns.Where(p => p != pk).ToList(); - var vals = cols.Select(c => c.GetValue(obj)); - var ps = new List(vals); - ps.Add(pk.GetValue(obj)); - var q = - $"update \"{map.TableName}\" set {string.Join(",", (cols.Select(c => "\"" + c.Name + "\" = ? ")).ToArray())} where {pk.Name} = ? "; - - try - { - rowsAffected = Execute(q, ps.ToArray()); - } - catch (SQLiteException ex) - { - - if (ex.Result == SQLite3.Result.Constraint && SQLite3.ExtendedErrCode(Handle) == SQLite3.ExtendedResult.ConstraintNotNull) - { - throw NotNullConstraintViolationException.New(ex, map, obj); - } - - throw; - } - - if (rowsAffected > 0) - OnTableChanged(map, NotifyTableChangedAction.Update); - - return rowsAffected; - } - - /// - /// Updates all specified objects. - /// - /// - /// An of the objects to insert. - /// - /// - /// The number of rows modified. - /// - public int UpdateAll(System.Collections.IEnumerable objects) - { - var c = 0; - RunInTransaction(() => - { - foreach (var r in objects) - { - c += Update(r); - } - }); - return c; - } - - /// - /// Deletes the given object from the database using its primary key. - /// - /// - /// The object to delete. It must have a primary key designated using the PrimaryKeyAttribute. - /// - /// - /// The number of rows deleted. - /// - public int Delete(object objectToDelete) - { - var map = GetMapping(objectToDelete.GetType()); - var pk = map.PK; - if (pk is null) - { - throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); - } - var q = $"delete from \"{map.TableName}\" where \"{pk.Name}\" = ?"; - var count = Execute(q, pk.GetValue(objectToDelete)); - if (count > 0) - OnTableChanged(map, NotifyTableChangedAction.Delete); - return count; - } - - /// - /// Deletes the object with the specified primary key. - /// - /// - /// The primary key of the object to delete. - /// - /// - /// The number of objects deleted. - /// - /// - /// The type of object. - /// - public int Delete(object primaryKey) - { - var map = GetMapping(typeof(T)); - var pk = map.PK; - if (pk is null) - { - throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); - } - var q = $"delete from \"{map.TableName}\" where \"{pk.Name}\" = ?"; - var count = Execute(q, primaryKey); - if (count > 0) - OnTableChanged(map, NotifyTableChangedAction.Delete); - return count; - } - - /// - /// Deletes all the objects from the specified table. - /// WARNING WARNING: Let me repeat. It deletes ALL the objects from the - /// specified table. Do you really want to do that? - /// - /// - /// The number of objects deleted. - /// - /// - /// The type of objects to delete. - /// - public int DeleteAll() - { - var map = GetMapping(typeof(T)); - var query = $"delete from \"{map.TableName}\""; - var count = Execute(query); - if (count > 0) - OnTableChanged(map, NotifyTableChangedAction.Delete); - return count; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) => Close(); - - public void Close() - { - if (_open && Handle == NullHandle) - { - try - { - if (_mappings is not null) - { - foreach (var sqlInsertCommand in _mappings.Values) - { - sqlInsertCommand.Dispose(); - } - } - var r = SQLite3.Close(Handle); - if (r != SQLite3.Result.OK) - { - string msg = SQLite3.GetErrmsg(Handle); - throw SQLiteException.New(r, msg); - } - } - finally - { - Handle = NullHandle; - _open = false; - } - } - } - - void OnTableChanged(TableMapping table, NotifyTableChangedAction action) - { - var ev = TableChanged; - if (ev is not null) - ev(this, new(table, action)); - } - - public event EventHandler TableChanged; - } - - public class NotifyTableChangedEventArgs : EventArgs - { - public TableMapping Table { get; private set; } - public NotifyTableChangedAction Action { get; private set; } - - public NotifyTableChangedEventArgs(TableMapping table, NotifyTableChangedAction action) - { - Table = table; - Action = action; - } - } - - public enum NotifyTableChangedAction - { - Insert, - Update, - Delete, - } - - /// - /// Represents a parsed connection string. - /// - class SQLiteConnectionString - { - public string ConnectionString { get; private set; } - public string DatabasePath { get; private set; } - public bool StoreDateTimeAsTicks { get; private set; } - - public SQLiteConnectionString(string databasePath, bool storeDateTimeAsTicks) - { - ConnectionString = databasePath; - StoreDateTimeAsTicks = storeDateTimeAsTicks; - DatabasePath = databasePath; - } - } - - [AttributeUsage(AttributeTargets.Class)] - public class TableAttribute : Attribute - { - public string Name { get; set; } - - public TableAttribute(string name) => Name = name; - } - - [AttributeUsage(AttributeTargets.Property)] - public class ColumnAttribute : Attribute - { - public string Name { get; set; } - - public ColumnAttribute(string name) => Name = name; - } - - [AttributeUsage(AttributeTargets.Property)] - public class PrimaryKeyAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Property)] - public class AutoIncrementAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Property)] - public class IndexedAttribute : Attribute - { - public string Name { get; set; } - public int Order { get; set; } - public virtual bool Unique { get; set; } - - public IndexedAttribute() - { - } - - public IndexedAttribute(string name, int order) - { - Name = name; - Order = order; - } - } - - [AttributeUsage(AttributeTargets.Property)] - public class IgnoreAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Property)] - public class UniqueAttribute : IndexedAttribute - { - public override bool Unique - { - get => true; - set { /* throw? */ } - } - } - - [AttributeUsage(AttributeTargets.Property)] - public class MaxLengthAttribute : Attribute - { - public int Value { get; private set; } - - public MaxLengthAttribute(int length) => Value = length; - } - - [AttributeUsage(AttributeTargets.Property)] - public class CollationAttribute : Attribute - { - public string Value { get; private set; } - - public CollationAttribute(string collation) => Value = collation; - } - - [AttributeUsage(AttributeTargets.Property)] - public class NotNullAttribute : Attribute - { - } - - public class TableMapping - { - public Type MappedType { get; private set; } - - public string TableName { get; private set; } - - public Column[] Columns { get; private set; } - - public Column PK { get; private set; } - - public string GetByPrimaryKeySql { get; private set; } - - readonly Column _autoPk; - Column[] _insertColumns; - Column[] _insertOrReplaceColumns; - - public TableMapping(Type type, CreateFlags createFlags = CreateFlags.None) - { - MappedType = type; - -#if USE_NEW_REFLECTION_API - var tableAttr = (TableAttribute)CustomAttributeExtensions - .GetCustomAttribute(type.GetTypeInfo(), typeof(TableAttribute), true); -#else - var tableAttr = (TableAttribute)type.GetCustomAttributes (typeof (TableAttribute), true).FirstOrDefault (); -#endif - - TableName = tableAttr is not null ? tableAttr.Name : MappedType.Name; - -#if !USE_NEW_REFLECTION_API - var props = MappedType.GetProperties (BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty); -#else - var props = from p in MappedType.GetRuntimeProperties() - where ((p.GetMethod is not null && p.GetMethod.IsPublic) || (p.SetMethod is not null && p.SetMethod.IsPublic) || (p.GetMethod is not null && p.GetMethod.IsStatic) || (p.SetMethod is not null && p.SetMethod.IsStatic)) - select p; -#endif - var cols = new List(); - foreach (var p in props) - { -#if !USE_NEW_REFLECTION_API - var ignore = p.GetCustomAttributes (typeof(IgnoreAttribute), true).Length > 0; -#else - var ignore = p.GetCustomAttributes(typeof(IgnoreAttribute), true).Length > 0; -#endif - if (p.CanWrite && !ignore) - { - cols.Add(new(p, createFlags)); - } - } - Columns = cols.ToArray(); - foreach (var c in Columns) - { - if (c.IsAutoInc && c.IsPK) - { - _autoPk = c; - } - if (c.IsPK) - { - PK = c; - } - } - - HasAutoIncPK = _autoPk is not null; - - GetByPrimaryKeySql = PK is not null ? - $"select * from \"{TableName}\" where \"{PK.Name}\" = ?" : - $"select * from \"{TableName}\" limit 1"; - } - - public bool HasAutoIncPK { get; private set; } - - public void SetAutoIncPK(object obj, long id) - { - if (_autoPk is not null) - { - _autoPk.SetValue(obj, Convert.ChangeType(id, _autoPk.ColumnType, null)); - } - } - - public Column[] InsertColumns - { - get - { - if (_insertColumns is null) - { - _insertColumns = Columns.Where(c => !c.IsAutoInc).ToArray(); - } - return _insertColumns; - } - } - - public Column[] InsertOrReplaceColumns - { - get - { - if (_insertOrReplaceColumns is null) - { - _insertOrReplaceColumns = Columns.ToArray(); - } - return _insertOrReplaceColumns; - } - } - - public Column FindColumnWithPropertyName(string propertyName) - { - var exact = Columns.FirstOrDefault(c => c.PropertyName == propertyName); - return exact; - } - - public Column FindColumn(string columnName) - { - var exact = Columns.FirstOrDefault(c => c.Name == columnName); - return exact; - } - - PreparedSqlLiteInsertCommand _insertCommand; - string _insertCommandExtra; - - public PreparedSqlLiteInsertCommand GetInsertCommand(SQLiteConnection conn, string extra) - { - if (_insertCommand is null) - { - _insertCommand = CreateInsertCommand(conn, extra); - _insertCommandExtra = extra; - } - else if (_insertCommandExtra != extra) - { - _insertCommand.Dispose(); - _insertCommand = CreateInsertCommand(conn, extra); - _insertCommandExtra = extra; - } - return _insertCommand; - } - - PreparedSqlLiteInsertCommand CreateInsertCommand(SQLiteConnection conn, string extra) - { - var cols = InsertColumns; - string insertSql; - if (!cols.Any() && Columns.Length == 1 && Columns[0].IsAutoInc) - { - insertSql = string.Format("insert {1} into \"{0}\" default values", TableName, extra); - } - else - { - var replacing = string.Compare(extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0; - - if (replacing) - { - cols = InsertOrReplaceColumns; - } - - insertSql = string.Format("insert {3} into \"{0}\"({1}) values ({2})", TableName, - string.Join(",", (from c in cols - select "\"" + c.Name + "\"").ToArray()), - string.Join(",", (from c in cols - select "?").ToArray()), extra); - - } - - var insertCommand = new PreparedSqlLiteInsertCommand(conn); - insertCommand.CommandText = insertSql; - return insertCommand; - } - - protected internal void Dispose() - { - if (_insertCommand is not null) - { - _insertCommand.Dispose(); - _insertCommand = null; - } - } - - public class Column - { - readonly PropertyInfo _prop; - - public string Name { get; private set; } - - public string PropertyName => _prop.Name; - - public Type ColumnType { get; private set; } - - public string Collation { get; private set; } - - public bool IsAutoInc { get; private set; } - public bool IsAutoGuid { get; private set; } - - public bool IsPK { get; private set; } - - public IEnumerable Indices { get; set; } - - public bool IsNullable { get; private set; } - - public int? MaxStringLength { get; private set; } - - public Column(PropertyInfo prop, CreateFlags createFlags = CreateFlags.None) - { - var colAttr = (ColumnAttribute)prop.GetCustomAttributes(typeof(ColumnAttribute), true).FirstOrDefault(); - - _prop = prop; - Name = colAttr is null ? prop.Name : colAttr.Name; - //If this type is Nullable then Nullable.GetUnderlyingType returns the T, otherwise it returns null, so get the actual type instead - ColumnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; - Collation = Orm.Collation(prop); - - IsPK = Orm.IsPK(prop) || - (((createFlags & CreateFlags.ImplicitPK) == CreateFlags.ImplicitPK) && - string.Compare(prop.Name, Orm.ImplicitPkName, StringComparison.OrdinalIgnoreCase) == 0); - - var isAuto = Orm.IsAutoInc(prop) || (IsPK && ((createFlags & CreateFlags.AutoIncPK) == CreateFlags.AutoIncPK)); - IsAutoGuid = isAuto && ColumnType == typeof(Guid); - IsAutoInc = isAuto && !IsAutoGuid; - - Indices = Orm.GetIndices(prop); - if (!Indices.Any() - && !IsPK - && ((createFlags & CreateFlags.ImplicitIndex) == CreateFlags.ImplicitIndex) - && Name.EndsWith(Orm.ImplicitIndexSuffix, StringComparison.OrdinalIgnoreCase) - ) - { - Indices = new IndexedAttribute[] { new() }; - } - IsNullable = !(IsPK || Orm.IsMarkedNotNull(prop)); - MaxStringLength = Orm.MaxStringLength(prop); - } - - public void SetValue(object obj, object val) => _prop.SetValue(obj, val, null); - - public object GetValue(object obj) => _prop.GetValue(obj, null); - } - } - - public static class Orm - { - public const int DefaultMaxStringLength = 140; - public const string ImplicitPkName = "Id"; - public const string ImplicitIndexSuffix = "Id"; - - public static string SqlDecl(TableMapping.Column p, bool storeDateTimeAsTicks) - { - string decl = "\"" + p.Name + "\" " + SqlType(p, storeDateTimeAsTicks) + " "; - - if (p.IsPK) - { - decl += "primary key "; - } - if (p.IsAutoInc) - { - decl += "autoincrement "; - } - if (!p.IsNullable) - { - decl += "not null "; - } - if (!string.IsNullOrEmpty(p.Collation)) - { - decl += "collate " + p.Collation + " "; - } - - return decl; - } - - public static string SqlType(TableMapping.Column p, bool storeDateTimeAsTicks) - { - var clrType = p.ColumnType; - if (clrType == typeof(bool) || clrType == typeof(byte) || clrType == typeof(ushort) || clrType == typeof(sbyte) || clrType == typeof(short) || clrType == typeof(int)) - { - return "integer"; - } - - if (clrType == typeof(uint) || clrType == typeof(long)) - { - return "bigint"; - } - if (clrType == typeof(float) || clrType == typeof(double) || clrType == typeof(decimal)) - { - return "float"; - } - if (clrType == typeof(string)) - { - int? len = p.MaxStringLength; - - if (len.HasValue) - return "varchar(" + len.Value + ")"; - - return "varchar"; - } - if (clrType == typeof(TimeSpan)) - { - return "bigint"; - } - if (clrType == typeof(DateTime)) - { - return storeDateTimeAsTicks ? "bigint" : "datetime"; - } - if (clrType == typeof(DateTimeOffset)) - { - return "bigint"; -#if !USE_NEW_REFLECTION_API - } else if (clrType.IsEnum) { -#else - } - if (clrType.GetTypeInfo().IsEnum) - { -#endif - return "integer"; - } - if (clrType == typeof(byte[])) - { - return "blob"; - } - if (clrType == typeof(Guid)) - { - return "varchar(36)"; - } - throw new NotSupportedException("Don't know about " + clrType); - } - - public static bool IsPK(MemberInfo p) - { - var attrs = p.GetCustomAttributes(typeof(PrimaryKeyAttribute), true); -#if !USE_NEW_REFLECTION_API - return attrs.Length > 0; -#else - return attrs.Length > 0; -#endif - } - - public static string Collation(MemberInfo p) - { - var attrs = p.GetCustomAttributes(typeof(CollationAttribute), true); -#if !USE_NEW_REFLECTION_API - if (attrs.Length > 0) { - return ((CollationAttribute)attrs [0]).Value; -#else - if (attrs.Length > 0) - { - return ((CollationAttribute)attrs.First()).Value; -#endif - } - - return string.Empty; - } - - public static bool IsAutoInc(MemberInfo p) - { - var attrs = p.GetCustomAttributes(typeof(AutoIncrementAttribute), true); -#if !USE_NEW_REFLECTION_API - return attrs.Length > 0; -#else - return attrs.Length > 0; -#endif - } - - public static IEnumerable GetIndices(MemberInfo p) - { - var attrs = p.GetCustomAttributes(typeof(IndexedAttribute), true); - return attrs.Cast(); - } - - public static int? MaxStringLength(PropertyInfo p) - { - var attrs = p.GetCustomAttributes(typeof(MaxLengthAttribute), true); -#if !USE_NEW_REFLECTION_API - if (attrs.Length > 0) - return ((MaxLengthAttribute)attrs [0]).Value; -#else - if (attrs.Length > 0) - return ((MaxLengthAttribute)attrs.First()).Value; -#endif - - return null; - } - - public static bool IsMarkedNotNull(MemberInfo p) - { - var attrs = p.GetCustomAttributes(typeof(NotNullAttribute), true); -#if !USE_NEW_REFLECTION_API - return attrs.Length > 0; -#else - return attrs.Length > 0; -#endif - } - } - - public partial class SQLiteCommand - { - readonly SQLiteConnection _conn; - private readonly List _bindings; - - public string CommandText { get; set; } - - internal SQLiteCommand(SQLiteConnection conn) - { - _conn = conn; - _bindings = new(); - CommandText = ""; - } - - public int ExecuteNonQuery() - { - if (_conn.Trace) - { - Debug.WriteLine("Executing: " + this); - } - - var r = SQLite3.Result.OK; - var stmt = Prepare(); - r = SQLite3.Step(stmt); - Finalize(stmt); - if (r == SQLite3.Result.Done) - { - int rowsAffected = SQLite3.Changes(_conn.Handle); - return rowsAffected; - } - - if (r == SQLite3.Result.Error) - { - string msg = SQLite3.GetErrmsg(_conn.Handle); - throw SQLiteException.New(r, msg); - } - if (r == SQLite3.Result.Constraint) - { - if (SQLite3.ExtendedErrCode(_conn.Handle) == SQLite3.ExtendedResult.ConstraintNotNull) - { - throw NotNullConstraintViolationException.New(r, SQLite3.GetErrmsg(_conn.Handle)); - } - } - - throw SQLiteException.New(r, r.ToString()); - } - - public IEnumerable ExecuteDeferredQuery() => ExecuteDeferredQuery(_conn.GetMapping(typeof(T))); - - public List ExecuteQuery() => ExecuteDeferredQuery(_conn.GetMapping(typeof(T))).ToList(); - - public List ExecuteQuery(TableMapping map) => ExecuteDeferredQuery(map).ToList(); - - /// - /// Invoked every time an instance is loaded from the database. - /// - /// - /// The newly created object. - /// - /// - /// This can be overridden in combination with the - /// method to hook into the life-cycle of objects. - /// - /// Type safety is not possible because MonoTouch does not support virtual generic methods. - /// - protected virtual void OnInstanceCreated(object obj) - { - // Can be overridden. - } - - public IEnumerable ExecuteDeferredQuery(TableMapping map) - { - if (_conn.Trace) - { - Debug.WriteLine("Executing Query: " + this); - } - - var stmt = Prepare(); - try - { - var cols = new TableMapping.Column[SQLite3.ColumnCount(stmt)]; - - for (int i = 0; i < cols.Length; i++) - { - var name = SQLite3.ColumnName16(stmt, i); - cols[i] = map.FindColumn(name); - } - - while (SQLite3.Step(stmt) == SQLite3.Result.Row) - { - var obj = Activator.CreateInstance(map.MappedType); - for (int i = 0; i < cols.Length; i++) - { - if (cols[i] is null) - continue; - var colType = SQLite3.ColumnType(stmt, i); - var val = ReadCol(stmt, i, colType, cols[i].ColumnType); - cols[i].SetValue(obj, val); - } - OnInstanceCreated(obj); - yield return (T)obj; - } - } - finally - { - SQLite3.Finalize(stmt); - } - } - - public T ExecuteScalar() - { - if (_conn.Trace) - { - Debug.WriteLine("Executing Query: " + this); - } - - T val = default(T); - - var stmt = Prepare(); - - try - { - var r = SQLite3.Step(stmt); - if (r == SQLite3.Result.Row) - { - var colType = SQLite3.ColumnType(stmt, 0); - val = (T)ReadCol(stmt, 0, colType, typeof(T)); - } - else if (r == SQLite3.Result.Done) - { - } - else - { - throw SQLiteException.New(r, SQLite3.GetErrmsg(_conn.Handle)); - } - } - finally - { - Finalize(stmt); - } - - return val; - } - - public void Bind(string name, object val) => - _bindings.Add(new() - { - Name = name, - Value = val - }); - - public void Bind(object val) => Bind(null, val); - - public override string ToString() - { - var parts = new string[1 + _bindings.Count]; - parts[0] = CommandText; - var i = 1; - foreach (var b in _bindings) - { - parts[i] = $" {i - 1}: {b.Value}"; - i++; - } - return string.Join(Environment.NewLine, parts); - } - - Sqlite3Statement Prepare() - { - var stmt = SQLite3.Prepare2(_conn.Handle, CommandText); - BindAll(stmt); - return stmt; - } - - static void Finalize(Sqlite3Statement stmt) => SQLite3.Finalize(stmt); - - void BindAll(Sqlite3Statement stmt) - { - var nextIdx = 1; - foreach (var b in _bindings) - { - b.Index = b.Name is not null ? SQLite3.BindParameterIndex(stmt, b.Name) : nextIdx++; - - BindParameter(stmt, b.Index, b.Value, _conn.StoreDateTimeAsTicks); - } - } - - internal static IntPtr NegativePointer = new(-1); - - internal static void BindParameter(Sqlite3Statement stmt, int index, object value, bool storeDateTimeAsTicks) - { - if (value is null) - { - SQLite3.BindNull(stmt, index); - } - else - { - if (value is int i) - { - SQLite3.BindInt(stmt, index, i); - } - else if (value is string s) - { - SQLite3.BindText(stmt, index, s, -1, NegativePointer); - } - else if (value is byte or ushort or sbyte or short) - { - SQLite3.BindInt(stmt, index, Convert.ToInt32(value)); - } - else if (value is bool b) - { - SQLite3.BindInt(stmt, index, b ? 1 : 0); - } - else if (value is uint or long) - { - SQLite3.BindInt64(stmt, index, Convert.ToInt64(value)); - } - else if (value is float or double or decimal) - { - SQLite3.BindDouble(stmt, index, Convert.ToDouble(value)); - } - else if (value is TimeSpan span) - { - SQLite3.BindInt64(stmt, index, span.Ticks); - } - else if (value is DateTime time) - { - if (storeDateTimeAsTicks) - { - SQLite3.BindInt64(stmt, index, time.Ticks); - } - else - { - SQLite3.BindText(stmt, index, time.ToString("yyyy-MM-dd HH:mm:ss"), -1, NegativePointer); - } - } - else if (value is DateTimeOffset offset) - { - SQLite3.BindInt64(stmt, index, offset.UtcTicks); -#if !USE_NEW_REFLECTION_API - } else if (value.GetType().IsEnum) { -#else - } - else if (value.GetType().GetTypeInfo().IsEnum) - { -#endif - SQLite3.BindInt(stmt, index, Convert.ToInt32(value)); - } - else if (value is byte[] bytes) - { - SQLite3.BindBlob(stmt, index, bytes, bytes.Length, NegativePointer); - } - else if (value is Guid guid) - { - SQLite3.BindText(stmt, index, guid.ToString(), 72, NegativePointer); - } - else - { - throw new NotSupportedException("Cannot store type: " + value.GetType()); - } - } - } - - class Binding - { - public string Name { get; set; } - - public object Value { get; set; } - - public int Index { get; set; } - } - - object ReadCol(Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clrType) - { - if (type == SQLite3.ColType.Null) - { - return null; - } - - if (clrType == typeof(string)) - { - return SQLite3.ColumnString(stmt, index); - } - - if (clrType == typeof(int)) - { - return (int)SQLite3.ColumnInt(stmt, index); - } - if (clrType == typeof(bool)) - { - return SQLite3.ColumnInt(stmt, index) == 1; - } - if (clrType == typeof(double)) - { - return SQLite3.ColumnDouble(stmt, index); - } - if (clrType == typeof(float)) - { - return (float)SQLite3.ColumnDouble(stmt, index); - } - if (clrType == typeof(TimeSpan)) - { - return new TimeSpan(SQLite3.ColumnInt64(stmt, index)); - } - if (clrType == typeof(DateTime)) - { - if (_conn.StoreDateTimeAsTicks) - { - return new DateTime(SQLite3.ColumnInt64(stmt, index)); - } - - var text = SQLite3.ColumnString(stmt, index); - return DateTime.Parse(text); - } - if (clrType == typeof(DateTimeOffset)) - { - return new DateTimeOffset(SQLite3.ColumnInt64(stmt, index), TimeSpan.Zero); -#if !USE_NEW_REFLECTION_API - } else if (clrType.IsEnum) { -#else - } - if (clrType.GetTypeInfo().IsEnum) - { -#endif - return SQLite3.ColumnInt(stmt, index); - } - if (clrType == typeof(long)) - { - return SQLite3.ColumnInt64(stmt, index); - } - if (clrType == typeof(uint)) - { - return (uint)SQLite3.ColumnInt64(stmt, index); - } - if (clrType == typeof(decimal)) - { - return (decimal)SQLite3.ColumnDouble(stmt, index); - } - if (clrType == typeof(byte)) - { - return (byte)SQLite3.ColumnInt(stmt, index); - } - if (clrType == typeof(ushort)) - { - return (ushort)SQLite3.ColumnInt(stmt, index); - } - if (clrType == typeof(short)) - { - return (short)SQLite3.ColumnInt(stmt, index); - } - if (clrType == typeof(sbyte)) - { - return (sbyte)SQLite3.ColumnInt(stmt, index); - } - if (clrType == typeof(byte[])) - { - return SQLite3.ColumnByteArray(stmt, index); - } - if (clrType == typeof(Guid)) - { - var text = SQLite3.ColumnString(stmt, index); - return new Guid(text); - } - throw new NotSupportedException("Don't know how to read " + clrType); - } - } - - /// - /// Since the insert never changed, we only need to prepare once. - /// - public class PreparedSqlLiteInsertCommand : IDisposable - { - public bool Initialized { get; set; } - - protected SQLiteConnection Connection { get; set; } - - public string CommandText { get; set; } - - protected Sqlite3Statement Statement { get; set; } - internal static readonly Sqlite3Statement NullStatement = default; - - internal PreparedSqlLiteInsertCommand(SQLiteConnection conn) => Connection = conn; - - public int ExecuteNonQuery(object[] source) - { - if (Connection.Trace) - { - Debug.WriteLine("Executing: " + CommandText); - } - - var r = SQLite3.Result.OK; - - if (!Initialized) - { - Statement = Prepare(); - Initialized = true; - } - - //bind the values. - if (source is not null) - { - for (int i = 0; i < source.Length; i++) - { - SQLiteCommand.BindParameter(Statement, i + 1, source[i], Connection.StoreDateTimeAsTicks); - } - } - r = SQLite3.Step(Statement); - - if (r == SQLite3.Result.Done) - { - int rowsAffected = SQLite3.Changes(Connection.Handle); - SQLite3.Reset(Statement); - return rowsAffected; - } - - if (r == SQLite3.Result.Error) - { - string msg = SQLite3.GetErrmsg(Connection.Handle); - SQLite3.Reset(Statement); - throw SQLiteException.New(r, msg); - } - if (r == SQLite3.Result.Constraint && SQLite3.ExtendedErrCode(Connection.Handle) == SQLite3.ExtendedResult.ConstraintNotNull) - { - SQLite3.Reset(Statement); - throw NotNullConstraintViolationException.New(r, SQLite3.GetErrmsg(Connection.Handle)); - } - SQLite3.Reset(Statement); - throw SQLiteException.New(r, r.ToString()); - } - - protected virtual Sqlite3Statement Prepare() - { - var stmt = SQLite3.Prepare2(Connection.Handle, CommandText); - return stmt; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (Statement == NullStatement) - { - try - { - SQLite3.Finalize(Statement); - } - finally - { - Statement = NullStatement; - Connection = null; - } - } - } - - ~PreparedSqlLiteInsertCommand() => Dispose(false); - } - - public abstract class BaseTableQuery - { - protected class Ordering - { - public string ColumnName { get; set; } - public bool Ascending { get; set; } - } - } - - public class TableQuery : BaseTableQuery, IEnumerable - { - public SQLiteConnection Connection { get; private set; } - - public TableMapping Table { get; private set; } - - Expression _where; - List _orderBys; - int? _limit; - int? _offset; - - BaseTableQuery _joinInner; - Expression _joinInnerKeySelector; - BaseTableQuery _joinOuter; - Expression _joinOuterKeySelector; - Expression _joinSelector; - - Expression _selector; - - TableQuery(SQLiteConnection conn, TableMapping table) - { - Connection = conn; - Table = table; - } - - public TableQuery(SQLiteConnection conn) - { - Connection = conn; - Table = Connection.GetMapping(typeof(T)); - } - - public TableQuery Clone() - { - var q = new TableQuery(Connection, Table); - q._where = _where; - q._deferred = _deferred; - if (_orderBys is not null) - { - q._orderBys = new(_orderBys); - } - q._limit = _limit; - q._offset = _offset; - q._joinInner = _joinInner; - q._joinInnerKeySelector = _joinInnerKeySelector; - q._joinOuter = _joinOuter; - q._joinOuterKeySelector = _joinOuterKeySelector; - q._joinSelector = _joinSelector; - q._selector = _selector; - return q; - } - - public TableQuery Where(Expression> predExpr) - { - if (predExpr.NodeType == ExpressionType.Lambda) - { - var lambda = (LambdaExpression)predExpr; - var pred = lambda.Body; - var q = Clone(); - q.AddWhere(pred); - return q; - } - - throw new NotSupportedException("Must be a predicate"); - } - - public TableQuery Take(int n) - { - var q = Clone(); - q._limit = n; - return q; - } - - public TableQuery Skip(int n) - { - var q = Clone(); - q._offset = n; - return q; - } - - public T ElementAt(int index) => Skip(index).Take(1).First(); - - bool _deferred; - public TableQuery Deferred() - { - var q = Clone(); - q._deferred = true; - return q; - } - - public TableQuery OrderBy(Expression> orderExpr) => AddOrderBy(orderExpr, true); - - public TableQuery OrderByDescending(Expression> orderExpr) => AddOrderBy(orderExpr, false); - - public TableQuery ThenBy(Expression> orderExpr) => AddOrderBy(orderExpr, true); - - public TableQuery ThenByDescending(Expression> orderExpr) => AddOrderBy(orderExpr, false); - - private TableQuery AddOrderBy(Expression> orderExpr, bool asc) - { - if (orderExpr.NodeType == ExpressionType.Lambda) - { - var lambda = (LambdaExpression)orderExpr; - - MemberExpression mem = null; - - if (lambda.Body is UnaryExpression unary && unary.NodeType == ExpressionType.Convert) - { - mem = unary.Operand as MemberExpression; - } - else - { - mem = lambda.Body as MemberExpression; - } - - if (mem is not null && (mem.Expression.NodeType == ExpressionType.Parameter)) - { - var q = Clone(); - q._orderBys ??= new(); - q._orderBys.Add(new() - { - ColumnName = Table.FindColumnWithPropertyName(mem.Member.Name).Name, - Ascending = asc - }); - return q; - } - - throw new NotSupportedException("Order By does not support: " + orderExpr); - } - - throw new NotSupportedException("Must be a predicate"); - } - - private void AddWhere(Expression pred) => _where = _where is null ? pred : Expression.AndAlso(_where, pred); - - public TableQuery Join( - TableQuery inner, - Expression> outerKeySelector, - Expression> innerKeySelector, - Expression> resultSelector) - { - var q = new TableQuery(Connection, Connection.GetMapping(typeof(TResult))) - { - _joinOuter = this, - _joinOuterKeySelector = outerKeySelector, - _joinInner = inner, - _joinInnerKeySelector = innerKeySelector, - _joinSelector = resultSelector, - }; - return q; - } - - public TableQuery Select(Expression> selector) - { - var q = Clone(); - q._selector = selector; - return q; - } - - private SQLiteCommand GenerateCommand(string selectionList) - { - if (_joinInner is not null && _joinOuter is not null) - { - throw new NotSupportedException("Joins are not supported."); - } - - var cmdText = "select " + selectionList + " from \"" + Table.TableName + "\""; - var args = new List(); - if (_where is not null) - { - var w = CompileExpr(_where, args); - cmdText += " where " + w.CommandText; - } - if ((_orderBys is not null) && (_orderBys.Count > 0)) - { - var t = string.Join(", ", _orderBys.Select(o => "\"" + o.ColumnName + "\"" + (o.Ascending ? "" : " desc")).ToArray()); - cmdText += " order by " + t; - } - if (_limit.HasValue) - { - cmdText += " limit " + _limit.Value; - } - if (_offset.HasValue) - { - if (!_limit.HasValue) - { - cmdText += " limit -1 "; - } - cmdText += " offset " + _offset.Value; - } - return Connection.CreateCommand(cmdText, args.ToArray()); - } - - class CompileResult - { - public string CommandText { get; set; } - - public object Value { get; set; } - } - - private CompileResult CompileExpr(Expression expr, IList queryArgs) - { - if (expr is null) - { - throw new NotSupportedException("Expression is NULL"); - } - - if (expr is BinaryExpression bin) - { - var leftr = CompileExpr(bin.Left, queryArgs); - var rightr = CompileExpr(bin.Right, queryArgs); - - //If either side is a parameter and is null, then handle the other side specially (for "is null"/"is not null") - string text; - if (leftr.CommandText == "?" && leftr.Value is null) - text = CompileNullBinaryExpression(bin, rightr); - else if (rightr.CommandText == "?" && rightr.Value is null) - text = CompileNullBinaryExpression(bin, leftr); - else - text = "(" + leftr.CommandText + " " + GetSqlName(bin) + " " + rightr.CommandText + ")"; - return new() { CommandText = text }; - } - if (expr.NodeType == ExpressionType.Call) - { - - var call = (MethodCallExpression)expr; - var args = new CompileResult[call.Arguments.Count]; - var obj = call.Object is not null ? CompileExpr(call.Object, queryArgs) : null; - - for (var i = 0; i < args.Length; i++) - { - args[i] = CompileExpr(call.Arguments[i], queryArgs); - } - - var sqlCall = ""; - - if (call.Method.Name == "Like" && args.Length == 2) - { - sqlCall = "(" + args[0].CommandText + " like " + args[1].CommandText + ")"; - } - else if (call.Method.Name == "Contains" && args.Length == 2) - { - sqlCall = "(" + args[1].CommandText + " in " + args[0].CommandText + ")"; - } - else if (call.Method.Name == "Contains" && args.Length == 1) - { - if (call.Object is not null && call.Object.Type == typeof(string)) - { - sqlCall = "(" + obj.CommandText + " like ('%' || " + args[0].CommandText + " || '%'))"; - } - else - { - sqlCall = "(" + args[0].CommandText + " in " + obj.CommandText + ")"; - } - } - else if (call.Method.Name == "StartsWith" && args.Length == 1) - { - sqlCall = "(" + obj.CommandText + " like (" + args[0].CommandText + " || '%'))"; - } - else if (call.Method.Name == "EndsWith" && args.Length == 1) - { - sqlCall = "(" + obj.CommandText + " like ('%' || " + args[0].CommandText + "))"; - } - else if (call.Method.Name == "Equals" && args.Length == 1) - { - sqlCall = "(" + obj.CommandText + " = (" + args[0].CommandText + "))"; - } - else if (call.Method.Name == "ToLower") - { - sqlCall = "(lower(" + obj.CommandText + "))"; - } - else if (call.Method.Name == "ToUpper") - { - sqlCall = "(upper(" + obj.CommandText + "))"; - } - else - { - sqlCall = call.Method.Name.ToLower() + "(" + string.Join(",", args.Select(a => a.CommandText).ToArray()) + ")"; - } - return new() { CommandText = sqlCall }; - - } - if (expr.NodeType == ExpressionType.Constant) - { - var c = (ConstantExpression)expr; - queryArgs.Add(c.Value); - return new() - { - CommandText = "?", - Value = c.Value - }; - } - if (expr.NodeType == ExpressionType.Convert) - { - var u = (UnaryExpression)expr; - var ty = u.Type; - var valr = CompileExpr(u.Operand, queryArgs); - return new() - { - CommandText = valr.CommandText, - Value = valr.Value is not null ? ConvertTo(valr.Value, ty) : null - }; - } - if (expr.NodeType == ExpressionType.MemberAccess) - { - var mem = (MemberExpression)expr; - - if (mem.Expression is not null && mem.Expression.NodeType == ExpressionType.Parameter) - { - // - // This is a column of our table, output just the column name - // Need to translate it if that column name is mapped - // - var columnName = Table.FindColumnWithPropertyName(mem.Member.Name).Name; - return new() { CommandText = "\"" + columnName + "\"" }; - } - - object obj = null; - if (mem.Expression is not null) - { - var r = CompileExpr(mem.Expression, queryArgs); - if (r.Value is null) - { - throw new NotSupportedException("Member access failed to compile expression"); - } - if (r.CommandText == "?") - { - queryArgs.RemoveAt(queryArgs.Count - 1); - } - obj = r.Value; - } - - // - // Get the member value - // - object val = null; - -#if !USE_NEW_REFLECTION_API - if (mem.Member.MemberType == MemberTypes.Property) { -#else - if (mem.Member is PropertyInfo info) - { -#endif - val = info.GetValue(obj, null); -#if !USE_NEW_REFLECTION_API - } else if (mem.Member.MemberType == MemberTypes.Field) { -#else - } - else if (mem.Member is FieldInfo member) - { -#endif - val = member.GetValue(obj); - } - else - { -#if !USE_NEW_REFLECTION_API - throw new NotSupportedException ("MemberExpr: " + mem.Member.MemberType); -#else - throw new NotSupportedException("MemberExpr: " + mem.Member.DeclaringType); -#endif - } - - // - // Work special magic for enumerables - // - if (val is System.Collections.IEnumerable enumerable && enumerable is not string && enumerable is not IEnumerable) - { - var sb = new StringBuilder(); - sb.Append("("); - var head = ""; - foreach (var a in enumerable) - { - queryArgs.Add(a); - sb.Append(head); - sb.Append("?"); - head = ","; - } - sb.Append(")"); - return new() - { - CommandText = sb.ToString(), - Value = enumerable - }; - } - - queryArgs.Add(val); - return new() - { - CommandText = "?", - Value = val - }; - } - - throw new NotSupportedException("Cannot compile: " + expr.NodeType.ToString()); - } - - static object ConvertTo(object obj, Type t) - { - Type nut = Nullable.GetUnderlyingType(t); - - if (nut is not null) - { - if (obj is null) - return null; - return Convert.ChangeType(obj, nut); - } - - return Convert.ChangeType(obj, t); - } - /// - /// Compiles a BinaryExpression where one of the parameters is null. - /// - /// The expression to compile. - /// The non-null parameter - private static string CompileNullBinaryExpression(Expression expression, CompileResult parameter) => - expression.NodeType switch - { - ExpressionType.Equal => "(" + parameter.CommandText + " is ?)", - ExpressionType.NotEqual => "(" + parameter.CommandText + " is not ?)", - _ => throw new NotSupportedException("Cannot compile Null-BinaryExpression with type " + - expression.NodeType.ToString()) - }; - - static string GetSqlName(Expression expr) - { - var n = expr.NodeType; - return n switch - { - ExpressionType.GreaterThan => ">", - ExpressionType.GreaterThanOrEqual => ">=", - ExpressionType.LessThan => "<", - ExpressionType.LessThanOrEqual => "<=", - ExpressionType.And => "&", - ExpressionType.AndAlso => "and", - ExpressionType.Or => "|", - ExpressionType.OrElse => "or", - ExpressionType.Equal => "=", - ExpressionType.NotEqual => "!=", - _ => throw new NotSupportedException("Cannot get SQL for: " + n) - }; - } - - public int Count() => GenerateCommand("count(*)").ExecuteScalar(); - - public int Count(Expression> predExpr) => Where(predExpr).Count(); - - public IEnumerator GetEnumerator() - { - if (!_deferred) - return GenerateCommand("*").ExecuteQuery().GetEnumerator(); - - return GenerateCommand("*").ExecuteDeferredQuery().GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); - - public T First() - { - var query = Take(1); - return query.ToList().First(); - } - - public T FirstOrDefault() - { - var query = Take(1); - return query.ToList().FirstOrDefault(); - } - } - - - public static class SQLite3 - { - public enum Result : int - { - OK = 0, - Error = 1, - Internal = 2, - Perm = 3, - Abort = 4, - Busy = 5, - Locked = 6, - NoMem = 7, - ReadOnly = 8, - Interrupt = 9, - IOError = 10, - Corrupt = 11, - NotFound = 12, - Full = 13, - CannotOpen = 14, - LockErr = 15, - Empty = 16, - SchemaChngd = 17, - TooBig = 18, - Constraint = 19, - Mismatch = 20, - Misuse = 21, - NotImplementedLFS = 22, - AccessDenied = 23, - Format = 24, - Range = 25, - NonDBFile = 26, - Notice = 27, - Warning = 28, - Row = 100, - Done = 101 - } - - public enum ExtendedResult : int - { - IOErrorRead = (Result.IOError | (1 << 8)), - IOErrorShortRead = (Result.IOError | (2 << 8)), - IOErrorWrite = (Result.IOError | (3 << 8)), - IOErrorFsync = (Result.IOError | (4 << 8)), - IOErrorDirFSync = (Result.IOError | (5 << 8)), - IOErrorTruncate = (Result.IOError | (6 << 8)), - IOErrorFStat = (Result.IOError | (7 << 8)), - IOErrorUnlock = (Result.IOError | (8 << 8)), - IOErrorRdlock = (Result.IOError | (9 << 8)), - IOErrorDelete = (Result.IOError | (10 << 8)), - IOErrorBlocked = (Result.IOError | (11 << 8)), - IOErrorNoMem = (Result.IOError | (12 << 8)), - IOErrorAccess = (Result.IOError | (13 << 8)), - IOErrorCheckReservedLock = (Result.IOError | (14 << 8)), - IOErrorLock = (Result.IOError | (15 << 8)), - IOErrorClose = (Result.IOError | (16 << 8)), - IOErrorDirClose = (Result.IOError | (17 << 8)), - IOErrorSHMOpen = (Result.IOError | (18 << 8)), - IOErrorSHMSize = (Result.IOError | (19 << 8)), - IOErrorSHMLock = (Result.IOError | (20 << 8)), - IOErrorSHMMap = (Result.IOError | (21 << 8)), - IOErrorSeek = (Result.IOError | (22 << 8)), - IOErrorDeleteNoEnt = (Result.IOError | (23 << 8)), - IOErrorMMap = (Result.IOError | (24 << 8)), - LockedSharedcache = (Result.Locked | (1 << 8)), - BusyRecovery = (Result.Busy | (1 << 8)), - CannottOpenNoTempDir = (Result.CannotOpen | (1 << 8)), - CannotOpenIsDir = (Result.CannotOpen | (2 << 8)), - CannotOpenFullPath = (Result.CannotOpen | (3 << 8)), - CorruptVTab = (Result.Corrupt | (1 << 8)), - ReadonlyRecovery = (Result.ReadOnly | (1 << 8)), - ReadonlyCannotLock = (Result.ReadOnly | (2 << 8)), - ReadonlyRollback = (Result.ReadOnly | (3 << 8)), - AbortRollback = (Result.Abort | (2 << 8)), - ConstraintCheck = (Result.Constraint | (1 << 8)), - ConstraintCommitHook = (Result.Constraint | (2 << 8)), - ConstraintForeignKey = (Result.Constraint | (3 << 8)), - ConstraintFunction = (Result.Constraint | (4 << 8)), - ConstraintNotNull = (Result.Constraint | (5 << 8)), - ConstraintPrimaryKey = (Result.Constraint | (6 << 8)), - ConstraintTrigger = (Result.Constraint | (7 << 8)), - ConstraintUnique = (Result.Constraint | (8 << 8)), - ConstraintVTab = (Result.Constraint | (9 << 8)), - NoticeRecoverWAL = (Result.Notice | (1 << 8)), - NoticeRecoverRollback = (Result.Notice | (2 << 8)) - } - public enum ConfigOption : int - { - SingleThread = 1, - MultiThread = 2, - Serialized = 3 - } - -#if !USE_CSHARP_SQLITE && !USE_WP8_NATIVE_SQLITE && !USE_SQLITEPCL_RAW - [DllImport("sqlite3", EntryPoint = "sqlite3_open", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Open ([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db); - - [DllImport("sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Open ([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db, int flags, IntPtr zvfs); - - [DllImport("sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention = CallingConvention.Cdecl)] - public static extern Result Open(byte[] filename, out IntPtr db, int flags, IntPtr zvfs); - - [DllImport("sqlite3", EntryPoint = "sqlite3_open16", CallingConvention = CallingConvention.Cdecl)] - public static extern Result Open16([MarshalAs(UnmanagedType.LPWStr)] string filename, out IntPtr db); - - [DllImport("sqlite3", EntryPoint = "sqlite3_enable_load_extension", CallingConvention=CallingConvention.Cdecl)] - public static extern Result EnableLoadExtension (IntPtr db, int onoff); - - [DllImport("sqlite3", EntryPoint = "sqlite3_close", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Close (IntPtr db); - - [DllImport("sqlite3", EntryPoint = "sqlite3_initialize", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Initialize(); - - [DllImport("sqlite3", EntryPoint = "sqlite3_shutdown", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Shutdown(); - - [DllImport("sqlite3", EntryPoint = "sqlite3_config", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Config (ConfigOption option); - - [DllImport("sqlite3", EntryPoint = "sqlite3_win32_set_directory", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Unicode)] - public static extern int SetDirectory (uint directoryType, string directoryPath); - - [DllImport("sqlite3", EntryPoint = "sqlite3_busy_timeout", CallingConvention=CallingConvention.Cdecl)] - public static extern Result BusyTimeout (IntPtr db, int milliseconds); - - [DllImport("sqlite3", EntryPoint = "sqlite3_changes", CallingConvention=CallingConvention.Cdecl)] - public static extern int Changes (IntPtr db); - - [DllImport("sqlite3", EntryPoint = "sqlite3_prepare_v2", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Prepare2 (IntPtr db, [MarshalAs(UnmanagedType.LPStr)] string sql, int numBytes, out IntPtr stmt, IntPtr pzTail); - -#if NETFX_CORE - [DllImport ("sqlite3", EntryPoint = "sqlite3_prepare_v2", CallingConvention = CallingConvention.Cdecl)] - public static extern Result Prepare2 (IntPtr db, byte[] queryBytes, int numBytes, out IntPtr stmt, IntPtr pzTail); -#endif - - public static IntPtr Prepare2 (IntPtr db, string query) - { - IntPtr stmt; -#if NETFX_CORE - byte[] queryBytes = System.Text.UTF8Encoding.UTF8.GetBytes (query); - var r = Prepare2 (db, queryBytes, queryBytes.Length, out stmt, IntPtr.Zero); -#else - var r = Prepare2 (db, query, System.Text.UTF8Encoding.UTF8.GetByteCount (query), out stmt, IntPtr.Zero); -#endif - if (r != Result.OK) { - throw SQLiteException.New (r, GetErrmsg (db)); - } - return stmt; - } - - [DllImport("sqlite3", EntryPoint = "sqlite3_step", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Step (IntPtr stmt); - - [DllImport("sqlite3", EntryPoint = "sqlite3_reset", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Reset (IntPtr stmt); - - [DllImport("sqlite3", EntryPoint = "sqlite3_finalize", CallingConvention=CallingConvention.Cdecl)] - public static extern Result Finalize (IntPtr stmt); - - [DllImport("sqlite3", EntryPoint = "sqlite3_last_insert_rowid", CallingConvention=CallingConvention.Cdecl)] - public static extern long LastInsertRowid (IntPtr db); - - [DllImport("sqlite3", EntryPoint = "sqlite3_errmsg16", CallingConvention=CallingConvention.Cdecl)] - public static extern IntPtr Errmsg (IntPtr db); - - public static string GetErrmsg (IntPtr db) - { - return Marshal.PtrToStringUni (Errmsg (db)); - } - - [DllImport("sqlite3", EntryPoint = "sqlite3_bind_parameter_index", CallingConvention=CallingConvention.Cdecl)] - public static extern int BindParameterIndex (IntPtr stmt, [MarshalAs(UnmanagedType.LPStr)] string name); - - [DllImport("sqlite3", EntryPoint = "sqlite3_bind_null", CallingConvention=CallingConvention.Cdecl)] - public static extern int BindNull (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_bind_int", CallingConvention=CallingConvention.Cdecl)] - public static extern int BindInt (IntPtr stmt, int index, int val); - - [DllImport("sqlite3", EntryPoint = "sqlite3_bind_int64", CallingConvention=CallingConvention.Cdecl)] - public static extern int BindInt64 (IntPtr stmt, int index, long val); - - [DllImport("sqlite3", EntryPoint = "sqlite3_bind_double", CallingConvention=CallingConvention.Cdecl)] - public static extern int BindDouble (IntPtr stmt, int index, double val); - - [DllImport("sqlite3", EntryPoint = "sqlite3_bind_text16", CallingConvention=CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern int BindText (IntPtr stmt, int index, [MarshalAs(UnmanagedType.LPWStr)] string val, int n, IntPtr free); - - [DllImport("sqlite3", EntryPoint = "sqlite3_bind_blob", CallingConvention=CallingConvention.Cdecl)] - public static extern int BindBlob (IntPtr stmt, int index, byte[] val, int n, IntPtr free); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_count", CallingConvention=CallingConvention.Cdecl)] - public static extern int ColumnCount (IntPtr stmt); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_name", CallingConvention=CallingConvention.Cdecl)] - public static extern IntPtr ColumnName (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_name16", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr ColumnName16Internal (IntPtr stmt, int index); - public static string ColumnName16(IntPtr stmt, int index) - { - return Marshal.PtrToStringUni(ColumnName16Internal(stmt, index)); - } - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_type", CallingConvention=CallingConvention.Cdecl)] - public static extern ColType ColumnType (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_int", CallingConvention=CallingConvention.Cdecl)] - public static extern int ColumnInt (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_int64", CallingConvention=CallingConvention.Cdecl)] - public static extern long ColumnInt64 (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_double", CallingConvention=CallingConvention.Cdecl)] - public static extern double ColumnDouble (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_text", CallingConvention=CallingConvention.Cdecl)] - public static extern IntPtr ColumnText (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_text16", CallingConvention=CallingConvention.Cdecl)] - public static extern IntPtr ColumnText16 (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_blob", CallingConvention=CallingConvention.Cdecl)] - public static extern IntPtr ColumnBlob (IntPtr stmt, int index); - - [DllImport("sqlite3", EntryPoint = "sqlite3_column_bytes", CallingConvention=CallingConvention.Cdecl)] - public static extern int ColumnBytes (IntPtr stmt, int index); - - public static string ColumnString (IntPtr stmt, int index) - { - return Marshal.PtrToStringUni (SQLite3.ColumnText16 (stmt, index)); - } - - public static byte[] ColumnByteArray (IntPtr stmt, int index) - { - int length = ColumnBytes (stmt, index); - var result = new byte[length]; - if (length > 0) - Marshal.Copy (ColumnBlob (stmt, index), result, 0, length); - return result; - } - - [DllImport ("sqlite3", EntryPoint = "sqlite3_extended_errcode", CallingConvention = CallingConvention.Cdecl)] - public static extern ExtendedResult ExtendedErrCode (IntPtr db); - - [DllImport ("sqlite3", EntryPoint = "sqlite3_libversion_number", CallingConvention = CallingConvention.Cdecl)] - public static extern int LibVersionNumber (); -#else - public static Result Open(string filename, out Sqlite3DatabaseHandle db) => (Result)Sqlite3Raw.sqlite3_open(filename, out db); - - public static Result Open(string filename, out Sqlite3DatabaseHandle db, int flags, IntPtr zVfs) - { -#if USE_WP8_NATIVE_SQLITE - return (Result)Sqlite3.sqlite3_open_v2(filename, out db, flags, ""); -#else - return (Result)Sqlite3Raw.sqlite3_open_v2(filename, out db, flags, null); -#endif - } - - public static Result Close(Sqlite3DatabaseHandle db) => (Result)Sqlite3Raw.sqlite3_close(db); - - public static Result BusyTimeout(Sqlite3DatabaseHandle db, int milliseconds) => (Result)Sqlite3Raw.sqlite3_busy_timeout(db, milliseconds); - - public static int Changes(Sqlite3DatabaseHandle db) => Sqlite3Raw.sqlite3_changes(db); - - public static Sqlite3Statement Prepare2(Sqlite3DatabaseHandle db, string query) - { - var stmt = default(Sqlite3Statement); -#if USE_WP8_NATIVE_SQLITE || USE_SQLITEPCL_RAW - var r = Sqlite3Raw.sqlite3_prepare_v2(db, query, out stmt); -#else - stmt = new Sqlite3Statement(); - var r = Sqlite3.sqlite3_prepare_v2(db, query, -1, ref stmt, 0); -#endif - if (r != 0) - { - throw SQLiteException.New((Result)r, GetErrmsg(db)); - } - return stmt; - } - - public static Result Step(Sqlite3Statement stmt) => (Result)Sqlite3Raw.sqlite3_step(stmt); - - public static Result Reset(Sqlite3Statement stmt) => (Result)Sqlite3Raw.sqlite3_reset(stmt); - - public static Result Finalize(Sqlite3Statement stmt) => (Result)Sqlite3Raw.sqlite3_finalize(stmt); - - public static long LastInsertRowid(Sqlite3DatabaseHandle db) => Sqlite3Raw.sqlite3_last_insert_rowid(db); - - public static string GetErrmsg(Sqlite3DatabaseHandle db) => Sqlite3Raw.sqlite3_errmsg(db).utf8_to_string(); - - public static int BindParameterIndex(Sqlite3Statement stmt, string name) => Sqlite3Raw.sqlite3_bind_parameter_index(stmt, name); - - public static int BindNull(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_bind_null(stmt, index); - - public static int BindInt(Sqlite3Statement stmt, int index, int val) => Sqlite3Raw.sqlite3_bind_int(stmt, index, val); - - public static int BindInt64(Sqlite3Statement stmt, int index, long val) => Sqlite3Raw.sqlite3_bind_int64(stmt, index, val); - - public static int BindDouble(Sqlite3Statement stmt, int index, double val) => Sqlite3Raw.sqlite3_bind_double(stmt, index, val); - - public static int BindText(Sqlite3Statement stmt, int index, string val, int n, IntPtr free) - { -#if USE_WP8_NATIVE_SQLITE - return Sqlite3.sqlite3_bind_text(stmt, index, val, n); -#elif USE_SQLITEPCL_RAW - return Sqlite3Raw.sqlite3_bind_text(stmt, index, val); -#else - return Sqlite3.sqlite3_bind_text(stmt, index, val, n, null); -#endif - } - - public static int BindBlob(Sqlite3Statement stmt, int index, byte[] val, int n, IntPtr free) - { -#if USE_WP8_NATIVE_SQLITE - return Sqlite3.sqlite3_bind_blob(stmt, index, val, n); -#elif USE_SQLITEPCL_RAW - return Sqlite3Raw.sqlite3_bind_blob(stmt, index, val); -#else - return Sqlite3.sqlite3_bind_blob(stmt, index, val, n, null); -#endif - } - - public static int ColumnCount(Sqlite3Statement stmt) => Sqlite3Raw.sqlite3_column_count(stmt); - - public static string ColumnName(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_name(stmt, index).utf8_to_string(); - - public static string ColumnName16(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_name(stmt, index).utf8_to_string(); - - public static ColType ColumnType(Sqlite3Statement stmt, int index) => (ColType)Sqlite3Raw.sqlite3_column_type(stmt, index); - - public static int ColumnInt(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_int(stmt, index); - - public static long ColumnInt64(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_int64(stmt, index); - - public static double ColumnDouble(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_double(stmt, index); - - public static string ColumnText(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_text(stmt, index).utf8_to_string(); - - public static string ColumnText16(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_text(stmt, index).utf8_to_string(); - - public static byte[] ColumnBlob(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_blob(stmt, index).ToArray(); - - public static int ColumnBytes(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_bytes(stmt, index); - - public static string ColumnString(Sqlite3Statement stmt, int index) => Sqlite3Raw.sqlite3_column_text(stmt, index).utf8_to_string(); - - public static byte[] ColumnByteArray(Sqlite3Statement stmt, int index) => ColumnBlob(stmt, index); - -#if !USE_SQLITEPCL_RAW - public static Result EnableLoadExtension(Sqlite3DatabaseHandle db, int onoff) - { - return (Result)Sqlite3.sqlite3_enable_load_extension(db, onoff); - } -#endif - - public static ExtendedResult ExtendedErrCode(Sqlite3DatabaseHandle db) => (ExtendedResult)Sqlite3Raw.sqlite3_extended_errcode(db); -#endif - - public enum ColType : int - { - Integer = 1, - Float = 2, - Text = 3, - Blob = 4, - Null = 5 - } - } - -} diff --git a/src/Akavache.Sqlite3/SqlLiteCache/CacheElement.cs b/src/Akavache.Sqlite3/SqlLiteCache/CacheElement.cs index 44a23a442..c7255a6c1 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/CacheElement.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/CacheElement.cs @@ -1,9 +1,9 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Sqlite3.Internal; +using SQLite; namespace Akavache.Sqlite3; @@ -15,10 +15,10 @@ internal class CacheElement [Indexed] public string? TypeName { get; set; } - public byte[] Value { get; set; } = Array.Empty(); + public byte[] Value { get; set; } = []; [Indexed] public DateTime Expiration { get; set; } public DateTime CreatedAt { get; set; } -} \ No newline at end of file +} diff --git a/src/Akavache.Sqlite3/SqlLiteCache/IObjectWrapper.cs b/src/Akavache.Sqlite3/SqlLiteCache/IObjectWrapper.cs index 46e9db451..09b8589a0 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/IObjectWrapper.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/IObjectWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs b/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs index e49cc59a5..349f4c74c 100755 --- a/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/ObjectWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/SqlLiteCache/SQLiteEncryptedBlobCache.cs b/src/Akavache.Sqlite3/SqlLiteCache/SQLiteEncryptedBlobCache.cs index 6798f4720..f21ef2836 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/SQLiteEncryptedBlobCache.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/SQLiteEncryptedBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/SqlLiteCache/SchemaInfo.cs b/src/Akavache.Sqlite3/SqlLiteCache/SchemaInfo.cs index 6fd605c3f..b5fd44ccf 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/SchemaInfo.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/SchemaInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/SqlLiteCache/SqlLite.cs b/src/Akavache.Sqlite3/SqlLiteCache/SqlLite.cs index f85876e01..3ff593805 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/SqlLite.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/SqlLite.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs b/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs index 24bab1ea4..4a065966b 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -7,12 +7,11 @@ using System.Globalization; using System.Reactive.Disposables; -using Akavache.Sqlite3.Internal; - using Newtonsoft.Json; using Newtonsoft.Json.Bson; using Splat; +using SQLite; namespace Akavache.Sqlite3; @@ -411,7 +410,7 @@ public IObservable Insert(IDictionary keyValuePairs, DateT var createdAt = Scheduler.Now.UtcDateTime; return _initializer - .SelectMany(_ => keyValuePairs.Select(x => BeforeWriteToDiskFilter(x.Value, Scheduler).Select(data => (key: x.Key, data: data)))) + .SelectMany(_ => keyValuePairs.Select(x => BeforeWriteToDiskFilter(x.Value, Scheduler).Select(data => (key: x.Key, data)))) .Merge().ToList() .SelectMany(list => _opQueue.Insert(list.Select(data => new CacheElement @@ -450,7 +449,7 @@ public IObservable> Get(IEnumerable keys) return Observable.Return(cacheElements.ToDictionary(element => element.Key, element => element.Value)); }) - .SelectMany(dict => dict.Select(x => AfterReadFromDiskFilter(x.Value, Scheduler).Select(data => (key: x.Key, data: data)))) + .SelectMany(dict => dict.Select(x => AfterReadFromDiskFilter(x.Value, Scheduler).Select(data => (key: x.Key, data)))) .Merge() .ToDictionary(x => x.key, x => x.data) .PublishLast().PermaRef(); @@ -525,7 +524,7 @@ public IObservable InsertObjects(IDictionary keyValuePairs, var createdAt = Scheduler.Now.UtcDateTime; return _initializer - .SelectMany(_ => dataToAdd.Select(x => BeforeWriteToDiskFilter(x.value, Scheduler).Select(data => (key: x.key, data: data)))) + .SelectMany(_ => dataToAdd.Select(x => BeforeWriteToDiskFilter(x.value, Scheduler).Select(data => (x.key, data)))) .Merge().ToList() .SelectMany(list => _opQueue.Insert(list.Select(data => new CacheElement @@ -564,9 +563,9 @@ public IObservable> GetObjects(IEnumerable key var cacheElements = x.ToList(); return Observable.Return(cacheElements.ToDictionary(element => element.Key, element => element.Value)); }) - .SelectMany(dict => dict.Select(x => AfterReadFromDiskFilter(x.Value, Scheduler).Select(data => (key: x.Key, data: data)))) + .SelectMany(dict => dict.Select(x => AfterReadFromDiskFilter(x.Value, Scheduler).Select(data => (key: x.Key, data)))) .Merge() - .SelectMany(x => DeserializeObject(x.data).Where(y => y is not null).Select(obj => (key: x.key, data: obj!))) + .SelectMany(x => DeserializeObject(x.data).Where(y => y is not null).Select(obj => (x.key, data: obj!))) .ToDictionary(x => x.key, x => x.data) .PublishLast().PermaRef(); } diff --git a/src/Akavache.Sqlite3/sqlite3-hint.txt b/src/Akavache.Sqlite3/sqlite3-hint.txt deleted file mode 100644 index 2fc7b9f5c..000000000 --- a/src/Akavache.Sqlite3/sqlite3-hint.txt +++ /dev/null @@ -1,15 +0,0 @@ -Akavache.SQLite3 depends on a native sqlite3.dll being present. How you do -that depends on what platform you're on: - -WPF / Desktop: -1. Copy sqlite3.dll from http://www.sqlite.org/download.html into bin/Debug -2. Make sure your project is set to x86, not AnyCPU - -Pro-Tip: To do this, make folders called ".\ext\x86", then in the post-build -event command line, put: - -copy "$(SolutionDir)ext\x86\sqlite3.dll" "$(ProjectDir)$(OutDir)sqlite3.dll" - -WP8 / WinRT: -1. Download the Extension VSIX from http://www.sqlite.org/download.html -2. Follow http://is.gd/LFKkEb to set it up (works on both WP8 and WinRT) diff --git a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.net6.0.approved.txt b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.DotNet6_0.verified.txt similarity index 99% rename from src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.net6.0.approved.txt rename to src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.DotNet6_0.verified.txt index c1e6bda0b..fbac23e95 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.net6.0.approved.txt +++ b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.DotNet6_0.verified.txt @@ -1,5 +1,4 @@ -[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/reactiveui/akavache")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache.Drawing")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache.Mobile")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache.Sqlite3")] diff --git a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.net48.approved.txt b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.Net4_8.verified.txt similarity index 98% rename from src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.net48.approved.txt rename to src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.Net4_8.verified.txt index fbd0915c9..01fdfccfe 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.net48.approved.txt +++ b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheCore.Net4_8.verified.txt @@ -1,10 +1,9 @@ -[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/reactiveui/akavache")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache.Drawing")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache.Mobile")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache.Sqlite3")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akavache.Tests")] -[assembly: System.Runtime.Versioning.TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName=".NET Framework 4.6.2")] +[assembly: System.Runtime.Versioning.TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName=".NET Standard 2.0")] namespace Akavache { public class AkavacheHttpMixin : Akavache.IAkavacheHttpMixin diff --git a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.net6.0.approved.txt b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.DotNet6_0.verified.txt similarity index 88% rename from src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.net6.0.approved.txt rename to src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.DotNet6_0.verified.txt index c1c1c8843..28b9950e6 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.net6.0.approved.txt +++ b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.DotNet6_0.verified.txt @@ -1,5 +1,4 @@ -[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/reactiveui/akavache")] -[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")] +[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")] namespace Akavache { public static class BitmapImageMixin diff --git a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.net48.approved.txt b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.Net4_8.verified.txt similarity index 87% rename from src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.net48.approved.txt rename to src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.Net4_8.verified.txt index 4592f6631..9eb2a57a2 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.net48.approved.txt +++ b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheDrawing.Net4_8.verified.txt @@ -1,5 +1,4 @@ -[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/reactiveui/akavache")] -[assembly: System.Runtime.Versioning.TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName=".NET Framework 4.6.2")] +[assembly: System.Runtime.Versioning.TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName=".NET Standard 2.0")] namespace Akavache { public static class BitmapImageMixin diff --git a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.net6.0.approved.txt b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.DotNet6_0.verified.txt similarity index 72% rename from src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.net6.0.approved.txt rename to src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.DotNet6_0.verified.txt index bf8d2ae82..22c33a136 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.net6.0.approved.txt +++ b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.DotNet6_0.verified.txt @@ -1,5 +1,4 @@ -[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/reactiveui/akavache")] -[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")] +[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")] namespace Akavache { public class Registrations diff --git a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.net48.approved.txt b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.Net4_8.verified.txt similarity index 71% rename from src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.net48.approved.txt rename to src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.Net4_8.verified.txt index cf779bcb6..5021077c2 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.net48.approved.txt +++ b/src/Akavache.Tests/API/ApiApprovalTests.AkavacheProject.Net4_8.verified.txt @@ -1,5 +1,4 @@ -[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/reactiveui/akavache")] -[assembly: System.Runtime.Versioning.TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName=".NET Framework 4.6.2")] +[assembly: System.Runtime.Versioning.TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName=".NET Standard 2.0")] namespace Akavache { public class Registrations diff --git a/src/Akavache.Tests/API/ApiApprovalTests.cs b/src/Akavache.Tests/API/ApiApprovalTests.cs index 6bfe934d1..669929771 100644 --- a/src/Akavache.Tests/API/ApiApprovalTests.cs +++ b/src/Akavache.Tests/API/ApiApprovalTests.cs @@ -1,99 +1,41 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics.CodeAnalysis; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text.RegularExpressions; using Akavache.Sqlite3; -using DiffEngine; - -using PublicApiGenerator; - -using Splat; - -using Xunit; - namespace Akavache.APITests; /// /// Tests for handling API approval. /// [ExcludeFromCodeCoverage] +[UsesVerify] public class ApiApprovalTests { - private static readonly Regex _removeCoverletSectionRegex = new(@"^namespace Coverlet\.Core\.Instrumentation\.Tracker.*?^}", RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.Compiled); - /// /// Tests to make sure the akavache project is approved. /// + /// A representing the asynchronous unit test. [Fact] - public void AkavacheProject() => CheckApproval(typeof(SQLitePersistentBlobCache).Assembly); + public Task AkavacheProject() => typeof(SQLitePersistentBlobCache).Assembly.CheckApproval(["Akavache"]); /// /// Tests to make sure the akavache core project is approved. /// + /// A representing the asynchronous unit test. [Fact] - public void AkavacheCore() => CheckApproval(typeof(BlobCache).Assembly); + public Task AkavacheCore() => typeof(BlobCache).Assembly.CheckApproval(["Akavache"]); +#if !NETSTANDARD /// /// Tests to make sure the akavache drawing project is approved. /// -#if !NETSTANDARD + /// A representing the asynchronous unit test. [Fact] - public void AkavacheDrawing() => CheckApproval(typeof(Akavache.Drawing.Registrations).Assembly); + public Task AkavacheDrawing() => typeof(Akavache.Drawing.Registrations).Assembly.CheckApproval(["Akavache"]); #endif - - private static void CheckApproval(Assembly assembly, [CallerMemberName] string memberName = null, [CallerFilePath] string filePath = null) - { - var targetFrameworkName = Assembly.GetExecutingAssembly().GetTargetFrameworkName(); - - var sourceDirectory = Path.GetDirectoryName(filePath); - - var approvedFileName = Path.Combine(sourceDirectory, $"ApiApprovalTests.{memberName}.{targetFrameworkName}.approved.txt"); - var receivedFileName = Path.Combine(sourceDirectory, $"ApiApprovalTests.{memberName}.{targetFrameworkName}.received.txt"); - - if (!File.Exists(receivedFileName)) - { - File.Create(receivedFileName).Close(); - } - - if (!File.Exists(approvedFileName)) - { - File.Create(approvedFileName).Close(); - } - - var approvedPublicApi = File.ReadAllText(approvedFileName); - - var generatorOptions = new ApiGeneratorOptions { AllowNamespacePrefixes = new[] { "Akavache" } }; - var receivedPublicApi = Filter(assembly.GeneratePublicApi(generatorOptions)); - - if (!string.Equals(receivedPublicApi, approvedPublicApi, StringComparison.InvariantCulture)) - { - File.WriteAllText(receivedFileName, receivedPublicApi); - DiffRunner.Launch(receivedFileName, approvedFileName); - } - - Assert.Equal(approvedPublicApi, receivedPublicApi); - } - - private static string Filter(string text) - { - text = _removeCoverletSectionRegex.Replace(text, string.Empty); - return string.Join(Environment.NewLine, text.Split( - new[] - { - Environment.NewLine - }, - StringSplitOptions.RemoveEmptyEntries) - .Where(l => - !l.StartsWith("[assembly: AssemblyVersion(", StringComparison.InvariantCulture) && - !l.StartsWith("[assembly: AssemblyFileVersion(", StringComparison.InvariantCulture) && - !l.StartsWith("[assembly: AssemblyInformationalVersion(", StringComparison.InvariantCulture) && - !string.IsNullOrWhiteSpace(l))); - } } diff --git a/src/Akavache.Tests/API/ApiExtensions.cs b/src/Akavache.Tests/API/ApiExtensions.cs new file mode 100644 index 000000000..7978fcb2f --- /dev/null +++ b/src/Akavache.Tests/API/ApiExtensions.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2023 .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.Reflection; +using System.Runtime.CompilerServices; +using PublicApiGenerator; + +namespace Akavache.APITests; + +/// +/// A helper for doing API approvals. +/// +public static class ApiExtensions +{ + /// + /// Checks to make sure the API is approved. + /// + /// The assembly that is being checked. + /// The namespaces. + /// The caller file path. + /// + /// A Task. + /// + public static async Task CheckApproval(this Assembly assembly, string[] namespaces, [CallerFilePath] string filePath = "") + { + var generatorOptions = new ApiGeneratorOptions { AllowNamespacePrefixes = namespaces }; + var apiText = assembly.GeneratePublicApi(generatorOptions); + var result = await Verify(apiText, null, filePath) + .UniqueForRuntimeAndVersion() + .ScrubEmptyLines() + .ScrubLines(l => + l.StartsWith("[assembly: AssemblyVersion(", StringComparison.InvariantCulture) || + l.StartsWith("[assembly: AssemblyFileVersion(", StringComparison.InvariantCulture) || + l.StartsWith("[assembly: AssemblyInformationalVersion(", StringComparison.InvariantCulture) || + l.StartsWith("[assembly: System.Reflection.AssemblyMetadata(", StringComparison.InvariantCulture)); + } +} diff --git a/src/Akavache.Tests/Akavache.Tests.csproj b/src/Akavache.Tests/Akavache.Tests.csproj index 2979a93b2..619693a09 100644 --- a/src/Akavache.Tests/Akavache.Tests.csproj +++ b/src/Akavache.Tests/Akavache.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0 + net48;net6.0 $(NoWarn);CA1307;CA2000;CA1062 latest disable @@ -12,19 +12,20 @@ - + - - - + + + - + - + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Akavache.Tests/AsyncLockTests.cs b/src/Akavache.Tests/AsyncLockTests.cs index f0be81271..5c43484e2 100644 --- a/src/Akavache.Tests/AsyncLockTests.cs +++ b/src/Akavache.Tests/AsyncLockTests.cs @@ -1,10 +1,8 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Xunit; - using AsyncLock = Akavache.Sqlite3.Internal.AsyncLock; namespace Akavache.Tests; diff --git a/src/Akavache.Tests/BasicEncryptionTests.cs b/src/Akavache.Tests/BasicEncryptionTests.cs index 1a955da4c..eb476dc01 100644 --- a/src/Akavache.Tests/BasicEncryptionTests.cs +++ b/src/Akavache.Tests/BasicEncryptionTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Splat; -using Xunit; - namespace Akavache.Tests; /// @@ -22,12 +20,12 @@ public class BasicEncryptionTests public async Task ShouldEncrypt() { // TODO: This test is failing on .NET 6.0. Investigate. - Skip.IfNot(GetType().Assembly.GetTargetFrameworkName().StartsWith("net4")); + Skip.If(GetType().Assembly.GetTargetFrameworkName().StartsWith("net")); var provider = new EncryptionProvider(); var array = Encoding.ASCII.GetBytes("This is a test"); - var result = await AsArray(provider.EncryptBlock(array)).ConfigureAwait(false); + var result = await AsArray(provider.EncryptBlock(array)); Assert.True(array.Length < result.Length); // Encrypted bytes should be much larger. Assert.NotEqual(array.ToList(), result); @@ -45,8 +43,8 @@ public async Task ShouldDecrypt() var provider = new EncryptionProvider(); var array = Encoding.ASCII.GetBytes("This is a test"); - var encrypted = await AsArray(provider.EncryptBlock(array)).ConfigureAwait(false); - var decrypted = await AsArray(provider.DecryptBlock(encrypted)).ConfigureAwait(false); + var encrypted = await AsArray(provider.EncryptBlock(array)); + var decrypted = await AsArray(provider.DecryptBlock(encrypted)); Assert.Equal(array.ToList(), decrypted); Assert.Equal(Encoding.ASCII.GetString(decrypted), "This is a test"); } diff --git a/src/Akavache.Tests/BlockingDispose/BlockingDisposeBulkCache.cs b/src/Akavache.Tests/BlockingDispose/BlockingDisposeBulkCache.cs index c9f449d85..3356a9817 100644 --- a/src/Akavache.Tests/BlockingDispose/BlockingDisposeBulkCache.cs +++ b/src/Akavache.Tests/BlockingDispose/BlockingDisposeBulkCache.cs @@ -1,17 +1,12 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. namespace Akavache.Tests; -internal class BlockingDisposeBulkCache : BlockingDisposeCache, IObjectBulkBlobCache +internal class BlockingDisposeBulkCache(IBlobCache inner) : BlockingDisposeCache(inner), IObjectBulkBlobCache { - public BlockingDisposeBulkCache(IBlobCache inner) - : base(inner) - { - } - public IObservable Insert(IDictionary keyValuePairs, DateTimeOffset? absoluteExpiration = null) => Inner.Insert(keyValuePairs, absoluteExpiration); public IObservable> Get(IEnumerable keys) => Inner.Get(keys); diff --git a/src/Akavache.Tests/BlockingDispose/BlockingDisposeCache.cs b/src/Akavache.Tests/BlockingDispose/BlockingDisposeCache.cs index 2d23c220b..6da56bd2c 100644 --- a/src/Akavache.Tests/BlockingDispose/BlockingDisposeCache.cs +++ b/src/Akavache.Tests/BlockingDispose/BlockingDisposeCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/BlockingDispose/BlockingDisposeObjectCache.cs b/src/Akavache.Tests/BlockingDispose/BlockingDisposeObjectCache.cs index 93687b2a3..9758491d8 100644 --- a/src/Akavache.Tests/BlockingDispose/BlockingDisposeObjectCache.cs +++ b/src/Akavache.Tests/BlockingDispose/BlockingDisposeObjectCache.cs @@ -1,17 +1,12 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. namespace Akavache.Tests; -internal class BlockingDisposeObjectCache : BlockingDisposeCache, IObjectBlobCache +internal class BlockingDisposeObjectCache(IObjectBlobCache cache) : BlockingDisposeCache(cache), IObjectBlobCache { - public BlockingDisposeObjectCache(IObjectBlobCache cache) - : base(cache) - { - } - public IObservable InsertObject(string key, T value, DateTimeOffset? absoluteExpiration = null) => ((IObjectBlobCache)Inner).InsertObject(key, value, absoluteExpiration); public IObservable GetObject(string key) => ((IObjectBlobCache)Inner).GetObject(key); diff --git a/src/Akavache.Tests/CoalescerTests.cs b/src/Akavache.Tests/CoalescerTests.cs index 316d5bcaa..8721590df 100644 --- a/src/Akavache.Tests/CoalescerTests.cs +++ b/src/Akavache.Tests/CoalescerTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -7,8 +7,6 @@ using DynamicData; -using Xunit; - #pragma warning disable CS4014 // Await on awaitable items. -- We don't wait on the observables. namespace Akavache.Tests; @@ -175,9 +173,9 @@ public void InterpolatedOpsDontGetDeduped() { var fixture = new SqliteOperationQueue(); fixture.Select(new[] { "Foo" }); - fixture.Insert(new[] { new CacheElement { Key = "Foo", Value = new byte[] { 1, 2, 3 } } }); + fixture.Insert(new[] { new CacheElement { Key = "Foo", Value = [1, 2, 3] } }); fixture.Select(new[] { "Foo" }); - fixture.Insert(new[] { new CacheElement { Key = "Foo", Value = new byte[] { 4, 5, 6 } } }); + fixture.Insert(new[] { new CacheElement { Key = "Foo", Value = [4, 5, 6] } }); var queue = fixture.DumpQueue(); var result = SqliteOperationQueue.CoalesceOperations(queue); diff --git a/src/Akavache.Tests/DateTimeResolverTests.cs b/src/Akavache.Tests/DateTimeResolverTests.cs index e8e147ec5..29acbb76e 100644 --- a/src/Akavache.Tests/DateTimeResolverTests.cs +++ b/src/Akavache.Tests/DateTimeResolverTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Newtonsoft.Json.Serialization; -using Xunit; - namespace Akavache.Tests; /// diff --git a/src/Akavache.Tests/EncryptedSqliteBlobBulkExtensionsTest.cs b/src/Akavache.Tests/EncryptedSqliteBlobBulkExtensionsTest.cs index c138a0390..d9ecfb047 100644 --- a/src/Akavache.Tests/EncryptedSqliteBlobBulkExtensionsTest.cs +++ b/src/Akavache.Tests/EncryptedSqliteBlobBulkExtensionsTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/EncryptedSqliteBlobCacheBulkOperationsTests.cs b/src/Akavache.Tests/EncryptedSqliteBlobCacheBulkOperationsTests.cs index 8a7f6b7e9..d885f22e3 100644 --- a/src/Akavache.Tests/EncryptedSqliteBlobCacheBulkOperationsTests.cs +++ b/src/Akavache.Tests/EncryptedSqliteBlobCacheBulkOperationsTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/EncryptedSqliteBlobCacheDateTimeTests.cs b/src/Akavache.Tests/EncryptedSqliteBlobCacheDateTimeTests.cs index bbe3ac74b..d4c2024fb 100644 --- a/src/Akavache.Tests/EncryptedSqliteBlobCacheDateTimeTests.cs +++ b/src/Akavache.Tests/EncryptedSqliteBlobCacheDateTimeTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/EncryptedSqliteBlobCacheExtensionsFixture.cs b/src/Akavache.Tests/EncryptedSqliteBlobCacheExtensionsFixture.cs index 9001b6dba..f81c514cc 100644 --- a/src/Akavache.Tests/EncryptedSqliteBlobCacheExtensionsFixture.cs +++ b/src/Akavache.Tests/EncryptedSqliteBlobCacheExtensionsFixture.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/EncryptedSqliteBlobCacheObjectBulkOperationsTests.cs b/src/Akavache.Tests/EncryptedSqliteBlobCacheObjectBulkOperationsTests.cs index 46e0b665d..e8fcbfaff 100644 --- a/src/Akavache.Tests/EncryptedSqliteBlobCacheObjectBulkOperationsTests.cs +++ b/src/Akavache.Tests/EncryptedSqliteBlobCacheObjectBulkOperationsTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Fixtures/DummyRoutedViewModel.cs b/src/Akavache.Tests/Fixtures/DummyRoutedViewModel.cs index a91df4e80..9e834c375 100644 --- a/src/Akavache.Tests/Fixtures/DummyRoutedViewModel.cs +++ b/src/Akavache.Tests/Fixtures/DummyRoutedViewModel.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -12,17 +12,15 @@ namespace Akavache.Tests; /// /// A dummy object used in tests that replicates a routed view model. /// +/// +/// Initializes a new instance of the class. +/// +/// The screen object to set. [DataContract] -public class DummyRoutedViewModel : ReactiveObject, IRoutableViewModel +public class DummyRoutedViewModel(IScreen screen) : ReactiveObject, IRoutableViewModel { private Guid _aRandomGuid; - /// - /// Initializes a new instance of the class. - /// - /// The screen object to set. - public DummyRoutedViewModel(IScreen screen) => HostScreen = screen; - /// /// Gets the url path segment. /// @@ -32,7 +30,7 @@ public class DummyRoutedViewModel : ReactiveObject, IRoutableViewModel /// Gets the host screen. /// [DataMember] - public IScreen HostScreen { get; private set; } + public IScreen HostScreen { get; private set; } = screen; /// /// Gets or sets a guid value. diff --git a/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionContractResolver.cs b/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionContractResolver.cs index 71b5c85ec..888bc892a 100644 --- a/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionContractResolver.cs +++ b/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionContractResolver.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs b/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs index c46de0eb0..6325e1814 100644 --- a/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs +++ b/src/Akavache.Tests/Fixtures/FakeDateTimeHighPrecisionJsonConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Fixtures/ServiceProvider.cs b/src/Akavache.Tests/Fixtures/ServiceProvider.cs index 934b768f1..804beae62 100644 --- a/src/Akavache.Tests/Fixtures/ServiceProvider.cs +++ b/src/Akavache.Tests/Fixtures/ServiceProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Fixtures/TestObjectDateTime.cs b/src/Akavache.Tests/Fixtures/TestObjectDateTime.cs index 5f63da8cd..9a3e0374a 100644 --- a/src/Akavache.Tests/Fixtures/TestObjectDateTime.cs +++ b/src/Akavache.Tests/Fixtures/TestObjectDateTime.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Fixtures/TestObjectDateTimeOffset.cs b/src/Akavache.Tests/Fixtures/TestObjectDateTimeOffset.cs index 5f1882699..451940646 100644 --- a/src/Akavache.Tests/Fixtures/TestObjectDateTimeOffset.cs +++ b/src/Akavache.Tests/Fixtures/TestObjectDateTimeOffset.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Fixtures/UserModel.cs b/src/Akavache.Tests/Fixtures/UserModel.cs index eb00bc285..cd1dcdac5 100644 --- a/src/Akavache.Tests/Fixtures/UserModel.cs +++ b/src/Akavache.Tests/Fixtures/UserModel.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -8,14 +8,12 @@ namespace Akavache.Tests; /// /// A mock for the user models. /// -public class UserModel +/// +/// Initializes a new instance of the class. +/// +/// The user to abstract. +public class UserModel(UserObject user) { - /// - /// Initializes a new instance of the class. - /// - /// The user to abstract. - public UserModel(UserObject user) => User = user; - /// /// Gets or sets the name. /// @@ -29,5 +27,5 @@ public class UserModel /// /// Gets or sets the user. /// - public UserObject User { get; set; } + public UserObject User { get; set; } = user; } \ No newline at end of file diff --git a/src/Akavache.Tests/Fixtures/UserObject.cs b/src/Akavache.Tests/Fixtures/UserObject.cs index a40c8fa31..38385b1c9 100644 --- a/src/Akavache.Tests/Fixtures/UserObject.cs +++ b/src/Akavache.Tests/Fixtures/UserObject.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs b/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs index 7f84364eb..aacf91440 100644 --- a/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs +++ b/src/Akavache.Tests/Helpers/IntegrationTestHelper.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -45,7 +45,11 @@ public static string GetIntegrationTestRootDirectory() /// /// The paths for the web service. /// The response from the server. +#if NETFRAMEWORK + public static System.Net.Http.HttpResponseMessage GetResponse(params string[] paths) +#else public static HttpResponseMessage GetResponse(params string[] paths) +#endif { var bytes = File.ReadAllBytes(GetPath(paths)); @@ -69,10 +73,17 @@ public static HttpResponseMessage GetResponse(params string[] paths) var headerText = Encoding.UTF8.GetString(bytes, 0, bodyIndex); var lines = headerText.Split('\n'); var statusCode = (HttpStatusCode)int.Parse(lines[0].Split(' ')[1], CultureInfo.InvariantCulture); +#if NETFRAMEWORK + var ret = new System.Net.Http.HttpResponseMessage(statusCode) + { + Content = new System.Net.Http.ByteArrayContent(bytes, bodyIndex + 2, bytes.Length - bodyIndex - 2) + }; +#else var ret = new HttpResponseMessage(statusCode) { Content = new ByteArrayContent(bytes, bodyIndex + 2, bytes.Length - bodyIndex - 2) }; +#endif foreach (var line in lines.Skip(1)) { diff --git a/src/Akavache.Tests/Helpers/Utility.cs b/src/Akavache.Tests/Helpers/Utility.cs index 85560b7a5..bc45ca70c 100644 --- a/src/Akavache.Tests/Helpers/Utility.cs +++ b/src/Akavache.Tests/Helpers/Utility.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/InMemoryBlobCacheBulkOperationsTests.cs b/src/Akavache.Tests/InMemoryBlobCacheBulkOperationsTests.cs index d338c1ed5..711650f8a 100644 --- a/src/Akavache.Tests/InMemoryBlobCacheBulkOperationsTests.cs +++ b/src/Akavache.Tests/InMemoryBlobCacheBulkOperationsTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/InMemoryBlobCacheDateTimeTests.cs b/src/Akavache.Tests/InMemoryBlobCacheDateTimeTests.cs index fc687fdf2..e01dd1e9c 100644 --- a/src/Akavache.Tests/InMemoryBlobCacheDateTimeTests.cs +++ b/src/Akavache.Tests/InMemoryBlobCacheDateTimeTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/InMemoryBlobCacheInterfaceTests.cs b/src/Akavache.Tests/InMemoryBlobCacheInterfaceTests.cs index 32c1204ae..dd0222acc 100644 --- a/src/Akavache.Tests/InMemoryBlobCacheInterfaceTests.cs +++ b/src/Akavache.Tests/InMemoryBlobCacheInterfaceTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/InMemoryBlobCacheObjectBulkOperationsTests.cs b/src/Akavache.Tests/InMemoryBlobCacheObjectBulkOperationsTests.cs index f60446f38..5efc01ae4 100644 --- a/src/Akavache.Tests/InMemoryBlobCacheObjectBulkOperationsTests.cs +++ b/src/Akavache.Tests/InMemoryBlobCacheObjectBulkOperationsTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/InMemoryBlobCacheTests.cs b/src/Akavache.Tests/InMemoryBlobCacheTests.cs index 7be3ed8ad..66c8ad450 100644 --- a/src/Akavache.Tests/InMemoryBlobCacheTests.cs +++ b/src/Akavache.Tests/InMemoryBlobCacheTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Performance/PerfHelper.cs b/src/Akavache.Tests/Performance/PerfHelper.cs index e58e03ea4..e337570e0 100644 --- a/src/Akavache.Tests/Performance/PerfHelper.cs +++ b/src/Akavache.Tests/Performance/PerfHelper.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Performance/ReadTests.cs b/src/Akavache.Tests/Performance/ReadTests.cs index 56b5bf392..23583680b 100644 --- a/src/Akavache.Tests/Performance/ReadTests.cs +++ b/src/Akavache.Tests/Performance/ReadTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics; -using Xunit; - namespace Akavache.Tests.Performance; /// diff --git a/src/Akavache.Tests/Performance/Sqlite3ReadTests.cs b/src/Akavache.Tests/Performance/Sqlite3ReadTests.cs index 72b63f8a3..13a74189f 100644 --- a/src/Akavache.Tests/Performance/Sqlite3ReadTests.cs +++ b/src/Akavache.Tests/Performance/Sqlite3ReadTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Performance/Sqlite3WriteTests.cs b/src/Akavache.Tests/Performance/Sqlite3WriteTests.cs index 05184445e..9eba8d708 100644 --- a/src/Akavache.Tests/Performance/Sqlite3WriteTests.cs +++ b/src/Akavache.Tests/Performance/Sqlite3WriteTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/Performance/WriteTests.cs b/src/Akavache.Tests/Performance/WriteTests.cs index cf1ab1af0..0ee23e3c4 100644 --- a/src/Akavache.Tests/Performance/WriteTests.cs +++ b/src/Akavache.Tests/Performance/WriteTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Diagnostics; -using Xunit; - namespace Akavache.Tests.Performance; /// diff --git a/src/Akavache.Tests/SqliteBlobCacheBulkExtensionsTest.cs b/src/Akavache.Tests/SqliteBlobCacheBulkExtensionsTest.cs index 2f2163095..036a931a5 100644 --- a/src/Akavache.Tests/SqliteBlobCacheBulkExtensionsTest.cs +++ b/src/Akavache.Tests/SqliteBlobCacheBulkExtensionsTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/SqliteBlobCacheBulkOperationsTests.cs b/src/Akavache.Tests/SqliteBlobCacheBulkOperationsTests.cs index 2888e145f..7985862e9 100644 --- a/src/Akavache.Tests/SqliteBlobCacheBulkOperationsTests.cs +++ b/src/Akavache.Tests/SqliteBlobCacheBulkOperationsTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/SqliteBlobCacheDateTimeTests.cs b/src/Akavache.Tests/SqliteBlobCacheDateTimeTests.cs index 507ebbf8d..2dc40a4e0 100644 --- a/src/Akavache.Tests/SqliteBlobCacheDateTimeTests.cs +++ b/src/Akavache.Tests/SqliteBlobCacheDateTimeTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/SqliteBlobCacheExtensionsTests.cs b/src/Akavache.Tests/SqliteBlobCacheExtensionsTests.cs index c165b7164..ea402b32f 100644 --- a/src/Akavache.Tests/SqliteBlobCacheExtensionsTests.cs +++ b/src/Akavache.Tests/SqliteBlobCacheExtensionsTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Sqlite3; -using Xunit; - namespace Akavache.Tests; /// diff --git a/src/Akavache.Tests/SqliteBlobCacheInterfaceTests.cs b/src/Akavache.Tests/SqliteBlobCacheInterfaceTests.cs index e8c660e47..5871ce388 100644 --- a/src/Akavache.Tests/SqliteBlobCacheInterfaceTests.cs +++ b/src/Akavache.Tests/SqliteBlobCacheInterfaceTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/SqliteBlobCacheObjectBulkOperationsTests.cs b/src/Akavache.Tests/SqliteBlobCacheObjectBulkOperationsTests.cs index 0b2092b28..a30f63ace 100644 --- a/src/Akavache.Tests/SqliteBlobCacheObjectBulkOperationsTests.cs +++ b/src/Akavache.Tests/SqliteBlobCacheObjectBulkOperationsTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. diff --git a/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs b/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs index a5fdec7ca..0acfede53 100644 --- a/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs +++ b/src/Akavache.Tests/TestBases/BlobCacheExtensionsTestBase.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -11,7 +11,6 @@ using ReactiveUI.Testing; using Splat; -using Xunit; namespace Akavache.Tests; @@ -251,7 +250,7 @@ public async Task ArraysShouldBeRoundtrippableUsingObjectFactory() public async Task FetchFunctionShouldBeCalledOnceForGetOrFetchObject() { // TODO: This test is failing on .NET 6.0. Investigate. - Skip.IfNot(GetType().Assembly.GetTargetFrameworkName().StartsWith("net4")); + Skip.If(GetType().Assembly.GetTargetFrameworkName().StartsWith("net")); var fetchCount = 0; var fetcher = new Func>>(() => @@ -300,7 +299,7 @@ public void FetchFunctionShouldDebounceConcurrentRequests() => new TestScheduler().With(sched => { // TODO: TestScheduler tests aren't gonna work with new SQLite. - Skip.IfNot(GetType().Assembly.GetTargetFrameworkName().StartsWith("net4")); + Skip.If(GetType().Assembly.GetTargetFrameworkName().StartsWith("net")); using (Utility.WithEmptyDirectory(out var path)) { var callCount = 0; @@ -434,7 +433,7 @@ public void GetOrFetchShouldRespectExpiration() => new TestScheduler().With(sched => { // TODO: TestScheduler tests aren't gonna work with new SQLite. - Skip.IfNot(GetType().Assembly.GetTargetFrameworkName().StartsWith("net4")); + Skip.If(GetType().Assembly.GetTargetFrameworkName().StartsWith("net")); using (Utility.WithEmptyDirectory(out var path)) { var fixture = CreateBlobCache(path); diff --git a/src/Akavache.Tests/TestBases/BlobCacheInterfaceTestBase.cs b/src/Akavache.Tests/TestBases/BlobCacheInterfaceTestBase.cs index 264ea027b..6e85063a2 100644 --- a/src/Akavache.Tests/TestBases/BlobCacheInterfaceTestBase.cs +++ b/src/Akavache.Tests/TestBases/BlobCacheInterfaceTestBase.cs @@ -1,15 +1,12 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Reactive.Threading.Tasks; - using Microsoft.Reactive.Testing; - using ReactiveUI.Testing; using Splat; -using Xunit; namespace Akavache.Tests; @@ -28,19 +25,19 @@ public async Task CacheShouldBeAbleToGetAndInsertBlobs() using (Utility.WithEmptyDirectory(out var path)) using (var fixture = CreateBlobCache(path)) { - await fixture.Insert("Foo", new byte[] { 1, 2, 3 }); - await fixture.Insert("Bar", new byte[] { 4, 5, 6 }); + await fixture.Insert("Foo", [1, 2, 3]); + await fixture.Insert("Bar", [4, 5, 6]); - await Assert.ThrowsAsync(async () => await fixture.Insert(null, new byte[] { 7, 8, 9 }).FirstAsync()).ConfigureAwait(false); + await Assert.ThrowsAsync(async () => await fixture.Insert(null, [7, 8, 9]).FirstAsync()); var output1 = await fixture.Get("Foo"); var output2 = await fixture.Get("Bar"); await Assert.ThrowsAsync(async () => - await fixture.Get(null).FirstAsync()).ConfigureAwait(false); + await fixture.Get(null).FirstAsync()); await Assert.ThrowsAsync(async () => - await fixture.Get("Baz").FirstAsync()).ConfigureAwait(false); + await fixture.Get("Baz").FirstAsync()); Assert.Equal(3, output1.Length); Assert.Equal(3, output2.Length); @@ -68,7 +65,7 @@ public async Task CacheShouldBeRoundtrippable() return; } - await fixture.Insert("Foo", new byte[] { 1, 2, 3 }); + await fixture.Insert("Foo", [1, 2, 3]); } fixture.Shutdown.Wait(); @@ -93,7 +90,7 @@ public void CreatedAtShouldBeSetAutomaticallyAndBeRetrievable() DateTimeOffset roughCreationTime; using (fixture) { - fixture.Insert("Foo", new byte[] { 1, 2, 3 }).Wait(); + fixture.Insert("Foo", [1, 2, 3]).Wait(); roughCreationTime = fixture.Scheduler.Now; } @@ -121,13 +118,13 @@ public async Task InsertingAnItemTwiceShouldAlwaysGetTheNewOne() using (Utility.WithEmptyDirectory(out var path)) using (var fixture = CreateBlobCache(path)) { - fixture.Insert("Foo", new byte[] { 1, 2, 3 }).Wait(); + fixture.Insert("Foo", [1, 2, 3]).Wait(); var output = await fixture.Get("Foo").FirstAsync(); Assert.Equal(3, output.Length); Assert.Equal(1, output[0]); - fixture.Insert("Foo", new byte[] { 4, 5 }).Wait(); + fixture.Insert("Foo", [4, 5]).Wait(); output = await fixture.Get("Foo").FirstAsync(); Assert.Equal(2, output.Length); @@ -142,7 +139,7 @@ public async Task InsertingAnItemTwiceShouldAlwaysGetTheNewOne() public void CacheShouldRespectExpiration() { // TODO: TestScheduler tests aren't gonna work with new SQLite. - Skip.IfNot(GetType().Assembly.GetTargetFrameworkName().StartsWith("net4")); + Skip.If(GetType().Assembly.GetTargetFrameworkName().StartsWith("net")); using (Utility.WithEmptyDirectory(out var path)) { new TestScheduler().With(sched => @@ -152,8 +149,8 @@ public void CacheShouldRespectExpiration() using (var fixture = CreateBlobCache(path)) { wasTestCache = fixture is InMemoryBlobCache; - fixture.Insert("foo", new byte[] { 1, 2, 3 }, TimeSpan.FromMilliseconds(100)); - fixture.Insert("bar", new byte[] { 4, 5, 6 }, TimeSpan.FromMilliseconds(500)); + fixture.Insert("foo", [1, 2, 3], TimeSpan.FromMilliseconds(100)); + fixture.Insert("bar", [4, 5, 6], TimeSpan.FromMilliseconds(500)); byte[] result = null; sched.AdvanceToMs(20); @@ -168,7 +165,7 @@ public void CacheShouldRespectExpiration() sched.AdvanceToMs(120); fixture.Get("foo").Subscribe( x => result = x, - ex => shouldFail = false); + _ => shouldFail = false); fixture.Get("bar").Subscribe(x => result = x); sched.AdvanceToMs(300); @@ -200,7 +197,7 @@ public void CacheShouldRespectExpiration() sched.AdvanceToMs(1000); fixture.Get("bar").Subscribe( x => result = x, - ex => shouldFail = false); + _ => shouldFail = false); sched.AdvanceToMs(1010); Assert.False(shouldFail); @@ -222,9 +219,9 @@ public async Task InvalidateAllReallyDoesInvalidateEverything() { using (var fixture = CreateBlobCache(path)) { - await fixture.Insert("Foo", new byte[] { 1, 2, 3 }).FirstAsync(); - await fixture.Insert("Bar", new byte[] { 4, 5, 6 }).FirstAsync(); - await fixture.Insert("Bamf", new byte[] { 7, 8, 9 }).FirstAsync(); + await fixture.Insert("Foo", [1, 2, 3]).FirstAsync(); + await fixture.Insert("Bar", [4, 5, 6]).FirstAsync(); + await fixture.Insert("Bamf", [7, 8, 9]).FirstAsync(); Assert.NotEqual(0, (await fixture.GetAllKeys().FirstAsync()).Count()); @@ -253,9 +250,9 @@ public async Task GetAllKeysShouldntReturnExpiredKeys() { var inThePast = BlobCache.TaskpoolScheduler.Now - TimeSpan.FromDays(1.0); - await fixture.Insert("Foo", new byte[] { 1, 2, 3 }, inThePast).FirstAsync(); - await fixture.Insert("Bar", new byte[] { 4, 5, 6 }, inThePast).FirstAsync(); - await fixture.Insert("Bamf", new byte[] { 7, 8, 9 }).FirstAsync(); + await fixture.Insert("Foo", [1, 2, 3], inThePast).FirstAsync(); + await fixture.Insert("Bar", [4, 5, 6], inThePast).FirstAsync(); + await fixture.Insert("Bamf", [7, 8, 9]).FirstAsync(); Assert.Equal(1, (await fixture.GetAllKeys().FirstAsync()).Count()); } @@ -286,10 +283,10 @@ public async Task VacuumDoesntPurgeKeysThatShouldBeThere() var inThePast = BlobCache.TaskpoolScheduler.Now - TimeSpan.FromDays(1.0); var inTheFuture = BlobCache.TaskpoolScheduler.Now + TimeSpan.FromDays(1.0); - await fixture.Insert("Foo", new byte[] { 1, 2, 3 }, inThePast).FirstAsync(); - await fixture.Insert("Bar", new byte[] { 4, 5, 6 }, inThePast).FirstAsync(); - await fixture.Insert("Bamf", new byte[] { 7, 8, 9 }).FirstAsync(); - await fixture.Insert("Baz", new byte[] { 7, 8, 9 }, inTheFuture).FirstAsync(); + await fixture.Insert("Foo", [1, 2, 3], inThePast).FirstAsync(); + await fixture.Insert("Bar", [4, 5, 6], inThePast).FirstAsync(); + await fixture.Insert("Bamf", [7, 8, 9]).FirstAsync(); + await fixture.Insert("Baz", [7, 8, 9], inTheFuture).FirstAsync(); try { @@ -329,10 +326,10 @@ public async Task VacuumPurgeEntriesThatAreExpired() var inThePast = BlobCache.TaskpoolScheduler.Now - TimeSpan.FromDays(1.0); var inTheFuture = BlobCache.TaskpoolScheduler.Now + TimeSpan.FromDays(1.0); - await fixture.Insert("Foo", new byte[] { 1, 2, 3 }, inThePast).FirstAsync(); - await fixture.Insert("Bar", new byte[] { 4, 5, 6 }, inThePast).FirstAsync(); - await fixture.Insert("Bamf", new byte[] { 7, 8, 9 }).FirstAsync(); - await fixture.Insert("Baz", new byte[] { 7, 8, 9 }, inTheFuture).FirstAsync(); + await fixture.Insert("Foo", [1, 2, 3], inThePast).FirstAsync(); + await fixture.Insert("Bar", [4, 5, 6], inThePast).FirstAsync(); + await fixture.Insert("Bamf", [7, 8, 9]).FirstAsync(); + await fixture.Insert("Baz", [7, 8, 9], inTheFuture).FirstAsync(); try { @@ -344,8 +341,8 @@ public async Task VacuumPurgeEntriesThatAreExpired() // just make the test pass } - await Assert.ThrowsAsync(() => fixture.Get("Foo").FirstAsync().ToTask()).ConfigureAwait(false); - await Assert.ThrowsAsync(() => fixture.Get("Bar").FirstAsync().ToTask()).ConfigureAwait(false); + await Assert.ThrowsAsync(() => fixture.Get("Foo").FirstAsync().ToTask()); + await Assert.ThrowsAsync(() => fixture.Get("Bar").FirstAsync().ToTask()); } } diff --git a/src/Akavache.Tests/TestBases/BulkOperationsTestBase.cs b/src/Akavache.Tests/TestBases/BulkOperationsTestBase.cs index 6b93c0bfe..7e7abec1e 100644 --- a/src/Akavache.Tests/TestBases/BulkOperationsTestBase.cs +++ b/src/Akavache.Tests/TestBases/BulkOperationsTestBase.cs @@ -1,10 +1,8 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Xunit; - namespace Akavache.Tests; /// @@ -110,4 +108,4 @@ public async Task InvalidateShouldTrashMultipleKeys() /// The path to the blob cache. /// The blob cache for testing. protected abstract IBlobCache CreateBlobCache(string path); -} \ No newline at end of file +} diff --git a/src/Akavache.Tests/TestBases/DateTimeTestBase.cs b/src/Akavache.Tests/TestBases/DateTimeTestBase.cs index 6c73c97ed..8453441ad 100644 --- a/src/Akavache.Tests/TestBases/DateTimeTestBase.cs +++ b/src/Akavache.Tests/TestBases/DateTimeTestBase.cs @@ -1,10 +1,8 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Xunit; - namespace Akavache.Tests; /// @@ -18,7 +16,7 @@ public abstract class DateTimeTestBase public static IEnumerable DateTimeOffsetData => new[] { new object[] { new TestObjectDateTimeOffset { Timestamp = TestNowOffset, TimestampNullable = null } }, - new object[] { new TestObjectDateTimeOffset { Timestamp = TestNowOffset, TimestampNullable = TestNowOffset } }, + [new TestObjectDateTimeOffset { Timestamp = TestNowOffset, TimestampNullable = TestNowOffset }], }; /// @@ -27,7 +25,7 @@ public abstract class DateTimeTestBase public static IEnumerable DateTimeData => new[] { new object[] { new TestObjectDateTime { Timestamp = TestNow, TimestampNullable = null } }, - new object[] { new TestObjectDateTime { Timestamp = TestNow, TimestampNullable = TestNow } }, + [new TestObjectDateTime { Timestamp = TestNow, TimestampNullable = TestNow }], }; /// @@ -36,7 +34,7 @@ public abstract class DateTimeTestBase public static IEnumerable DateLocalTimeData => new[] { new object[] { new TestObjectDateTime { Timestamp = LocalTestNow, TimestampNullable = null } }, - new object[] { new TestObjectDateTime { Timestamp = LocalTestNow, TimestampNullable = LocalTestNow } }, + [new TestObjectDateTime { Timestamp = LocalTestNow, TimestampNullable = LocalTestNow }], }; /// @@ -66,7 +64,7 @@ public async Task GetOrFetchAsyncDateTimeOffsetShouldBeEqualEveryTime(TestObject using (Utility.WithEmptyDirectory(out var path)) using (var blobCache = CreateBlobCache(path)) { - var (firstResult, secondResult) = await PerformTimeStampGrab(blobCache, data).ConfigureAwait(false); + var (firstResult, secondResult) = await PerformTimeStampGrab(blobCache, data); Assert.Equal(firstResult.Timestamp, secondResult.Timestamp); Assert.Equal(firstResult.Timestamp.UtcTicks, secondResult.Timestamp.UtcTicks); Assert.Equal(firstResult.Timestamp.Offset, secondResult.Timestamp.Offset); @@ -87,7 +85,7 @@ public async Task GetOrFetchAsyncDateTimeShouldBeEqualEveryTime(TestObjectDateTi using (Utility.WithEmptyDirectory(out var path)) using (var blobCache = CreateBlobCache(path)) { - var (firstResult, secondResult) = await PerformTimeStampGrab(blobCache, data).ConfigureAwait(false); + var (firstResult, secondResult) = await PerformTimeStampGrab(blobCache, data); Assert.Equal(secondResult.Timestamp.Kind, DateTimeKind.Utc); Assert.Equal(firstResult.Timestamp.ToUniversalTime(), secondResult.Timestamp.ToUniversalTime()); Assert.Equal(firstResult.TimestampNullable?.ToUniversalTime(), secondResult.TimestampNullable?.ToUniversalTime()); @@ -107,7 +105,7 @@ public async Task GetOrFetchAsyncDateTimeWithForcedLocal(TestObjectDateTime data using (var blobCache = CreateBlobCache(path)) { blobCache.ForcedDateTimeKind = DateTimeKind.Local; - var (firstResult, secondResult) = await PerformTimeStampGrab(blobCache, data).ConfigureAwait(false); + var (firstResult, secondResult) = await PerformTimeStampGrab(blobCache, data); Assert.Equal(secondResult.Timestamp.Kind, DateTimeKind.Local); Assert.Equal(firstResult.Timestamp, secondResult.Timestamp); Assert.Equal(firstResult.Timestamp.ToUniversalTime(), secondResult.Timestamp.ToUniversalTime()); diff --git a/src/Akavache.Tests/TestBases/ObjectBulkOperationsTestBase.cs b/src/Akavache.Tests/TestBases/ObjectBulkOperationsTestBase.cs index b8b7758e5..4bc091300 100644 --- a/src/Akavache.Tests/TestBases/ObjectBulkOperationsTestBase.cs +++ b/src/Akavache.Tests/TestBases/ObjectBulkOperationsTestBase.cs @@ -1,10 +1,8 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Xunit; - namespace Akavache.Tests; /// @@ -25,7 +23,7 @@ public async Task GetShouldWorkWithMultipleKeys() var data = Tuple.Create("Foo", 4); var keys = new[] { "Foo", "Bar", "Baz", }; - await Task.WhenAll(keys.Select(async v => await fixture.InsertObject(v, data).FirstAsync())).ConfigureAwait(false); + await Task.WhenAll(keys.Select(async v => await fixture.InsertObject(v, data).FirstAsync())); Assert.Equal(keys.Length, (await fixture.GetAllKeys().FirstAsync()).Count()); @@ -49,7 +47,7 @@ public async Task GetShouldInvalidateOldKeys() var data = Tuple.Create("Foo", 4); var keys = new[] { "Foo", "Bar", "Baz", }; - await Task.WhenAll(keys.Select(async v => await fixture.InsertObject(v, data, DateTimeOffset.MinValue).FirstAsync())).ConfigureAwait(false); + await Task.WhenAll(keys.Select(async v => await fixture.InsertObject(v, data, DateTimeOffset.MinValue).FirstAsync())); var allData = await fixture.GetObjects>(keys).FirstAsync(); Assert.Equal(0, allData.Count); @@ -94,7 +92,7 @@ public async Task InvalidateShouldTrashMultipleKeys() var data = Tuple.Create("Foo", 4); var keys = new[] { "Foo", "Bar", "Baz", }; - await Task.WhenAll(keys.Select(async v => await fixture.InsertObject(v, data).FirstAsync())).ConfigureAwait(false); + await Task.WhenAll(keys.Select(async v => await fixture.InsertObject(v, data).FirstAsync())); Assert.Equal(keys.Length, (await fixture.GetAllKeys().FirstAsync()).Count()); @@ -110,4 +108,4 @@ public async Task InvalidateShouldTrashMultipleKeys() /// The path to the blob cache. /// The blob cache for testing. protected abstract IBlobCache CreateBlobCache(string path); -} \ No newline at end of file +} diff --git a/src/Akavache.Tests/UtilityTests.cs b/src/Akavache.Tests/UtilityTests.cs index ed247925a..f10b3fc34 100644 --- a/src/Akavache.Tests/UtilityTests.cs +++ b/src/Akavache.Tests/UtilityTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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.Runtime.InteropServices; -using Xunit; - namespace Akavache.Tests; /// diff --git a/src/Akavache.sln b/src/Akavache.sln index 7e1d934e5..f04ed7394 100644 --- a/src/Akavache.sln +++ b/src/Akavache.sln @@ -5,9 +5,11 @@ VisualStudioVersion = 17.2.32616.157 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9407D902-E9CF-4CB6-B601-77CDF74B9475}" ProjectSection(SolutionItems) = preProject + ..\.github\workflows\ci-build.yml = ..\.github\workflows\ci-build.yml Directory.build.props = Directory.build.props Directory.build.targets = Directory.build.targets global.json = global.json + ..\.github\workflows\release.yml = ..\.github\workflows\release.yml stylecop.json = stylecop.json ..\version.json = ..\version.json EndProjectSection diff --git a/src/Akavache/Akavache.csproj b/src/Akavache/Akavache.csproj index b1632f6cc..eba4bcbbf 100644 --- a/src/Akavache/Akavache.csproj +++ b/src/Akavache/Akavache.csproj @@ -1,22 +1,17 @@ - + - netstandard2.0;netstandard2.1;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10;MonoAndroid12.0;MonoAndroid12.1;MonoAndroid13.0;tizen40;net6.0;net7.0;net7.0-android;net7.0-ios;net7.0-tvos;net7.0-macos;net7.0-maccatalyst - $(TargetFrameworks);net462 + $(AkavacheTargetFrameworks) Akavache Akavache An asynchronous, persistent key-value store for desktop and mobile applications on .NET akavache - latest - enable - - + - - + diff --git a/src/Akavache/LinkerPreserve.cs b/src/Akavache/LinkerPreserve.cs index 821c32e43..8ab0f7b95 100644 --- a/src/Akavache/LinkerPreserve.cs +++ b/src/Akavache/LinkerPreserve.cs @@ -1,11 +1,9 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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; using System.Diagnostics.CodeAnalysis; - using Akavache.Core; namespace Akavache.Sqlite3; diff --git a/src/Akavache/Properties/AssemblyInfo.cs b/src/Akavache/Properties/AssemblyInfo.cs index 6ffa486e8..40ea939b7 100644 --- a/src/Akavache/Properties/AssemblyInfo.cs +++ b/src/Akavache/Properties/AssemblyInfo.cs @@ -1,8 +1,6 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Core; - -[assembly: Preserve] +[assembly: Akavache.Core.Preserve] diff --git a/src/Akavache/Registrations.cs b/src/Akavache/Registrations.cs index a99607727..7c9d6a04c 100644 --- a/src/Akavache/Registrations.cs +++ b/src/Akavache/Registrations.cs @@ -1,10 +1,9 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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 Akavache.Core; - using Splat; namespace Akavache; diff --git a/src/Akavache/SQLitePersistentBlobCache.cs b/src/Akavache/SQLitePersistentBlobCache.cs index d4e411656..9b772132a 100644 --- a/src/Akavache/SQLitePersistentBlobCache.cs +++ b/src/Akavache/SQLitePersistentBlobCache.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2023 .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. @@ -16,15 +16,11 @@ namespace Akavache.Sqlite3; /// Thus this class was moved here so it provides the hook for the linker and then registers and inits the sqlraw bundle. /// /// -public class SQLitePersistentBlobCache : SqlRawPersistentBlobCache +/// +/// Initializes a new instance of the class. +/// +/// The location of the database file which to store the blobs in. +/// Scheduler to use for contained observables. +public class SQLitePersistentBlobCache(string databaseFile, IScheduler? scheduler = null) : SqlRawPersistentBlobCache(databaseFile, scheduler) { - /// - /// Initializes a new instance of the class. - /// - /// The location of the database file which to store the blobs in. - /// Scheduler to use for contained observables. - public SQLitePersistentBlobCache(string databaseFile, IScheduler? scheduler = null) - : base(databaseFile, scheduler) - { - } } diff --git a/src/Directory.build.props b/src/Directory.build.props index fbf832556..0bd38d666 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -25,7 +25,10 @@ latest enable enable - IDE1006;SA1313; + preview + IDE1006;SA1313;SA1010 + netstandard2.0;netstandard2.1;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10;MonoAndroid13.0;tizen40;net6.0;net7.0;net7.0-android;net7.0-ios;net7.0-tvos;net7.0-macos;net7.0-maccatalyst;net8.0;net8.0-android;net8.0-ios;net8.0-tvos;net8.0-macos;net8.0-maccatalyst + @@ -46,12 +49,12 @@ - + - + diff --git a/src/Directory.build.targets b/src/Directory.build.targets index 8cef42fe8..d1f1e324e 100644 --- a/src/Directory.build.targets +++ b/src/Directory.build.targets @@ -6,25 +6,22 @@ $(DefineConstants);NET_461;XAML - - $(DefineConstants);NETFX_CORE;XAML;WINDOWS_UWP - $(DefineConstants);MONO;UIKIT;COCOA;XAMARIN_MOBILE $(DefineConstants);MONO;COCOA - + $(DefineConstants);MONO;COCOA $(DefineConstants);MONO;UIKIT;COCOA;XAMARIN_MOBILE - + $(DefineConstants);MONO;UIKIT;COCOA;XAMARIN_MOBILE - + $(DefineConstants);MONO;UIKIT;COCOA;XAMARIN_MOBILE @@ -33,7 +30,7 @@ $(DefineConstants);MONO;ANDROID;XAMARIN_MOBILE - + $(DefineConstants);MONO;ANDROID;XAMARIN_MOBILE diff --git a/src/global.json b/src/global.json index 6439f5c63..cdf9c3335 100644 --- a/src/global.json +++ b/src/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.400", + "version": "8.0.10", "rollForward": "latestMinor" }, "msbuild-sdks": { diff --git a/src/stylecop.json b/src/stylecop.json index 44a6ef8df..670ff3043 100644 --- a/src/stylecop.json +++ b/src/stylecop.json @@ -13,7 +13,7 @@ "documentPrivateFields": false, "documentationCulture": "en-US", "companyName": ".NET Foundation and Contributors", - "copyrightText": "Copyright (c) 2022 {companyName}. All rights reserved.\nLicensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the {licenseName} license.\nSee the {licenseFile} file in the project root for full license information.", + "copyrightText": "Copyright (c) 2023 {companyName}. All rights reserved.\nLicensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the {licenseName} license.\nSee the {licenseFile} file in the project root for full license information.", "variables": { "licenseName": "MIT", "licenseFile": "LICENSE"