mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-03-30 11:18:38 -07:00
Rename JSONAPITestLib to JSONAPITesting to fit with naming convention I am adopting going forward. Added OpenAPI JSON schema types. Added default schema types for a handful of Swift primitives.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
|
||||
import JSONAPI
|
||||
|
||||
extension Attribute: ExpressibleByUnicodeScalarLiteral where RawValue: ExpressibleByUnicodeScalarLiteral {
|
||||
public typealias UnicodeScalarLiteralType = RawValue.UnicodeScalarLiteralType
|
||||
|
||||
public init(unicodeScalarLiteral value: RawValue.UnicodeScalarLiteralType) {
|
||||
self.init(value: RawValue(unicodeScalarLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: ExpressibleByExtendedGraphemeClusterLiteral where RawValue: ExpressibleByExtendedGraphemeClusterLiteral {
|
||||
public typealias ExtendedGraphemeClusterLiteralType = RawValue.ExtendedGraphemeClusterLiteralType
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: RawValue.ExtendedGraphemeClusterLiteralType) {
|
||||
self.init(value: RawValue(extendedGraphemeClusterLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: ExpressibleByStringLiteral where RawValue: ExpressibleByStringLiteral {
|
||||
public typealias StringLiteralType = RawValue.StringLiteralType
|
||||
|
||||
public init(stringLiteral value: RawValue.StringLiteralType) {
|
||||
self.init(value: RawValue(stringLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: ExpressibleByNilLiteral where RawValue: ExpressibleByNilLiteral {
|
||||
public init(nilLiteral: ()) {
|
||||
self.init(value: RawValue(nilLiteral: ()))
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: ExpressibleByFloatLiteral where RawValue: ExpressibleByFloatLiteral {
|
||||
public typealias FloatLiteralType = RawValue.FloatLiteralType
|
||||
|
||||
public init(floatLiteral value: RawValue.FloatLiteralType) {
|
||||
self.init(value: RawValue(floatLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: ExpressibleByFloatLiteral where Wrapped: ExpressibleByFloatLiteral {
|
||||
public typealias FloatLiteralType = Wrapped.FloatLiteralType
|
||||
|
||||
public init(floatLiteral value: FloatLiteralType) {
|
||||
self = .some(Wrapped(floatLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: ExpressibleByBooleanLiteral where RawValue: ExpressibleByBooleanLiteral {
|
||||
public typealias BooleanLiteralType = RawValue.BooleanLiteralType
|
||||
|
||||
public init(booleanLiteral value: BooleanLiteralType) {
|
||||
self.init(value: RawValue(booleanLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: ExpressibleByBooleanLiteral where Wrapped: ExpressibleByBooleanLiteral {
|
||||
public typealias BooleanLiteralType = Wrapped.BooleanLiteralType
|
||||
|
||||
public init(booleanLiteral value: BooleanLiteralType) {
|
||||
self = .some(Wrapped(booleanLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: ExpressibleByIntegerLiteral where RawValue: ExpressibleByIntegerLiteral {
|
||||
public typealias IntegerLiteralType = RawValue.IntegerLiteralType
|
||||
|
||||
public init(integerLiteral value: IntegerLiteralType) {
|
||||
self.init(value: RawValue(integerLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: ExpressibleByIntegerLiteral where Wrapped: ExpressibleByIntegerLiteral {
|
||||
public typealias IntegerLiteralType = Wrapped.IntegerLiteralType
|
||||
|
||||
public init(integerLiteral value: IntegerLiteralType) {
|
||||
self = .some(Wrapped(integerLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
// regretably, array and dictionary literals are not so easy because Dictionaries and Arrays
|
||||
// cannot be turned back into variadic arguments to pass onto the RawValue type's constructor.
|
||||
|
||||
// we can still provide a case for the Array and Dictionary types, though.
|
||||
public protocol DictionaryType {
|
||||
associatedtype Key: Hashable
|
||||
associatedtype Value
|
||||
|
||||
init<S>(_ keysAndValues: S, uniquingKeysWith combine: (Dictionary<Key, Value>.Value, Dictionary<Key, Value>.Value) throws -> Dictionary<Key, Value>.Value) rethrows where S : Sequence, S.Element == (Key, Value)
|
||||
}
|
||||
extension Dictionary: DictionaryType {}
|
||||
|
||||
extension Attribute: ExpressibleByDictionaryLiteral where RawValue: DictionaryType {
|
||||
public typealias Key = RawValue.Key
|
||||
|
||||
public typealias Value = RawValue.Value
|
||||
|
||||
public init(dictionaryLiteral elements: (RawValue.Key, RawValue.Value)...) {
|
||||
|
||||
// we arbitrarily keep the first value if two values are assigned to the same key
|
||||
self.init(value: RawValue(elements, uniquingKeysWith: { val, _ in val }))
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: DictionaryType where Wrapped: DictionaryType {
|
||||
public typealias Key = Wrapped.Key
|
||||
|
||||
public typealias Value = Wrapped.Value
|
||||
|
||||
public init<S>(_ keysAndValues: S, uniquingKeysWith combine: (Dictionary<Key, Value>.Value, Dictionary<Key, Value>.Value) throws -> Dictionary<Key, Value>.Value) rethrows where S : Sequence, S.Element == (Key, Value) {
|
||||
self = try .some(Wrapped(keysAndValues, uniquingKeysWith: combine))
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ArrayType {
|
||||
associatedtype Element
|
||||
|
||||
init<S>(_ s: S) where Element == S.Element, S : Sequence
|
||||
}
|
||||
extension Array: ArrayType {}
|
||||
extension ArraySlice: ArrayType {}
|
||||
|
||||
extension Attribute: ExpressibleByArrayLiteral where RawValue: ArrayType {
|
||||
public typealias ArrayLiteralElement = RawValue.Element
|
||||
|
||||
public init(arrayLiteral elements: ArrayLiteralElement...) {
|
||||
self.init(value: RawValue(elements))
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: ArrayType where Wrapped: ArrayType {
|
||||
public typealias Element = Wrapped.Element
|
||||
|
||||
public init<S>(_ s: S) where Element == S.Element, S : Sequence {
|
||||
self = .some(Wrapped(s))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// EntityCheck.swift
|
||||
// JSONAPITestLib
|
||||
//
|
||||
// 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 {
|
||||
public 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Id+Literal.swift
|
||||
// JSONAPI
|
||||
//
|
||||
// Created by Mathew Polzin on 11/27/18.
|
||||
//
|
||||
|
||||
import JSONAPI
|
||||
|
||||
extension Id: ExpressibleByUnicodeScalarLiteral where RawType: ExpressibleByUnicodeScalarLiteral {
|
||||
public typealias UnicodeScalarLiteralType = RawType.UnicodeScalarLiteralType
|
||||
|
||||
public init(unicodeScalarLiteral value: RawType.UnicodeScalarLiteralType) {
|
||||
self.init(rawValue: RawType(unicodeScalarLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Id: ExpressibleByExtendedGraphemeClusterLiteral where RawType: ExpressibleByExtendedGraphemeClusterLiteral {
|
||||
public typealias ExtendedGraphemeClusterLiteralType = RawType.ExtendedGraphemeClusterLiteralType
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: RawType.ExtendedGraphemeClusterLiteralType) {
|
||||
self.init(rawValue: RawType(extendedGraphemeClusterLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Id: ExpressibleByStringLiteral where RawType: ExpressibleByStringLiteral {
|
||||
public typealias StringLiteralType = RawType.StringLiteralType
|
||||
|
||||
public init(stringLiteral value: RawType.StringLiteralType) {
|
||||
self.init(rawValue: RawType(stringLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Id: ExpressibleByIntegerLiteral where RawType: ExpressibleByIntegerLiteral {
|
||||
public typealias IntegerLiteralType = RawType.IntegerLiteralType
|
||||
|
||||
public init(integerLiteral value: IntegerLiteralType) {
|
||||
self.init(rawValue: RawType(integerLiteral: value))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Optional+Literal.swift
|
||||
// JSONAPITestLib
|
||||
//
|
||||
// Created by Mathew Polzin on 11/29/18.
|
||||
//
|
||||
|
||||
extension Optional: ExpressibleByUnicodeScalarLiteral where Wrapped: ExpressibleByUnicodeScalarLiteral {
|
||||
public typealias UnicodeScalarLiteralType = Wrapped.UnicodeScalarLiteralType
|
||||
|
||||
public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
|
||||
self = .some(Wrapped(unicodeScalarLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: ExpressibleByExtendedGraphemeClusterLiteral where Wrapped: ExpressibleByExtendedGraphemeClusterLiteral {
|
||||
public typealias ExtendedGraphemeClusterLiteralType = Wrapped.ExtendedGraphemeClusterLiteralType
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
|
||||
self = .some(Wrapped(extendedGraphemeClusterLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: ExpressibleByStringLiteral where Wrapped: ExpressibleByStringLiteral {
|
||||
public typealias StringLiteralType = Wrapped.StringLiteralType
|
||||
|
||||
public init(stringLiteral value: StringLiteralType) {
|
||||
self = .some(Wrapped(stringLiteral: value))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Relationship+Literal.swift
|
||||
// JSONAPITestLib
|
||||
//
|
||||
// Created by Mathew Polzin on 11/27/18.
|
||||
//
|
||||
|
||||
import JSONAPI
|
||||
|
||||
extension ToOneRelationship: ExpressibleByNilLiteral where Identifiable.Identifier: ExpressibleByNilLiteral, MetaType == NoMetadata, LinksType == NoLinks {
|
||||
public init(nilLiteral: ()) {
|
||||
|
||||
self.init(id: Identifiable.Identifier(nilLiteral: ()))
|
||||
}
|
||||
}
|
||||
|
||||
extension ToOneRelationship: ExpressibleByUnicodeScalarLiteral where Identifiable.Identifier: ExpressibleByUnicodeScalarLiteral, MetaType == NoMetadata, LinksType == NoLinks {
|
||||
public typealias UnicodeScalarLiteralType = Identifiable.Identifier.UnicodeScalarLiteralType
|
||||
|
||||
public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
|
||||
self.init(id: Identifiable.Identifier(unicodeScalarLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension ToOneRelationship: ExpressibleByExtendedGraphemeClusterLiteral where Identifiable.Identifier: ExpressibleByExtendedGraphemeClusterLiteral, MetaType == NoMetadata, LinksType == NoLinks {
|
||||
public typealias ExtendedGraphemeClusterLiteralType = Identifiable.Identifier.ExtendedGraphemeClusterLiteralType
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
|
||||
self.init(id: Identifiable.Identifier(extendedGraphemeClusterLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension ToOneRelationship: ExpressibleByStringLiteral where Identifiable.Identifier: ExpressibleByStringLiteral, MetaType == NoMetadata, LinksType == NoLinks {
|
||||
public typealias StringLiteralType = Identifiable.Identifier.StringLiteralType
|
||||
|
||||
public init(stringLiteral value: StringLiteralType) {
|
||||
self.init(id: Identifiable.Identifier(stringLiteral: value))
|
||||
}
|
||||
}
|
||||
|
||||
extension ToManyRelationship: ExpressibleByArrayLiteral where MetaType == NoMetadata, LinksType == NoLinks {
|
||||
public typealias ArrayLiteralElement = Relatable.Identifier
|
||||
|
||||
public init(arrayLiteral elements: ArrayLiteralElement...) {
|
||||
self.init(ids: elements)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user