// // CoreStore+CustomDebugStringConvertible.swift // CoreStore // // Copyright © 2018 John Rommel Estropia // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // import Foundation import CoreData // MARK: - AsynchronousDataTransaction extension AsynchronousDataTransaction: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("context", self.context), ("supportsUndo", self.supportsUndo), ("bypassesQueueing", self.bypassesQueueing), ("isCommitted", self.isCommitted) ) } } // MARK: - CoreStoreError extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { let firstLine: String var info: DumpInfo = [ ("errorDomain", Self.errorDomain), ("errorCode", self.errorCode), ] switch self { case .unknown: firstLine = ".unknown" case .differentStorageExistsAtURL(let existingPersistentStoreURL): firstLine = ".differentStorageExistsAtURL" info.append(("existingPersistentStoreURL", existingPersistentStoreURL)) case .mappingModelNotFound(let localStoreURL, let targetModel, let targetModelVersion): firstLine = ".mappingModelNotFound" info.append(("localStoreURL", localStoreURL)) info.append(("targetModel", targetModel)) info.append(("targetModelVersion", targetModelVersion)) case .progressiveMigrationRequired(let localStoreURL): firstLine = ".progressiveMigrationRequired" info.append(("localStoreURL", localStoreURL)) case .asynchronousMigrationRequired(let localStoreURL, let NSError): firstLine = ".asynchronousMigrationRequired" info.append(("localStoreURL", localStoreURL)) info.append(("NSError", NSError)) case .internalError(let NSError): firstLine = ".internalError" info.append(("NSError", NSError)) case .userError(error: let error): firstLine = ".userError" info.append(("Error", error)) case .userCancelled: firstLine = ".userCancelled" case .persistentStoreNotFound(let entity): firstLine = ".persistentStoreNotFound" info.append(("entity", entity)) } return createFormattedString( "\(firstLine) (", ")", info ) } } // MARK: - CoreStoreObject extension CoreStoreObject: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("rawObject", self.rawObject as Any) ) } } // MARK: - CoreStoreSchema extension CoreStoreSchema: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("modelVersion", self.modelVersion), ("entitiesByConfiguration", self.entitiesByConfiguration), ("rawModel", self.rawModel()) ) } } // MARK: - DataStack extension DataStack: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("coordinator", self.coordinator), ("rootSavingContext", self.rootSavingContext), ("mainContext", self.mainContext), ("schemaHistory", self.schemaHistory), ("coordinator.persistentStores", self.coordinator.persistentStores) ) } } // MARK: - Entity extension Entity: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("type", self.type), ("entityName", self.entityName), ("isAbstract", self.isAbstract), ("versionHashModifier", self.versionHashModifier as Any) ) } } // MARK: - From extension From: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { var info: DumpInfo = [("entityClass", self.entityClass)] if let configurations = self.configurations { info.append(("configurations", configurations)) } return createFormattedString( "(", ")", info ) } } // MARK: - GroupBy extension GroupBy: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("keyPaths", self.keyPaths) ) } } // MARK: - InMemoryStore extension InMemoryStore: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("configuration", self.configuration as Any), ("storeOptions", self.storeOptions as Any) ) } } // MARK: - Into extension Into: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("entityClass", self.entityClass), ("configuration", self.configuration as Any), ("inferStoreIfPossible", self.inferStoreIfPossible) ) } } // MARK: - UnsafeDataModelSchema extension UnsafeDataModelSchema: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("modelVersion", self.modelVersion), ("rawModel", self.rawModel()) ) } } // MARK: - ListMonitor fileprivate struct CoreStoreFetchedSectionInfoWrapper: CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible var coreStoreDumpString: String { return createFormattedString( "\"\(self.sectionName)\" (", ")", ("numberOfObjects", self.numberOfObjects), ("indexTitle", self.sectionIndexTitle as Any) ) } // MARK: FilePrivate fileprivate init(_ sectionInfo: NSFetchedResultsSectionInfo) { self.sectionName = sectionInfo.name self.numberOfObjects = sectionInfo.numberOfObjects self.sectionIndexTitle = sectionInfo.indexTitle } fileprivate init(_ section: Internals.DiffableDataSourceSnapshot.Section) { self.sectionName = section.differenceIdentifier self.numberOfObjects = section.elements.count self.sectionIndexTitle = nil } // MARK: Private private let sectionName: String private let sectionIndexTitle: String? private let numberOfObjects: Int } extension ListMonitor: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("isPendingRefetch", self.isPendingRefetch), ("numberOfObjects", self.numberOfObjects()), ("sections", self.sections().map(CoreStoreFetchedSectionInfoWrapper.init)) ) } } // MARK: - ListPublisher extension ListPublisher: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("snapshot", self.snapshot) ) } } // MARK: - ListSnapshot extension ListSnapshot: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("numberOfObjects", self.numberOfItems), ("sections", self.diffableSnapshot.sections.map(CoreStoreFetchedSectionInfoWrapper.init)) ) } } // MARK: - LocalStorageOptions extension LocalStorageOptions: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { var flags = [String]() if self.contains(.recreateStoreOnModelMismatch) { flags.append(".recreateStoreOnModelMismatch") } if self.contains(.preventProgressiveMigration) { flags.append(".preventProgressiveMigration") } if self.contains(.allowSynchronousLightweightMigration) { flags.append(".allowSynchronousLightweightMigration") } switch flags.count { case 0: return "[.none]" case 1: return "[.\(flags[0])]" default: var string = "[\n" string.append(flags.joined(separator: ",\n")) string.indent(1) string.append("\n]") return string } } } // MARK: - MigrationChain extension MigrationChain: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { guard self.isValid else { return "" } var paths = [String]() for var version in self.rootVersions { var steps = [version] while let nextVersion = self.nextVersionFrom(version) { steps.append(nextVersion) version = nextVersion } paths.append(steps.joined(separator: " → ")) } switch paths.count { case 0: return "[]" case 1: return "[\(paths[0])]" default: var string = "[" paths.forEach { string.append("\n\($0);") } string.indent(1) string.append("\n]") return string } } } // MARK: - MigrationType extension MigrationType: CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { switch self { case .none(let version): return ".none (\"\(version)\")" case .lightweight(let sourceVersion, let destinationVersion): return ".lightweight (\"\(sourceVersion)\" → \"\(destinationVersion)\")" case .heavyweight(let sourceVersion, let destinationVersion): return ".heavyweight (\"\(sourceVersion)\" → \"\(destinationVersion)\")" } } } // MARK: - ObjectMonitor extension ObjectMonitor: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("isObjectDeleted", self.isObjectDeleted), ("object", self.object as Any) ) } } // MARK: - ObjectPublisher extension ObjectPublisher: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("objectID", self.objectID()), ("object", self.object as Any) ) } } // MARK: - ObjectSnapshot extension ObjectSnapshot: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("objectID", self.objectID()), ("dictionaryForValues", self.dictionaryForValues()) ) } } // MARK: - OrderBy extension OrderBy: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("sortDescriptors", self.sortDescriptors) ) } } // MARK: - PartialObject extension PartialObject: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("rawObject", self.rawObject as Any) ) } } // MARK: - SectionBy extension SectionBy: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("sectionKeyPath", self.sectionKeyPath) ) } } // MARK: - SchemaHistory extension SchemaHistory: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("currentModelVersion", self.currentModelVersion), ("migrationChain", self.migrationChain), ("schemaByVersion", self.schemaByVersion) ) } } // MARK: - Select extension Select: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("selectTerms", self.selectTerms) ) } } // MARK: - SelectTerm extension SelectTerm: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { switch self { case ._attribute(let keyPath): return createFormattedString( ".attribute (", ")", ("keyPath", keyPath) ) case ._aggregate(let function, let keyPath, let alias, let nativeType): return createFormattedString( ".aggregate (", ")", ("function", function), ("keyPath", keyPath), ("alias", alias), ("nativeType", nativeType) ) case ._identity(let alias, let nativeType): return createFormattedString( ".identity (", ")", ("alias", alias), ("nativeType", nativeType) ) } } } // MARK: - SQLiteStore extension SQLiteStore: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("configuration", self.configuration as Any), ("storeOptions", self.storeOptions as Any), ("fileURL", self.fileURL), ("migrationMappingProviders", self.migrationMappingProviders), ("localStorageOptions", self.localStorageOptions), ("fileSize", self.fileSize() as Any) ) } } // MARK: - SynchronousDataTransaction extension SynchronousDataTransaction: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("context", self.context), ("supportsUndo", self.supportsUndo), ("bypassesQueueing", self.bypassesQueueing), ("isCommitted", self.isCommitted) ) } } // MARK: - Tweak extension Tweak: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return "" } } // MARK: - UnsafeDataTransaction extension UnsafeDataTransaction: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("context", self.context), ("supportsUndo", self.supportsUndo) ) } } // MARK: - Where extension Where: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("predicate", self.predicate) ) } } // MARK: - VersionLock extension VersionLock: CustomStringConvertible, CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomStringConvertible public var description: String { var string = "[" if self.hashesByEntityName.isEmpty { string.append(":]") return string } for (index, keyValue) in self.hashesByEntityName.sorted(by: { $0.key < $1.key }).enumerated() { let data = keyValue.value let bytes = data.withUnsafeBytes { (pointer) in return pointer .bindMemory(to: VersionLock.HashElement.self) .map({ "\("0x\(String($0, radix: 16, uppercase: false))")" }) } string.append("\(index == 0 ? "\n" : ",\n")\"\(keyValue.key)\": [\(bytes.joined(separator: ", "))]") } string.indent(1) string.append("\n]") return string } // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return self.description } } // MARK: - XcodeDataModelSchema extension XcodeDataModelSchema: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { // MARK: CustomDebugStringConvertible public var debugDescription: String { return formattedDebugDescription(self) } // MARK: CoreStoreDebugStringConvertible public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("modelVersion", self.modelVersion), ("modelVersionFileURL", self.modelVersionFileURL), ("rawModel", self.rawModel()) ) } } // MARK: - Private: Utilities private typealias DumpInfo = [(key: String, value: Any)] private func formattedValue(_ any: Any) -> String { switch any { case let any as CoreStoreDebugStringConvertible: return any.coreStoreDumpString default: return "\(any)" } } private func formattedDebugDescription(_ any: Any) -> String { var string = "(\(String(reflecting: type(of: any)))) " string.append(formattedValue(any)) return string } private func createFormattedString(_ firstLine: String, _ lastLine: String, _ info: (key: String, value: Any)...) -> String { return createFormattedString(firstLine, lastLine, info) } private func createFormattedString(_ firstLine: String, _ lastLine: String, _ info: [(key: String, value: Any)]) -> String { var string = firstLine for (key, value) in info { string.appendDumpInfo(key, value) } string.indent(1) string.append("\n\(lastLine)") return string } extension String { fileprivate static func indention(_ level: Int = 1) -> String { return String(repeating: " ", count: level * 4) } fileprivate mutating func indent(_ level: Int) { self = self.replacingOccurrences(of: "\n", with: "\n\(String.indention(level))") } fileprivate mutating func appendDumpInfo(_ key: String, _ value: Any) { self.append("\n.\(key) = \(formattedValue(value));") } } // MARK: - Private: CoreStoreDebugStringConvertible public protocol CoreStoreDebugStringConvertible: CustomDebugStringConvertible { var coreStoreDumpString: String { get } } // MARK: - Standard Types: extension Array: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { var string = "\(self.count) item(s) [" if self.isEmpty { string.append("]") return string } else { for (index, item) in self.enumerated() { string.append("\n\(index) = \(formattedValue(item));") } string.indent(1) string.append("\n]") return string } } } extension Dictionary: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { var string = "\(self.count) key-value(s) [" if self.isEmpty { string.append("]") return string } else { for (key, value) in self { string.append("\n\(formattedValue(key)) = \(formattedValue(value));") } string.indent(1) string.append("\n]") return string } } } extension NSAttributeDescription: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("attributeType", self.attributeType), ("attributeValueClassName", self.attributeValueClassName as Any), ("defaultValue", self.defaultValue as Any), ("valueTransformerName", self.valueTransformerName as Any), ("allowsExternalBinaryDataStorage", self.allowsExternalBinaryDataStorage), ("entity.name", self.entity.name as Any), ("name", self.name), ("isOptional", self.isOptional), ("isTransient", self.isTransient), ("userInfo", self.userInfo as Any), ("versionHash", self.versionHash), ("versionHashModifier", self.versionHashModifier as Any), ("isIndexedBySpotlight", self.isIndexedBySpotlight), ("renamingIdentifier", self.renamingIdentifier as Any) ) } } extension NSAttributeType: CoreStoreDebugStringConvertible { public var debugDescription: String { return formattedDebugDescription(self) } public var coreStoreDumpString: String { switch self { case .undefinedAttributeType: return ".undefinedAttributeType" case .integer16AttributeType: return ".integer16AttributeType" case .integer32AttributeType: return ".integer32AttributeType" case .integer64AttributeType: return ".integer64AttributeType" case .decimalAttributeType: return ".decimalAttributeType" case .doubleAttributeType: return ".doubleAttributeType" case .floatAttributeType: return ".floatAttributeType" case .stringAttributeType: return ".stringAttributeType" case .booleanAttributeType: return ".booleanAttributeType" case .dateAttributeType: return ".dateAttributeType" case .binaryDataAttributeType: return ".binaryDataAttributeType" case .transformableAttributeType: return ".transformableAttributeType" case .objectIDAttributeType: return ".objectIDAttributeType" case .UUIDAttributeType: return ".UUIDAttributeType" case .URIAttributeType: return ".URIAttributeType" @unknown default: fatalError() } } } extension Bundle: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return "\(self.bundleIdentifier.flatMap({ "\"\($0)\"" }) ?? "") (\(self.bundleURL.lastPathComponent))" } } extension NSDeleteRule: CoreStoreDebugStringConvertible { public var debugDescription: String { return formattedDebugDescription(self) } public var coreStoreDumpString: String { switch self { case .noActionDeleteRule: return ".noActionDeleteRule" case .nullifyDeleteRule: return ".nullifyDeleteRule" case .cascadeDeleteRule: return ".cascadeDeleteRule" case .denyDeleteRule: return ".denyDeleteRule" @unknown default: fatalError() } } } extension NSEntityDescription: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("managedObjectClassName", self.managedObjectClassName!), ("name", self.name as Any), ("indexes", self.indexes), ("isAbstract", self.isAbstract), ("superentity?.name", self.superentity?.name as Any), ("subentities", self.subentities.map({ $0.name })), ("properties", self.properties), ("uniquenessConstraints", self.uniquenessConstraints), ("userInfo", self.userInfo as Any), ("versionHash", self.versionHash), ("versionHashModifier", self.versionHashModifier as Any), ("renamingIdentifier", self.renamingIdentifier as Any) ) } } extension NSError: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("domain", self.domain), ("code", self.code), ("userInfo", self.userInfo) ) } } extension NSManagedObjectModel: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("configurations", self.configurations), ("entities", self.entities) ) } } extension NSManagedObjectID: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return createFormattedString( "\(self.uriRepresentation().coreStoreDumpString) (", ")", ("entity.name", self.entity.name as Any), ("isTemporaryID", self.isTemporaryID as Any), ("persistentStore?.url", self.persistentStore?.url as Any) ) } } extension NSMappingModel: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return "\(self)" } } extension NSPredicate: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return "\"\(self)\"" } } extension NSRelationshipDescription: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("destinationEntity?.name", self.destinationEntity?.name as Any), ("inverseRelationship?.name", self.inverseRelationship?.name as Any), ("minCount", self.minCount), ("maxCount", self.maxCount), ("deleteRule", self.deleteRule), ("isToMany", self.isToMany), ("isOrdered", self.isOrdered), ("entity.name", self.entity.name as Any), ("name", self.name), ("isOptional", self.isOptional), ("isTransient", self.isTransient), ("userInfo", self.userInfo as Any), ("versionHash", self.versionHash), ("versionHashModifier", self.versionHashModifier as Any), ("isIndexedBySpotlight", self.isIndexedBySpotlight), ("renamingIdentifier", self.renamingIdentifier as Any) ) } } extension NSSortDescriptor: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return createFormattedString( "(", ")", ("key", self.key as Any), ("ascending", self.ascending), ("selector", self.selector as Any) ) } } extension NSString: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return "\"\(self)\"" } } extension NSURL: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return "\"\(self)\"" } } extension Optional: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { if let value = self { return formattedValue(value) } return "nil" } } extension Result: CoreStoreDebugStringConvertible { public var debugDescription: String { return formattedDebugDescription(self) } public var coreStoreDumpString: String { switch self { case .success(let info): return createFormattedString( ".success (", ")", ("info", info) ) case .failure(let error): return createFormattedString( ".failure (", ")", ("error", error) ) } } } extension Selector: CoreStoreDebugStringConvertible { public var debugDescription: String { return formattedDebugDescription(self) } public var coreStoreDumpString: String { return "\"\(self)\"" } } extension String: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return "\"\(self)\"" } } extension URL: CoreStoreDebugStringConvertible { public var coreStoreDumpString: String { return "\"\(self)\"" } }