mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-03-30 11:18:38 -07:00
Make Attribute a Functor to make computed attributes easier to write.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Attribute+Functor.swift
|
||||
// JSONAPI
|
||||
//
|
||||
// Created by Mathew Polzin on 11/28/18.
|
||||
//
|
||||
|
||||
public extension TransformedAttribute {
|
||||
/// Map an Attribute to a new wrapped type.
|
||||
/// Note that the resulting Attribute will have no transformer, even if the
|
||||
/// source Attribute has a transformer.
|
||||
/// You are mapping the output of the source transform into
|
||||
/// the RawValue of a new transformerless Attribute.
|
||||
///
|
||||
/// Generally, this is the most useful operation. The transformer gives you
|
||||
/// control over the decoding of the Attribute, but once the Attribute exists,
|
||||
/// mapping on it is most useful for creating computed Attribute properties.
|
||||
public func map<T: Codable>(_ transform: (Transformer.To) throws -> T) rethrows -> Attribute<T> {
|
||||
return Attribute<T>(value: try transform(value))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Attribute+FunctorTests.swift
|
||||
// JSONAPITests
|
||||
//
|
||||
// Created by Mathew Polzin on 11/28/18.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import JSONAPI
|
||||
import JSONAPITestLib
|
||||
|
||||
class Attribute_FunctorTests: XCTestCase {
|
||||
func test_mapGuaranteed() {
|
||||
let entity = try? TestType(attributes: .init(name: "Frankie", number: .init(rawValue: 22.0)))
|
||||
|
||||
XCTAssertNotNil(entity)
|
||||
|
||||
XCTAssertEqual(entity?[\.computedString], "Frankie2")
|
||||
}
|
||||
|
||||
func test_mapOptionalSuccess() {
|
||||
let entity = try? TestType(attributes: .init(name: "Frankie", number: .init(rawValue: 22.0)))
|
||||
|
||||
XCTAssertNotNil(entity)
|
||||
|
||||
XCTAssertEqual(entity?[\.computedNumber], 22)
|
||||
}
|
||||
|
||||
func test_mapOptionalFailure() {
|
||||
let entity = try? TestType(attributes: .init(name: "Frankie", number: .init(rawValue: 22.5)))
|
||||
|
||||
XCTAssertNotNil(entity)
|
||||
|
||||
XCTAssertNil(entity?[\.computedNumber])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Test types
|
||||
extension Attribute_FunctorTests {
|
||||
enum TestTypeDescription: EntityDescription {
|
||||
public static var type: String { return "test" }
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
let name: Attribute<String>
|
||||
let number: TransformedAttribute<Double, DoubleToString>
|
||||
var computedString: Attribute<String> {
|
||||
return name.map { $0 + "2" }
|
||||
}
|
||||
var computedNumber: Attribute<Int>? {
|
||||
return try? number.map { string in
|
||||
let num = Double(string).flatMap { Int(exactly: $0) }
|
||||
guard let ret = num else {
|
||||
throw DecodingError.typeMismatch(Int.self, .init(codingPath: [], debugDescription: "String was not an Int."))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public typealias Relationships = NoRelationships
|
||||
}
|
||||
|
||||
typealias TestType = Entity<TestTypeDescription>
|
||||
|
||||
enum DoubleToString: Transformer {
|
||||
public static func transform(_ from: Double) -> String {
|
||||
return String(from)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ class ComputedPropertiesTests: XCTestCase {
|
||||
func test_ComputedAttributeAccess() {
|
||||
let entity = decoded(type: TestType.self, data: computed_property_attribute)
|
||||
|
||||
XCTAssertEqual(entity[\.computed], "Sarah")
|
||||
XCTAssertEqual(entity[\.computed], "Sarah2")
|
||||
}
|
||||
|
||||
func test_ComputedRelationshipAccess() {
|
||||
@@ -44,7 +44,7 @@ extension ComputedPropertiesTests {
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
public let name: Attribute<String>
|
||||
public var computed: Attribute<String> {
|
||||
return name
|
||||
return name.map { $0 + "2" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user