merge default IOS-1433
authorAlejandro Gelos <alejandro@pep-project.org>
Thu, 27 Jun 2019 14:09:02 +0200
branchIOS-1433
changeset 35010f7c997b7da3
parent 3498 66077ab55ff8
parent 3494 e16f0c20522b
child 3502 aee110aeed0d
merge default
MessageModel/MessageModel/Submodule/CoreData/Stack.swift
MessageModel/MessageModel/Util/MessageModelData.swift
     1.1 --- a/MessageModel/MessageModel.xcodeproj/project.pbxproj	Thu Jun 27 13:39:47 2019 +0200
     1.2 +++ b/MessageModel/MessageModel.xcodeproj/project.pbxproj	Thu Jun 27 14:09:02 2019 +0200
     1.3 @@ -46,6 +46,7 @@
     1.4  		15679F022292CADA0051DCC3 /* CdAccount+Trusted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15679F012292CAD90051DCC3 /* CdAccount+Trusted.swift */; };
     1.5  		15679F052292CB2C0051DCC3 /* Account+FetchingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15679F042292CB2C0051DCC3 /* Account+FetchingTest.swift */; };
     1.6  		156FF8CA22994A47002A2566 /* RealFolderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF8C922994A47002A2566 /* RealFolderProtocol.swift */; };
     1.7 +		15795BE722C3A30A00010938 /* Stack+Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15795BE622C3A30A00010938 /* Stack+Defaults.swift */; };
     1.8  		15865A8420318E2D00F7A4B5 /* CdMessage+PredicateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15865A8320318E2D00F7A4B5 /* CdMessage+PredicateFactory.swift */; };
     1.9  		1587D137204570BB002C2157 /* MessageModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1587D135204570BA002C2157 /* MessageModel.xcdatamodeld */; };
    1.10  		1587D167204DA3C3002C2157 /* KeyChain+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1587D166204DA3C2002C2157 /* KeyChain+Extensions.swift */; };
    1.11 @@ -282,7 +283,6 @@
    1.12  		B7DFEA50225365080080A2BA /* DisplayableFolderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DFEA4F225365080080A2BA /* DisplayableFolderProtocol.swift */; };
    1.13  		B7E02ABF2227F49600741157 /* MessageQueryResultsSearchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7E02ABE2227F49600741157 /* MessageQueryResultsSearchTest.swift */; };
    1.14  		B7FE66471DDF1D5D008A53BE /* PersistentSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7FE66461DDF1D5D008A53BE /* PersistentSetup.swift */; };
    1.15 -		B7FE664A1DDF1E73008A53BE /* MessageModelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7FE66491DDF1E73008A53BE /* MessageModelData.swift */; };
    1.16  /* End PBXBuildFile section */
    1.17  
    1.18  /* Begin PBXContainerItemProxy section */
    1.19 @@ -351,6 +351,7 @@
    1.20  		15679F042292CB2C0051DCC3 /* Account+FetchingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Account+FetchingTest.swift"; sourceTree = "<group>"; };
    1.21  		156BCD6F223273FB00A80C62 /* refactor0.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = refactor0.1.xcdatamodel; sourceTree = "<group>"; };
    1.22  		156FF8C922994A47002A2566 /* RealFolderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealFolderProtocol.swift; sourceTree = "<group>"; };
    1.23 +		15795BE622C3A30A00010938 /* Stack+Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Stack+Defaults.swift"; sourceTree = "<group>"; };
    1.24  		15865A8320318E2D00F7A4B5 /* CdMessage+PredicateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CdMessage+PredicateFactory.swift"; sourceTree = "<group>"; };
    1.25  		1587D136204570BA002C2157 /* pEpForiOS.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = pEpForiOS.xcdatamodel; sourceTree = "<group>"; };
    1.26  		1587D166204DA3C2002C2157 /* KeyChain+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyChain+Extensions.swift"; sourceTree = "<group>"; };
    1.27 @@ -591,7 +592,6 @@
    1.28  		B7DFEA4F225365080080A2BA /* DisplayableFolderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayableFolderProtocol.swift; sourceTree = "<group>"; };
    1.29  		B7E02ABE2227F49600741157 /* MessageQueryResultsSearchTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageQueryResultsSearchTest.swift; sourceTree = "<group>"; };
    1.30  		B7FE66461DDF1D5D008A53BE /* PersistentSetup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistentSetup.swift; sourceTree = "<group>"; };
    1.31 -		B7FE66491DDF1E73008A53BE /* MessageModelData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageModelData.swift; sourceTree = "<group>"; };
    1.32  /* End PBXFileReference section */
    1.33  
    1.34  /* Begin PBXFrameworksBuildPhase section */
    1.35 @@ -876,6 +876,15 @@
    1.36  			path = MessageFetchingOperations;
    1.37  			sourceTree = "<group>";
    1.38  		};
    1.39 +		15795BE522C3A2E600010938 /* Stack */ = {
    1.40 +			isa = PBXGroup;
    1.41 +			children = (
    1.42 +				8BE4608F1DB7B5FC008D63C6 /* Stack.swift */,
    1.43 +				15795BE622C3A30A00010938 /* Stack+Defaults.swift */,
    1.44 +			);
    1.45 +			path = Stack;
    1.46 +			sourceTree = "<group>";
    1.47 +		};
    1.48  		15865A852031990200F7A4B5 /* PredicateFacories */ = {
    1.49  			isa = PBXGroup;
    1.50  			children = (
    1.51 @@ -970,10 +979,10 @@
    1.52  		43598DF51DA7F74F00EAD0B7 /* CoreData */ = {
    1.53  			isa = PBXGroup;
    1.54  			children = (
    1.55 +				15795BE522C3A2E600010938 /* Stack */,
    1.56  				155FE568228B5092003D3E68 /* CdObjects */,
    1.57  				15175F3F2225A71A00C91DB8 /* gen */,
    1.58  				156BCDF02237C7EA00A80C62 /* CoreDataUtils */,
    1.59 -				8BE4608F1DB7B5FC008D63C6 /* Stack.swift */,
    1.60  				43A6E05B1E57725C005BEE69 /* CdKey+Extension.swift */,
    1.61  				43AABD4020EF5D2E00FBD5D0 /* CdMessage+Util.swift */,
    1.62  				374A8AE5224E2D16001914D5 /* RelationshipKeyPath.swift */,
    1.63 @@ -1138,7 +1147,6 @@
    1.64  				3785564F229D2DCE00AACFD2 /* Internal */,
    1.65  				15865A852031990200F7A4B5 /* PredicateFacories */,
    1.66  				490FF7FD1E795B1500BC15F9 /* Int16+ImapFlagBits.swift */,
    1.67 -				B7FE66491DDF1E73008A53BE /* MessageModelData.swift */,
    1.68  				B7FE66461DDF1D5D008A53BE /* PersistentSetup.swift */,
    1.69  				4352FA261DC7A1C20081161A /* KeyChain.swift */,
    1.70  				434DC0E51DAE8BE7007C98B8 /* MutableOrderedSet.swift */,
    1.71 @@ -1742,7 +1750,6 @@
    1.72  				8BE460901DB7B5FC008D63C6 /* Query.swift in Sources */,
    1.73  				43EA4871221E9518006E8F83 /* OAuth2AccessTokenProtocol.swift in Sources */,
    1.74  				43EA4895221E9518006E8F83 /* PantomimeError.swift in Sources */,
    1.75 -				B7FE664A1DDF1E73008A53BE /* MessageModelData.swift in Sources */,
    1.76  				155FE55F228B4F8E003D3E68 /* CdImapFields.swift in Sources */,
    1.77  				43AB6A152248EDC5008E40CC /* FolderInfoCache.swift in Sources */,
    1.78  				43EA486A221E9518006E8F83 /* Notification+CWServiceClientNotificationParsing.swift in Sources */,
    1.79 @@ -1752,6 +1759,7 @@
    1.80  				8BE4607D1DB7B2D4008D63C6 /* CdHeaderField.swift in Sources */,
    1.81  				43EA4848221E9518006E8F83 /* EmailConnectInfo.swift in Sources */,
    1.82  				155FE563228B4FE1003D3E68 /* CdKey.swift in Sources */,
    1.83 +				15795BE722C3A30A00010938 /* Stack+Defaults.swift in Sources */,
    1.84  				43753CEC222D39B3002EE98B /* ImapFlags+Pantomime.swift in Sources */,
    1.85  				8BE460771DB7B1D2008D63C6 /* CdAccount.swift in Sources */,
    1.86  				15175EFE222543DB00C91DB8 /* MessageModel+PerformBlock.swift in Sources */,
    1.87 @@ -2057,7 +2065,7 @@
    1.88  				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
    1.89  				ONLY_ACTIVE_ARCH = "$(inherited)";
    1.90  				OTHER_SWIFT_FLAGS = "$(inherited)";
    1.91 -				PRODUCT_BUNDLE_IDENTIFIER = "net.pep-security.apps.MessageModel";
    1.92 +				PRODUCT_BUNDLE_IDENTIFIER = security.pep.MessageModel;
    1.93  				PRODUCT_NAME = "$(TARGET_NAME)";
    1.94  				SKIP_INSTALL = YES;
    1.95  				SWIFT_VERSION = 5.0;
    1.96 @@ -2080,7 +2088,7 @@
    1.97  				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
    1.98  				ONLY_ACTIVE_ARCH = "$(inherited)";
    1.99  				OTHER_SWIFT_FLAGS = "$(inherited)";
   1.100 -				PRODUCT_BUNDLE_IDENTIFIER = "net.pep-security.apps.MessageModel";
   1.101 +				PRODUCT_BUNDLE_IDENTIFIER = security.pep.MessageModel;
   1.102  				PRODUCT_NAME = "$(TARGET_NAME)";
   1.103  				SKIP_INSTALL = YES;
   1.104  				SWIFT_VERSION = 5.0;
     2.1 --- a/MessageModel/MessageModel/Interface/MessageModel/MessageModel+PerformBlock.swift	Thu Jun 27 13:39:47 2019 +0200
     2.2 +++ b/MessageModel/MessageModel/Interface/MessageModel/MessageModel+PerformBlock.swift	Thu Jun 27 14:09:02 2019 +0200
     2.3 @@ -13,7 +13,6 @@
     2.4  
     2.5  public class MessageModelUtil {}
     2.6  
     2.7 -
     2.8  extension MessageModelUtil {
     2.9  
    2.10      /// The client is responsible to *always* use perform or performAndWait when creating,
     3.1 --- a/MessageModel/MessageModel/Interface/MessageModelObjects/Interface/SessionAware/Message+SessionAware.swift	Thu Jun 27 13:39:47 2019 +0200
     3.2 +++ b/MessageModel/MessageModel/Interface/MessageModelObjects/Interface/SessionAware/Message+SessionAware.swift	Thu Jun 27 14:09:02 2019 +0200
     3.3 @@ -49,7 +49,7 @@
     3.4          return createe
     3.5      }
     3.6  
     3.7 -    public static func newObject(onSession session: Session) -> Message {
     3.8 +    public static func newObject(onSession session: Session) -> MMO {
     3.9          let moc = session.moc
    3.10          let cdCreatee = CdMessage(context: moc)
    3.11          return MMO(cdObject: cdCreatee, context: moc)
     4.1 --- a/MessageModel/MessageModel/Interface/MessageModelObjects/Internal/Record/Query.swift	Thu Jun 27 13:39:47 2019 +0200
     4.2 +++ b/MessageModel/MessageModel/Interface/MessageModelObjects/Internal/Record/Query.swift	Thu Jun 27 14:09:02 2019 +0200
     4.3 @@ -43,15 +43,11 @@
     4.4       You may override this property in your custom `NSManagedObject` subclass if needed,
     4.5       but it should work 'out of the box' generally.
     4.6       */
     4.7 -    class var entityName: String {
     4.8 -        var name = NSStringFromClass(self)
     4.9 -        name = name.components(separatedBy: ".").last!
    4.10 -        return name
    4.11 -    }
    4.12 -
    4.13 -    /// An `NSEntityDescription` object which describes an entity in Core Data.
    4.14 -    class var entityDescription: NSEntityDescription? {
    4.15 -        return NSEntityDescription.entity(forEntityName: entityName, in: Record.Context.default)
    4.16 +    static var entityName: String {
    4.17 +        guard let entityName = entity().name else {
    4.18 +            fatalError("Entity without name!")
    4.19 +        }
    4.20 +        return entityName
    4.21      }
    4.22  
    4.23      /**
    4.24 @@ -64,7 +60,6 @@
    4.25       */
    4.26      class func createFetchRequest<T: NSManagedObject>(predicate: NSPredicate? = nil,
    4.27                                    sortDescriptors: [NSSortDescriptor]? = nil) -> NSFetchRequest<T> {
    4.28 -
    4.29          let request = NSFetchRequest<T>(entityName: entityName)
    4.30          request.predicate = predicate
    4.31          request.sortDescriptors = sortDescriptors
    4.32 @@ -105,6 +100,9 @@
    4.33      @available(*, deprecated, message: "Use CdObject(context:NSManagedContext) instead")
    4.34      @discardableResult class func create(context: NSManagedObjectContext? = nil) -> Self {
    4.35          let moc = context ?? Record.Context.default
    4.36 +        guard let entityName = entity().name else {
    4.37 +            fatalError("NSManagedObject without Entity name.")
    4.38 +        }
    4.39          let entityDescription = NSEntityDescription.entity(forEntityName: entityName, in: moc)!
    4.40          let object = self.init(entity: entityDescription, insertInto: moc)
    4.41          return object
    4.42 @@ -196,7 +194,7 @@
    4.43          let request = createFetchRequest(predicate: predicate)
    4.44          request.fetchLimit = 1
    4.45  
    4.46 -        let objects = Record.execute(fetchRequest: request, in: moc)
    4.47 +        let objects = Stack.shared.execute(fetchRequest: request, in: moc)
    4.48          return (objects.first ?? create(attributes: attributes, in: moc)) as! T
    4.49      }
    4.50  
    4.51 @@ -246,7 +244,7 @@
    4.52          let request = createFetchRequest(sortDescriptors: sortDescriptors)
    4.53          request.fetchLimit = 1
    4.54  
    4.55 -        let objects = Record.execute(fetchRequest: request, in: moc)
    4.56 +        let objects = Stack.shared.execute(fetchRequest: request, in: moc)
    4.57          return objects.first as? T
    4.58      }
    4.59  
    4.60 @@ -280,7 +278,7 @@
    4.61          let request = createFetchRequest(predicate: predicate, sortDescriptors: sortDescriptors)
    4.62          request.fetchLimit = 1
    4.63  
    4.64 -        let objects = Record.execute(fetchRequest: request, in: moc)
    4.65 +        let objects = Stack.shared.execute(fetchRequest: request, in: moc)
    4.66          return objects.first as? T
    4.67      }
    4.68  
    4.69 @@ -334,7 +332,7 @@
    4.70                     in context: NSManagedObjectContext? = nil) -> [NSManagedObject]? {
    4.71          let moc = context ?? Record.Context.default
    4.72          let request = createFetchRequest(sortDescriptors: sortDescriptors)
    4.73 -        let objects = Record.execute(fetchRequest: request, in: moc)
    4.74 +        let objects = Stack.shared.execute(fetchRequest: request, in: moc)
    4.75          return objects.count > 0 ? objects : nil
    4.76      }
    4.77  
    4.78 @@ -366,7 +364,7 @@
    4.79                     in context: NSManagedObjectContext? = nil) -> [NSManagedObject]? {
    4.80          let moc = context ?? Record.Context.default
    4.81          let request = createFetchRequest(predicate: predicate, sortDescriptors: sortDescriptors)
    4.82 -        let objects = Record.execute(fetchRequest: request, in: moc)
    4.83 +        let objects = Stack.shared.execute(fetchRequest: request, in: moc)
    4.84          return objects.count > 0 ? objects : nil
    4.85      }
    4.86  
    4.87 @@ -396,7 +394,7 @@
    4.88  
    4.89       - returns: Optional managed object.
    4.90       */
    4.91 -    class func all(attribute: String, value: Any, orderedBy sortDescriptors: [NSSortDescriptor]? = nil,
    4.92 +    class private func all(attribute: String, value: Any, orderedBy sortDescriptors: [NSSortDescriptor]? = nil,
    4.93                     in context: NSManagedObjectContext? = nil) -> [NSManagedObject]? {
    4.94          let moc = context ?? Record.Context.default
    4.95          let predicate = NSPredicate(format: "%K = %@", argumentArray: [attribute, value])
    4.96 @@ -404,23 +402,6 @@
    4.97      }
    4.98  
    4.99      /**
   4.100 -     Finds all records for given attribute and value. Generic version
   4.101 -
   4.102 -     - parameter attribute: Attribute name.
   4.103 -     - parameter value: Attribute value.
   4.104 -     - parameter sortDescriptors: Sort descriptors.
   4.105 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.106 -
   4.107 -     - returns: Optional array of `Self` instances.
   4.108 -     */
   4.109 -    class func all<T>(attribute: String, value: Any, orderedBy sortDescriptors: [NSSortDescriptor]? = nil,
   4.110 -                   in context: NSManagedObjectContext? = nil) -> [T]? {
   4.111 -        let moc = context ?? Record.Context.default
   4.112 -        let objects = all(attribute: attribute, value: value, orderedBy: sortDescriptors, in: moc)
   4.113 -        return objects?.map { $0 as! T }
   4.114 -    }
   4.115 -
   4.116 -    /**
   4.117       Finds all records for given attributes.
   4.118  
   4.119       - parameter attributes: Dictionary of attribute names and values.
   4.120 @@ -430,6 +411,7 @@
   4.121  
   4.122       - returns: Optional managed object.
   4.123       */
   4.124 +    //!!!: move to test target
   4.125      class func all(attributes: [AnyHashable : Any],
   4.126                     predicateType: NSCompoundPredicate.LogicalType = defaultPredicateType,
   4.127                     orderedBy sortDescriptors: [NSSortDescriptor]? = nil,
   4.128 @@ -470,297 +452,4 @@
   4.129          let moc = context ?? Record.Context.default
   4.130          moc.delete(self)
   4.131      }
   4.132 -
   4.133 -    /**
   4.134 -     Deletes all records.
   4.135 -
   4.136 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.137 -     */
   4.138 -    class func deleteAll(context: NSManagedObjectContext? = nil) {
   4.139 -        let moc = context ?? Record.Context.default
   4.140 -        if let objects = self.all(in: moc) {
   4.141 -            for object in objects {
   4.142 -                moc.delete(object)
   4.143 -            }
   4.144 -        }
   4.145 -    }
   4.146 -
   4.147 -    /**
   4.148 -     Deletes all records for given predicate.
   4.149 -
   4.150 -     - parameter predicate: Predicate.
   4.151 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.152 -     */
   4.153 -    class func deleteAll(predicate: NSPredicate,
   4.154 -                         context: NSManagedObjectContext? = nil) {
   4.155 -        let moc = context ?? Record.Context.default
   4.156 -        if let objects = all(predicate: predicate, in: moc) {
   4.157 -            for object in objects {
   4.158 -                moc.delete(object)
   4.159 -            }
   4.160 -        }
   4.161 -    }
   4.162 -
   4.163 -    /**
   4.164 -     Deletes all records for given attribute name and value.
   4.165 -
   4.166 -     - parameter attribute: Attribute name.
   4.167 -     - parameter value: Attribute value.
   4.168 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.169 -     */
   4.170 -    class func deleteAll(attribute: String, value: Any,
   4.171 -                         context: NSManagedObjectContext? = nil) {
   4.172 -        let moc = context ?? Record.Context.default
   4.173 -        if let objects = all(attribute: attribute, value: value, in: moc) {
   4.174 -            for object in objects {
   4.175 -                moc.delete(object)
   4.176 -            }
   4.177 -        }
   4.178 -    }
   4.179 -
   4.180 -    /**
   4.181 -     Deletes all records for given attributes.
   4.182 -
   4.183 -     - parameter attributes: Dictionary of attribute names and values.
   4.184 -     - parameter predicateType: If not specified, `.AndPredicateType` will be used.
   4.185 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.186 -     */
   4.187 -    class func deleteAll(attributes: [AnyHashable : Any],
   4.188 -                         predicateType: NSCompoundPredicate.LogicalType = defaultPredicateType,
   4.189 -                         context: NSManagedObjectContext? = nil) {
   4.190 -        let moc = context ?? Record.Context.default
   4.191 -        if let objects = all(attributes: attributes, predicateType: predicateType, in: moc) {
   4.192 -            for object in objects {
   4.193 -                moc.delete(object)
   4.194 -            }
   4.195 -        }
   4.196 -    }
   4.197 -
   4.198 -    // MARK: - Count
   4.199 -
   4.200 -    /**
   4.201 -     Counts all records for given predicate.
   4.202 -
   4.203 -     - parameter predicate: Predicate.
   4.204 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.205 -
   4.206 -     - returns: Count of records.
   4.207 -     */
   4.208 -    class func count(predicate: NSPredicate? = nil,
   4.209 -                     in context: NSManagedObjectContext? = nil) -> Int {
   4.210 -        let moc = context ?? Record.Context.default
   4.211 -        let request = createFetchRequest(predicate: predicate)
   4.212 -        request.includesSubentities = false
   4.213 -
   4.214 -        var count = 0
   4.215 -
   4.216 -        do {
   4.217 -            count = try moc.count(for: request)
   4.218 -        } catch {
   4.219 -            Log.shared.errorAndCrash(error: error)
   4.220 -        }
   4.221 -
   4.222 -        return count
   4.223 -    }
   4.224 -
   4.225 -    /**
   4.226 -     Counts all records for given attribute name and value.
   4.227 -
   4.228 -     - parameter attribute: Attribute name.
   4.229 -     - parameter value: Attribute value.
   4.230 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.231 -
   4.232 -     - returns: Count of records.
   4.233 -     */
   4.234 -    class func count(attribute: String, value: Any,
   4.235 -                     in context: NSManagedObjectContext? = nil) -> Int {
   4.236 -        let moc = context ?? Record.Context.default
   4.237 -        return count(attributes: [attribute : value], in: moc)
   4.238 -    }
   4.239 -
   4.240 -    /**
   4.241 -     Counts all records for given attributes.
   4.242 -
   4.243 -     - parameter attributes: Dictionary of attribute names and values.
   4.244 -     - parameter predicateType: If not specified, `.AndPredicateType` will be used.
   4.245 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.246 -
   4.247 -     - returns: Count of records.
   4.248 -     */
   4.249 -    class func count(attributes: [AnyHashable : Any],
   4.250 -                     predicateType: NSCompoundPredicate.LogicalType = defaultPredicateType,
   4.251 -                     in context: NSManagedObjectContext? = nil) -> Int {
   4.252 -        let moc = context ?? Record.Context.default
   4.253 -        let predicate = createPredicate(attributes: attributes, predicateType: predicateType)
   4.254 -        return count(predicate: predicate, in: moc)
   4.255 -    }
   4.256 -
   4.257 -    // MARK: - Distinct
   4.258 -
   4.259 -    /**
   4.260 -     Gets distinct values for given attribute and predicate.
   4.261 -
   4.262 -     - parameter attribute: Attribute name.
   4.263 -     - parameter predicate: Predicate.
   4.264 -     - parameter sortDescriptors: Sort descriptors.
   4.265 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.266 -
   4.267 -     - returns: Throws optional Array of `Any`.
   4.268 -     */
   4.269 -    class func distinctValues(attribute: String,
   4.270 -                              predicate: NSPredicate? = nil, orderedBy sortDescriptors: [NSSortDescriptor]? = nil,
   4.271 -                              in context: NSManagedObjectContext? = nil) throws -> [Any]? {
   4.272 -        let moc = context ?? Record.Context.default
   4.273 -        var distinctValues = [Any]()
   4.274 -
   4.275 -        if let distinctRecords = try distinctRecords(attributes: [attribute], predicate: predicate,
   4.276 -                                                     orderedBy: sortDescriptors, in: moc)
   4.277 -        {
   4.278 -            for record in distinctRecords {
   4.279 -                if let value = record[attribute] {
   4.280 -                    distinctValues.append(value)
   4.281 -                }
   4.282 -            }
   4.283 -        }
   4.284 -
   4.285 -        return distinctValues.count > 0 ? distinctValues : nil
   4.286 -    }
   4.287 -
   4.288 -    /**
   4.289 -     Gets distinct values for given attributes and predicate.
   4.290 -
   4.291 -     - parameter attributes: Dictionary of attribute names and values.
   4.292 -     - parameter predicate: Predicate.
   4.293 -     - parameter sortDescriptors: Sort descriptors.
   4.294 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.295 -
   4.296 -     - returns: Throws optional Array of `Any`.
   4.297 -     */
   4.298 -    class func distinctRecords(attributes: [AnyHashable],
   4.299 -                               predicate: NSPredicate? = nil, orderedBy sortDescriptors: [NSSortDescriptor]? = nil,
   4.300 -                               in context: NSManagedObjectContext? = nil) throws -> [NSDictionary]? {
   4.301 -        let moc = context ?? Record.Context.default
   4.302 -        let request = NSFetchRequest<NSDictionary>(entityName: entityName)
   4.303 -        request.predicate = predicate
   4.304 -        request.sortDescriptors = sortDescriptors
   4.305 -        request.resultType = .dictionaryResultType
   4.306 -        request.propertiesToFetch = attributes
   4.307 -        request.returnsDistinctResults = true
   4.308 -
   4.309 -        let distinctRecords = try? moc.fetch(request)
   4.310 -
   4.311 -        return distinctRecords
   4.312 -    }
   4.313 -
   4.314 -    // MARK: - Other
   4.315 -
   4.316 -    /**
   4.317 -     Gets next ID for given attribute name. Attribute must be of `Int` type.
   4.318 -
   4.319 -     - parameter attribute: Attribute name.
   4.320 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.321 -
   4.322 -     - returns: Auto incremented ID.
   4.323 -     */
   4.324 -    class func autoIncrementedInteger(attribute: String,
   4.325 -                                      in context: NSManagedObjectContext? = nil) -> Int {
   4.326 -        let moc = context ?? Record.Context.default
   4.327 -        let sortDescriptor = NSSortDescriptor(key: attribute, ascending: false)
   4.328 -        guard
   4.329 -            let object = self.first(sortDescriptors: [sortDescriptor], in: moc),
   4.330 -            let max = object.value(forKey: attribute) as? Int
   4.331 -            else { return 0 }
   4.332 -        return max + 1
   4.333 -    }
   4.334 -
   4.335 -    /**
   4.336 -     Turns object into fault.
   4.337 -
   4.338 -     - parameter mergeChanges: A Boolean value.
   4.339 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.340 -     */
   4.341 -    func refresh(mergeChanges: Bool = true, in context: NSManagedObjectContext? = nil) {
   4.342 -        let moc = context ?? Record.Context.default
   4.343 -        Record.refreshObjects(objectIDs: [objectID], mergeChanges: mergeChanges, context: moc)
   4.344 -    }
   4.345 -
   4.346 -    // MARK: - Batch Update
   4.347 -
   4.348 -    /**
   4.349 -     Updates data directly in persistent store.
   4.350 -
   4.351 -     - parameter properties: Properties to update.
   4.352 -     - parameter predicate: Predicate.
   4.353 -     - parameter resultType: If not specified, `StatusOnlyResultType` will be used.
   4.354 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.355 -
   4.356 -     - returns: Batch update result.
   4.357 -     */
   4.358 -    class func batchUpdate(properties: [AnyHashable : Any], predicate: NSPredicate? = nil,
   4.359 -                           resultType: NSBatchUpdateRequestResultType = .statusOnlyResultType,
   4.360 -                           in context: NSManagedObjectContext? = nil) -> NSBatchUpdateResult? {
   4.361 -        let moc = context ?? Record.Context.default
   4.362 -        let request = NSBatchUpdateRequest(entityName: entityName)
   4.363 -        request.predicate = predicate
   4.364 -        request.propertiesToUpdate = properties
   4.365 -        request.resultType = resultType
   4.366 -        
   4.367 -        var batchResult: NSBatchUpdateResult? = nil
   4.368 -        
   4.369 -        moc.performAndWait {
   4.370 -            do {
   4.371 -                if let result = try moc.execute(request) as? NSBatchUpdateResult {
   4.372 -                    batchResult = result
   4.373 -                }
   4.374 -            } catch {
   4.375 -                Log.shared.errorAndCrash(error: error)
   4.376 -            }
   4.377 -        }
   4.378 -
   4.379 -        return batchResult
   4.380 -    }
   4.381 -
   4.382 -    /**
   4.383 -     Updates data directly in persistent store.
   4.384 -
   4.385 -     - parameter properties: Properties to update.
   4.386 -     - parameter predicate: Predicate.
   4.387 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.388 -
   4.389 -     - returns: Count of updated objects.
   4.390 -     */
   4.391 -    class func objectsCountForBatchUpdate(properties: [AnyHashable : Any], predicate: NSPredicate? = nil,
   4.392 -                                          in context: NSManagedObjectContext? = nil) -> Int {
   4.393 -        let moc = context ?? Record.Context.default
   4.394 -        let type = NSBatchUpdateRequestResultType.updatedObjectsCountResultType
   4.395 -        if let result = batchUpdate(properties: properties, predicate: predicate, resultType: type, in: moc) {
   4.396 -            if let count = result.result as? Int {
   4.397 -                return count
   4.398 -            } else {
   4.399 -                return 0
   4.400 -            }
   4.401 -        } else {
   4.402 -            return 0
   4.403 -        }
   4.404 -    }
   4.405 -
   4.406 -    /**
   4.407 -     Updates data directly in persistent store.
   4.408 -
   4.409 -     Objects are turned into faults after updating *(managed object context is refreshed)*.
   4.410 -
   4.411 -     - parameter properties: Properties to update.
   4.412 -     - parameter predicate: Predicate.
   4.413 -     - parameter context: If not specified, `Record.Context.default` will be used.
   4.414 -     */
   4.415 -    class func batchUpdateAndRefreshObjects(properties: [AnyHashable : Any], predicate: NSPredicate? = nil,
   4.416 -                                            in context: NSManagedObjectContext? = nil) {
   4.417 -        let moc = context ?? Record.Context.default
   4.418 -        let type = NSBatchUpdateRequestResultType.updatedObjectIDsResultType
   4.419 -        if let result = batchUpdate(properties: properties, predicate: predicate, resultType: type, in: moc) {
   4.420 -            if let objectIDs = result.result as? [NSManagedObjectID] {
   4.421 -                Record.refreshObjects(objectIDs: objectIDs, mergeChanges: true, context: moc)
   4.422 -            }
   4.423 -        }
   4.424 -    }
   4.425  }
     5.1 --- a/MessageModel/MessageModel/Interface/MessageModelObjects/Internal/Record/Record.swift	Thu Jun 27 13:39:47 2019 +0200
     5.2 +++ b/MessageModel/MessageModel/Interface/MessageModelObjects/Internal/Record/Record.swift	Thu Jun 27 14:09:02 2019 +0200
     5.3 @@ -45,114 +45,7 @@
     5.4           @available(*, deprecated, message: "Obsolete. Do not use it any more. If you are looking for a context to initialize a MessageModelObjectt, use Stack.MessageModelObjectContext. Else use Stack.shared.[newPrivateConcurrent]Context")
     5.5          public static var background: NSManagedObjectContext { return Stack.MessageModelObjectContext.background }
     5.6      }
     5.7 -    
     5.8 -//    /// Persistent Store Coordinator for current stack.
     5.9 -//    open class var storeCoordinator: NSPersistentStoreCoordinator? { return Stack.shared.coordinator }
    5.10 -//
    5.11 -    // MARK: - Stack
    5.12 -    
    5.13 -    /**
    5.14 -        Loads Core Data Stack (creates new if it doesn't already exist) with given options (all options are optional).
    5.15 -    
    5.16 -        - NOTE:
    5.17 -        Default option for `managedObjectModel` is `NSManagedObjectModel.mergedModelFromBundles(nil)!`,
    5.18 -        custom may be provided by using `modelFromBundle:` method.
    5.19  
    5.20 -        Default option for `storeType` is `NSSQLiteStoreType`
    5.21 -     
    5.22 -        Default option for `storeURL` is `bundleIdentifier + ".sqlite"` inside `applicationDocumentsDirectory`,
    5.23 -        custom may be provided by using `storeURLForName:` method.
    5.24 -    
    5.25 -        - parameter managedObjectModel: Managed object model for Core Data Stack.
    5.26 -        - parameter storeType: Store type for Persistent Store creation.
    5.27 -        - parameter configuration: Configuration for Persistent Store creation.
    5.28 -        - parameter storeURL: File URL for Persistent Store creation.
    5.29 -        - parameter options: Options for Persistent Store creation.
    5.30 -    
    5.31 -        - returns: Throws error if something went wrong.
    5.32 -    */
    5.33 -    public static func loadCoreDataStack(managedObjectModel: NSManagedObjectModel?,
    5.34 -                                      storeType: String = NSSQLiteStoreType,
    5.35 -                                      configuration: String? = nil,
    5.36 -                                      storeURL: URL?,
    5.37 -                                      options: [AnyHashable : Any]? = nil) throws {
    5.38 -        let saveManagedObject = managedObjectModel ?? Stack.defaultModel
    5.39 -        let saveStoreUrl = storeURL ?? Stack.defaultURL
    5.40 -        try Stack.shared.loadCoreDataStack(managedObjectModel: saveManagedObject,
    5.41 -                                           storeType: storeType,
    5.42 -                                           configuration: configuration,
    5.43 -                                           storeURL: saveStoreUrl,
    5.44 -                                           options: options)
    5.45 -        #if !(DEBUG)
    5.46 -        let mergeType = NSMergePolicy(merge:
    5.47 -            NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
    5.48 -        set(mergePolicy: mergeType)
    5.49 -        #endif
    5.50 -    }
    5.51 -
    5.52 -    /**
    5.53 -        Destroys Core Data Stack for the given store URL (stop notifications, reset contexts,
    5.54 -        remove persistent store and delete .sqlite file). This action can't be undone.
    5.55 -    
    5.56 -        - parameter storeURL: Store URL for stack to destroy.
    5.57 -    
    5.58 -        - returns: Throws error if something went wrong.
    5.59 -    */
    5.60 -    class func destroyCoreDataStack(
    5.61 -        managedObjectModel: NSManagedObjectModel = Stack.defaultModel,
    5.62 -        storeType: String = NSSQLiteStoreType, storeURL: URL = Stack.defaultURL) throws {
    5.63 -        try Stack.shared.destroyCoreDataStack(
    5.64 -            managedObjectModel: managedObjectModel, storeType: storeType, storeURL: storeURL)
    5.65 -    }
    5.66 -    
    5.67 -    /**
    5.68 -         Returns the final URL for the store with given name.
    5.69 -         
    5.70 -         - parameter name: Filename for the store.
    5.71 -         
    5.72 -         - returns: File URL for the store with given name.
    5.73 -    */
    5.74 -    open class func storeURL(for name: String) -> URL {
    5.75 -        return Stack.storeURL(for: name)
    5.76 -    }
    5.77 -    
    5.78 -    /**
    5.79 -         Returns merged model from the bundle for given class.
    5.80 -         
    5.81 -         - parameter aClass: Class inside bundle with data model.
    5.82 -         
    5.83 -         - returns: Merged model from the bundle for given class.
    5.84 -    */
    5.85 -    open class func modelFromBundle(for aClass: AnyClass) -> NSManagedObjectModel {
    5.86 -        return Stack.modelFromBundle(for: aClass)
    5.87 -    }
    5.88 -    
    5.89 -    // MARK: - Context
    5.90 -    
    5.91 -    /**
    5.92 -        Executes given fetch request.
    5.93 -    
    5.94 -        - parameter request: Fetch request to execute.
    5.95 -        - parameter context: If not specified, `Context.default` will be used.
    5.96 -     
    5.97 -        - returns: Result of executed fetch request.
    5.98 -    */
    5.99 -    open class func execute<T: NSManagedObject>(fetchRequest request: NSFetchRequest<T>,
   5.100 -                            in context: NSManagedObjectContext? = nil) -> [T] {
   5.101 -        let moc = context ?? Context.default
   5.102 -        return Stack.shared.execute(fetchRequest: request, in: moc)
   5.103 -    }
   5.104 -    
   5.105 -    /**
   5.106 -        Saves context asynchronously.
   5.107 -    
   5.108 -        - parameter context: If not specified, `Context.default` will be used.
   5.109 -    */
   5.110 -    open class func save(context: NSManagedObjectContext? = nil) {
   5.111 -        let moc = context ?? Context.default
   5.112 -        Stack.shared.save(context: moc)
   5.113 -    }
   5.114 -    
   5.115      /**
   5.116          Saves context synchronously.
   5.117          
   5.118 @@ -160,47 +53,6 @@
   5.119      */
   5.120      open class func saveAndWait(context: NSManagedObjectContext? = nil) {
   5.121          let moc = context ?? Context.default
   5.122 -        Stack.shared.saveAndWait(context: moc)
   5.123 -    }
   5.124 -    
   5.125 -    /**
   5.126 -        Turns objects into faults for given Array of `NSManagedObjectID`.
   5.127 -    
   5.128 -        - parameter context: If not specified, `Context.default` will be used.
   5.129 -        - parameter objectIDS: Array of `NSManagedObjectID` objects to turn into fault.
   5.130 -        - parameter mergeChanges: A Boolean value.
   5.131 -    */
   5.132 -    open class func refreshObjects(objectIDs: [NSManagedObjectID], mergeChanges: Bool,
   5.133 -                                   context: NSManagedObjectContext? = nil) {
   5.134 -        let moc = context ?? Context.default
   5.135 -        Stack.refreshObjects(objectIDs: objectIDs, mergeChanges: mergeChanges, in: moc)
   5.136 -    }
   5.137 -    
   5.138 -//    /**
   5.139 -//        Turns all registered objects into faults.
   5.140 -//
   5.141 -//        - parameter context: If not specified, `Context.default` will be used.
   5.142 -//        - parameter mergeChanges: A Boolean value.
   5.143 -//    */
   5.144 -//    open class func refreshRegisteredObjects(mergeChanges: Bool,
   5.145 -//                                             in context: NSManagedObjectContext? = nil) {
   5.146 -//        let moc = context ?? Context.default
   5.147 -//        Stack.refreshRegisteredObjects(mergeChanges: mergeChanges, in: moc)
   5.148 -//    }
   5.149 -
   5.150 -    /**
   5.151 -        Deletes all records from all entities contained in the model.
   5.152 -
   5.153 -        - parameter context: If not specified, `Context.default` will be used.
   5.154 -    */
   5.155 -//    open class func truncateAllData(in context: NSManagedObjectContext? = nil) {
   5.156 -//        let moc = context ?? Context.default
   5.157 -//        Stack.shared.truncateAllData(in: moc)
   5.158 -//    }
   5.159 -
   5.160 -    // MARK: - Merge Policy
   5.161 -
   5.162 -    public static func set(mergePolicy: NSMergePolicy) {
   5.163 -        Stack.shared.set(mergePolicy: mergePolicy)
   5.164 +        moc.saveAndLogErrors()
   5.165      }
   5.166  }
     6.1 --- a/MessageModel/MessageModel/Modules/QueryResultsController/QueryResultsController/QueryResultsController.swift	Thu Jun 27 13:39:47 2019 +0200
     6.2 +++ b/MessageModel/MessageModel/Modules/QueryResultsController/QueryResultsController/QueryResultsController.swift	Thu Jun 27 14:09:02 2019 +0200
     6.3 @@ -16,15 +16,17 @@
     6.4  
     6.5      private var frc: NSFetchedResultsController<T>?
     6.6      private func setupFRC(with predicate: NSPredicate?,
     6.7 -                           context: NSManagedObjectContext,
     6.8 -                           cacheName: String?,
     6.9 -                           sortDescriptors: [NSSortDescriptor]) {
    6.10 -        let fetchRequest = NSFetchRequest<T>(entityName: T.entityName)
    6.11 +                          context: NSManagedObjectContext,
    6.12 +                          cacheName: String?,
    6.13 +                          sortDescriptors: [NSSortDescriptor]) {
    6.14 +        let fetchRequest = T.createFetchRequest()
    6.15          fetchRequest.predicate = predicate
    6.16          fetchRequest.sortDescriptors = sortDescriptors
    6.17          let createe = NSFetchedResultsController(fetchRequest: fetchRequest,
    6.18                                                   managedObjectContext: context,
    6.19 -                                                 sectionNameKeyPath: nil, cacheName: cacheName)
    6.20 +                                                 sectionNameKeyPath: nil,
    6.21 +                                                 cacheName: cacheName)
    6.22 +            as! NSFetchedResultsController<T>
    6.23          createe.delegate = self
    6.24          frc = createe
    6.25      }
     7.1 --- a/MessageModel/MessageModel/Submodule/CoreData/Stack.swift	Thu Jun 27 13:39:47 2019 +0200
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,356 +0,0 @@
     7.4 -//
     7.5 -// Stack.swift
     7.6 -//
     7.7 -// Copyright (c) 2014-2016 appculture AG http://appculture.com
     7.8 -//
     7.9 -// Permission is hereby granted, free of charge, to any person obtaining a copy
    7.10 -// of this software and associated documentation files (the "Software"), to deal
    7.11 -// in the Software without restriction, including without limitation the rights
    7.12 -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    7.13 -// copies of the Software, and to permit persons to whom the Software is
    7.14 -// furnished to do so, subject to the following conditions:
    7.15 -//
    7.16 -// The above copyright notice and this permission notice shall be included in all
    7.17 -// copies or substantial portions of the Software.
    7.18 -//
    7.19 -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    7.20 -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    7.21 -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    7.22 -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    7.23 -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    7.24 -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    7.25 -// SOFTWARE.
    7.26 -//
    7.27 -
    7.28 -import CoreData
    7.29 -
    7.30 -import pEpIOSToolbox
    7.31 -
    7.32 -//!!!: review, cleanup
    7.33 -
    7.34 -/// This internal class is core of Record as it configures and accesses Core Data Stack.
    7.35 -class Stack {
    7.36 -
    7.37 -    // MARK: - Singleton
    7.38 -
    7.39 -    static let shared = Stack()
    7.40 -
    7.41 -    // MARK: - Defaults
    7.42 -
    7.43 -    class var defaultModel: NSManagedObjectModel {
    7.44 -        return NSManagedObjectModel.mergedModel(from: nil)!
    7.45 -    }
    7.46 -
    7.47 -    class var defaultName: String {
    7.48 -        guard let identifier = Bundle.main.bundleIdentifier
    7.49 -            else { return Bundle(for: Stack.self).bundleIdentifier! }
    7.50 -        return identifier
    7.51 -    }
    7.52 -
    7.53 -    class var defaultURL: URL {
    7.54 -        return storeURL(for: defaultName)
    7.55 -    }
    7.56 -
    7.57 -    class var defaultDirectory: FileManager.SearchPathDirectory {
    7.58 -        #if os(tvOS)
    7.59 -        return .cachesDirectory
    7.60 -        #else
    7.61 -        return .documentDirectory
    7.62 -        #endif
    7.63 -    }
    7.64 -
    7.65 -    let defaultMergePolicy = NSMergePolicy(merge:
    7.66 -        NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
    7.67 -
    7.68 -
    7.69 -    var newPrivateConcurrentContext: NSManagedObjectContext {
    7.70 -        let createe = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    7.71 -        createe.parent = backgroundContext
    7.72 -        createe.name = "privateQueueConcurrent context crated on \(Date())"
    7.73 -        createe.automaticallyMergesChangesFromParent = true
    7.74 -        createe.undoManager = nil
    7.75 -        createe.mergePolicy = defaultMergePolicy
    7.76 -        return createe
    7.77 -    }
    7.78 -
    7.79 -    // MARK: - Properties
    7.80 -
    7.81 -    private var model: NSManagedObjectModel?
    7.82 -    private var coordinator: NSPersistentStoreCoordinator?
    7.83 -
    7.84 -    var mainContext: NSManagedObjectContext!
    7.85 -    fileprivate var backgroundContext: NSManagedObjectContext!
    7.86 -
    7.87 -    // MARK: - Stack
    7.88 -
    7.89 -    /**
    7.90 -     Returns the final URL for the store with given name.
    7.91 -
    7.92 -     - parameter name: Filename for the store.
    7.93 -
    7.94 -     - returns: File URL for the store with given name.
    7.95 -     */
    7.96 -    class func storeURL(for name: String) -> URL {
    7.97 -        let fileManager = FileManager.default
    7.98 -        let directoryURL = fileManager.urls(for: defaultDirectory, in: .userDomainMask).last!
    7.99 -        let storeName = "\(name).sqlite"
   7.100 -        return directoryURL.appendingPathComponent(storeName)
   7.101 -    }
   7.102 -
   7.103 -    class func modelFromBundle(for aClass: AnyClass) -> NSManagedObjectModel {
   7.104 -        let bundle = Bundle(for: aClass)
   7.105 -        return NSManagedObjectModel.mergedModel(from: [bundle])!
   7.106 -    }
   7.107 -
   7.108 -    /**
   7.109 -     Loads Core Data Stack (creates new if it doesn't already exist) with given options (all options are optional).
   7.110 -
   7.111 -     - NOTE:
   7.112 -     Default option for `managedObjectModel` is `NSManagedObjectModel.mergedModelFromBundles(nil)!`,
   7.113 -     custom may be provided by using `modelFromBundle:` method.
   7.114 -
   7.115 -     Default option for `storeType` is `NSSQLiteStoreType`
   7.116 -
   7.117 -     Default option for `storeURL` is `bundleIdentifier + ".sqlite"` inside `applicationDocumentsDirectory`,
   7.118 -     custom may be provided by using `storeURLForName:` method.
   7.119 -
   7.120 -     - parameter managedObjectModel: Managed object model for Core Data Stack.
   7.121 -     - parameter storeType: Store type for Persistent Store creation.
   7.122 -     - parameter configuration: Configuration for Persistent Store creation.
   7.123 -     - parameter storeURL: File URL for Persistent Store creation.
   7.124 -     - parameter options: Options for Persistent Store creation.
   7.125 -
   7.126 -     - returns: Throws error if something went wrong.
   7.127 -     */
   7.128 -    func loadCoreDataStack(managedObjectModel: NSManagedObjectModel = defaultModel,
   7.129 -                           storeType: String = NSSQLiteStoreType,
   7.130 -                           configuration: String? = nil,
   7.131 -                           storeURL: URL = defaultURL,
   7.132 -                           options: [AnyHashable : Any]? = nil) throws {
   7.133 -        model = managedObjectModel
   7.134 -        try configureStoreCoordinator(model: managedObjectModel,
   7.135 -                                      type: storeType,
   7.136 -                                      configuration: configuration,
   7.137 -                                      url: storeURL,
   7.138 -                                      options: options)
   7.139 -        configureManagedObjectContexts()
   7.140 -        startReceivingContextNotifications()
   7.141 -
   7.142 -        #if !(DEBUG)
   7.143 -        // In case of a conflict:
   7.144 -        // In release mode we prefer the objects changes over the store's changes.
   7.145 -        // In DEBUG we crash intentionally whenever merge conflicts happen.
   7.146 -        let mergeType = NSMergePolicy(merge:
   7.147 -            NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
   7.148 -        set(mergePolicy: mergeType)
   7.149 -        #endif
   7.150 -    }
   7.151 -
   7.152 -    private func configureManagedObjectContexts() {
   7.153 -        guard coordinator != nil else {
   7.154 -            Log.shared.errorAndCrash("We MUST have a cooridinator @ this point")
   7.155 -            return
   7.156 -        }
   7.157 -        mainContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
   7.158 -        mainContext.persistentStoreCoordinator = coordinator
   7.159 -        mainContext.name = "mainContext"
   7.160 -        mainContext.undoManager = nil
   7.161 -        mainContext.mergePolicy = defaultMergePolicy
   7.162 -
   7.163 -        backgroundContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
   7.164 -        backgroundContext.persistentStoreCoordinator = coordinator
   7.165 -        backgroundContext.name = "backgroundContext"
   7.166 -        backgroundContext.automaticallyMergesChangesFromParent = true
   7.167 -        backgroundContext.undoManager = nil
   7.168 -        backgroundContext.mergePolicy = defaultMergePolicy
   7.169 -    }
   7.170 -
   7.171 -    private func configureStoreCoordinator(model: NSManagedObjectModel,
   7.172 -                                           type: String,
   7.173 -                                           configuration: String?,
   7.174 -                                           url: URL,
   7.175 -                                           options: [AnyHashable : Any]?) throws {
   7.176 -        coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
   7.177 -        try coordinator?.addPersistentStore(ofType: type, configurationName: configuration, at: url, options: options)
   7.178 -    }
   7.179 -
   7.180 -    /**
   7.181 -     Destroys Core Data Stack for the given store URL (stop notifications, reset contexts,
   7.182 -     remove persistent store and delete .sqlite file). This action can't be undone.
   7.183 -
   7.184 -     - parameter storeURL: Store URL for stack to destroy.
   7.185 -
   7.186 -     - returns: Throws error if something went wrong.
   7.187 -     */
   7.188 -    func destroyCoreDataStack(managedObjectModel: NSManagedObjectModel = defaultModel,
   7.189 -                              storeType: String = NSSQLiteStoreType,
   7.190 -                              storeURL: URL = defaultURL) throws {
   7.191 -        stopReceivingContextNotifications()
   7.192 -        guard let _ = mainContext.persistentStoreCoordinator else {
   7.193 -            // The stack has not been setup yet.
   7.194 -            return
   7.195 -        }
   7.196 -        resetContexts()
   7.197 -        resetCoordinatorAndModel()
   7.198 -        try destroyPersistentStore(storeURL: storeURL, storeType: storeType)
   7.199 -    }
   7.200 -
   7.201 -    private func resetContexts() { // Rename in MessageModelObjecContexts
   7.202 -        mainContext.performAndWait {
   7.203 -            mainContext.reset()
   7.204 -        }
   7.205 -        backgroundContext.performAndWait {
   7.206 -            backgroundContext.reset()
   7.207 -        }
   7.208 -    }
   7.209 -
   7.210 -    private func destroyPersistentStore(storeURL: URL,
   7.211 -                                        storeType: String = NSSQLiteStoreType) throws {
   7.212 -        try coordinator?.destroyPersistentStore(at: storeURL, ofType: storeType)
   7.213 -    }
   7.214 -
   7.215 -    private func resetCoordinatorAndModel() {
   7.216 -        coordinator = nil
   7.217 -        model = nil
   7.218 -    }
   7.219 -
   7.220 -    deinit {
   7.221 -        stopReceivingContextNotifications()
   7.222 -    }
   7.223 -
   7.224 -    // MARK: - Context
   7.225 -
   7.226 -    func execute<T: NSManagedObject>(fetchRequest request: NSFetchRequest<T>,
   7.227 -                                     in context: NSManagedObjectContext) -> [T] {
   7.228 -        var fetchedObjects = [T]()
   7.229 -        context.performAndWait {
   7.230 -            do {
   7.231 -                fetchedObjects = try context.fetch(request)
   7.232 -            } catch {
   7.233 -                Log.shared.errorAndCrash(error: error)
   7.234 -            }
   7.235 -        }
   7.236 -        return fetchedObjects
   7.237 -    }
   7.238 -
   7.239 -    func save(context: NSManagedObjectContext) {
   7.240 -        context.perform {
   7.241 -            context.saveAndLogErrors()
   7.242 -        }
   7.243 -    }
   7.244 -
   7.245 -    func saveAndWait(context: NSManagedObjectContext) {
   7.246 -        context.performAndWait {
   7.247 -            context.saveAndLogErrors()
   7.248 -        }
   7.249 -    }
   7.250 -
   7.251 -    class func refreshObjects(objectIDs: [NSManagedObjectID], //!!!: rename in 
   7.252 -                              mergeChanges: Bool,
   7.253 -                              in context: NSManagedObjectContext = Record.Context.default) {
   7.254 -        for objectID in objectIDs {
   7.255 -            context.performAndWait {
   7.256 -                do {
   7.257 -                    let managedObject = try context.existingObject(with: objectID)
   7.258 -                    // turn managed object into fault
   7.259 -                    context.refresh(managedObject, mergeChanges: mergeChanges)
   7.260 -                } catch {
   7.261 -                    Log.shared.errorAndCrash(error: error)
   7.262 -                }
   7.263 -            }
   7.264 -        }
   7.265 -    }
   7.266 -
   7.267 -    class func refreshRegisteredObjects(mergeChanges: Bool, in context: NSManagedObjectContext) {
   7.268 -        let registeredObjectIDs = context.registeredObjects.map { return $0.objectID }
   7.269 -        refreshObjects(objectIDs: registeredObjectIDs, mergeChanges: mergeChanges, in: context)
   7.270 -    }
   7.271 -
   7.272 -    func truncateAllData(in context: NSManagedObjectContext) {
   7.273 -        if let mom = model {
   7.274 -            for entity in mom.entities {
   7.275 -                if let entityType = NSClassFromString(entity.managedObjectClassName) as? NSManagedObject.Type {
   7.276 -                    entityType.deleteAll(context: context)
   7.277 -                }
   7.278 -            }
   7.279 -        }
   7.280 -    }
   7.281 -
   7.282 -    private func mergeChanges(from notification: Notification, in context: NSManagedObjectContext) {
   7.283 -        context.perform {
   7.284 -            context.mergeChanges(fromContextDidSave: notification)
   7.285 -        }
   7.286 -    }
   7.287 -
   7.288 -    // MARK: - Notifications
   7.289 -
   7.290 -    func startReceivingContextNotifications() {
   7.291 -        let center = NotificationCenter.default
   7.292 -
   7.293 -        // Contexts Sync
   7.294 -        let didSave = #selector(Stack.contextDidSave(_:))
   7.295 -        let didSaveName = NSNotification.Name.NSManagedObjectContextDidSave
   7.296 -        center.addObserver(self, selector: didSave, name: didSaveName, object: mainContext)
   7.297 -        center.addObserver(self, selector: didSave, name: didSaveName, object: backgroundContext)
   7.298 -    }
   7.299 -
   7.300 -    func stopReceivingContextNotifications() {
   7.301 -        NotificationCenter.default.removeObserver(self)
   7.302 -    }
   7.303 -
   7.304 -    // MARK: - Sync
   7.305 -
   7.306 -    @objc func contextDidSave(_ notification: Notification) {
   7.307 -        guard let context = notification.object as? NSManagedObjectContext  else {
   7.308 -                Log.shared.errorAndCrash("No context")
   7.309 -                return
   7.310 -        }
   7.311 -
   7.312 -        let contextToRefresh: NSManagedObjectContext
   7.313 -        if context == mainContext {
   7.314 -            contextToRefresh = backgroundContext
   7.315 -        } else if context == backgroundContext {
   7.316 -            contextToRefresh = mainContext
   7.317 -        } else {
   7.318 -            // It's an independent context. Do nothing.
   7.319 -            return
   7.320 -        }
   7.321 -        mergeChanges(from: notification, in: contextToRefresh)
   7.322 -    }
   7.323 -
   7.324 -    // MARK: - Merge Policy
   7.325 -
   7.326 -    func set(mergePolicy: NSMergePolicy) { //!!!: rm with Record
   7.327 -        mainContext.mergePolicy = mergePolicy
   7.328 -        backgroundContext.mergePolicy = mergePolicy
   7.329 -    }
   7.330 -}
   7.331 -
   7.332 -//!!!!: move! Or better: RE-move
   7.333 -
   7.334 -extension Stack {
   7.335 -    /// Struct that holds different instances of managed object context.
   7.336 -    /// -note: those contexts MUST be used for MessageModelObject initialization ONLY!
   7.337 -    public struct MessageModelObjectContext { //!!!: MUST be internal
   7.338 -        /// Managed object context for current thread.
   7.339 -        /// -note: MUST be used for MessageModelObject initialization ONLY!
   7.340 -        static var `default`: NSManagedObjectContext {
   7.341 -            let defaultContext: NSManagedObjectContext
   7.342 -
   7.343 -            if Thread.isMainThread {
   7.344 -                defaultContext = Stack.shared.mainContext
   7.345 -            } else {
   7.346 -                defaultContext = Stack.shared.backgroundContext
   7.347 -            }
   7.348 -            return defaultContext
   7.349 -        }
   7.350 -
   7.351 -        /// Managed object context for main thread.
   7.352 -        /// -note: MUST be used for MessageModelObject initialization ONLY!
   7.353 -        static var main: NSManagedObjectContext { return Stack.shared.mainContext }
   7.354 -
   7.355 -        /// Managed object context for background thread.
   7.356 -        /// -note: MUST be used for MessageModelObject initialization ONLY!
   7.357 -        static var background: NSManagedObjectContext { return Stack.shared.backgroundContext }
   7.358 -    }
   7.359 -}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/MessageModel/MessageModel/Submodule/CoreData/Stack/Stack+Defaults.swift	Thu Jun 27 14:09:02 2019 +0200
     8.3 @@ -0,0 +1,52 @@
     8.4 +//
     8.5 +//  Stack+ManagedObjectModel.swift
     8.6 +//  MessageModel
     8.7 +//
     8.8 +//  Created by Andreas Buff on 26.06.19.
     8.9 +//  Copyright © 2019 pEp Security S.A. All rights reserved.
    8.10 +//
    8.11 +
    8.12 +import CoreData
    8.13 +
    8.14 +extension Stack {
    8.15 +
    8.16 +    static var defaultManagedObjectModel: NSManagedObjectModel {
    8.17 +        let messageModelBundle = Bundle(for: self)
    8.18 +        let modelURL = messageModelBundle.url(forResource: "MessageModel", withExtension: "momd")!
    8.19 +        let objectModel = NSManagedObjectModel(contentsOf: modelURL)!
    8.20 +        return objectModel
    8.21 +    }
    8.22 +
    8.23 +    // MARK: - Defaults
    8.24 +
    8.25 +    static var defaultName: String {
    8.26 +        guard let bundleId = Bundle.main.bundleIdentifier else {
    8.27 +            /// There is nothing we can do.
    8.28 +            fatalError()
    8.29 +        }
    8.30 +        return bundleId
    8.31 +    }
    8.32 +
    8.33 +
    8.34 +    static var defaultURL: URL {
    8.35 +        return storeURL(for: defaultName)
    8.36 +    }
    8.37 +
    8.38 +    static var defaultDirectory: FileManager.SearchPathDirectory {
    8.39 +        #if os(tvOS)
    8.40 +        return .cachesDirectory
    8.41 +        #else
    8.42 +        return .documentDirectory
    8.43 +        #endif
    8.44 +    }
    8.45 +
    8.46 +    static var defaultOptions: [String:Bool] {
    8.47 +        return [NSMigratePersistentStoresAutomaticallyOption: true,
    8.48 +                NSInferMappingModelAutomaticallyOption: true]
    8.49 +
    8.50 +    }
    8.51 +
    8.52 +    static var defaultMergePolicy: NSMergePolicy {
    8.53 +        return NSMergePolicy(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
    8.54 +    }
    8.55 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/MessageModel/MessageModel/Submodule/CoreData/Stack/Stack.swift	Thu Jun 27 14:09:02 2019 +0200
     9.3 @@ -0,0 +1,300 @@
     9.4 +//
     9.5 +// Stack.swift
     9.6 +//
     9.7 +// Copyright (c) 2014-2016 appculture AG http://appculture.com
     9.8 +//
     9.9 +// Permission is hereby granted, free of charge, to any person obtaining a copy
    9.10 +// of this software and associated documentation files (the "Software"), to deal
    9.11 +// in the Software without restriction, including without limitation the rights
    9.12 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    9.13 +// copies of the Software, and to permit persons to whom the Software is
    9.14 +// furnished to do so, subject to the following conditions:
    9.15 +//
    9.16 +// The above copyright notice and this permission notice shall be included in all
    9.17 +// copies or substantial portions of the Software.
    9.18 +//
    9.19 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    9.20 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    9.21 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    9.22 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    9.23 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    9.24 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    9.25 +// SOFTWARE.
    9.26 +//
    9.27 +
    9.28 +import CoreData
    9.29 +
    9.30 +import pEpIOSToolbox
    9.31 +
    9.32 +//!!!: review, cleanup
    9.33 +
    9.34 +/// This internal class is core of Record as it configures and accesses Core Data Stack.
    9.35 +class Stack {
    9.36 +
    9.37 +    // MARK: - Singleton
    9.38 +
    9.39 +    static let shared: Stack = {
    9.40 +        return Stack()
    9.41 +    }()
    9.42 +
    9.43 +    private init() {
    9.44 +        // Make sure the Stack is setup on the main queue, because the main context MUST be created
    9.45 +        // on the main queue.
    9.46 +        if Thread.current.isMainThread {
    9.47 +            do {
    9.48 +                try loadCoreDataStack()
    9.49 +            } catch {
    9.50 +                fatalError("No Stack, no running app, sorry.")
    9.51 +            }
    9.52 +        } else {
    9.53 +            DispatchQueue.main.sync {
    9.54 +                do {
    9.55 +                    try loadCoreDataStack()
    9.56 +                } catch {
    9.57 +                    fatalError("No Stack, no running app, sorry.")
    9.58 +                }
    9.59 +            }
    9.60 +        }
    9.61 +    }
    9.62 +
    9.63 +    deinit {
    9.64 +        stopReceivingContextNotifications()
    9.65 +    }
    9.66 +
    9.67 +    // MARK: - Properties
    9.68 +
    9.69 +    private var model: NSManagedObjectModel?
    9.70 +    private var coordinator: NSPersistentStoreCoordinator?
    9.71 +
    9.72 +    var mainContext: NSManagedObjectContext!
    9.73 +    private var backgroundContext: NSManagedObjectContext!
    9.74 +
    9.75 +    var newPrivateConcurrentContext: NSManagedObjectContext {
    9.76 +        objc_sync_enter(self)
    9.77 +
    9.78 +        let createe = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    9.79 +        createe.parent = backgroundContext
    9.80 +        createe.name = "privateQueueConcurrent context created on \(Date())"
    9.81 +        createe.automaticallyMergesChangesFromParent = true
    9.82 +        createe.undoManager = nil
    9.83 +        createe.mergePolicy = Stack.defaultMergePolicy
    9.84 +
    9.85 +        objc_sync_exit(self)
    9.86 +
    9.87 +        return createe
    9.88 +
    9.89 +    }
    9.90 +}
    9.91 +
    9.92 +// MARK: - Setup
    9.93 +
    9.94 +extension Stack {
    9.95 +
    9.96 +    /**
    9.97 +     Returns the final URL for the store with given name.
    9.98 +
    9.99 +     - parameter name: Filename for the store.
   9.100 +
   9.101 +     - returns: File URL for the store with given name.
   9.102 +     */
   9.103 +    //!!!: make private after Record is gone
   9.104 +    static func storeURL(for name: String) -> URL {
   9.105 +        let fileManager = FileManager.default
   9.106 +        let directoryURL = fileManager.urls(for: defaultDirectory, in: .userDomainMask).last!
   9.107 +        let storeName = "\(name).sqlite"
   9.108 +        return directoryURL.appendingPathComponent(storeName)
   9.109 +    }
   9.110 +
   9.111 +    /// Loads Core Data Stack (creates new if it doesn't already exist) with given options (all
   9.112 +    /// options are optional).
   9.113 +    ///
   9.114 +    /// - NOTE:
   9.115 +    /// Default option for `managedObjectModel` is `NSManagedObjectModel.mergedModelFromBundles(nil)!`,
   9.116 +    /// custom may be provided by using `modelFromBundle:` method.
   9.117 +    ///
   9.118 +    /// Default option for `storeType` is `NSSQLiteStoreType`
   9.119 +    ///
   9.120 +    /// Default option for `storeURL` is `bundleIdentifier + ".sqlite"` inside
   9.121 +    /// `applicationDocumentsDirectory`, custom may be provided by using `storeURLForName:` method.
   9.122 +    ///
   9.123 +    /// - parameter managedObjectModel: Managed object model for Core Data Stack.
   9.124 +    /// - parameter storeType: Store type for Persistent Store creation.
   9.125 +    /// - parameter configuration: Configuration for Persistent Store creation.
   9.126 +    /// - parameter storeURL: File URL for Persistent Store creation.
   9.127 +    /// - parameter options: Options for Persistent Store creation.
   9.128 +    ///
   9.129 +    /// - returns: Throws error if something went wrong.
   9.130 +    func loadCoreDataStack(managedObjectModel: NSManagedObjectModel = defaultManagedObjectModel,
   9.131 +                           storeType: String = NSSQLiteStoreType,
   9.132 +                           configuration: String? = nil,
   9.133 +                           storeURL: URL = defaultURL,
   9.134 +                           options: [AnyHashable : Any]? = defaultOptions) throws {
   9.135 +        model = managedObjectModel
   9.136 +        try configureStoreCoordinator(model: managedObjectModel,
   9.137 +                                      type: storeType,
   9.138 +                                      configuration: configuration,
   9.139 +                                      url: storeURL,
   9.140 +                                      options: options)
   9.141 +        configureManagedObjectContexts()
   9.142 +        startReceivingContextNotifications()
   9.143 +    }
   9.144 +
   9.145 +    private func configureManagedObjectContexts() {
   9.146 +        guard coordinator != nil else {
   9.147 +            Log.shared.errorAndCrash("We MUST have a cooridinator @ this point")
   9.148 +            return
   9.149 +        }
   9.150 +        mainContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
   9.151 +        mainContext.persistentStoreCoordinator = coordinator
   9.152 +        mainContext.name = "mainContext"
   9.153 +        mainContext.undoManager = nil
   9.154 +        mainContext.mergePolicy = Stack.defaultMergePolicy
   9.155 +
   9.156 +        backgroundContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
   9.157 +        backgroundContext.persistentStoreCoordinator = coordinator
   9.158 +        backgroundContext.name = "backgroundContext"
   9.159 +        backgroundContext.automaticallyMergesChangesFromParent = true
   9.160 +        backgroundContext.undoManager = nil
   9.161 +        backgroundContext.mergePolicy = Stack.defaultMergePolicy
   9.162 +    }
   9.163 +
   9.164 +    private func configureStoreCoordinator(model: NSManagedObjectModel,
   9.165 +                                           type: String,
   9.166 +                                           configuration: String?,
   9.167 +                                           url: URL,
   9.168 +                                           options: [AnyHashable : Any]?) throws {
   9.169 +        coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
   9.170 +        try coordinator?.addPersistentStore(ofType: type, configurationName: configuration, at: url, options: options)
   9.171 +    }
   9.172 +}
   9.173 +
   9.174 +// MARK: - Tear DOwn
   9.175 +//!!!: move to test target
   9.176 +extension Stack {
   9.177 +    ///Destroys Core Data Stack for the given store URL (stop notifications, reset contexts,
   9.178 +    ///remove persistent store and delete .sqlite file). This action can't be undone.
   9.179 +    ///
   9.180 +    /// - parameter storeURL: Store URL for stack to destroy.
   9.181 +    /// - returns: Throws error if something went wrong.
   9.182 +    func destroyCoreDataStack(managedObjectModel: NSManagedObjectModel = Stack.defaultManagedObjectModel,
   9.183 +                              storeType: String = NSSQLiteStoreType,
   9.184 +                              storeURL: URL = defaultURL) throws {
   9.185 +        stopReceivingContextNotifications()
   9.186 +        guard let _ = mainContext.persistentStoreCoordinator else {
   9.187 +            // The stack has not been setup yet.
   9.188 +            return
   9.189 +        }
   9.190 +        resetContexts()
   9.191 +        resetCoordinatorAndModel()
   9.192 +        try destroyPersistentStore(storeURL: storeURL, storeType: storeType)
   9.193 +    }
   9.194 +
   9.195 +    private func resetContexts() { // Rename in MessageModelObjecContexts
   9.196 +        mainContext.performAndWait {
   9.197 +            mainContext.reset()
   9.198 +        }
   9.199 +        backgroundContext.performAndWait {
   9.200 +            backgroundContext.reset()
   9.201 +        }
   9.202 +    }
   9.203 +
   9.204 +    private func destroyPersistentStore(storeURL: URL,
   9.205 +                                        storeType: String = NSSQLiteStoreType) throws {
   9.206 +        try coordinator?.destroyPersistentStore(at: storeURL, ofType: storeType)
   9.207 +    }
   9.208 +
   9.209 +    private func resetCoordinatorAndModel() {
   9.210 +        coordinator = nil
   9.211 +        model = nil
   9.212 +    }
   9.213 +}
   9.214 +
   9.215 +//!!!!: move! Or better: RE-move
   9.216 +
   9.217 +extension Stack {
   9.218 +
   9.219 +    func execute<T: NSManagedObject>(fetchRequest request: NSFetchRequest<T>,
   9.220 +                                     in context: NSManagedObjectContext) -> [T] {
   9.221 +        var fetchedObjects = [T]()
   9.222 +        context.performAndWait {
   9.223 +            do {
   9.224 +                fetchedObjects = try context.fetch(request)
   9.225 +            } catch {
   9.226 +                Log.shared.errorAndCrash(error: error)
   9.227 +            }
   9.228 +        }
   9.229 +        return fetchedObjects
   9.230 +    }
   9.231 +
   9.232 +    /// Struct that holds different instances of managed object context.
   9.233 +    /// -note: those contexts MUST be used for MessageModelObject initialization ONLY!
   9.234 +    public struct MessageModelObjectContext { //!!!: MUST be internal
   9.235 +        /// Managed object context for current thread.
   9.236 +        /// -note: MUST be used for MessageModelObject initialization ONLY!
   9.237 +        static var `default`: NSManagedObjectContext {
   9.238 +            let defaultContext: NSManagedObjectContext
   9.239 +
   9.240 +            if Thread.isMainThread {
   9.241 +                defaultContext = Stack.shared.mainContext
   9.242 +            } else {
   9.243 +                defaultContext = Stack.shared.backgroundContext
   9.244 +            }
   9.245 +            return defaultContext
   9.246 +        }
   9.247 +
   9.248 +        /// Managed object context for main thread.
   9.249 +        /// -note: MUST be used for MessageModelObject initialization ONLY!
   9.250 +        static var main: NSManagedObjectContext { return Stack.shared.mainContext }
   9.251 +
   9.252 +        /// Managed object context for background thread.
   9.253 +        /// -note: MUST be used for MessageModelObject initialization ONLY!
   9.254 +        static var background: NSManagedObjectContext { return Stack.shared.backgroundContext }
   9.255 +    }
   9.256 +}
   9.257 +
   9.258 +// MARK: - Merge Contexts
   9.259 +
   9.260 +//!!!: try to make obsolete improving the Stack. See ticket.
   9.261 +
   9.262 +extension Stack {
   9.263 +
   9.264 +    private func mergeChanges(from notification: Notification, in context: NSManagedObjectContext) {
   9.265 +        context.perform {
   9.266 +            context.mergeChanges(fromContextDidSave: notification)
   9.267 +        }
   9.268 +    }
   9.269 +
   9.270 +    func startReceivingContextNotifications() {
   9.271 +        let center = NotificationCenter.default
   9.272 +
   9.273 +        // Contexts Sync
   9.274 +        let didSave = #selector(Stack.contextDidSave(_:))
   9.275 +        let didSaveName = NSNotification.Name.NSManagedObjectContextDidSave
   9.276 +        center.addObserver(self, selector: didSave, name: didSaveName, object: mainContext)
   9.277 +        center.addObserver(self, selector: didSave, name: didSaveName, object: backgroundContext)
   9.278 +    }
   9.279 +
   9.280 +    func stopReceivingContextNotifications() {
   9.281 +        NotificationCenter.default.removeObserver(self)
   9.282 +    }
   9.283 +
   9.284 +    // MARK: - Sync
   9.285 +
   9.286 +    @objc func contextDidSave(_ notification: Notification) {
   9.287 +        guard let context = notification.object as? NSManagedObjectContext  else {
   9.288 +            Log.shared.errorAndCrash("No context")
   9.289 +            return
   9.290 +        }
   9.291 +
   9.292 +        let contextToRefresh: NSManagedObjectContext
   9.293 +        if context == mainContext {
   9.294 +            contextToRefresh = backgroundContext
   9.295 +        } else if context == backgroundContext {
   9.296 +            contextToRefresh = mainContext
   9.297 +        } else {
   9.298 +            // It's an independent context. Do nothing.
   9.299 +            return
   9.300 +        }
   9.301 +        mergeChanges(from: notification, in: contextToRefresh)
   9.302 +    }
   9.303 +}
    10.1 --- a/MessageModel/MessageModel/Util/MessageModelData.swift	Thu Jun 27 13:39:47 2019 +0200
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,18 +0,0 @@
    10.4 -//
    10.5 -//  AppDataModel.swift
    10.6 -//  pEpForiOS
    10.7 -//
    10.8 -//  Created by Dirk Zimmermann on 31/10/16.
    10.9 -//  Copyright © 2016 p≡p Security S.A. All rights reserved.
   10.10 -//
   10.11 -
   10.12 -import CoreData
   10.13 -
   10.14 -open class MessageModelData {
   10.15 -    public static func MessageModelData() -> NSManagedObjectModel {
   10.16 -        let messageModelBundle = Bundle(identifier: "net.pep-security.apps.MessageModel")!
   10.17 -        let modelURL = messageModelBundle.url(forResource: "MessageModel", withExtension: "momd")!
   10.18 -        let objectModel = NSManagedObjectModel(contentsOf: modelURL)!
   10.19 -        return objectModel
   10.20 -    }
   10.21 -}
    11.1 --- a/MessageModel/MessageModel/Util/PersistentSetup.swift	Thu Jun 27 13:39:47 2019 +0200
    11.2 +++ b/MessageModel/MessageModel/Util/PersistentSetup.swift	Thu Jun 27 14:09:02 2019 +0200
    11.3 @@ -10,9 +10,10 @@
    11.4  
    11.5  import pEpIOSToolbox
    11.6  
    11.7 +//!!: MUST go to test target!
    11.8  open class PersistentSetup {
    11.9      let storeType: String
   11.10 -    lazy var objectModel = MessageModelData.MessageModelData()
   11.11 +    lazy var objectModel = Stack.defaultManagedObjectModel
   11.12  
   11.13      public init(storeType: String = NSInMemoryStoreType) {
   11.14          self.storeType = storeType
   11.15 @@ -79,9 +80,9 @@
   11.16      func loadCoreDataStack() {
   11.17          do {
   11.18              removeDataStore()
   11.19 -            try Record.loadCoreDataStack(
   11.20 -                managedObjectModel: objectModel, storeType: storeType,
   11.21 -                storeURL: defaultURL)
   11.22 +            try Stack.shared.loadCoreDataStack(managedObjectModel: objectModel,
   11.23 +                                           storeType: storeType,
   11.24 +                                           storeURL: defaultURL)
   11.25          } catch {
   11.26              Log.shared.log(error: error)
   11.27          }
   11.28 @@ -89,8 +90,9 @@
   11.29  
   11.30      func tearDownCoreDataStack() {
   11.31          do {
   11.32 -            try Record.destroyCoreDataStack(managedObjectModel: objectModel,
   11.33 -                                            storeType: storeType, storeURL: defaultURL)
   11.34 +            try Stack.shared.destroyCoreDataStack(managedObjectModel: objectModel,
   11.35 +                                                   storeType: storeType,
   11.36 +                                                   storeURL: defaultURL)
   11.37          } catch {
   11.38              Log.shared.log(error: error)
   11.39          }
    12.1 --- a/MessageModel/MessageModelTests/CoreData/SendMessageCallbackHandlerTest.swift	Thu Jun 27 13:39:47 2019 +0200
    12.2 +++ b/MessageModel/MessageModelTests/CoreData/SendMessageCallbackHandlerTest.swift	Thu Jun 27 14:09:02 2019 +0200
    12.3 @@ -12,6 +12,7 @@
    12.4  @testable import MessageModel
    12.5  import PEPObjCAdapterFramework
    12.6  
    12.7 +//!!!: Tests must use the same project structure as production target. This is clearly not Core Data. Move!
    12.8  class SendMessageCallbackHandlerTest: PersistentStoreDrivenTestBase {
    12.9      let ownAddress = "this_is_my_own@example.com"
   12.10      let attachmentData = Data(repeating: 5, count: 100)
    13.1 --- a/MessageModel/MessageModelTests/MessageModelTests.swift	Thu Jun 27 13:39:47 2019 +0200
    13.2 +++ b/MessageModel/MessageModelTests/MessageModelTests.swift	Thu Jun 27 14:09:02 2019 +0200
    13.3 @@ -22,7 +22,7 @@
    13.4          persistentSetup = PersistentSetup(storeType: NSInMemoryStoreType)
    13.5          moc = Stack.shared.mainContext
    13.6          fixCdMessage = TestUtil.createMessage(moc: Stack.shared.mainContext)
    13.7 -        Record.saveAndWait()
    13.8 +        moc.saveAndLogErrors()
    13.9      }
   13.10  
   13.11      override func tearDown() {
   13.12 @@ -140,7 +140,7 @@
   13.13  
   13.14              XCTAssertTrue(cdId.isMySelf)
   13.15          }
   13.16 -        Record.saveAndWait()
   13.17 +        moc.saveAndLogErrors()
   13.18          
   13.19          let accounts = Account.all()
   13.20          XCTAssertFalse(accounts.isEmpty)