Skip to content

Commit 28d5984

Browse files
committed
Drop CodableBox, not required?
Directly store the Codable Swift value in the property as an Any. Disadvantage: We cannot set the `transformedValueClass` in the transformer nor the `attributeValueClassName` in the `Attribute` (which will stick to `Any`. But that doesn't seem to confused CoreData.
1 parent 431ce35 commit 28d5984

File tree

5 files changed

+70
-113
lines changed

5 files changed

+70
-113
lines changed

Sources/ManagedModels/PersistentModel/PersistentModel+KVC.swift

+7-14
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,14 @@ public extension PersistentModel {
232232

233233
func setValue<T>(forKey key: String, to value: T) where T: Codable {
234234
willChangeValue(forKey: key); defer { didChangeValue(forKey: key) }
235-
setPrimitiveValue(CodableBox<T>(value), forKey: key)
235+
setPrimitiveValue(value, forKey: key)
236236
}
237237

238238
func setValue<T>(forKey key: String, to value: T)
239239
where T: Codable & AnyOptional
240240
{
241241
willChangeValue(forKey: key); defer { didChangeValue(forKey: key) }
242-
if value.isSome { setPrimitiveValue(CodableBox<T>(value), forKey: key) }
242+
if value.isSome { setPrimitiveValue(value, forKey: key) }
243243
else { setPrimitiveValue(nil, forKey: key) }
244244
}
245245

@@ -249,10 +249,7 @@ public extension PersistentModel {
249249
fatalError("No box found for non-optional Codable value for key \(key)?")
250250
}
251251

252-
if let box = value as? CodableBox<T> {
253-
guard let value = box.value else {
254-
fatalError("Box has no value for non-optional Codable for key \(key)?")
255-
}
252+
if let value = value as? T {
256253
return value
257254
}
258255

@@ -266,17 +263,13 @@ public extension PersistentModel {
266263
}
267264
}
268265

269-
guard let value = value as? T else {
270-
fatalError("Unexpected value for key \(key)? \(value)")
271-
}
272-
assertionFailure("Codable value is directly stored? \(value)")
273-
return value
266+
fatalError("Codable value type doesn't match? \(value)")
274267
}
275268

276269
func getValue<T>(forKey key: String) -> T where T: Codable & AnyOptional {
277270
willAccessValue(forKey: key); defer { didAccessValue(forKey: key) }
278271
guard let value = primitiveValue(forKey: key) else { return .noneValue }
279-
if let box = value as? CodableBox<T> { return box.value ?? .noneValue }
272+
if let value = value as? T { return value }
280273

281274
if let data = value as? Data {
282275
assertionFailure("Unexpected Data as primitive!")
@@ -291,7 +284,7 @@ public extension PersistentModel {
291284
guard let value = value as? T else {
292285
fatalError("Unexpected value for key \(key)? \(value)")
293286
}
294-
assertionFailure("Codable value is directly stored? \(value)")
295-
return value
287+
assertionFailure("Codable value type doesn't match? \(value)")
288+
return .noneValue
296289
}
297290
}

Sources/ManagedModels/SchemaCompatibility/CodableBox.swift

-86
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// Created by Helge Heß.
3+
// Copyright © 2023 ZeeZide GmbH.
4+
//
5+
6+
import Foundation
7+
import CoreData
8+
9+
final class CodableTransformer<T: Codable>: ValueTransformer {
10+
11+
#if false
12+
override class func transformedValueClass() -> AnyClass {
13+
T.self // doesn't work
14+
}
15+
#endif
16+
override class func allowsReverseTransformation() -> Bool { true }
17+
18+
override func transformedValue(_ value: Any?) -> Any? {
19+
// value is the box
20+
guard let value else { return nil }
21+
guard let typed = value as? T else {
22+
assertionFailure("Value to be transformed is not the right type? \(value)")
23+
return nil
24+
}
25+
do {
26+
return try JSONEncoder().encode(typed)
27+
}
28+
catch {
29+
assertionFailure("Could not encode JSON value of property? \(error)")
30+
return nil
31+
}
32+
}
33+
34+
override func reverseTransformedValue(_ value: Any?) -> Any? {
35+
guard let value else { return nil }
36+
guard let data = value as? Data else {
37+
assert(value is Data, "Reverse value is not `Data`?")
38+
return nil
39+
}
40+
do {
41+
return try JSONDecoder().decode(T.self, from: data)
42+
}
43+
catch {
44+
assertionFailure("Could not decode JSON value of property? \(error)")
45+
return nil
46+
}
47+
}
48+
}

Sources/ManagedModels/SchemaCompatibility/NSAttributeDescription+Data.swift

+9-7
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ extension CoreData.NSAttributeDescription: SchemaProperty {
4040

4141
if let primitiveType = newValue as? CoreDataPrimitiveValue.Type {
4242
let config = primitiveType.coreDataValue
43-
self.attributeType = config.attributeType
44-
self.isOptional = config.isOptional
43+
self.attributeType = config.attributeType
44+
self.isOptional = config.isOptional
4545
if let newClassName = config.attributeValueClassName {
4646
self.attributeValueClassName = newClassName
4747
}
@@ -55,8 +55,8 @@ extension CoreData.NSAttributeDescription: SchemaProperty {
5555
let rawType = type.RawValue.self
5656
if let primitiveType = rawType as? CoreDataPrimitiveValue.Type {
5757
let config = primitiveType.coreDataValue
58-
self.attributeType = config.attributeType
59-
self.isOptional = config.isOptional
58+
self.attributeType = config.attributeType
59+
self.isOptional = config.isOptional
6060
if let newClassName = config.attributeValueClassName {
6161
self.attributeValueClassName = newClassName
6262
}
@@ -75,12 +75,14 @@ extension CoreData.NSAttributeDescription: SchemaProperty {
7575
self.isOptional = newValue is any AnyOptional.Type
7676

7777
func setValueClassName<T: Codable>(for type: T.Type) {
78-
self.attributeValueClassName = NSStringFromClass(CodableBox<T>.self)
78+
#if false // doesn't work
79+
self.attributeValueClassName = NSStringFromClass(T.self)
80+
#endif
7981

80-
let name = NSStringFromClass(CodableBox<T>.Transformer.self)
82+
let name = NSStringFromClass(CodableTransformer<T>.self)
8183
if !ValueTransformer.valueTransformerNames().contains(.init(name)) {
8284
// no access to valueTransformerForName?
83-
let transformer = CodableBox<T>.Transformer()
85+
let transformer = CodableTransformer<T>()
8486
ValueTransformer
8587
.setValueTransformer(transformer, forName: .init(name))
8688
}

Tests/ManagedModelTests/CodablePropertiesTest.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ final class CodablePropertiesTests: XCTestCase {
3232

3333
let transformerName = try XCTUnwrap(
3434
ValueTransformer.valueTransformerNames().first(where: {
35-
$0.rawValue.range(of: "CodableBox11TransformerVOO17ManagedModelTests8")
35+
$0.rawValue.range(of: "CodableTransformerVOO17ManagedModelTests8")
3636
!= nil
3737
})
3838
)
3939
let transformer = try XCTUnwrap(ValueTransformer(forName: transformerName))
4040
_ = transformer // to clear unused-wraning
4141

42-
XCTAssertTrue(attribute.valueType ==
43-
CodableBox<Fixtures.CodablePropertiesSchema.AccessSIP>.self)
42+
XCTAssertTrue(attribute.valueType == Any.self)
43+
// Fixtures.CodablePropertiesSchema.AccessSIP.self
4444
XCTAssertNotNil(attribute.valueTransformerName)
4545
XCTAssertEqual(attribute.valueTransformerName, transformerName.rawValue)
4646
}
@@ -54,7 +54,7 @@ final class CodablePropertiesTests: XCTestCase {
5454
// CodableBox.
5555
let transformerName = try XCTUnwrap(
5656
ValueTransformer.valueTransformerNames().first(where: {
57-
$0.rawValue.range(of: "CodableBox11TransformerVOO17ManagedModelTests8")
57+
$0.rawValue.range(of: "CodableTransformerVOO17ManagedModelTests8")
5858
!= nil
5959
})
6060
)
@@ -63,8 +63,8 @@ final class CodablePropertiesTests: XCTestCase {
6363

6464
let attribute = try XCTUnwrap(entity.attributesByName["sip"])
6565
XCTAssertEqual(attribute.name, "sip")
66-
XCTAssertTrue(attribute.valueType ==
67-
CodableBox<Fixtures.CodablePropertiesSchema.AccessSIP>.self)
66+
XCTAssertTrue(attribute.valueType == Any.self)
67+
// Fixtures.CodablePropertiesSchema.AccessSIP.self)
6868
XCTAssertNotNil(attribute.valueTransformerName)
6969
XCTAssertEqual(attribute.valueTransformerName, transformerName.rawValue)
7070
}

0 commit comments

Comments
 (0)