mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-03-30 11:18:38 -07:00
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:
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,39 @@
|
||||
|
||||
import AnyCodable
|
||||
|
||||
// MARK: Node (i.e. schema) Protocols
|
||||
|
||||
/// Anything conforming to `OpenAPINodeType` can provide an
|
||||
/// OpenAPI schema representing itself.
|
||||
public protocol OpenAPINodeType {
|
||||
static var openAPINode: JSONNode { get }
|
||||
static func openAPINode() throws -> JSONNode
|
||||
}
|
||||
|
||||
/// Anything conforming to `RawOpenAPINodeType` can provide an
|
||||
/// OpenAPI schema representing itself. This second protocol is
|
||||
/// necessary so that one type can conditionally provide a
|
||||
/// schema and then (under different conditions) provide a
|
||||
/// different schema. The "different" conditions have to do
|
||||
/// with Raw Representability, hence the name of this protocol.
|
||||
public protocol RawOpenAPINodeType {
|
||||
static func openAPINode() throws -> JSONNode
|
||||
}
|
||||
|
||||
/// Anything conforming to `AnyJSONCaseIterable` can provide a
|
||||
/// list of its possible values.
|
||||
public protocol AnyJSONCaseIterable {
|
||||
static var allCases: [Any] { get }
|
||||
}
|
||||
|
||||
/// Anything conforming to `AnyJSONCaseIterable` can provide a
|
||||
/// list of its possible values. This second protocol is
|
||||
/// necessary so that one type can conditionally provide a
|
||||
/// list of possible values and then (under different conditions)
|
||||
/// provide a different list of possible values.
|
||||
/// The "different" conditions have to do
|
||||
/// with Optionality, hence the name of this protocol.
|
||||
public protocol AnyWrappedJSONCaseIterable {
|
||||
static var allCases: [Any] { get }
|
||||
}
|
||||
|
||||
public protocol SwiftTyped {
|
||||
@@ -210,6 +241,14 @@ public enum JSONNode {
|
||||
nullable: true,
|
||||
allowedValues: allowedValues)
|
||||
}
|
||||
|
||||
/// Return this context with the given list of possible values
|
||||
public func with(allowedValues: [Format.SwiftType]?) -> Context {
|
||||
return .init(format: format,
|
||||
required: required,
|
||||
nullable: nullable,
|
||||
allowedValues: allowedValues)
|
||||
}
|
||||
}
|
||||
|
||||
public struct NumericContext {
|
||||
@@ -393,4 +432,64 @@ public enum JSONNode {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
public func with<T>(allowedValues: [T]) throws -> JSONNode where T: RawRepresentable, T.RawValue == String {
|
||||
return try with(allowedValues: allowedValues.map { $0.rawValue })
|
||||
}
|
||||
|
||||
public func with(allowedValues: [JSONTypeFormat.BooleanFormat.SwiftType]) throws -> JSONNode {
|
||||
guard case let .boolean(contextA) = self else {
|
||||
throw AllowedValueError(expectation: jsonTypeFormat?.jsonType, receivedType: JSONTypeFormat.BooleanFormat.SwiftType.self)
|
||||
}
|
||||
return .boolean(contextA.with(allowedValues: allowedValues))
|
||||
}
|
||||
|
||||
public func with(allowedValues: [JSONTypeFormat.ObjectFormat.SwiftType]) throws -> JSONNode {
|
||||
guard case let .object(contextA, contextB) = self else {
|
||||
throw AllowedValueError(expectation: jsonTypeFormat?.jsonType, receivedType: JSONTypeFormat.ObjectFormat.SwiftType.self)
|
||||
}
|
||||
return .object(contextA.with(allowedValues: allowedValues), contextB)
|
||||
}
|
||||
|
||||
public func with(allowedValues: [JSONTypeFormat.ArrayFormat.SwiftType]) throws -> JSONNode {
|
||||
guard case let .array(contextA, contextB) = self else {
|
||||
throw AllowedValueError(expectation: jsonTypeFormat?.jsonType, receivedType: JSONTypeFormat.ArrayFormat.SwiftType.self)
|
||||
}
|
||||
return .array(contextA.with(allowedValues: allowedValues), contextB)
|
||||
}
|
||||
|
||||
public func with(allowedValues: [JSONTypeFormat.NumberFormat.SwiftType]) throws -> JSONNode {
|
||||
guard case let .number(contextA, contextB) = self else {
|
||||
throw AllowedValueError(expectation: jsonTypeFormat?.jsonType, receivedType: JSONTypeFormat.NumberFormat.SwiftType.self)
|
||||
}
|
||||
return .number(contextA.with(allowedValues: allowedValues), contextB)
|
||||
}
|
||||
|
||||
public func with(allowedValues: [JSONTypeFormat.IntegerFormat.SwiftType]) throws -> JSONNode {
|
||||
guard case let .integer(contextA, contextB) = self else {
|
||||
throw AllowedValueError(expectation: jsonTypeFormat?.jsonType, receivedType: JSONTypeFormat.IntegerFormat.SwiftType.self)
|
||||
}
|
||||
return .integer(contextA.with(allowedValues: allowedValues), contextB)
|
||||
}
|
||||
|
||||
public func with(allowedValues: [JSONTypeFormat.StringFormat.SwiftType]) throws -> JSONNode {
|
||||
guard case let .string(contextA, contextB) = self else {
|
||||
throw AllowedValueError(expectation: jsonTypeFormat?.jsonType, receivedType: JSONTypeFormat.StringFormat.SwiftType.self)
|
||||
}
|
||||
return .string(contextA.with(allowedValues: allowedValues), contextB)
|
||||
}
|
||||
}
|
||||
|
||||
public struct AllowedValueError: Swift.Error, CustomStringConvertible {
|
||||
public let expectation: JSONType?
|
||||
public let receivedType: Any.Type
|
||||
|
||||
public init(expectation: JSONType?, receivedType: Any.Type) {
|
||||
self.expectation = expectation
|
||||
self.receivedType = receivedType
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
return "Expected type compatible with JSON Type \(String(describing: expectation)) but found \(receivedType)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Optional+ZipWith.swift
|
||||
// JSONAPIOpenAPI
|
||||
//
|
||||
// Created by Mathew Polzin on 1/19/19.
|
||||
//
|
||||
|
||||
func zip<X, Y, Z>(_ left: X?, _ right: Y?, with fn: (X, Y) -> Z) -> Z? {
|
||||
return left.flatMap { lft in right.map { rght in fn(lft, rght) }}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// 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 {
|
||||
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
|
||||
let maybeAllCases: [Any]? = {
|
||||
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:
|
||||
return try valType.openAPINode()
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
// put it all together
|
||||
let newNode: JSONNode?
|
||||
if let allCases = maybeAllCases,
|
||||
let openAPINode = maybeOpenAPINode {
|
||||
newNode = try {
|
||||
if let cases = allCases as? [JSONTypeFormat.BooleanFormat.SwiftType] {
|
||||
return try openAPINode.with(allowedValues: cases)
|
||||
|
||||
} else if let cases = allCases as? [JSONTypeFormat.ArrayFormat.SwiftType] {
|
||||
return try openAPINode.with(allowedValues: cases)
|
||||
|
||||
} else if let cases = allCases as? [JSONTypeFormat.ObjectFormat.SwiftType] {
|
||||
return try openAPINode.with(allowedValues: cases)
|
||||
|
||||
} else if let cases = allCases as? [JSONTypeFormat.NumberFormat.SwiftType] {
|
||||
return try openAPINode.with(allowedValues: cases)
|
||||
|
||||
} else if let cases = allCases as? [JSONTypeFormat.IntegerFormat.SwiftType] {
|
||||
return try openAPINode.with(allowedValues: cases)
|
||||
|
||||
} else if let cases = allCases as? [JSONTypeFormat.StringFormat.SwiftType] {
|
||||
return try openAPINode.with(allowedValues: cases)
|
||||
|
||||
} else if allCases.compactMap({ $0 as? RawStringRepresentable }).count == allCases.count {
|
||||
return try openAPINode.with(allowedValues: allCases.compactMap { ($0 as? RawStringRepresentable)?.rawValue })
|
||||
|
||||
} else {
|
||||
throw SampleableError.allowedValuesNotOfExpectedType(forNode: openAPINode, allowedValues: allCases)
|
||||
}
|
||||
}()
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
public enum SampleableError: Swift.Error {
|
||||
case allowedValuesNotOfExpectedType(forNode: JSONNode, allowedValues: [Any])
|
||||
}
|
||||
@@ -30,13 +30,25 @@ Any object:
|
||||
**/
|
||||
|
||||
extension Optional: OpenAPINodeType where Wrapped: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
return Wrapped.openAPINode.optionalNode()
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return try Wrapped.openAPINode().optionalNode()
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: RawOpenAPINodeType where Wrapped: RawRepresentable, Wrapped.RawValue: OpenAPINodeType {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return try Wrapped.RawValue.openAPINode().optionalNode()
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: AnyJSONCaseIterable where Wrapped: CaseIterable {
|
||||
public static var allCases: [Any] {
|
||||
return Array(Wrapped.allCases)
|
||||
}
|
||||
}
|
||||
|
||||
extension String: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .string(.init(format: .generic,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -44,22 +56,22 @@ extension String: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Bool: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .boolean(.init(format: .generic,
|
||||
required: true))
|
||||
}
|
||||
}
|
||||
|
||||
extension Array: OpenAPINodeType where Element: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .array(.init(format: .generic,
|
||||
required: true),
|
||||
.init(items: Element.openAPINode))
|
||||
.init(items: try Element.openAPINode()))
|
||||
}
|
||||
}
|
||||
|
||||
extension Double: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .number(.init(format: .double,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -67,7 +79,7 @@ extension Double: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Float: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .number(.init(format: .float,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -75,7 +87,7 @@ extension Float: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Int: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .integer(.init(format: .generic,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -83,7 +95,7 @@ extension Int: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Int32: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .integer(.init(format: .int32,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -91,7 +103,7 @@ extension Int32: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Int64: OpenAPINodeType {
|
||||
static public var openAPINode: JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .integer(.init(format: .int64,
|
||||
required: true),
|
||||
.init())
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// JSONAPIEntityOpenAPITests.swift
|
||||
// JSONAPIOpenAPITests
|
||||
//
|
||||
// Created by Mathew Polzin on 1/15/19.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import JSONAPI
|
||||
import JSONAPIOpenAPI
|
||||
|
||||
class JSONAPIEntityOpenAPITests: XCTestCase {
|
||||
func test_EmptyEntity() {
|
||||
let node = try! TestType1.openAPINode()
|
||||
|
||||
// TODO: Write test
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
let string = String(data: try! encoder.encode(node), encoding: .utf8)!
|
||||
print(string)
|
||||
}
|
||||
|
||||
func test_AttributesEntity() {
|
||||
|
||||
let tmp = ["hello"] as [Any]
|
||||
let tmp2 = tmp as! [String]
|
||||
let tmp3 = tmp as? RawStringArrayRepresentable
|
||||
let tmp4 = tmp2 as? RawStringArrayRepresentable
|
||||
|
||||
let y = TestType2Description.EnumType.one
|
||||
let z = y as Any
|
||||
|
||||
let x = [y as? TestType2Description.EnumType]
|
||||
|
||||
let node = try! TestType2.openAPINode()
|
||||
|
||||
// TODO: Write test
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
let string = String(data: try! encoder.encode(node), encoding: .utf8)!
|
||||
print(string)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Test Types
|
||||
extension JSONAPIEntityOpenAPITests {
|
||||
enum TestType1Description: EntityDescription {
|
||||
public static var jsonType: String { return "test1" }
|
||||
|
||||
public typealias Attributes = NoAttributes
|
||||
|
||||
public typealias Relationships = NoRelationships
|
||||
}
|
||||
|
||||
typealias TestType1 = BasicEntity<TestType1Description>
|
||||
|
||||
enum TestType2Description: EntityDescription {
|
||||
public static var jsonType: String { return "test1" }
|
||||
|
||||
public enum EnumType: String, CaseIterable, Codable, Equatable {
|
||||
case one
|
||||
case two
|
||||
}
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes, Sampleable {
|
||||
let stringProperty: Attribute<String>
|
||||
let enumProperty: Attribute<EnumType>
|
||||
var computedProperty: Attribute<EnumType> {
|
||||
return enumProperty
|
||||
}
|
||||
|
||||
public static var sample: Attributes {
|
||||
return Attributes(stringProperty: .init(value: "hello"),
|
||||
enumProperty: .init(value: .one))
|
||||
}
|
||||
}
|
||||
|
||||
public typealias Relationships = NoRelationships
|
||||
}
|
||||
|
||||
typealias TestType2 = BasicEntity<TestType2Description>
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import JSONAPIOpenAPI
|
||||
class JSONAPIRelationshipsOpenAPITests: XCTestCase {
|
||||
|
||||
func test_ToOne() {
|
||||
let node = ToOneRelationship<TestEntity1, NoMetadata, NoLinks>.openAPINode
|
||||
let node = try! ToOneRelationship<TestEntity1, NoMetadata, NoLinks>.openAPINode()
|
||||
|
||||
XCTAssertTrue(node.required)
|
||||
XCTAssertEqual(node.jsonTypeFormat, .object(.generic))
|
||||
@@ -47,7 +47,7 @@ class JSONAPIRelationshipsOpenAPITests: XCTestCase {
|
||||
}
|
||||
|
||||
func test_OptionalToOne() {
|
||||
let node = ToOneRelationship<TestEntity1, NoMetadata, NoLinks>?.openAPINode
|
||||
let node = try! ToOneRelationship<TestEntity1, NoMetadata, NoLinks>?.openAPINode()
|
||||
|
||||
XCTAssertFalse(node.required)
|
||||
XCTAssertEqual(node.jsonTypeFormat, .object(.generic))
|
||||
@@ -80,7 +80,7 @@ class JSONAPIRelationshipsOpenAPITests: XCTestCase {
|
||||
}
|
||||
|
||||
func test_NullableToOne() {
|
||||
let node = ToOneRelationship<TestEntity1?, NoMetadata, NoLinks>.openAPINode
|
||||
let node = try! ToOneRelationship<TestEntity1?, NoMetadata, NoLinks>.openAPINode()
|
||||
|
||||
XCTAssertTrue(node.required)
|
||||
XCTAssertEqual(node.jsonTypeFormat, .object(.generic))
|
||||
@@ -113,7 +113,7 @@ class JSONAPIRelationshipsOpenAPITests: XCTestCase {
|
||||
}
|
||||
|
||||
func test_OptionalNullableToOne() {
|
||||
let node = ToOneRelationship<TestEntity1?, NoMetadata, NoLinks>?.openAPINode
|
||||
let node = try! ToOneRelationship<TestEntity1?, NoMetadata, NoLinks>?.openAPINode()
|
||||
|
||||
XCTAssertFalse(node.required)
|
||||
XCTAssertEqual(node.jsonTypeFormat, .object(.generic))
|
||||
@@ -146,7 +146,7 @@ class JSONAPIRelationshipsOpenAPITests: XCTestCase {
|
||||
}
|
||||
|
||||
func test_ToMany() {
|
||||
let node = ToManyRelationship<TestEntity1, NoMetadata, NoLinks>.openAPINode
|
||||
let node = try! ToManyRelationship<TestEntity1, NoMetadata, NoLinks>.openAPINode()
|
||||
|
||||
XCTAssertTrue(node.required)
|
||||
XCTAssertEqual(node.jsonTypeFormat, .object(.generic))
|
||||
@@ -189,7 +189,7 @@ class JSONAPIRelationshipsOpenAPITests: XCTestCase {
|
||||
}
|
||||
|
||||
func test_OptionalToMany() {
|
||||
let node = ToManyRelationship<TestEntity1, NoMetadata, NoLinks>?.openAPINode
|
||||
let node = try! ToManyRelationship<TestEntity1, NoMetadata, NoLinks>?.openAPINode()
|
||||
|
||||
XCTAssertFalse(node.required)
|
||||
XCTAssertEqual(node.jsonTypeFormat, .object(.generic))
|
||||
|
||||
Reference in New Issue
Block a user