From aa566ff2e0d2f0f2bdf96f888ad27fdba30d4963 Mon Sep 17 00:00:00 2001 From: Levi Eggert Date: Fri, 8 Nov 2024 14:45:52 -0500 Subject: [PATCH] Add extension for observing realm object changes and replace objectWillChange with extension --- godtools.xcodeproj/project.pbxproj | 8 +++ .../Cache/RealmAppLanguagesCache.swift | 7 +-- .../Cache/RealmDownloadedLanguagesCache.swift | 5 +- .../Cache/RealmUserAppLanguageCache.swift | 10 +-- .../Cache/RealmGlobalAnalyticsCache.swift | 5 +- .../Cache/RealmUserLessonFiltersCache.swift | 5 +- .../Cache/RealmUserToolFiltersCache.swift | 10 ++- .../Cache/RealmUserLessonProgressCache.swift | 6 +- .../Cache/RealmFavoritedResourcesCache.swift | 5 +- .../Cache/RealmLanguagesCache.swift | 6 +- .../RealmDatabase+ObserveChanges.swift | 33 ++++++++++ .../Cache/RealmResourcesCache.swift | 6 +- .../Cache/RealmUserCountersCache.swift | 5 +- .../Cache/RealmUserDetailsCache.swift | 10 ++- .../RealmDatabaseObserveChangesTests.swift | 61 +++++++++++++++++++ 15 files changed, 134 insertions(+), 48 deletions(-) create mode 100644 godtools/App/Share/Data/RealmDatabase/RealmDatabase+ObserveChanges.swift create mode 100644 godtoolsTests/App/Share/Data/RealmDatabase/RealmDatabaseObserveChangesTests.swift diff --git a/godtools.xcodeproj/project.pbxproj b/godtools.xcodeproj/project.pbxproj index 45b7e57ad5..ae06d2ea99 100644 --- a/godtools.xcodeproj/project.pbxproj +++ b/godtools.xcodeproj/project.pbxproj @@ -749,6 +749,8 @@ 45931FFB2B34C1F9008034C8 /* ReviewShareShareableInterfaceStringsDomainModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45931FFA2B34C1F9008034C8 /* ReviewShareShareableInterfaceStringsDomainModel.swift */; }; 45931FFD2B34C235008034C8 /* GetReviewShareShareableInterfaceStringsRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45931FFC2B34C235008034C8 /* GetReviewShareShareableInterfaceStringsRepositoryInterface.swift */; }; 45931FFF2B34C266008034C8 /* GetReviewShareShareableInterfaceStringsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45931FFE2B34C266008034C8 /* GetReviewShareShareableInterfaceStringsRepository.swift */; }; + 4593EB7D2CDE9B1B00C0EED4 /* RealmDatabase+ObserveChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4593EB7C2CDE9B1300C0EED4 /* RealmDatabase+ObserveChanges.swift */; }; + 4593EB812CDE9F6600C0EED4 /* RealmDatabaseObserveChangesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4593EB802CDE9F6600C0EED4 /* RealmDatabaseObserveChangesTests.swift */; }; 4595E0DB2A8523DC00D88DAE /* MobileContentApiUsersMeCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4595E0DA2A8523DC00D88DAE /* MobileContentApiUsersMeCodable.swift */; }; 4595E0DD2A8527F300D88DAE /* UserDetailsDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4595E0DC2A8527F300D88DAE /* UserDetailsDataModel.swift */; }; 4595E0DF2A8529C800D88DAE /* UserDetailsDataModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4595E0DE2A8529C800D88DAE /* UserDetailsDataModelType.swift */; }; @@ -2414,6 +2416,8 @@ 45931FFA2B34C1F9008034C8 /* ReviewShareShareableInterfaceStringsDomainModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewShareShareableInterfaceStringsDomainModel.swift; sourceTree = ""; }; 45931FFC2B34C235008034C8 /* GetReviewShareShareableInterfaceStringsRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetReviewShareShareableInterfaceStringsRepositoryInterface.swift; sourceTree = ""; }; 45931FFE2B34C266008034C8 /* GetReviewShareShareableInterfaceStringsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetReviewShareShareableInterfaceStringsRepository.swift; sourceTree = ""; }; + 4593EB7C2CDE9B1300C0EED4 /* RealmDatabase+ObserveChanges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RealmDatabase+ObserveChanges.swift"; sourceTree = ""; }; + 4593EB802CDE9F6600C0EED4 /* RealmDatabaseObserveChangesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealmDatabaseObserveChangesTests.swift; sourceTree = ""; }; 4595E0DA2A8523DC00D88DAE /* MobileContentApiUsersMeCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobileContentApiUsersMeCodable.swift; sourceTree = ""; }; 4595E0DC2A8527F300D88DAE /* UserDetailsDataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDetailsDataModel.swift; sourceTree = ""; }; 4595E0DE2A8529C800D88DAE /* UserDetailsDataModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsDataModelType.swift; sourceTree = ""; }; @@ -4886,6 +4890,7 @@ isa = PBXGroup; children = ( 457E7A372BE5B39800265D92 /* RealmDatabaseDeleteTests.swift */, + 4593EB802CDE9F6600C0EED4 /* RealmDatabaseObserveChangesTests.swift */, 45AA12D82BE55CF300C85BFF /* RealmDatabaseReadTests.swift */, 45AA12DC2BE5741000C85BFF /* RealmDatabaseWriteTests.swift */, 45368A082ABB2D840028A570 /* TestRealmObject.swift */, @@ -8636,6 +8641,7 @@ 450397322B360F1B00938EE9 /* IdentifiableRealmObject.swift */, 45B212AA2922965F00C9A94D /* RealmDatabase.swift */, 45B54C562A2641FE0042CD0E /* RealmDatabase+Delete.swift */, + 4593EB7C2CDE9B1300C0EED4 /* RealmDatabase+ObserveChanges.swift */, 45B54C542A2641FE0042CD0E /* RealmDatabase+Read.swift */, 45B54C552A2641FE0042CD0E /* RealmDatabase+Write.swift */, 4556CEA229F2D57800643BBC /* Configuration */, @@ -13151,6 +13157,7 @@ 45558409269F2DA500C3FF14 /* MobileContentPageCell.swift in Sources */, 45F7162A290A12D70019B715 /* PrivacyPolicyWebContent.swift in Sources */, D4960CC82CC6DEAE0090B114 /* UserLessonProgressDomainModel.swift in Sources */, + 4593EB7D2CDE9B1B00C0EED4 /* RealmDatabase+ObserveChanges.swift in Sources */, 4564E2092B1E181000DA4040 /* ToolShortcutLinkDomainModel.swift in Sources */, 45369ADA2AFA7FA500BD10F0 /* ToolScreenShareFeatureDataLayerDependencies.swift in Sources */, 45AAC2AB2BB30F0A000AE690 /* MobileContentGlobalAnalyticsDecodable.swift in Sources */, @@ -13926,6 +13933,7 @@ 450FB8922BFBA1060015D945 /* RealmDatabaseWriteTests.swift in Sources */, 45243C5B2C5828C600BD6F49 /* MockRealmTranslation.swift in Sources */, 45CBDA092BA3930B0007DEC8 /* MockLaunchCountRepository.swift in Sources */, + 4593EB812CDE9F6600C0EED4 /* RealmDatabaseObserveChangesTests.swift in Sources */, 45EB68E12C334D84008A5FF2 /* MockLocalizationServices.swift in Sources */, 45368A182ABB2D850028A570 /* TestRealmObject.swift in Sources */, 453E2A122BC8C8810047D4C6 /* GetToolsRepositoryTests.swift in Sources */, diff --git a/godtools/App/Features/AppLanguage/Data/AppLanguagesRepository/Cache/RealmAppLanguagesCache.swift b/godtools/App/Features/AppLanguage/Data/AppLanguagesRepository/Cache/RealmAppLanguagesCache.swift index 8f961ca9ab..835c2edd0e 100644 --- a/godtools/App/Features/AppLanguage/Data/AppLanguagesRepository/Cache/RealmAppLanguagesCache.swift +++ b/godtools/App/Features/AppLanguage/Data/AppLanguagesRepository/Cache/RealmAppLanguagesCache.swift @@ -20,10 +20,9 @@ class RealmAppLanguagesCache { } func observeChangesPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmAppLanguage.self) - .objectWillChange - .prepend(Void()) + + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmLanguage.self, prepend: true) .eraseToAnyPublisher() } diff --git a/godtools/App/Features/AppLanguage/Data/DownloadedLanguagesRepository/Cache/RealmDownloadedLanguagesCache.swift b/godtools/App/Features/AppLanguage/Data/DownloadedLanguagesRepository/Cache/RealmDownloadedLanguagesCache.swift index 2c816ece24..80592cefb1 100644 --- a/godtools/App/Features/AppLanguage/Data/DownloadedLanguagesRepository/Cache/RealmDownloadedLanguagesCache.swift +++ b/godtools/App/Features/AppLanguage/Data/DownloadedLanguagesRepository/Cache/RealmDownloadedLanguagesCache.swift @@ -21,9 +21,8 @@ class RealmDownloadedLanguagesCache { func getDownloadedLanguagesChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmDownloadedLanguage.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmDownloadedLanguage.self, prepend: false) .eraseToAnyPublisher() } diff --git a/godtools/App/Features/AppLanguage/Data/UserAppLanguageRepository/Cache/RealmUserAppLanguageCache.swift b/godtools/App/Features/AppLanguage/Data/UserAppLanguageRepository/Cache/RealmUserAppLanguageCache.swift index 87c9cb5551..35ba2792df 100644 --- a/godtools/App/Features/AppLanguage/Data/UserAppLanguageRepository/Cache/RealmUserAppLanguageCache.swift +++ b/godtools/App/Features/AppLanguage/Data/UserAppLanguageRepository/Cache/RealmUserAppLanguageCache.swift @@ -39,13 +39,9 @@ class RealmUserAppLanguageCache { } func getLanguageChangedPublisher() -> AnyPublisher { - - return realmDatabase.openRealm() - .objects(RealmUserAppLanguage.self) - .objectWillChange - .map { _ in - Void() - } + + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserAppLanguage.self, prepend: false) .eraseToAnyPublisher() } diff --git a/godtools/App/Features/GlobalActivity/Data/GlobalAnalyticsRepository/Cache/RealmGlobalAnalyticsCache.swift b/godtools/App/Features/GlobalActivity/Data/GlobalAnalyticsRepository/Cache/RealmGlobalAnalyticsCache.swift index af3974db36..d2d6323971 100644 --- a/godtools/App/Features/GlobalActivity/Data/GlobalAnalyticsRepository/Cache/RealmGlobalAnalyticsCache.swift +++ b/godtools/App/Features/GlobalActivity/Data/GlobalAnalyticsRepository/Cache/RealmGlobalAnalyticsCache.swift @@ -21,9 +21,8 @@ class RealmGlobalAnalyticsCache { func getGlobalAnalyticsChangedPublisher(id: String) -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmGlobalAnalytics.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmGlobalAnalytics.self, prepend: false) .map { _ in return self.getGlobalAnalytics(id: id) diff --git a/godtools/App/Features/LessonFilter/Data/UserLessonFiltersRepository/Cache/RealmUserLessonFiltersCache.swift b/godtools/App/Features/LessonFilter/Data/UserLessonFiltersRepository/Cache/RealmUserLessonFiltersCache.swift index ae7c46d5dd..7bab18c22e 100644 --- a/godtools/App/Features/LessonFilter/Data/UserLessonFiltersRepository/Cache/RealmUserLessonFiltersCache.swift +++ b/godtools/App/Features/LessonFilter/Data/UserLessonFiltersRepository/Cache/RealmUserLessonFiltersCache.swift @@ -20,9 +20,8 @@ class RealmUserLessonFiltersCache { func getUserLessonLanguageFilterChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm().objects(RealmUserLessonLanguageFilter.self) - .objectWillChange - .prepend(Void()) + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserLessonLanguageFilter.self, prepend: true) .eraseToAnyPublisher() } diff --git a/godtools/App/Features/ToolsFilter/Data/UserToolFiltersRepository/Cache/RealmUserToolFiltersCache.swift b/godtools/App/Features/ToolsFilter/Data/UserToolFiltersRepository/Cache/RealmUserToolFiltersCache.swift index 93bb3b8100..56fe4d462b 100644 --- a/godtools/App/Features/ToolsFilter/Data/UserToolFiltersRepository/Cache/RealmUserToolFiltersCache.swift +++ b/godtools/App/Features/ToolsFilter/Data/UserToolFiltersRepository/Cache/RealmUserToolFiltersCache.swift @@ -20,17 +20,15 @@ class RealmUserToolFiltersCache { func getUserToolCategoryFilterChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmUserToolCategoryFilter.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserToolCategoryFilter.self, prepend: false) .eraseToAnyPublisher() } func getUserToolLanguageFilterChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmUserToolLanguageFilter.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserToolLanguageFilter.self, prepend: false) .eraseToAnyPublisher() } diff --git a/godtools/App/Features/UserLessonProgress/Data/UserLessonProgressRepository/Cache/RealmUserLessonProgressCache.swift b/godtools/App/Features/UserLessonProgress/Data/UserLessonProgressRepository/Cache/RealmUserLessonProgressCache.swift index 3f1c087d83..1d3a027fa0 100644 --- a/godtools/App/Features/UserLessonProgress/Data/UserLessonProgressRepository/Cache/RealmUserLessonProgressCache.swift +++ b/godtools/App/Features/UserLessonProgress/Data/UserLessonProgressRepository/Cache/RealmUserLessonProgressCache.swift @@ -20,10 +20,8 @@ class RealmUserLessonProgressCache { func getUserLessonProgressChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmUserLessonProgress.self) - .objectWillChange - .prepend(Void()) + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserLessonProgress.self, prepend: true) .eraseToAnyPublisher() } diff --git a/godtools/App/Share/Data/FavoritedResourcesRepository/Cache/RealmFavoritedResourcesCache.swift b/godtools/App/Share/Data/FavoritedResourcesRepository/Cache/RealmFavoritedResourcesCache.swift index 90e888e561..8ff85e0a1a 100644 --- a/godtools/App/Share/Data/FavoritedResourcesRepository/Cache/RealmFavoritedResourcesCache.swift +++ b/godtools/App/Share/Data/FavoritedResourcesRepository/Cache/RealmFavoritedResourcesCache.swift @@ -25,9 +25,8 @@ class RealmFavoritedResourcesCache { func getFavoritedResourcesChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmFavoritedResource.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmFavoritedResource.self, prepend: false) .eraseToAnyPublisher() } diff --git a/godtools/App/Share/Data/LanguagesRepository/Cache/RealmLanguagesCache.swift b/godtools/App/Share/Data/LanguagesRepository/Cache/RealmLanguagesCache.swift index b174ee2134..34e3ff8b25 100644 --- a/godtools/App/Share/Data/LanguagesRepository/Cache/RealmLanguagesCache.swift +++ b/godtools/App/Share/Data/LanguagesRepository/Cache/RealmLanguagesCache.swift @@ -28,9 +28,9 @@ class RealmLanguagesCache { } func getLanguagesChanged() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmLanguage.self) - .objectWillChange + + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmLanguage.self, prepend: false) .eraseToAnyPublisher() } diff --git a/godtools/App/Share/Data/RealmDatabase/RealmDatabase+ObserveChanges.swift b/godtools/App/Share/Data/RealmDatabase/RealmDatabase+ObserveChanges.swift new file mode 100644 index 0000000000..d556dc1ea1 --- /dev/null +++ b/godtools/App/Share/Data/RealmDatabase/RealmDatabase+ObserveChanges.swift @@ -0,0 +1,33 @@ +// +// RealmDatabase+ObserveChanges.swift +// godtools +// +// Created by Levi Eggert on 11/8/24. +// Copyright © 2024 Cru. All rights reserved. +// + +import Foundation +import Combine +import RealmSwift + +extension RealmDatabase { + + func observeCollectionChangesPublisher(objectClass: Object.Type, prepend: Bool) -> AnyPublisher { + + if prepend { + + return openRealm() + .objects(objectClass.self) + .objectWillChange + .prepend(Void()) + .eraseToAnyPublisher() + } + else { + + return openRealm() + .objects(objectClass.self) + .objectWillChange + .eraseToAnyPublisher() + } + } +} diff --git a/godtools/App/Share/Data/ResourcesRepository/Cache/RealmResourcesCache.swift b/godtools/App/Share/Data/ResourcesRepository/Cache/RealmResourcesCache.swift index 3829517945..4e53db72b9 100644 --- a/godtools/App/Share/Data/ResourcesRepository/Cache/RealmResourcesCache.swift +++ b/godtools/App/Share/Data/ResourcesRepository/Cache/RealmResourcesCache.swift @@ -26,9 +26,9 @@ class RealmResourcesCache { } func getResourcesChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmResource.self) - .objectWillChange + + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmResource.self, prepend: false) .eraseToAnyPublisher() } diff --git a/godtools/App/Share/Data/UserCountersRepository/Cache/RealmUserCountersCache.swift b/godtools/App/Share/Data/UserCountersRepository/Cache/RealmUserCountersCache.swift index 0a6aa20abf..13e3689630 100644 --- a/godtools/App/Share/Data/UserCountersRepository/Cache/RealmUserCountersCache.swift +++ b/godtools/App/Share/Data/UserCountersRepository/Cache/RealmUserCountersCache.swift @@ -23,9 +23,8 @@ class RealmUserCountersCache { func getUserCountersChanged() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmUserCounter.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserCounter.self, prepend: false) .eraseToAnyPublisher() } diff --git a/godtools/App/Share/Data/UserDetailsRepository/Cache/RealmUserDetailsCache.swift b/godtools/App/Share/Data/UserDetailsRepository/Cache/RealmUserDetailsCache.swift index 92666cc89f..83b6cc2055 100644 --- a/godtools/App/Share/Data/UserDetailsRepository/Cache/RealmUserDetailsCache.swift +++ b/godtools/App/Share/Data/UserDetailsRepository/Cache/RealmUserDetailsCache.swift @@ -23,9 +23,8 @@ class RealmUserDetailsCache { func getAuthUserDetailsChangedPublisher() -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmUserDetails.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserDetails.self, prepend: false) .map { _ in return self.getAuthUserDetails() } @@ -34,9 +33,8 @@ class RealmUserDetailsCache { func getUserDetailsChangedPublisher(id: String) -> AnyPublisher { - return realmDatabase.openRealm() - .objects(RealmUserDetails.self) - .objectWillChange + return realmDatabase + .observeCollectionChangesPublisher(objectClass: RealmUserDetails.self, prepend: false) .map { _ in let realmObject: RealmUserDetails? = self.realmDatabase.readObject(primaryKey: id) diff --git a/godtoolsTests/App/Share/Data/RealmDatabase/RealmDatabaseObserveChangesTests.swift b/godtoolsTests/App/Share/Data/RealmDatabase/RealmDatabaseObserveChangesTests.swift new file mode 100644 index 0000000000..30600580fc --- /dev/null +++ b/godtoolsTests/App/Share/Data/RealmDatabase/RealmDatabaseObserveChangesTests.swift @@ -0,0 +1,61 @@ +// +// RealmDatabaseObserveChangesTests.swift +// godtools +// +// Created by Levi Eggert on 11/8/24. +// Copyright © 2024 Cru. All rights reserved. +// + +import XCTest +@testable import godtools +import RealmSwift +import Combine + +class RealmDatabaseObserveChangesTests: XCTestCase { + + private let realmDatabase: RealmDatabase = RealmDatabase( + databaseConfiguration: RealmDatabaseConfiguration( + cacheType: .disk( + fileName: "RealmDatabaseObserveChangesTests", + migrationBlock: {migration,oldSchemaVersion in }), + schemaVersion: 1 + ) + ) + + private var cancellables: Set = Set() + + override func setUp() { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testObserveChangesFires() { + + let expectation = expectation(description: "") + + var didReceiveValue: Bool = false + + realmDatabase + .observeCollectionChangesPublisher(objectClass: TestRealmObject.self, prepend: false) + .receive(on: DispatchQueue.main) + .sink { _ in + + } receiveValue: { _ in + + if !didReceiveValue { + + didReceiveValue = true + + expectation.fulfill() + } + } + .store(in: &cancellables) + + wait(for: [expectation], timeout: 5) + + XCTAssertTrue(didReceiveValue) + } +}