From 0c7e87985b4978a379610cf53978e88420a20817 Mon Sep 17 00:00:00 2001 From: Tomasz Szulc Date: Thu, 3 Dec 2020 12:26:18 +0100 Subject: [PATCH] Integrate with newest Contentful SDK and add option to set limit for sync (#103) --- .env | 2 +- Cartfile | 2 +- Cartfile.resolved | 4 ++-- Carthage/Checkouts/OHHTTPStubs | 2 +- Carthage/Checkouts/contentful.swift | 2 +- Config.xcconfig | 2 +- Scripts/.env | 2 +- Scripts/Config.xcconfig | 2 +- .../ContentfulPersistence/CoreDataStore.swift | 9 +++++++++ .../PersistenceStore.swift | 12 +++++++++++ .../SynchronizationManager.swift | 20 ++++++++++--------- .../SynchronizationManagerTests.swift | 10 ++++++++++ 12 files changed, 51 insertions(+), 18 deletions(-) diff --git a/.env b/.env index 95c61229..a6b514da 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -CONTENTFUL_PERSISTENCE_VERSION=0.16.1 +CONTENTFUL_PERSISTENCE_VERSION=0.17.0 diff --git a/Cartfile b/Cartfile index e3e8143b..18d81c65 100644 --- a/Cartfile +++ b/Cartfile @@ -1,2 +1,2 @@ -github "contentful/contentful.swift" ~> 5.3.1 +github "contentful/contentful.swift" ~> 5.4.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index e644aed4..aaeabf40 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,2 +1,2 @@ -github "AliSoftware/OHHTTPStubs" "9.0.0" -github "contentful/contentful.swift" "5.3.1" +github "AliSoftware/OHHTTPStubs" "9.1.0" +github "contentful/contentful.swift" "5.4.0" diff --git a/Carthage/Checkouts/OHHTTPStubs b/Carthage/Checkouts/OHHTTPStubs index e92b5a57..12f19662 160000 --- a/Carthage/Checkouts/OHHTTPStubs +++ b/Carthage/Checkouts/OHHTTPStubs @@ -1 +1 @@ -Subproject commit e92b5a5746ef16add2a1424f1fc19529d9a75cde +Subproject commit 12f19662426d0434d6c330c6974d53e2eb10ecd9 diff --git a/Carthage/Checkouts/contentful.swift b/Carthage/Checkouts/contentful.swift index 9b65d0b8..cfc14e34 160000 --- a/Carthage/Checkouts/contentful.swift +++ b/Carthage/Checkouts/contentful.swift @@ -1 +1 @@ -Subproject commit 9b65d0b86b3b53194dcde7c5e3cc95b40a71a8c2 +Subproject commit cfc14e34f7d94a6fa322e438747d9beef420f2df diff --git a/Config.xcconfig b/Config.xcconfig index 95c61229..a6b514da 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -1 +1 @@ -CONTENTFUL_PERSISTENCE_VERSION=0.16.1 +CONTENTFUL_PERSISTENCE_VERSION=0.17.0 diff --git a/Scripts/.env b/Scripts/.env index 95c61229..a6b514da 100644 --- a/Scripts/.env +++ b/Scripts/.env @@ -1 +1 @@ -CONTENTFUL_PERSISTENCE_VERSION=0.16.1 +CONTENTFUL_PERSISTENCE_VERSION=0.17.0 diff --git a/Scripts/Config.xcconfig b/Scripts/Config.xcconfig index 95c61229..a6b514da 100644 --- a/Scripts/Config.xcconfig +++ b/Scripts/Config.xcconfig @@ -1 +1 @@ -CONTENTFUL_PERSISTENCE_VERSION=0.16.1 +CONTENTFUL_PERSISTENCE_VERSION=0.17.0 diff --git a/Sources/ContentfulPersistence/CoreDataStore.swift b/Sources/ContentfulPersistence/CoreDataStore.swift index 07483cb7..ae2d4646 100644 --- a/Sources/ContentfulPersistence/CoreDataStore.swift +++ b/Sources/ContentfulPersistence/CoreDataStore.swift @@ -94,6 +94,15 @@ public class CoreDataStore: PersistenceStore { return items } + public func fetchOne( + type: Any.Type, + predicate: NSPredicate + ) throws -> T { + let request = try fetchRequest(for: type, predicate: predicate) + request.fetchLimit = 1 + return try context.fetch(request).first as! T + } + /** Returns an array of names of properties the given type stores persistently. diff --git a/Sources/ContentfulPersistence/PersistenceStore.swift b/Sources/ContentfulPersistence/PersistenceStore.swift index 6bb4522c..5eae26b8 100644 --- a/Sources/ContentfulPersistence/PersistenceStore.swift +++ b/Sources/ContentfulPersistence/PersistenceStore.swift @@ -43,6 +43,18 @@ public protocol PersistenceStore { */ func fetchAll(type: Any.Type, predicate: NSPredicate) throws -> [T] + /** + Fetches one object of a specific type which matches the predicate. + + - parameter type: Type of which object should be fetched. + - parameter predicate: The predicate used for matching object to fetch. + + - throws: If an invalid type was specified + + - returns: Matching object + */ + func fetchOne(type: Any.Type, predicate: NSPredicate) throws -> T + /** Returns an array of names of properties the given type stores persistently. diff --git a/Sources/ContentfulPersistence/SynchronizationManager.swift b/Sources/ContentfulPersistence/SynchronizationManager.swift index c42ef90e..e2adec4b 100644 --- a/Sources/ContentfulPersistence/SynchronizationManager.swift +++ b/Sources/ContentfulPersistence/SynchronizationManager.swift @@ -112,14 +112,16 @@ public class SynchronizationManager: PersistenceIntegration { method is thread safe and will delegate to the thread that your data store is tied to. Execute queries on your local data store in the callback for this method. + + - parameter limit: Number of elements per page. See documentation for details. */ - public func sync(then completion: @escaping ResultsHandler) { + public func sync(limit: Int? = nil, then completion: @escaping ResultsHandler) { resolveCachedRelationships { [weak self] in - self?.syncSafely(then: completion) + self?.syncSafely(limit: limit, then: completion) } } - private func syncSafely(then completion: @escaping ResultsHandler) { + private func syncSafely(limit: Int?, then completion: @escaping ResultsHandler) { let safeCompletion: ResultsHandler = { [weak self] result in self?.persistentStore.performBlock { completion(result) @@ -127,9 +129,9 @@ public class SynchronizationManager: PersistenceIntegration { } if let syncToken = self.syncToken { - client?.sync(for: SyncSpace(syncToken: syncToken), then: safeCompletion) + client?.sync(for: SyncSpace(syncToken: syncToken, limit: limit), then: safeCompletion) } else { - client?.sync(for: SyncSpace(), then: safeCompletion) + client?.sync(for: SyncSpace(limit: limit), then: safeCompletion) } } @@ -331,13 +333,13 @@ public class SynchronizationManager: PersistenceIntegration { let type = persistenceModel.assetType let fetchPredicate = predicate(for: asset.id, localeCodes: localeCodes) - let fetched: [AssetPersistable]? = try? persistentStore.fetchAll(type: type, predicate: fetchPredicate) + let fetched: AssetPersistable? = try? persistentStore.fetchOne(type: type, predicate: fetchPredicate) for localeCode in localeCodes { asset.setLocale(withCode: localeCode) let persistable: AssetPersistable - if let fetched = (fetched?.first { $0.localeCode == localeCode }) { + if let fetched = fetched, fetched.localeCode == localeCode { persistable = fetched } else { do { @@ -395,13 +397,13 @@ public class SynchronizationManager: PersistenceIntegration { guard let type = persistenceModel.entryTypes.filter({ $0.contentTypeId == contentTypeId }).first else { return } let fetchPredicate = predicate(for: entry.id, localeCodes: localeCodes) - let fetched: [EntryPersistable]? = try? persistentStore.fetchAll(type: type, predicate: fetchPredicate) + let fetched: EntryPersistable? = try? persistentStore.fetchOne(type: type, predicate: fetchPredicate) for localeCode in localeCodes { entry.setLocale(withCode: localeCode) let persistable: EntryPersistable - if let fetched = (fetched?.first { $0.localeCode == localeCode }) { + if let fetched = fetched, fetched.localeCode == localeCode { persistable = fetched } else { do { diff --git a/Tests/ContentfulPersistenceTests/SynchronizationManagerTests.swift b/Tests/ContentfulPersistenceTests/SynchronizationManagerTests.swift index 021117b1..4fb6ecb2 100644 --- a/Tests/ContentfulPersistenceTests/SynchronizationManagerTests.swift +++ b/Tests/ContentfulPersistenceTests/SynchronizationManagerTests.swift @@ -117,6 +117,16 @@ class ContentfulPersistenceTests: XCTestCase { waitForExpectations(timeout: 10.0, handler: nil) } + func testFetchOneAssetFromTheStore() { + let expectation = self.expectation(description: "Can fetch single asset from the store.") + self.client.sync { _ in + let asset: Asset? = try? self.store.fetchOne(type: Asset.self, predicate: self.assetPredicate) + XCTAssertEqual(asset?.id, "bXvdSYHB3Guy2uUmuEco8") + expectation.fulfill() + } + waitForExpectations(timeout: 10.0, handler: nil) + } + func testCanStoreAssetPersistables() { let expectation = self.expectation(description: "Can store Asset Persistables expecatation")