currently in a pretty broken state with support for enumerations being turned into allowed values via reflection. I think I am going to have to give up type safety if I want to use reflection and keep things open ended

This commit is contained in:
Mathew Polzin
2019-01-19 15:30:09 -08:00
parent 52d2e9819d
commit cf746e182f
7 changed files with 422 additions and 49 deletions
@@ -11,48 +11,78 @@ private protocol _Optional {}
extension Optional: _Optional {}
extension Attribute: OpenAPINodeType where RawValue: OpenAPINodeType {
static public var openAPINode: JSONNode {
static public func openAPINode() throws -> JSONNode {
// If the RawValue is not required, we actually consider it
// nullable. To be not required is for the Attribute itself
// to be optional.
if !RawValue.openAPINode.required {
return RawValue.openAPINode.requiredNode().nullableNode()
if try !RawValue.openAPINode().required {
return try RawValue.openAPINode().requiredNode().nullableNode()
}
return RawValue.openAPINode
return try RawValue.openAPINode()
}
}
extension Attribute: RawOpenAPINodeType where RawValue: RawRepresentable, RawValue.RawValue: OpenAPINodeType {
static public func openAPINode() throws -> JSONNode {
if try !RawValue.RawValue.openAPINode().required {
return try RawValue.RawValue.openAPINode().requiredNode().nullableNode()
}
return try RawValue.RawValue.openAPINode()
}
}
extension Attribute: AnyJSONCaseIterable where RawValue: CaseIterable {
public static var allCases: [Any] {
return Array(RawValue.allCases)
}
}
extension Attribute: AnyWrappedJSONCaseIterable where RawValue: AnyJSONCaseIterable {
public static var allCases: [Any] {
return RawValue.allCases
}
}
extension TransformedAttribute: OpenAPINodeType where RawValue: OpenAPINodeType {
static public var openAPINode: JSONNode {
static public func openAPINode() throws -> JSONNode {
// If the RawValue is not required, we actually consider it
// nullable. To be not required is for the Attribute itself
// to be optional.
if !RawValue.openAPINode.required {
return RawValue.openAPINode.requiredNode().nullableNode()
if try !RawValue.openAPINode().required {
return try RawValue.openAPINode().requiredNode().nullableNode()
}
return RawValue.openAPINode
return try RawValue.openAPINode()
}
}
extension RelationshipType {
static func relationshipNode(nullable: Bool) -> JSONNode {
let propertiesDict: [String: JSONNode] = [
"id": .string(.init(format: .generic,
required: true),
.init()),
"type": .string(.init(format: .generic,
required: true),
.init())
]
return .object(.init(format: .generic,
required: true,
nullable: nullable),
.init(properties: propertiesDict))
}
}
extension ToOneRelationship: OpenAPINodeType {
// TODO: const for json `type`
// TODO: metadata & links
static public var openAPINode: JSONNode {
static public func openAPINode() throws -> JSONNode {
let nullable = Identifiable.self is _Optional.Type
return .object(.init(format: .generic,
required: true),
.init(properties: [
"data": .object(.init(format: .generic,
required: true,
nullable: nullable),
.init(properties: [
"id": .string(.init(format: .generic,
required: true),
.init()),
"type": .string(.init(format: .generic,
required: true),
.init())
]))
"data": ToOneRelationship.relationshipNode(nullable: nullable)
]))
}
}
@@ -60,22 +90,38 @@ extension ToOneRelationship: OpenAPINodeType {
extension ToManyRelationship: OpenAPINodeType {
// TODO: const for json `type`
// TODO: metadata & links
static public var openAPINode: JSONNode {
static public func openAPINode() throws -> JSONNode {
return .object(.init(format: .generic,
required: true),
.init(properties: [
"data": .array(.init(format: .generic,
required: true),
.init(items: .object(.init(format: .generic,
required: true),
.init(properties: [
"id": .string(.init(format: .generic,
required: true),
.init()),
"type": .string(.init(format: .generic,
required: true),
.init())
]))))
.init(items: ToManyRelationship.relationshipNode(nullable: false)))
]))
}
}
extension Entity: OpenAPINodeType where Description.Attributes: Sampleable, Description.Relationships: Sampleable {
public static func openAPINode() throws -> JSONNode {
let attributesNode: JSONNode? = Description.Attributes.self == NoAttributes.self
? nil
: try Description.Attributes.genericObjectOpenAPINode()
let attributesProperty = attributesNode.map { ("attributes", $0) }
let relationshipsNode: JSONNode? = Description.Relationships.self == NoRelationships.self
? nil
: try Description.Relationships.genericObjectOpenAPINode()
let relationshipsProperty = relationshipsNode.map { ("relationships", $0) }
let propertiesDict = Dictionary([
attributesProperty,
relationshipsProperty
].compactMap { $0 }) { _, value in value }
return .object(.init(format: .generic,
required: true),
.init(properties: propertiesDict))
}
}