mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-07-10 12:18:40 -07:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| abe16dda0d | |||
| 5257fd79fa | |||
| f7a81df451 | |||
| c8fbc09582 | |||
| a88bb77bd0 | |||
| 247848e788 | |||
| 7adbdb4505 | |||
| ea663bb229 | |||
| f48c385f99 | |||
| c96bfadd82 | |||
| 88be701062 | |||
| 1e85e1d2a3 | |||
| 11a7727ac9 | |||
| e8bfbc881b | |||
| af757a2fac | |||
| 84955872f8 |
@@ -1,46 +0,0 @@
|
|||||||
//: [Previous](@previous)
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import JSONAPI
|
|
||||||
import JSONAPIOpenAPI
|
|
||||||
import Poly
|
|
||||||
|
|
||||||
// print Entity Schema
|
|
||||||
let encoder = JSONEncoder()
|
|
||||||
encoder.outputFormatting = .prettyPrinted
|
|
||||||
|
|
||||||
let personSchemaData = try? encoder.encode(Person.openAPINode())
|
|
||||||
|
|
||||||
print("Person Schema")
|
|
||||||
print("====")
|
|
||||||
print(personSchemaData.map { String(data: $0, encoding: .utf8)! } ?? "Schema Construction Failed")
|
|
||||||
print("====")
|
|
||||||
|
|
||||||
let dogDocumentSchemaData = try? encoder.encode(SingleDogDocument.openAPINodeWithExample(using: encoder))
|
|
||||||
|
|
||||||
print("Dog Document Schema")
|
|
||||||
print("====")
|
|
||||||
print(dogDocumentSchemaData.map { String(data: $0, encoding: .utf8)! } ?? "Schema Construction Failed")
|
|
||||||
print("====")
|
|
||||||
|
|
||||||
let batchPersonSchemaData = try? encoder.encode(BatchPeopleDocument.openAPINodeWithExample(using: encoder))
|
|
||||||
|
|
||||||
print("Batch Person Document Schema")
|
|
||||||
print("====")
|
|
||||||
print(batchPersonSchemaData.map { String(data: $0, encoding: .utf8)! } ?? "Schema Construction Failed")
|
|
||||||
print("====")
|
|
||||||
|
|
||||||
let tmp: [String: OpenAPIComponents.SchemasDict.RefType] = [
|
|
||||||
"BatchPerson": try! BatchPeopleDocument.openAPINodeWithExample()
|
|
||||||
]
|
|
||||||
|
|
||||||
let components = OpenAPIComponents(schemas: tmp)
|
|
||||||
|
|
||||||
let batchPeopleRef = JSONReference(type: \OpenAPIComponents.schemas, selector: "BatchPerson")
|
|
||||||
|
|
||||||
let tmp2 = JSONNode.reference(batchPeopleRef)
|
|
||||||
|
|
||||||
print("====")
|
|
||||||
print("====")
|
|
||||||
//print(String(data: try! encoder.encode(components), encoding: .utf8)!)
|
|
||||||
print(String(data: try! encoder.encode(tmp2), encoding: .utf8)!)
|
|
||||||
@@ -63,7 +63,7 @@ public enum PersonDescription: EntityDescription {
|
|||||||
public typealias Person = ExampleEntity<PersonDescription>
|
public typealias Person = ExampleEntity<PersonDescription>
|
||||||
|
|
||||||
public extension Entity where Description == PersonDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
public extension Entity where Description == PersonDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
||||||
public init(id: Person.Id? = nil,name: [String], favoriteColor: String, friends: [Person], dogs: [Dog], home: House) throws {
|
init(id: Person.Id? = nil,name: [String], favoriteColor: String, friends: [Person], dogs: [Dog], home: House) throws {
|
||||||
self = Person(id: id ?? Person.Id(), attributes: .init(name: .init(value: name), favoriteColor: .init(value: favoriteColor)), relationships: .init(friends: .init(entities: friends), dogs: .init(entities: dogs), home: .init(entity: home)), meta: .none, links: .none)
|
self = Person(id: id ?? Person.Id(), attributes: .init(name: .init(value: name), favoriteColor: .init(value: favoriteColor)), relationships: .init(friends: .init(entities: friends), dogs: .init(entities: dogs), home: .init(entity: home)), meta: .none, links: .none)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,11 +120,11 @@ public enum AlternativeDogDescription: EntityDescription {
|
|||||||
public typealias AlternativeDog = ExampleEntity<AlternativeDogDescription>
|
public typealias AlternativeDog = ExampleEntity<AlternativeDogDescription>
|
||||||
|
|
||||||
public extension Entity where Description == DogDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
public extension Entity where Description == DogDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
||||||
public init(name: String, owner: Person?) throws {
|
init(name: String, owner: Person?) throws {
|
||||||
self = Dog(attributes: .init(name: .init(value: name)), relationships: DogDescription.Relationships(owner: .init(entity: owner)), meta: .none, links: .none)
|
self = Dog(attributes: .init(name: .init(value: name)), relationships: DogDescription.Relationships(owner: .init(entity: owner)), meta: .none, links: .none)
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(name: String, owner: Person.Id) throws {
|
init(name: String, owner: Person.Id) throws {
|
||||||
self = Dog(attributes: .init(name: .init(value: name)), relationships: .init(owner: .init(id: owner)), meta: .none, links: .none)
|
self = Dog(attributes: .init(name: .init(value: name)), relationships: .init(owner: .init(id: owner)), meta: .none, links: .none)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import JSONAPI
|
|
||||||
import JSONAPITesting // for the convenience of literal initialization
|
|
||||||
import JSONAPIOpenAPI
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPIArbitrary
|
|
||||||
|
|
||||||
extension PersonDescription.Attributes: Arbitrary, Sampleable {
|
|
||||||
public static var arbitrary: Gen<PersonDescription.Attributes> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
return PersonDescription.Attributes(name: c.generate(),
|
|
||||||
favoriteColor: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static var sample: PersonDescription.Attributes {
|
|
||||||
return .init(name: ["Abbie", "Eibba"], favoriteColor: "Blue")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension PersonDescription.Relationships: Arbitrary, Sampleable {
|
|
||||||
public static var arbitrary: Gen<PersonDescription.Relationships> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
return PersonDescription.Relationships(friends: c.generate(),
|
|
||||||
dogs: c.generate(),
|
|
||||||
home: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static var sample: PersonDescription.Relationships {
|
|
||||||
return .init(friends: ["1", "2"], dogs: ["2"], home: "1")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DogDescription.Attributes: Arbitrary, Sampleable {
|
|
||||||
public static var arbitrary: Gen<DogDescription.Attributes> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
return DogDescription.Attributes(name: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static var sample: DogDescription.Attributes {
|
|
||||||
return DogDescription.Attributes.arbitrary.generate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DogDescription.Relationships: Arbitrary, Sampleable {
|
|
||||||
public static var arbitrary: Gen<DogDescription.Relationships> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
return DogDescription.Relationships(owner: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static var sample: DogDescription.Relationships {
|
|
||||||
return DogDescription.Relationships.arbitrary.generate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document: Sampleable where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary, APIDescription: Arbitrary {
|
|
||||||
public static var sample: Document {
|
|
||||||
return Document.arbitrary.generate
|
|
||||||
}
|
|
||||||
|
|
||||||
public static var successSample: Document? {
|
|
||||||
return Document.arbitraryData.generate
|
|
||||||
}
|
|
||||||
|
|
||||||
public static var failureSample: Document? {
|
|
||||||
return Document.arbitraryErrors.generate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +1,6 @@
|
|||||||
{
|
{
|
||||||
"object": {
|
"object": {
|
||||||
"pins": [
|
"pins": [
|
||||||
{
|
|
||||||
"package": "AnyCodable",
|
|
||||||
"repositoryURL": "https://github.com/Flight-School/AnyCodable.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "396ccc3dba5bdee04c1e742e7fab40582861401e",
|
|
||||||
"version": "0.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "FileCheck",
|
|
||||||
"repositoryURL": "https://github.com/llvm-swift/FileCheck.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "89b8480055f9adf8ce2f9ad5e2fac7ac1076242e",
|
|
||||||
"version": "0.0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"package": "Poly",
|
"package": "Poly",
|
||||||
"repositoryURL": "https://github.com/mattpolzin/Poly.git",
|
"repositoryURL": "https://github.com/mattpolzin/Poly.git",
|
||||||
@@ -27,15 +9,6 @@
|
|||||||
"revision": "77f45b8963a51c02d71fc4075eba5cff47ff0d07",
|
"revision": "77f45b8963a51c02d71fc4075eba5cff47ff0d07",
|
||||||
"version": "1.0.0"
|
"version": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "SwiftCheck",
|
|
||||||
"repositoryURL": "https://github.com/typelift/SwiftCheck.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "cf9958085b2ee1643e541e407c3233d1b76c18ff",
|
|
||||||
"version": "0.11.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
+2
-22
@@ -11,18 +11,10 @@ let package = Package(
|
|||||||
targets: ["JSONAPI"]),
|
targets: ["JSONAPI"]),
|
||||||
.library(
|
.library(
|
||||||
name: "JSONAPITesting",
|
name: "JSONAPITesting",
|
||||||
targets: ["JSONAPITesting"]),
|
targets: ["JSONAPITesting"])
|
||||||
.library(
|
|
||||||
name: "JSONAPIArbitrary",
|
|
||||||
targets: ["JSONAPIArbitrary"]),
|
|
||||||
.library(
|
|
||||||
name: "JSONAPIOpenAPI",
|
|
||||||
targets: ["JSONAPIOpenAPI"])
|
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/mattpolzin/Poly.git", from: "1.0.0"),
|
.package(url: "https://github.com/mattpolzin/Poly.git", from: "1.0.0"),
|
||||||
.package(url: "https://github.com/Flight-School/AnyCodable.git", from: "0.1.0"),
|
|
||||||
.package(url: "https://github.com/typelift/SwiftCheck.git", from: "0.11.0")
|
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
@@ -31,24 +23,12 @@ let package = Package(
|
|||||||
.target(
|
.target(
|
||||||
name: "JSONAPITesting",
|
name: "JSONAPITesting",
|
||||||
dependencies: ["JSONAPI"]),
|
dependencies: ["JSONAPI"]),
|
||||||
.target(
|
|
||||||
name: "JSONAPIArbitrary",
|
|
||||||
dependencies: ["JSONAPI", "SwiftCheck"]),
|
|
||||||
.target(
|
|
||||||
name: "JSONAPIOpenAPI",
|
|
||||||
dependencies: ["JSONAPI", "AnyCodable", "JSONAPIArbitrary"]),
|
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "JSONAPITests",
|
name: "JSONAPITests",
|
||||||
dependencies: ["JSONAPI", "JSONAPITesting"]),
|
dependencies: ["JSONAPI", "JSONAPITesting"]),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "JSONAPITestingTests",
|
name: "JSONAPITestingTests",
|
||||||
dependencies: ["JSONAPI", "JSONAPITesting"]),
|
dependencies: ["JSONAPI", "JSONAPITesting"])
|
||||||
.testTarget(
|
|
||||||
name: "JSONAPIArbitraryTests",
|
|
||||||
dependencies: ["JSONAPI", "SwiftCheck", "JSONAPIArbitrary"]),
|
|
||||||
.testTarget(
|
|
||||||
name: "JSONAPIOpenAPITests",
|
|
||||||
dependencies: ["JSONAPI", "JSONAPIOpenAPI"])
|
|
||||||
],
|
],
|
||||||
swiftLanguageVersions: [.v4_2]
|
swiftLanguageVersions: [.v4_2]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -258,23 +258,23 @@ An `Entity` needs to be specialized on four generic types. The first is the `Ent
|
|||||||
|
|
||||||
#### `Meta`
|
#### `Meta`
|
||||||
|
|
||||||
The second generic specialization on `Entity` is `Meta`. This is described in its own section [below](#jsonapimeta). All `Meta` at any level of a JSON API Document follow the same rules.
|
The second generic specialization on `Entity` is `Meta`. This is described in its own section [below](#jsonapimeta). All `Meta` at any level of a JSON API Document follow the same rules. You can use `NoMetadata` if you do not need to package any metadata with the `Entity`.
|
||||||
|
|
||||||
#### `Links`
|
#### `Links`
|
||||||
|
|
||||||
The third generic specialization on `Entity` is `Links`. This is described in its own section [below](#jsonnapilinks). All `Links` at any level of a JSON API Document follow the same rules, although the **SPEC** makes different suggestions as to what types of links might live on which parts of the Document.
|
The third generic specialization on `Entity` is `Links`. This is described in its own section [below](#jsonnapilinks). All `Links` at any level of a JSON API Document follow the same rules, although the **SPEC** makes different suggestions as to what types of links might live on which parts of the Document. You can use `NoLinks` if you do not need to package any links with the `Entity`.
|
||||||
|
|
||||||
#### `IdType`
|
|
||||||
|
|
||||||
The second is the raw type of `Id` to use for the `Entity`. The actual `Id` of the `Entity` will not be a `RawIdType`, though. The `Id` will package a value of `RawIdType` with a specialized reference back to the `Entity` type it identifies. This just looks like `Id<RawIdType, Entity<EntityDescription, RawIdType>>`.
|
|
||||||
|
|
||||||
Having the `Entity` type associated with the `Id` makes it easy to store all of your entities in a hash broken out by `Entity` type; You can pass `Ids` around and always know where to look for the `Entity` to which the `Id` refers.
|
|
||||||
|
|
||||||
A `RawIdType` is the underlying type that uniquely identifies an `Entity`. This is often a `String` or a `UUID`.
|
|
||||||
|
|
||||||
#### `MaybeRawId`
|
#### `MaybeRawId`
|
||||||
|
|
||||||
`MaybeRawId` is either a `RawIdType` that can be used to uniquely identify `Entities` or it is `Unidentified` which is used to indicate an `Entity` does not have an `Id` (which is useful when a client is requesting that the server create an `Entity` and assign it a new `Id`).
|
The last generic specialization on `Entity` is `MaybeRawId`. This is either a `RawIdType` that can be used to uniquely identify `Entities` or it is `Unidentified` which is used to indicate an `Entity` does not have an `Id` (which is useful when a client is requesting that the server create an `Entity` and assign it a new `Id`).
|
||||||
|
|
||||||
|
##### `RawIdType`
|
||||||
|
|
||||||
|
The raw type of `Id` to use for the `Entity`. The actual `Id` of the `Entity` will not be a `RawIdType`, though. The `Id` will package a value of `RawIdType` with a specialized reference back to the `Entity` type it identifies. This just looks like `Id<RawIdType, Entity<EntityDescription, Meta, Links, RawIdType>>`.
|
||||||
|
|
||||||
|
Having the `Entity` type associated with the `Id` makes it easy to store all of your entities in a hash broken out by `Entity` type; You can pass `Ids` around and always know where to look for the `Entity` to which the `Id` refers. This encapsulation provides some type safety because the Ids of two `Entities` with the "raw ID" of `"1"` but different types will not compare as equal.
|
||||||
|
|
||||||
|
A `RawIdType` is the underlying type that uniquely identifies an `Entity`. This is often a `String` or a `UUID`.
|
||||||
|
|
||||||
#### Convenient `typealiases`
|
#### Convenient `typealiases`
|
||||||
|
|
||||||
@@ -836,11 +836,7 @@ print(response.author)
|
|||||||
The `JSONAPI` framework is packaged with a test library to help you test your `JSONAPI` integration. The test library is called `JSONAPITesting`. It provides literal expressibility for `Attribute`, `ToOneRelationship`, and `Id` in many situations so that you can easily write test `Entity` values into your unit tests. It also provides a `check()` function for each `Entity` type that can be used to catch problems with your `JSONAPI` structures that are not caught by Swift's type system. You can see the `JSONAPITesting` in action in the Playground included with the `JSONAPI` repository.
|
The `JSONAPI` framework is packaged with a test library to help you test your `JSONAPI` integration. The test library is called `JSONAPITesting`. It provides literal expressibility for `Attribute`, `ToOneRelationship`, and `Id` in many situations so that you can easily write test `Entity` values into your unit tests. It also provides a `check()` function for each `Entity` type that can be used to catch problems with your `JSONAPI` structures that are not caught by Swift's type system. You can see the `JSONAPITesting` in action in the Playground included with the `JSONAPI` repository.
|
||||||
|
|
||||||
# JSONAPI+Arbitrary
|
# JSONAPI+Arbitrary
|
||||||
The `JSONAPIArbitrary` framework adds `Arbitrary` support via `SwiftCheck`. With a little extra work on your part, this framework will allow you to create "arbitrary" (i.e. randomly generated) instances of your JSONAPI entities, includes, documents, etc.
|
This library has moved into its own Package. See https://github.com/mattpolzin/JSONAPI-Arbitrary
|
||||||
|
|
||||||
This Framework is currently undocumented, but familiarity with `SwiftCheck` will likely afford the user enough information to use this library to aid in the generation of arbitrary JSONAPI Documents for testing purposes.
|
|
||||||
|
|
||||||
# JSONAPI+OpenAPI
|
# JSONAPI+OpenAPI
|
||||||
The `JSONAPIOpenAPI` framework adds the ability to generate OpenAPI compliant JSON documentation of a JSONAPI Document.
|
This library has moved into its own Package. See https://github.com/mattpolzin/JSONAPI-OpenAPI
|
||||||
|
|
||||||
This library is in its infancy. The documentation will grow as the framework becomes more complete.
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public extension TransformedAttribute {
|
|||||||
/// Generally, this is the most useful operation. The transformer gives you
|
/// Generally, this is the most useful operation. The transformer gives you
|
||||||
/// control over the decoding of the Attribute, but once the Attribute exists,
|
/// control over the decoding of the Attribute, but once the Attribute exists,
|
||||||
/// mapping on it is most useful for creating computed Attribute properties.
|
/// mapping on it is most useful for creating computed Attribute properties.
|
||||||
public func map<T: Codable>(_ transform: (Transformer.To) throws -> T) rethrows -> Attribute<T> {
|
func map<T: Codable>(_ transform: (Transformer.To) throws -> T) rethrows -> Attribute<T> {
|
||||||
return Attribute<T>(value: try transform(value))
|
return Attribute<T>(value: try transform(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ public extension Attribute {
|
|||||||
/// Generally, this is the most useful operation. The transformer gives you
|
/// Generally, this is the most useful operation. The transformer gives you
|
||||||
/// control over the decoding of the Attribute, but once the Attribute exists,
|
/// control over the decoding of the Attribute, but once the Attribute exists,
|
||||||
/// mapping on it is most useful for creating computed Attribute properties.
|
/// mapping on it is most useful for creating computed Attribute properties.
|
||||||
public func map<T: Codable>(_ transform: (ValueType) throws -> T) rethrows -> Attribute<T> {
|
func map<T: Codable>(_ transform: (ValueType) throws -> T) rethrows -> Attribute<T> {
|
||||||
return Attribute<T>(value: try transform(value))
|
return Attribute<T>(value: try transform(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,20 +397,20 @@ public extension Entity where EntityRawIdType: JSONAPI.RawIdType {
|
|||||||
/// An Entity.Pointer is a `ToOneRelationship` with no metadata or links.
|
/// An Entity.Pointer is a `ToOneRelationship` with no metadata or links.
|
||||||
/// This is just a convenient way to reference an Entity so that
|
/// This is just a convenient way to reference an Entity so that
|
||||||
/// other Entities' Relationships can be built up from it.
|
/// other Entities' Relationships can be built up from it.
|
||||||
public typealias Pointer = ToOneRelationship<Entity, NoMetadata, NoLinks>
|
typealias Pointer = ToOneRelationship<Entity, NoMetadata, NoLinks>
|
||||||
|
|
||||||
/// Entity.Pointers is a `ToManyRelationship` with no metadata or links.
|
/// Entity.Pointers is a `ToManyRelationship` with no metadata or links.
|
||||||
/// This is just a convenient way to reference a bunch of Entities so
|
/// This is just a convenient way to reference a bunch of Entities so
|
||||||
/// that other Entities' Relationships can be built up from them.
|
/// that other Entities' Relationships can be built up from them.
|
||||||
public typealias Pointers = ToManyRelationship<Entity, NoMetadata, NoLinks>
|
typealias Pointers = ToManyRelationship<Entity, NoMetadata, NoLinks>
|
||||||
|
|
||||||
/// Get a pointer to this entity that can be used as a
|
/// Get a pointer to this entity that can be used as a
|
||||||
/// relationship to another entity.
|
/// relationship to another entity.
|
||||||
public var pointer: Pointer {
|
var pointer: Pointer {
|
||||||
return Pointer(entity: self)
|
return Pointer(entity: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func pointer<MType: JSONAPI.Meta, LType: JSONAPI.Links>(withMeta meta: MType, links: LType) -> ToOneRelationship<Entity, MType, LType> {
|
func pointer<MType: JSONAPI.Meta, LType: JSONAPI.Links>(withMeta meta: MType, links: LType) -> ToOneRelationship<Entity, MType, LType> {
|
||||||
return ToOneRelationship(entity: self, meta: meta, links: links)
|
return ToOneRelationship(entity: self, meta: meta, links: links)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,19 +419,19 @@ public extension Entity where EntityRawIdType: JSONAPI.RawIdType {
|
|||||||
public extension Entity where EntityRawIdType == Unidentified {
|
public extension Entity where EntityRawIdType == Unidentified {
|
||||||
/// Create a new Entity from this one with a newly created
|
/// Create a new Entity from this one with a newly created
|
||||||
/// unique Id of the given type.
|
/// unique Id of the given type.
|
||||||
public func identified<RawIdType: CreatableRawIdType>(byType: RawIdType.Type) -> Entity<Description, MetaType, LinksType, RawIdType> {
|
func identified<RawIdType: CreatableRawIdType>(byType: RawIdType.Type) -> Entity<Description, MetaType, LinksType, RawIdType> {
|
||||||
return .init(attributes: attributes, relationships: relationships, meta: meta, links: links)
|
return .init(attributes: attributes, relationships: relationships, meta: meta, links: links)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Entity from this one with the given Id.
|
/// Create a new Entity from this one with the given Id.
|
||||||
public func identified<RawIdType: JSONAPI.RawIdType>(by id: RawIdType) -> Entity<Description, MetaType, LinksType, RawIdType> {
|
func identified<RawIdType: JSONAPI.RawIdType>(by id: RawIdType) -> Entity<Description, MetaType, LinksType, RawIdType> {
|
||||||
return .init(id: Entity<Description, MetaType, LinksType, RawIdType>.Identifier(rawValue: id), attributes: attributes, relationships: relationships, meta: meta, links: links)
|
return .init(id: Entity<Description, MetaType, LinksType, RawIdType>.Identifier(rawValue: id), attributes: attributes, relationships: relationships, meta: meta, links: links)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension Entity where EntityRawIdType: CreatableRawIdType {
|
public extension Entity where EntityRawIdType: CreatableRawIdType {
|
||||||
/// Create a copy of this Entity with a new unique Id.
|
/// Create a copy of this Entity with a new unique Id.
|
||||||
public func withNewIdentifier() -> Entity {
|
func withNewIdentifier() -> Entity {
|
||||||
return Entity(attributes: attributes, relationships: relationships, meta: meta, links: links)
|
return Entity(attributes: attributes, relationships: relationships, meta: meta, links: links)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -485,14 +485,14 @@ public extension EntityProxy {
|
|||||||
/// Access to an Id of a `ToOneRelationship`.
|
/// Access to an Id of a `ToOneRelationship`.
|
||||||
/// This allows you to write `entity ~> \.other` instead
|
/// This allows you to write `entity ~> \.other` instead
|
||||||
/// of `entity.relationships.other.id`.
|
/// of `entity.relationships.other.id`.
|
||||||
public static func ~><OtherEntity: Identifiable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToOneRelationship<OtherEntity, MType, LType>>) -> OtherEntity.Identifier {
|
static func ~><OtherEntity: Identifiable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToOneRelationship<OtherEntity, MType, LType>>) -> OtherEntity.Identifier {
|
||||||
return entity.relationships[keyPath: path].id
|
return entity.relationships[keyPath: path].id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access to an Id of an optional `ToOneRelationship`.
|
/// Access to an Id of an optional `ToOneRelationship`.
|
||||||
/// This allows you to write `entity ~> \.other` instead
|
/// This allows you to write `entity ~> \.other` instead
|
||||||
/// of `entity.relationships.other?.id`.
|
/// of `entity.relationships.other?.id`.
|
||||||
public static func ~><OtherEntity: OptionalRelatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToOneRelationship<OtherEntity, MType, LType>?>) -> OtherEntity.Identifier {
|
static func ~><OtherEntity: OptionalRelatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToOneRelationship<OtherEntity, MType, LType>?>) -> OtherEntity.Identifier {
|
||||||
// Implementation Note: This signature applies to `ToOneRelationship<E?, _, _>?`
|
// Implementation Note: This signature applies to `ToOneRelationship<E?, _, _>?`
|
||||||
// whereas the one below applies to `ToOneRelationship<E, _, _>?`
|
// whereas the one below applies to `ToOneRelationship<E, _, _>?`
|
||||||
return entity.relationships[keyPath: path]?.id
|
return entity.relationships[keyPath: path]?.id
|
||||||
@@ -501,7 +501,7 @@ public extension EntityProxy {
|
|||||||
/// Access to an Id of an optional `ToOneRelationship`.
|
/// Access to an Id of an optional `ToOneRelationship`.
|
||||||
/// This allows you to write `entity ~> \.other` instead
|
/// This allows you to write `entity ~> \.other` instead
|
||||||
/// of `entity.relationships.other?.id`.
|
/// of `entity.relationships.other?.id`.
|
||||||
public static func ~><OtherEntity: Relatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToOneRelationship<OtherEntity, MType, LType>?>) -> OtherEntity.Identifier? {
|
static func ~><OtherEntity: Relatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToOneRelationship<OtherEntity, MType, LType>?>) -> OtherEntity.Identifier? {
|
||||||
// Implementation Note: This signature applies to `ToOneRelationship<E, _, _>?`
|
// Implementation Note: This signature applies to `ToOneRelationship<E, _, _>?`
|
||||||
// whereas the one above applies to `ToOneRelationship<E?, _, _>?`
|
// whereas the one above applies to `ToOneRelationship<E?, _, _>?`
|
||||||
return entity.relationships[keyPath: path]?.id
|
return entity.relationships[keyPath: path]?.id
|
||||||
@@ -510,14 +510,14 @@ public extension EntityProxy {
|
|||||||
/// Access to all Ids of a `ToManyRelationship`.
|
/// Access to all Ids of a `ToManyRelationship`.
|
||||||
/// This allows you to write `entity ~> \.others` instead
|
/// This allows you to write `entity ~> \.others` instead
|
||||||
/// of `entity.relationships.others.ids`.
|
/// of `entity.relationships.others.ids`.
|
||||||
public static func ~><OtherEntity: Relatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToManyRelationship<OtherEntity, MType, LType>>) -> [OtherEntity.Identifier] {
|
static func ~><OtherEntity: Relatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToManyRelationship<OtherEntity, MType, LType>>) -> [OtherEntity.Identifier] {
|
||||||
return entity.relationships[keyPath: path].ids
|
return entity.relationships[keyPath: path].ids
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access to all Ids of an optional `ToManyRelationship`.
|
/// Access to all Ids of an optional `ToManyRelationship`.
|
||||||
/// This allows you to write `entity ~> \.others` instead
|
/// This allows you to write `entity ~> \.others` instead
|
||||||
/// of `entity.relationships.others?.ids`.
|
/// of `entity.relationships.others?.ids`.
|
||||||
public static func ~><OtherEntity: Relatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToManyRelationship<OtherEntity, MType, LType>?>) -> [OtherEntity.Identifier]? {
|
static func ~><OtherEntity: Relatable, MType: JSONAPI.Meta, LType: JSONAPI.Links>(entity: Self, path: KeyPath<Description.Relationships, ToManyRelationship<OtherEntity, MType, LType>?>) -> [OtherEntity.Identifier]? {
|
||||||
return entity.relationships[keyPath: path]?.ids
|
return entity.relationships[keyPath: path]?.ids
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,14 +527,14 @@ public extension EntityProxy {
|
|||||||
/// Access to an Id of a `ToOneRelationship`.
|
/// Access to an Id of a `ToOneRelationship`.
|
||||||
/// This allows you to write `entity ~> \.other` instead
|
/// This allows you to write `entity ~> \.other` instead
|
||||||
/// of `entity.relationships.other.id`.
|
/// of `entity.relationships.other.id`.
|
||||||
public static func ~><Identifier: IdType>(entity: Self, path: KeyPath<Description.Relationships, (Self) -> Identifier>) -> Identifier {
|
static func ~><Identifier: IdType>(entity: Self, path: KeyPath<Description.Relationships, (Self) -> Identifier>) -> Identifier {
|
||||||
return entity.relationships[keyPath: path](entity)
|
return entity.relationships[keyPath: path](entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access to all Ids of a `ToManyRelationship`.
|
/// Access to all Ids of a `ToManyRelationship`.
|
||||||
/// This allows you to write `entity ~> \.others` instead
|
/// This allows you to write `entity ~> \.others` instead
|
||||||
/// of `entity.relationships.others.ids`.
|
/// of `entity.relationships.others.ids`.
|
||||||
public static func ~><Identifier: IdType>(entity: Self, path: KeyPath<Description.Relationships, (Self) -> [Identifier]>) -> [Identifier] {
|
static func ~><Identifier: IdType>(entity: Self, path: KeyPath<Description.Relationships, (Self) -> [Identifier]>) -> [Identifier] {
|
||||||
return entity.relationships[keyPath: path](entity)
|
return entity.relationships[keyPath: path](entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -552,7 +552,7 @@ private enum ResourceObjectCodingKeys: String, CodingKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public extension Entity {
|
public extension Entity {
|
||||||
public func encode(to encoder: Encoder) throws {
|
func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: ResourceObjectCodingKeys.self)
|
var container = encoder.container(keyedBy: ResourceObjectCodingKeys.self)
|
||||||
|
|
||||||
try container.encode(Entity.jsonType, forKey: .type)
|
try container.encode(Entity.jsonType, forKey: .type)
|
||||||
@@ -578,7 +578,7 @@ public extension Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
|
|
||||||
let container = try decoder.container(keyedBy: ResourceObjectCodingKeys.self)
|
let container = try decoder.container(keyedBy: ResourceObjectCodingKeys.self)
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// APIDescription+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/21/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension APIDescription: Arbitrary where Meta: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<APIDescription<Meta>> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
APIDescription(version: c.generate(),
|
|
||||||
meta: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NoAPIDescription: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<NoAPIDescription> {
|
|
||||||
return Gen.pure(.none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
//
|
|
||||||
// Attribute+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/15/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension Attribute: Arbitrary where RawValue: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Attribute<RawValue>> {
|
|
||||||
return RawValue.arbitrary.map { .init(value: $0) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot conform TransformedAttribute to Arbitrary here
|
|
||||||
// because there is no way to guarantee that an arbitrary
|
|
||||||
// RawValue will successfully transform or that an
|
|
||||||
// arbitrary Value will successfully reverse-transform.
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
//
|
|
||||||
// Document+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/21/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension Document.Body.Data: Arbitrary where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>.Body.Data> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
Document.Body.Data(primary: c.generate(),
|
|
||||||
includes: c.generate(),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document.Body: Arbitrary where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>.Body> {
|
|
||||||
return Gen.one(of: [
|
|
||||||
arbitraryData,
|
|
||||||
arbitraryErrors
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document.Body where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary {
|
|
||||||
/// Arbitrary Document.Body with data (guaranteed to not
|
|
||||||
/// be an error body).
|
|
||||||
public static var arbitraryData: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>.Body> {
|
|
||||||
return Document.Body.Data.arbitrary.map(Document.Body.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document.Body where MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary {
|
|
||||||
/// Arbitrary Document.Body with errors (guaranteed to not
|
|
||||||
/// be a data body).
|
|
||||||
public static var arbitraryErrors: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>.Body> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
Document.Body.errors(c.generate(),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document.Body where Error: Arbitrary {
|
|
||||||
/// Arbitrary Document.Body with errors but no
|
|
||||||
/// metadata or links (also guaranteed to not
|
|
||||||
/// be a data body).
|
|
||||||
public static var arbitraryErrorsWithoutMetaOrLinks: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>.Body> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
Document.Body.errors(c.generate(),
|
|
||||||
meta: nil,
|
|
||||||
links: nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document: Arbitrary where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary, APIDescription: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>> {
|
|
||||||
return Gen.one(of: [
|
|
||||||
arbitraryData,
|
|
||||||
arbitraryErrors
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary, APIDescription: Arbitrary {
|
|
||||||
/// Arbitrary Document with data (guaranteed to not
|
|
||||||
/// be an error body).
|
|
||||||
public static var arbitraryData: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
Document(apiDescription: c.generate(),
|
|
||||||
body: c.generate(),
|
|
||||||
includes: c.generate(),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document where MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary, APIDescription: Arbitrary {
|
|
||||||
/// Arbitrary Document with errors (guaranteed to not
|
|
||||||
/// be a data body).
|
|
||||||
public static var arbitraryErrors: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
Document(apiDescription: c.generate(),
|
|
||||||
errors: c.generate(),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document where Error: Arbitrary, APIDescription: Arbitrary {
|
|
||||||
/// Arbitrary Document with errors but no
|
|
||||||
/// metadata or links (also guaranteed to not
|
|
||||||
/// be a data body).
|
|
||||||
public static var arbitraryErrors: Gen<Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error>> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
Document(apiDescription: c.generate(),
|
|
||||||
errors: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
//
|
|
||||||
// Entity+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/14/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension NoMetadata: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<NoMetadata> {
|
|
||||||
return Gen.pure(.none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NoLinks: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<NoLinks> {
|
|
||||||
return Gen.pure(.none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NoAttributes: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<NoAttributes> {
|
|
||||||
return Gen.pure(.none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NoRelationships: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<NoRelationships> {
|
|
||||||
return Gen.pure(.none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Arbitrary conformance for MetaType, LinksType, Description.Attributes,
|
|
||||||
// and Description.Relationships must all be provided BY YOU for Entity to
|
|
||||||
// gain Arbitrary conformance (with the exception of NoMetadata, NoLinks,
|
|
||||||
// NoAttributes, and NoRelationships which all have Arbitrary conformance
|
|
||||||
// out of the box).
|
|
||||||
extension Entity: Arbitrary where MetaType: Arbitrary, LinksType: Arbitrary, Description.Attributes: Arbitrary, Description.Relationships: Arbitrary, EntityRawIdType: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Entity<Description, MetaType, LinksType, EntityRawIdType>> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
Entity(id: c.generate(),
|
|
||||||
attributes: c.generate(),
|
|
||||||
relationships: c.generate(),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// Error+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/21/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension UnknownJSONAPIError: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<UnknownJSONAPIError> {
|
|
||||||
return Gen.pure(.unknownError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
//
|
|
||||||
// Id+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/14/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension Unidentified: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Unidentified> {
|
|
||||||
return Gen.pure(.init())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Id: Arbitrary where RawType: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Id<RawType, IdentifiableType>> {
|
|
||||||
return RawType.arbitrary.map { Id(rawValue: $0) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
//
|
|
||||||
// Includes+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/21/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension Includes: Arbitrary where I: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Includes<I>> {
|
|
||||||
return I
|
|
||||||
.arbitrary
|
|
||||||
.proliferate
|
|
||||||
.map(Includes.init(values:))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NoIncludes: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<NoIncludes> {
|
|
||||||
return Gen.pure(NoIncludes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include1: Arbitrary where A: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include1<A>> {
|
|
||||||
return Gen.one(of: [
|
|
||||||
A.arbitrary.map(Include1.init)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include2: Arbitrary where A: Arbitrary, B: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include2<A, B>> {
|
|
||||||
return Gen.one(of: [
|
|
||||||
A.arbitrary.map(Include2.init),
|
|
||||||
B.arbitrary.map(Include2.init)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include3: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include3<A, B, C>> {
|
|
||||||
return Gen.one(of: [
|
|
||||||
A.arbitrary.map(Include3.init),
|
|
||||||
B.arbitrary.map(Include3.init),
|
|
||||||
C.arbitrary.map(Include3.init)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include4: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include4<A, B, C, D>> {
|
|
||||||
return Gen.one(of: [
|
|
||||||
A.arbitrary.map(Include4.init),
|
|
||||||
B.arbitrary.map(Include4.init),
|
|
||||||
C.arbitrary.map(Include4.init),
|
|
||||||
D.arbitrary.map(Include4.init)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include5: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include5<A, B, C, D, E>> {
|
|
||||||
return Gen.one(of: [
|
|
||||||
A.arbitrary.map(Include5.init),
|
|
||||||
B.arbitrary.map(Include5.init),
|
|
||||||
C.arbitrary.map(Include5.init),
|
|
||||||
D.arbitrary.map(Include5.init),
|
|
||||||
E.arbitrary.map(Include5.init)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include6: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include6<A, B, C, D, E, F>> {
|
|
||||||
// Note broken up because compiler cannot typecheck entire array
|
|
||||||
// before it times out
|
|
||||||
let set1: [Gen<Include6<A, B, C, D, E, F>>] = [
|
|
||||||
A.arbitrary.map(Include6.init),
|
|
||||||
B.arbitrary.map(Include6.init),
|
|
||||||
C.arbitrary.map(Include6.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
let set2: [Gen<Include6<A, B, C, D, E, F>>] = [
|
|
||||||
D.arbitrary.map(Include6.init),
|
|
||||||
E.arbitrary.map(Include6.init),
|
|
||||||
F.arbitrary.map(Include6.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
return Gen.one(of: set1 + set2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include7: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary, G: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include7<A, B, C, D, E, F, G>> {
|
|
||||||
// Note broken up because compiler cannot typecheck entire array
|
|
||||||
// before it times out
|
|
||||||
let set1: [Gen<Include7<A, B, C, D, E, F, G>>] = [
|
|
||||||
A.arbitrary.map(Include7.init),
|
|
||||||
B.arbitrary.map(Include7.init),
|
|
||||||
C.arbitrary.map(Include7.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
let set2: [Gen<Include7<A, B, C, D, E, F, G>>] = [
|
|
||||||
D.arbitrary.map(Include7.init),
|
|
||||||
E.arbitrary.map(Include7.init),
|
|
||||||
F.arbitrary.map(Include7.init),
|
|
||||||
G.arbitrary.map(Include7.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
return Gen.one(of: set1 + set2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include8: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary, G: Arbitrary, H: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include8<A, B, C, D, E, F, G, H>> {
|
|
||||||
// Note broken up because compiler cannot typecheck entire array
|
|
||||||
// before it times out
|
|
||||||
let set1: [Gen<Include8<A, B, C, D, E, F, G, H>>] = [
|
|
||||||
A.arbitrary.map(Include8.init),
|
|
||||||
B.arbitrary.map(Include8.init),
|
|
||||||
C.arbitrary.map(Include8.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
let set2: [Gen<Include8<A, B, C, D, E, F, G, H>>] = [
|
|
||||||
D.arbitrary.map(Include8.init),
|
|
||||||
E.arbitrary.map(Include8.init),
|
|
||||||
F.arbitrary.map(Include8.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
let set3: [Gen<Include8<A, B, C, D, E, F, G, H>>] = [
|
|
||||||
G.arbitrary.map(Include8.init),
|
|
||||||
H.arbitrary.map(Include8.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
return Gen.one(of: set1 + set2 + set3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include9: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary, G: Arbitrary, H: Arbitrary, I: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<Include9<A, B, C, D, E, F, G, H, I>> {
|
|
||||||
// Note broken up because compiler cannot typecheck entire array
|
|
||||||
// before it times out
|
|
||||||
let set1: [Gen<Include9<A, B, C, D, E, F, G, H, I>>] = [
|
|
||||||
A.arbitrary.map(Include9.init),
|
|
||||||
B.arbitrary.map(Include9.init),
|
|
||||||
C.arbitrary.map(Include9.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
let set2: [Gen<Include9<A, B, C, D, E, F, G, H, I>>] = [
|
|
||||||
D.arbitrary.map(Include9.init),
|
|
||||||
E.arbitrary.map(Include9.init),
|
|
||||||
F.arbitrary.map(Include9.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
let set3: [Gen<Include9<A, B, C, D, E, F, G, H, I>>] = [
|
|
||||||
G.arbitrary.map(Include9.init),
|
|
||||||
H.arbitrary.map(Include9.init),
|
|
||||||
I.arbitrary.map(Include9.init)
|
|
||||||
]
|
|
||||||
|
|
||||||
return Gen.one(of: set1 + set2 + set3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Relationship+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/15/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension ToOneRelationship: Arbitrary where Identifiable.Identifier: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<ToOneRelationship<Identifiable, MetaType, LinksType>> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
return .init(id: c.generate(),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ToOneRelationship where MetaType: Arbitrary, LinksType: Arbitrary {
|
|
||||||
/// Create a generator of arbitrary ToOneRelationships that will all
|
|
||||||
/// point to one of the given entities. This allows you to create
|
|
||||||
/// arbitrary relationships that make sense in a broader context where
|
|
||||||
/// the relationship must actually point to another entity.
|
|
||||||
public static func arbitrary<E: EntityType>(givenEntities: [E]) -> Gen<ToOneRelationship<Identifiable, MetaType, LinksType>> where E.Id == Identifiable.Identifier {
|
|
||||||
|
|
||||||
return Gen.compose { c in
|
|
||||||
let idGen = Gen.fromElements(of: givenEntities).map { $0.id }
|
|
||||||
return .init(id: c.generate(using: idGen),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ToManyRelationship: Arbitrary where Relatable.Identifier: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<ToManyRelationship<Relatable, MetaType, LinksType>> {
|
|
||||||
return Gen.compose { c in
|
|
||||||
return .init(ids: c.generate(),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ToManyRelationship where MetaType: Arbitrary, LinksType: Arbitrary {
|
|
||||||
/// Create a generator of arbitrary ToManyRelationships that will all
|
|
||||||
/// point to some number of the given entities. This allows you to create
|
|
||||||
/// arbitrary relationships that make sense in a broader context where
|
|
||||||
/// the relationship must actually point to other existing entities.
|
|
||||||
public static func arbitrary<E: EntityType>(givenEntities: [E]) -> Gen<ToManyRelationship<Relatable, MetaType, LinksType>> where E.Id == Relatable.Identifier {
|
|
||||||
return Gen.compose { c in
|
|
||||||
let idsGen = Gen.fromElements(of: givenEntities).map { $0.id }.proliferate
|
|
||||||
return .init(ids: c.generate(using: idsGen),
|
|
||||||
meta: c.generate(),
|
|
||||||
links: c.generate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
//
|
|
||||||
// ResourceBody+Arbitrary.swift
|
|
||||||
// JSONAPIArbitrary
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/21/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftCheck
|
|
||||||
import JSONAPI
|
|
||||||
|
|
||||||
extension SingleResourceBody: Arbitrary where Entity: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<SingleResourceBody<Entity>> {
|
|
||||||
return Entity.arbitrary.map(SingleResourceBody.init(entity:))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ManyResourceBody: Arbitrary where Entity: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<ManyResourceBody<Entity>> {
|
|
||||||
return Entity.arbitrary.proliferate.map(ManyResourceBody.init(entities:))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NoResourceBody: Arbitrary {
|
|
||||||
public static var arbitrary: Gen<NoResourceBody> {
|
|
||||||
return Gen.pure(.none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
//
|
|
||||||
// JSONAPIInclude+OpenAPI.swift
|
|
||||||
// JSONAPIOpenAPI
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/22/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import JSONAPI
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
extension Includes: OpenAPINodeType where I: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
let includeNode = try I.openAPINode()
|
|
||||||
|
|
||||||
return .array(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init(items: includeNode,
|
|
||||||
uniqueItems: true))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include0: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
throw OpenAPITypeError.invalidNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include1: OpenAPINodeType where A: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [A.openAPINode()])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include2: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include3: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode(),
|
|
||||||
C.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include4: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode(),
|
|
||||||
C.openAPINode(),
|
|
||||||
D.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include5: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode(),
|
|
||||||
C.openAPINode(),
|
|
||||||
D.openAPINode(),
|
|
||||||
E.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include6: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode(),
|
|
||||||
C.openAPINode(),
|
|
||||||
D.openAPINode(),
|
|
||||||
E.openAPINode(),
|
|
||||||
F.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include7: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType, G: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode(),
|
|
||||||
C.openAPINode(),
|
|
||||||
D.openAPINode(),
|
|
||||||
E.openAPINode(),
|
|
||||||
F.openAPINode(),
|
|
||||||
G.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include8: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType, G: OpenAPINodeType, H: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode(),
|
|
||||||
C.openAPINode(),
|
|
||||||
D.openAPINode(),
|
|
||||||
E.openAPINode(),
|
|
||||||
F.openAPINode(),
|
|
||||||
G.openAPINode(),
|
|
||||||
H.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Include9: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType, G: OpenAPINodeType, H: OpenAPINodeType, I: OpenAPINodeType {
|
|
||||||
public static func openAPINode() throws -> JSONNode {
|
|
||||||
return try .one(of: [
|
|
||||||
A.openAPINode(),
|
|
||||||
B.openAPINode(),
|
|
||||||
C.openAPINode(),
|
|
||||||
D.openAPINode(),
|
|
||||||
E.openAPINode(),
|
|
||||||
F.openAPINode(),
|
|
||||||
G.openAPINode(),
|
|
||||||
H.openAPINode(),
|
|
||||||
I.openAPINode()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
//
|
|
||||||
// JSONAPIOpenAPITypes.swift
|
|
||||||
// JSONAPIOpenAPI
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/13/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import JSONAPI
|
|
||||||
import Foundation
|
|
||||||
import AnyCodable
|
|
||||||
|
|
||||||
private protocol _Optional {}
|
|
||||||
extension Optional: _Optional {}
|
|
||||||
|
|
||||||
private protocol Wrapper {
|
|
||||||
associatedtype Wrapped
|
|
||||||
}
|
|
||||||
extension Optional: Wrapper {}
|
|
||||||
|
|
||||||
extension Attribute: OpenAPINodeType where RawValue: OpenAPINodeType {
|
|
||||||
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 try !RawValue.openAPINode().required {
|
|
||||||
return try RawValue.openAPINode().requiredNode().nullableNode()
|
|
||||||
}
|
|
||||||
return try RawValue.openAPINode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Attribute: RawOpenAPINodeType where RawValue: RawRepresentable, RawValue.RawValue: OpenAPINodeType {
|
|
||||||
static public func rawOpenAPINode() 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 try !RawValue.RawValue.openAPINode().required {
|
|
||||||
return try RawValue.RawValue.openAPINode().requiredNode().nullableNode()
|
|
||||||
}
|
|
||||||
return try RawValue.RawValue.openAPINode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Attribute: WrappedRawOpenAPIType where RawValue: RawOpenAPINodeType {
|
|
||||||
public static func wrappedOpenAPINode() 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 try !RawValue.rawOpenAPINode().required {
|
|
||||||
return try RawValue.rawOpenAPINode().requiredNode().nullableNode()
|
|
||||||
}
|
|
||||||
return try RawValue.rawOpenAPINode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Attribute: AnyJSONCaseIterable where RawValue: CaseIterable, RawValue: Codable {
|
|
||||||
public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] {
|
|
||||||
return (try? allCases(from: Array(RawValue.allCases), using: encoder)) ?? []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Attribute: AnyWrappedJSONCaseIterable where RawValue: AnyJSONCaseIterable {
|
|
||||||
public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] {
|
|
||||||
return RawValue.allCases(using: encoder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Attribute: GenericOpenAPINodeType where RawValue: GenericOpenAPINodeType {
|
|
||||||
public static func genericOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
|
||||||
return try RawValue.genericOpenAPINode(using: encoder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Attribute: DateOpenAPINodeType where RawValue: DateOpenAPINodeType {
|
|
||||||
public static func dateOpenAPINodeGuess(using encoder: JSONEncoder) -> JSONNode? {
|
|
||||||
return RawValue.dateOpenAPINodeGuess(using: encoder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TransformedAttribute: OpenAPINodeType where RawValue: OpenAPINodeType {
|
|
||||||
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 try !RawValue.openAPINode().required {
|
|
||||||
return try RawValue.openAPINode().requiredNode().nullableNode()
|
|
||||||
}
|
|
||||||
return try RawValue.openAPINode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: conform TransformedAttribute to all of the above protocols that Attribute conforms to.
|
|
||||||
|
|
||||||
extension RelationshipType {
|
|
||||||
static func relationshipNode(nullable: Bool, jsonType: String) -> JSONNode {
|
|
||||||
let propertiesDict: [String: JSONNode] = [
|
|
||||||
"id": .string(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init()),
|
|
||||||
"type": .string(.init(format: .generic,
|
|
||||||
required: true,
|
|
||||||
allowedValues: [.init(jsonType)]),
|
|
||||||
.init())
|
|
||||||
]
|
|
||||||
|
|
||||||
return .object(.init(format: .generic,
|
|
||||||
required: true,
|
|
||||||
nullable: nullable),
|
|
||||||
.init(properties: propertiesDict))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ToOneRelationship: OpenAPINodeType {
|
|
||||||
// NOTE: const for json `type` not supported by OpenAPI 3.0
|
|
||||||
// Will use "enum" with one possible value for now.
|
|
||||||
|
|
||||||
// TODO: metadata & links
|
|
||||||
static public func openAPINode() throws -> JSONNode {
|
|
||||||
let nullable = Identifiable.self is _Optional.Type
|
|
||||||
return .object(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init(properties: [
|
|
||||||
"data": ToOneRelationship.relationshipNode(nullable: nullable, jsonType: Identifiable.jsonType)
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ToManyRelationship: OpenAPINodeType {
|
|
||||||
// NOTE: const for json `type` not supported by OpenAPI 3.0
|
|
||||||
// Will use "enum" with one possible value for now.
|
|
||||||
|
|
||||||
// TODO: metadata & links
|
|
||||||
static public func openAPINode() throws -> JSONNode {
|
|
||||||
return .object(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init(properties: [
|
|
||||||
"data": .array(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init(items: ToManyRelationship.relationshipNode(nullable: false, jsonType: Relatable.jsonType)))
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Entity: OpenAPIEncodedNodeType where Description.Attributes: Sampleable, Description.Relationships: Sampleable {
|
|
||||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
|
||||||
// NOTE: const for json `type` not supported by OpenAPI 3.0
|
|
||||||
// Will use "enum" with one possible value for now.
|
|
||||||
|
|
||||||
// TODO: metadata, links
|
|
||||||
|
|
||||||
let idNode: JSONNode? = Id.RawType.self != Unidentified.self
|
|
||||||
? JSONNode.string(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init())
|
|
||||||
: nil
|
|
||||||
let idProperty = idNode.map { ("id", $0) }
|
|
||||||
|
|
||||||
let typeNode = JSONNode.string(.init(format: .generic,
|
|
||||||
required: true,
|
|
||||||
allowedValues: [.init(Entity.jsonType)]),
|
|
||||||
.init())
|
|
||||||
let typeProperty = ("type", typeNode)
|
|
||||||
|
|
||||||
let attributesNode: JSONNode? = Description.Attributes.self == NoAttributes.self
|
|
||||||
? nil
|
|
||||||
: try Description.Attributes.genericOpenAPINode(using: encoder)
|
|
||||||
|
|
||||||
let attributesProperty = attributesNode.map { ("attributes", $0) }
|
|
||||||
|
|
||||||
let relationshipsNode: JSONNode? = Description.Relationships.self == NoRelationships.self
|
|
||||||
? nil
|
|
||||||
: try Description.Relationships.genericOpenAPINode(using: encoder)
|
|
||||||
|
|
||||||
let relationshipsProperty = relationshipsNode.map { ("relationships", $0) }
|
|
||||||
|
|
||||||
let propertiesDict = Dictionary([
|
|
||||||
idProperty,
|
|
||||||
typeProperty,
|
|
||||||
attributesProperty,
|
|
||||||
relationshipsProperty
|
|
||||||
].compactMap { $0 }) { _, value in value }
|
|
||||||
|
|
||||||
return .object(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init(properties: propertiesDict))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension SingleResourceBody: OpenAPIEncodedNodeType where Entity: OpenAPIEncodedNodeType {
|
|
||||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
|
||||||
return try Entity.openAPINode(using: encoder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ManyResourceBody: OpenAPIEncodedNodeType where Entity: OpenAPIEncodedNodeType {
|
|
||||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
|
||||||
return .array(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init(items: try Entity.openAPINode(using: encoder)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Document: OpenAPIEncodedNodeType where PrimaryResourceBody: OpenAPIEncodedNodeType, IncludeType: OpenAPINodeType {
|
|
||||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
|
||||||
// TODO: metadata, links, api description, errors
|
|
||||||
// TODO: represent data and errors as the two distinct possible outcomes
|
|
||||||
|
|
||||||
let primaryDataNode: JSONNode? = try PrimaryResourceBody.openAPINode(using: encoder)
|
|
||||||
|
|
||||||
let primaryDataProperty = primaryDataNode.map { ("data", $0) }
|
|
||||||
|
|
||||||
let includeNode: JSONNode?
|
|
||||||
do {
|
|
||||||
includeNode = try Includes<Include>.openAPINode()
|
|
||||||
} catch let err as OpenAPITypeError {
|
|
||||||
guard case .invalidNode = err else {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
includeNode = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let includeProperty = includeNode.map { ("included", $0) }
|
|
||||||
|
|
||||||
let propertiesDict = Dictionary([
|
|
||||||
primaryDataProperty,
|
|
||||||
includeProperty
|
|
||||||
].compactMap { $0 }) { _, value in value }
|
|
||||||
|
|
||||||
return .object(.init(format: .generic,
|
|
||||||
required: true),
|
|
||||||
.init(properties: propertiesDict))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
//
|
|
||||||
// Date+OpenAPI.swift
|
|
||||||
// JSONAPIOpenAPI
|
|
||||||
//
|
|
||||||
// Created by Mathew Polzin on 1/24/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
extension Date: DateOpenAPINodeType {
|
|
||||||
public static func dateOpenAPINodeGuess(using encoder: JSONEncoder) -> JSONNode? {
|
|
||||||
|
|
||||||
switch encoder.dateEncodingStrategy {
|
|
||||||
case .deferredToDate, .custom:
|
|
||||||
// I don't know if we can say anything about this case without
|
|
||||||
// encoding the Date and looking at it, which is what `primitiveGuess()`
|
|
||||||
// does.
|
|
||||||
return nil
|
|
||||||
|
|
||||||
case .secondsSince1970,
|
|
||||||
.millisecondsSince1970:
|
|
||||||
return .number(.init(format: .double,
|
|
||||||
required: true),
|
|
||||||
.init())
|
|
||||||
|
|
||||||
case .iso8601:
|
|
||||||
return .string(.init(format: .dateTime,
|
|
||||||
required: true),
|
|
||||||
.init())
|
|
||||||
|
|
||||||
case .formatted(let formatter):
|
|
||||||
let hasTime = formatter.timeStyle != .none
|
|
||||||
let format: JSONTypeFormat.StringFormat = hasTime ? .dateTime : .date
|
|
||||||
|
|
||||||
return .string(.init(format: format,
|
|
||||||
required: true),
|
|
||||||
.init())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user