Files
JSONAPI/Sources/JSONAPITesting/EntityCheck.swift
T

95 lines
2.8 KiB
Swift

//
// EntityCheck.swift
// JSONAPITesting
//
// Created by Mathew Polzin on 11/27/18.
//
import JSONAPI
public enum EntityCheckError: Swift.Error {
/// The attributes should live in a struct, not
/// another type class.
case attributesNotStruct
/// The relationships should live in a struct, not
/// another type class.
case relationshipsNotStruct
/// All stored properties on an Attributes struct should
/// be one of the supplied Attribute types.
case nonAttribute(named: String)
/// All stored properties on a Relationships struct should
/// be one of the supplied Relationship types.
case nonRelationship(named: String)
/// It is explicitly stated by the JSON spec
/// a "none" value for arrays is an empty array, not `nil`.
case nullArray(named: String)
}
public struct EntityCheckErrors: Swift.Error {
let problems: [EntityCheckError]
}
private protocol OptionalAttributeType {}
extension Optional: OptionalAttributeType where Wrapped: AttributeType {}
private protocol OptionalArray {}
extension Optional: OptionalArray where Wrapped: ArrayType {}
private protocol AttributeTypeWithOptionalArray {}
extension TransformedAttribute: AttributeTypeWithOptionalArray where RawValue: OptionalArray {}
extension Attribute: AttributeTypeWithOptionalArray where RawValue: OptionalArray {}
private protocol OptionalRelationshipType {}
extension Optional: OptionalRelationshipType where Wrapped: RelationshipType {}
private protocol _RelationshipType {}
extension ToOneRelationship: _RelationshipType {}
extension ToManyRelationship: _RelationshipType {}
private protocol _AttributeType {}
extension TransformedAttribute: _AttributeType {}
extension Attribute: _AttributeType {}
public extension Entity {
static func check(_ entity: Entity) throws {
var problems = [EntityCheckError]()
let attributesMirror = Mirror(reflecting: entity.attributes)
if attributesMirror.displayStyle != .`struct` {
problems.append(.attributesNotStruct)
}
for attribute in attributesMirror.children {
if attribute.value as? _AttributeType == nil,
attribute.value as? OptionalAttributeType == nil {
problems.append(.nonAttribute(named: attribute.label ?? "unnamed"))
}
if attribute.value as? AttributeTypeWithOptionalArray != nil {
problems.append(.nullArray(named: attribute.label ?? "unnamed"))
}
}
let relationshipsMirror = Mirror(reflecting: entity.relationships)
if relationshipsMirror.displayStyle != .`struct` {
problems.append(.relationshipsNotStruct)
}
for relationship in relationshipsMirror.children {
if relationship.value as? _RelationshipType == nil,
relationship.value as? OptionalRelationshipType == nil {
problems.append(.nonRelationship(named: relationship.label ?? "unnamed"))
}
}
guard problems.count == 0 else {
throw EntityCheckErrors(problems: problems)
}
}
}