Skip to content

Commit 65b80ee

Browse files
committed
Add ReversibleTransformer and tests. remove unneeded check in Entity.check().
1 parent e91a03b commit 65b80ee

4 files changed

Lines changed: 67 additions & 10 deletions

File tree

Sources/JSONAPI/Resource/Attribute.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ public struct TransformedAttribute<RawValue: Codable, Transformer: JSONAPI.Trans
1919
}
2020
}
2121

22+
extension TransformedAttribute where Transformer: ReversibleTransformer {
23+
public init(transformedValue: Transformer.To) throws {
24+
self.value = transformedValue
25+
rawValue = try Transformer.reverse(value)
26+
}
27+
}
28+
2229
extension TransformedAttribute: CustomStringConvertible {
2330
public var description: String {
2431
return "Attribute<\(String(describing: Transformer.From.self)) -> \(String(describing: Transformer.To.self))>(\(String(describing: value)))"

Sources/JSONAPI/Resource/Transformer.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ public protocol Transformer {
99
associatedtype From
1010
associatedtype To
1111

12-
static func transform(_ from: From) throws -> To
12+
static func transform(_ value: From) throws -> To
1313
}
1414

15-
public enum IdentityTransformer<T>: Transformer {
16-
public static func transform(_ from: T) throws -> T { return from }
15+
public protocol ReversibleTransformer: Transformer {
16+
static func reverse(_ value: To) throws -> From
17+
}
18+
19+
public enum IdentityTransformer<T>: ReversibleTransformer {
20+
public static func transform(_ value: T) throws -> T { return value }
21+
public static func reverse(_ value: T) throws -> T { return value }
1722
}
1823

1924
// MARK: - Validator
@@ -22,10 +27,19 @@ public enum IdentityTransformer<T>: Transformer {
2227
/// is passed to it but it does not change the type of the value. Any
2328
/// Transformer will perform validation in one sense so a Validator is
2429
/// really just semantic sugar (it can provide clarity in its use).
25-
public protocol Validator: Transformer where From == To {}
30+
/// To enforce the semantics, any change of the value in your implementation
31+
/// of `Validator.transform()` will be ignored.
32+
public protocol Validator: ReversibleTransformer where From == To {
33+
}
2634

2735
extension Validator {
36+
public static func reverse(_ value: To) throws -> To {
37+
let _ = try transform(value)
38+
return value
39+
}
40+
2841
public static func validate(_ value: To) throws -> To {
29-
return try transform(value)
42+
let _ = try transform(value)
43+
return value
3044
}
3145
}

Sources/JSONAPITestLib/EntityCheck.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,25 @@
88
import JSONAPI
99

1010
public enum EntityCheckError: Swift.Error {
11+
/// The attributes should live in a struct, not
12+
/// another type class.
1113
case attributesNotStruct
14+
15+
/// The relationships should live in a struct, not
16+
/// another type class.
1217
case relationshipsNotStruct
18+
19+
/// All stored properties on an Attributes struct should
20+
/// be one of the supplied Attribute types.
1321
case nonAttribute(named: String)
22+
23+
/// All stored properties on a Relationships struct should
24+
/// be one of the supplied Relationship types.
1425
case nonRelationship(named: String)
26+
27+
/// It is explicitly stated by the JSON spec
28+
/// a "none" value for arrays is an empty array, not `nil`.
1529
case nullArray(named: String)
16-
case badId
1730
}
1831

1932
public struct EntityCheckErrors: Swift.Error {
@@ -36,10 +49,6 @@ public extension Entity {
3649
public static func check(_ entity: Entity) throws {
3750
var problems = [EntityCheckError]()
3851

39-
if Swift.type(of: entity.id).EntityType.Description.self != Description.self {
40-
problems.append(.badId)
41-
}
42-
4352
let attributesMirror = Mirror(reflecting: entity.attributes)
4453

4554
if attributesMirror.displayStyle != .`struct` {

Tests/JSONAPITests/Attribute/AttributeTests.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,31 @@ class AttributeTests: XCTestCase {
1818
XCTAssertEqual(try Attribute<String>(rawValue: "hello"), Attribute<String>(value: "hello"))
1919
}
2020

21+
func test_TransformedAttributeNoThrow() {
22+
XCTAssertNoThrow(try TransformedAttribute<String, TestTransformer>(rawValue: "10"))
23+
}
24+
25+
func test_TransformedAttributeThrows() {
26+
XCTAssertThrowsError(try TransformedAttribute<String, TestTransformer>(rawValue: "10.3"))
27+
}
28+
29+
func test_TransformedAttributeReversNoThrow() {
30+
XCTAssertNoThrow(try TransformedAttribute<String, TestTransformer>(transformedValue: 10))
31+
}
32+
}
33+
34+
// MARK: Test types
35+
extension AttributeTests {
36+
enum TestTransformer: ReversibleTransformer {
37+
public static func transform(_ value: String) throws -> Int {
38+
guard let ret = Int(value) else {
39+
throw DecodingError.typeMismatch(Int.self, .init(codingPath: [], debugDescription: "Expected Int from String."))
40+
}
41+
return ret
42+
}
43+
44+
public static func reverse(_ value: Int) throws -> String {
45+
return String(value)
46+
}
47+
}
2148
}

0 commit comments

Comments
 (0)