diff --git a/README.md b/README.md index 1cd8069..ea360bb 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,6 @@ align="right" width="64" height="64" /> -**2024-01-19**: Seems to be b0rked w/ Xcode 15.2: Issue https://github.com/Data-swift/ManagedModels/issues/25 - > Instead of wrapping CoreData, use it directly :-) The key thing **ManagedModels** provides is a `@Model` macro, diff --git a/Sources/ManagedModels/SchemaCompatibility/NSAttributeDescription+Data.swift b/Sources/ManagedModels/SchemaCompatibility/NSAttributeDescription+Data.swift index 141ad3a..66672c9 100644 --- a/Sources/ManagedModels/SchemaCompatibility/NSAttributeDescription+Data.swift +++ b/Sources/ManagedModels/SchemaCompatibility/NSAttributeDescription+Data.swift @@ -84,9 +84,12 @@ extension CoreData.NSAttributeDescription: SchemaProperty { ValueTransformer .setValueTransformer(transformer, forName: .init(name)) } + assert(ValueTransformer.valueTransformerNames().contains(.init(name))) valueTransformerName = name + assert(valueTransformerName != nil) } setValueClassName(for: codableType) + return } // TBD: @@ -162,7 +165,11 @@ public extension NSAttributeDescription { if let hashModifier { versionHashModifier = hashModifier } if let defaultValue { self.defaultValue = defaultValue } isOptional = valueType is any AnyOptional.Type + + assert(valueTransformerName == nil) + valueTransformerName = nil if valueType != Any.self { self.valueType = valueType } + setOptions(options) } } @@ -174,7 +181,6 @@ private extension NSAttributeDescription { allowsExternalBinaryDataStorage = false isIndexedBySpotlight = false isTransient = false - valueTransformerName = nil if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { allowsCloudEncryption = false } @@ -190,8 +196,10 @@ private extension NSAttributeDescription { case .ephemeral: isTransient = true case .transformableByName(let name): + assert(valueTransformerName == nil) valueTransformerName = name case .transformableByType(let type): + assert(valueTransformerName == nil) valueTransformerName = NSStringFromClass(type) case .allowsCloudEncryption: // FIXME: restrict availability diff --git a/Tests/ManagedModelTests/CodablePropertiesTest.swift b/Tests/ManagedModelTests/CodablePropertiesTest.swift new file mode 100644 index 0000000..7639fef --- /dev/null +++ b/Tests/ManagedModelTests/CodablePropertiesTest.swift @@ -0,0 +1,71 @@ +// +// Created by Helge Heß. +// Copyright © 2024 ZeeZide GmbH. +// + +import XCTest +import Foundation +import CoreData +@testable import ManagedModels + +final class CodablePropertiesTests: XCTestCase { + + private lazy var container = try? ModelContainer( + for: Fixtures.CodablePropertiesSchema.managedObjectModel, + configurations: ModelConfiguration(isStoredInMemoryOnly: true) + ) + + func testEntityName() throws { + let entityType = Fixtures.CodablePropertiesSchema.StoredAccess.self + XCTAssertEqual(entityType.entity().name, "StoredAccess") + } + + func testPropertySetup() throws { + let valueType = Fixtures.CodablePropertiesSchema.AccessSIP.self + let attribute = CoreData.NSAttributeDescription( + name: "sip", + valueType: valueType, + defaultValue: nil + ) + XCTAssertEqual(attribute.name, "sip") + XCTAssertEqual(attribute.attributeType, .transformableAttributeType) + + let transformerName = try XCTUnwrap( + ValueTransformer.valueTransformerNames().first(where: { + $0.rawValue.range(of: "CodableBox11TransformerVOO17ManagedModelTests8") + != nil + }) + ) + let transformer = try XCTUnwrap(ValueTransformer(forName: transformerName)) + _ = transformer // to clear unused-wraning + + XCTAssertTrue(attribute.valueType == + CodableBox.self) + XCTAssertNotNil(attribute.valueTransformerName) + XCTAssertEqual(attribute.valueTransformerName, transformerName.rawValue) + } + + func testCodablePropertyEntity() throws { + let entity = try XCTUnwrap( + container?.managedObjectModel.entitiesByName["StoredAccess"] + ) + + // Creating the entity should have registered the transformer for the + // CodableBox. + let transformerName = try XCTUnwrap( + ValueTransformer.valueTransformerNames().first(where: { + $0.rawValue.range(of: "CodableBox11TransformerVOO17ManagedModelTests8") + != nil + }) + ) + let transformer = try XCTUnwrap(ValueTransformer(forName: transformerName)) + _ = transformer // to clear unused-wraning + + let attribute = try XCTUnwrap(entity.attributesByName["sip"]) + XCTAssertEqual(attribute.name, "sip") + XCTAssertTrue(attribute.valueType == + CodableBox.self) + XCTAssertNotNil(attribute.valueTransformerName) + XCTAssertEqual(attribute.valueTransformerName, transformerName.rawValue) + } +} diff --git a/Tests/ManagedModelTests/Schemas/CodablePropertySchema.swift b/Tests/ManagedModelTests/Schemas/CodablePropertySchema.swift new file mode 100644 index 0000000..2482789 --- /dev/null +++ b/Tests/ManagedModelTests/Schemas/CodablePropertySchema.swift @@ -0,0 +1,31 @@ +// +// Created by Helge Heß. +// Copyright © 2024 ZeeZide GmbH. +// + +import ManagedModels + +extension Fixtures { + // https://github.com/Data-swift/ManagedModels/issues/27 + + enum CodablePropertiesSchema: VersionedSchema { + static var models : [ any PersistentModel.Type ] = [ + StoredAccess.self + ] + + public static let versionIdentifier = Schema.Version(0, 1, 0) + + @Model + final class StoredAccess: NSManagedObject { + var token : String + var expires : Date + var sip : AccessSIP + } + + struct AccessSIP: Codable { + var username : String + var password : String + var realm : String + } + } +}