2019-07-24 12:23:54 -07:00
//
// M e r g e P o l i c y . s w i f t
// A l t S t o r e
//
// C r e a t e d b y R i l e y T e s t u t o n 7 / 2 3 / 1 9 .
// C o p y r i g h t © 2 0 1 9 R i l e y T e s t u t . A l l r i g h t s r e s e r v e d .
//
import CoreData
import Roxas
open class MergePolicy : RSTRelationshipPreservingMergePolicy
{
open override func resolve ( constraintConflicts conflicts : [ NSConstraintConflict ] ) throws
{
guard conflicts . allSatisfy ( { $0 . databaseObject != nil } ) else {
2020-03-24 13:27:44 -07:00
for conflict in conflicts
{
switch conflict . conflictingObjects . first
{
case is StoreApp where conflict . conflictingObjects . count = = 2 :
// M o d i f i e d c a c h e d S t o r e A p p w h i l e r e p l a c i n g i t w i t h n e w o n e , c a u s i n g c o n t e x t - l e v e l c o n f l i c t .
// M o s t l i k e l y , w e s e t u p a r e l a t i o n s h i p b e t w e e n t h e n e w S t o r e A p p a n d a N e w s I t e m ,
// c a u s i n g c a c h e d S t o r e A p p t o d e l e t e i t ' s N e w s I t e m r e l a t i o n s h i p , r e s u l t i n g i n ( r e s o l v a b l e ) c o n f l i c t .
if let previousApp = conflict . conflictingObjects . first ( where : { ! $0 . isInserted } ) as ? StoreApp
{
// D e l e t e p r e v i o u s p e r m i s s i o n s ( s a m e a s b e l o w ) .
for permission in previousApp . permissions
{
permission . managedObjectContext ? . delete ( permission )
}
2022-09-12 17:05:55 -07:00
// D e l e t e p r e v i o u s v e r s i o n s ( d i f f e r e n t t h a n b e l o w ) .
for case let appVersion as AppVersion in previousApp . _versions where appVersion . app = = nil
{
appVersion . managedObjectContext ? . delete ( appVersion )
}
2020-03-24 13:27:44 -07:00
}
2022-09-13 15:31:14 -07:00
case is AppVersion where conflict . conflictingObjects . count = = 2 :
// O c c u r s f i r s t t i m e f e t c h i n g s o u r c e s a f t e r m i g r a t i n g f r o m p r e - A p p V e r s i o n d a t a b a s e m o d e l .
let conflictingAppVersions = conflict . conflictingObjects . lazy . compactMap { $0 as ? AppVersion }
// P r i m a r y A p p V e r s i o n = = A p p V e r s i o n w h o s e l a t e s t V e r s i o n A p p . l a t e s t V e r s i o n p o i n t s b a c k t o i t s e l f .
if let primaryAppVersion = conflictingAppVersions . first ( where : { $0 . latestVersionApp ? . latestVersion = = $0 } ) ,
let secondaryAppVersion = conflictingAppVersions . first ( where : { $0 != primaryAppVersion } )
{
secondaryAppVersion . managedObjectContext ? . delete ( secondaryAppVersion )
print ( " [ALTLog] Resolving AppVersion context-level conflict. Most likely due to migrating from pre-AppVersion model version. " , primaryAppVersion )
}
2023-04-09 13:32:22 -07:00
case is Source where conflict . conflictingObjects . count = = 2 :
// U s e t h e f i r s t o n e
let second = conflict . conflictingObjects [ 1 ]
second . managedObjectContext ? . delete ( second )
2020-03-24 13:27:44 -07:00
default :
// U n k n o w n c o n t e x t - l e v e l c o n f l i c t .
2023-04-09 13:32:22 -07:00
assertionFailure ( " MergePolicy is only intended to work with database-level conflicts. \( conflict . conflictingObjects . map { obj in obj . description } . joined ( separator : " , " ) ) " )
2020-03-24 13:27:44 -07:00
}
}
try super . resolve ( constraintConflicts : conflicts )
return
2019-07-24 12:23:54 -07:00
}
for conflict in conflicts
{
switch conflict . databaseObject
{
2019-07-31 14:07:00 -07:00
case let databaseObject as StoreApp :
2019-07-24 12:23:54 -07:00
// D e l e t e p r e v i o u s p e r m i s s i o n s
for permission in databaseObject . permissions
{
permission . managedObjectContext ? . delete ( permission )
}
2022-09-12 17:05:55 -07:00
if let contextApp = conflict . conflictingObjects . first as ? StoreApp
{
let contextVersions = Set ( contextApp . _versions . lazy . compactMap { $0 as ? AppVersion } . map { $0 . version } )
for case let appVersion as AppVersion in databaseObject . _versions where ! contextVersions . contains ( appVersion . version )
{
print ( " [ALTLog] Deleting cached app version: \( appVersion . appBundleID + " _ " + appVersion . version ) , not in: " , contextApp . versions . map { $0 . appBundleID + " _ " + $0 . version } )
appVersion . managedObjectContext ? . delete ( appVersion )
}
}
2019-07-30 17:00:04 -07:00
case let databaseObject as Source :
guard let conflictedObject = conflict . conflictingObjects . first as ? Source else { break }
let bundleIdentifiers = Set ( conflictedObject . apps . map { $0 . bundleIdentifier } )
2019-09-03 21:58:07 -07:00
let newsItemIdentifiers = Set ( conflictedObject . newsItems . map { $0 . identifier } )
2019-07-30 17:00:04 -07:00
for app in databaseObject . apps
{
if ! bundleIdentifiers . contains ( app . bundleIdentifier )
{
// N o l o n g e r l i s t e d i n S o u r c e , s o r e m o v e i t f r o m d a t a b a s e .
app . managedObjectContext ? . delete ( app )
}
}
2019-09-03 21:58:07 -07:00
for newsItem in databaseObject . newsItems
{
if ! newsItemIdentifiers . contains ( newsItem . identifier )
{
// N o l o n g e r l i s t e d i n S o u r c e , s o r e m o v e i t f r o m d a t a b a s e .
newsItem . managedObjectContext ? . delete ( newsItem )
}
}
2019-07-24 12:23:54 -07:00
default : break
}
}
try super . resolve ( constraintConflicts : conflicts )
}
}