Replaces StoreApp.latestVersion with latestSupportedVersion + latestAvailableVersion

We now store the latest supported version as a relationship on StoreApp, rather than the latest available version. This allows us to reference the latest supported version in predicates and sort descriptors.

However, we kept the underlying Core Data property name the same to avoid extra migration.
This commit is contained in:
Riley Testut
2022-11-15 16:21:44 -06:00
parent 324ec7907a
commit 7ea1ad5af0
12 changed files with 44 additions and 22 deletions

View File

@@ -40,7 +40,7 @@ public class AppVersion: NSManagedObject, Decodable, Fetchable
/* Relationships */
@NSManaged public private(set) var app: StoreApp?
@NSManaged public private(set) var latestVersionApp: StoreApp?
@NSManaged @objc(latestVersionApp) public internal(set) var latestSupportedVersionApp: StoreApp?
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
{
@@ -113,4 +113,8 @@ public extension AppVersion
return appVersion
}
var isSupported: Bool {
return true
}
}

View File

@@ -232,7 +232,7 @@ private extension DatabaseManager
else
{
storeApp = StoreApp.makeAltStoreApp(in: context)
storeApp.latestVersion?.version = localApp.version
storeApp.latestSupportedVersion?.version = localApp.version
storeApp.source = altStoreSource
}

View File

@@ -146,7 +146,7 @@ public extension InstalledApp
{
let fetchRequest = InstalledApp.fetchRequest() as NSFetchRequest<InstalledApp>
fetchRequest.predicate = NSPredicate(format: "%K == YES AND %K != nil AND %K != %K",
#keyPath(InstalledApp.isActive), #keyPath(InstalledApp.storeApp), #keyPath(InstalledApp.version), #keyPath(InstalledApp.storeApp.latestVersion.version))
#keyPath(InstalledApp.isActive), #keyPath(InstalledApp.storeApp), #keyPath(InstalledApp.version), #keyPath(InstalledApp.storeApp.latestSupportedVersion.version))
return fetchRequest
}

View File

@@ -44,7 +44,7 @@ open class MergePolicy: RSTRelationshipPreservingMergePolicy
let conflictingAppVersions = conflict.conflictingObjects.lazy.compactMap { $0 as? AppVersion }
// Primary AppVersion == AppVersion whose latestVersionApp.latestVersion points back to itself.
if let primaryAppVersion = conflictingAppVersions.first(where: { $0.latestVersionApp?.latestVersion == $0 }),
if let primaryAppVersion = conflictingAppVersions.first(where: { $0.latestSupportedVersionApp?.latestSupportedVersion == $0 }),
let secondaryAppVersion = conflictingAppVersions.first(where: { $0 != primaryAppVersion })
{
secondaryAppVersion.managedObjectContext?.delete(secondaryAppVersion)

View File

@@ -48,7 +48,7 @@ fileprivate extension NSManagedObject
func setStoreAppLatestVersion(_ appVersion: NSManagedObject)
{
self.setValue(appVersion, forKey: #keyPath(StoreApp.latestVersion))
self.setValue(appVersion, forKey: #keyPath(StoreApp.latestSupportedVersion))
let versions = NSOrderedSet(array: [appVersion])
self.setValue(versions, forKey: #keyPath(StoreApp._versions))

View File

@@ -78,7 +78,7 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
@NSManaged @objc(source) public var _source: Source?
@NSManaged @objc(permissions) public var _permissions: NSOrderedSet
@NSManaged public private(set) var latestVersion: AppVersion?
@NSManaged @objc(latestVersion) public private(set) var latestSupportedVersion: AppVersion?
@NSManaged @objc(versions) public private(set) var _versions: NSOrderedSet
@NSManaged public private(set) var loggedErrors: NSSet /* Set<LoggedError> */ // Use NSSet to avoid eagerly fetching values.
@@ -227,16 +227,30 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
}
}
private extension StoreApp
internal extension StoreApp
{
func setVersions(_ versions: [AppVersion])
{
guard let latestVersion = versions.first else { preconditionFailure("StoreApp must have at least one AppVersion.") }
self.latestVersion = latestVersion
self._versions = NSOrderedSet(array: versions)
let latestSupportedVersion = versions.first(where: { $0.isSupported })
self.latestSupportedVersion = latestSupportedVersion
for case let version as AppVersion in self._versions
{
if version == latestSupportedVersion
{
version.latestSupportedVersionApp = self
}
else
{
// Ensure we replace any previous relationship when merging.
version.latestSupportedVersionApp = nil
}
}
// Preserve backwards compatibility by assigning legacy property values.
guard let latestVersion = versions.first else { preconditionFailure("StoreApp must have at least one AppVersion.") }
self._version = latestVersion.version
self._versionDate = latestVersion.date
self._versionDescription = latestVersion.localizedDescription
@@ -247,6 +261,10 @@ private extension StoreApp
public extension StoreApp
{
var latestAvailableVersion: AppVersion? {
return self._versions.firstObject as? AppVersion
}
@nonobjc class func fetchRequest() -> NSFetchRequest<StoreApp>
{
return NSFetchRequest<StoreApp>(entityName: "StoreApp")