2019-01-19 15:30:09 -08:00
|
|
|
//
|
|
|
|
|
// Sampleable.swift
|
|
|
|
|
// JSONAPIOpenAPI
|
|
|
|
|
//
|
|
|
|
|
// Created by Mathew Polzin on 1/15/19.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import JSONAPI
|
|
|
|
|
import AnyCodable
|
|
|
|
|
|
|
|
|
|
/// A Sampleable type can provide a sample value.
|
|
|
|
|
/// This is useful for reflection.
|
|
|
|
|
public protocol Sampleable {
|
2019-01-20 18:54:37 -08:00
|
|
|
/// Get a sample value of type Self. This can be the
|
|
|
|
|
/// same value every time, or it can be an arbitrarily random
|
|
|
|
|
/// value each time.
|
2019-01-19 15:30:09 -08:00
|
|
|
static var sample: Self { get }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Sampleable {
|
|
|
|
|
public static func genericObjectOpenAPINode() throws -> JSONNode {
|
|
|
|
|
let mirror = Mirror(reflecting: Self.sample)
|
|
|
|
|
let properties: [(String, JSONNode)] = try mirror.children.compactMap { child in
|
|
|
|
|
|
|
|
|
|
// see if we can enumerate the possible values
|
2019-01-20 15:39:54 -08:00
|
|
|
let maybeAllCases: [AnyCodable]? = {
|
2019-01-19 15:30:09 -08:00
|
|
|
switch type(of: child.value) {
|
|
|
|
|
case let valType as AnyJSONCaseIterable.Type:
|
|
|
|
|
return valType.allCases
|
|
|
|
|
case let valType as AnyWrappedJSONCaseIterable.Type:
|
|
|
|
|
return valType.allCases
|
|
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// try to snag an OpenAPI Node
|
|
|
|
|
let maybeOpenAPINode: JSONNode? = try {
|
|
|
|
|
switch type(of: child.value) {
|
|
|
|
|
case let valType as OpenAPINodeType.Type:
|
|
|
|
|
return try valType.openAPINode()
|
|
|
|
|
|
|
|
|
|
case let valType as RawOpenAPINodeType.Type:
|
2019-01-20 18:18:35 -08:00
|
|
|
return try valType.rawOpenAPINode()
|
|
|
|
|
|
|
|
|
|
case let valType as WrappedRawOpenAPIType.Type:
|
|
|
|
|
return try valType.wrappedOpenAPINode()
|
2019-01-19 15:30:09 -08:00
|
|
|
|
2019-01-20 19:18:10 -08:00
|
|
|
case let valType as DoubleWrappedRawOpenAPIType.Type:
|
|
|
|
|
return try valType.wrappedOpenAPINode()
|
|
|
|
|
|
2019-01-19 15:30:09 -08:00
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// put it all together
|
|
|
|
|
let newNode: JSONNode?
|
|
|
|
|
if let allCases = maybeAllCases,
|
|
|
|
|
let openAPINode = maybeOpenAPINode {
|
2019-01-20 16:10:31 -08:00
|
|
|
newNode = try openAPINode.with(allowedValues: allCases)
|
2019-01-19 15:30:09 -08:00
|
|
|
} else {
|
|
|
|
|
newNode = maybeOpenAPINode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return zip(child.label, newNode) { ($0, $1) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There should not be any duplication of keys since these are
|
|
|
|
|
// property names, but rather than risk runtime exception, we just
|
|
|
|
|
// fail to the newer value arbitrarily
|
|
|
|
|
let propertiesDict = Dictionary(properties) { _, value2 in value2 }
|
|
|
|
|
|
|
|
|
|
return .object(.init(format: .generic,
|
|
|
|
|
required: true),
|
|
|
|
|
.init(properties: propertiesDict))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension NoAttributes: Sampleable {
|
|
|
|
|
public static var sample: NoAttributes {
|
|
|
|
|
return .none
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension NoRelationships: Sampleable {
|
|
|
|
|
public static var sample: NoRelationships {
|
|
|
|
|
return .none
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension NoMetadata: Sampleable {
|
|
|
|
|
public static var sample: NoMetadata {
|
|
|
|
|
return .none
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension NoLinks: Sampleable {
|
|
|
|
|
public static var sample: NoLinks {
|
|
|
|
|
return .none
|
|
|
|
|
}
|
|
|
|
|
}
|