mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-07-10 12:18:40 -07:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 61fa56e84b | |||
| a6bf3e0ae0 | |||
| 620f6989d2 | |||
| 715db33138 | |||
| e99abd26b3 | |||
| 099d17aa58 | |||
| 92d1239a98 | |||
| b7ce3d226e | |||
| 5b56d596e2 | |||
| e820f34253 | |||
| c75912ab79 | |||
| e4481c9e4f | |||
| e9b9a2bd78 | |||
| fc78958f76 | |||
| f73ca8bc2c | |||
| 176eca3dce | |||
| 4e0e44c45d | |||
| e09e3cd8ac | |||
| 502f82ad14 | |||
| 2bb238b092 | |||
| 491fe1fbea | |||
| 6b6f40c968 | |||
| 14bd29bf42 | |||
| cf4d8fc378 | |||
| 10b756f6db |
+5
-5
@@ -19,13 +19,13 @@ extension String: CreatableRawIdType {
|
||||
// We create a typealias given that we do not expect JSON:API Resource
|
||||
// Objects for this particular API to have Metadata or Links associated
|
||||
// with them. We also expect them to have String Identifiers.
|
||||
typealias JSONEntity<Description: EntityDescription> = JSONAPI.Entity<Description, NoMetadata, NoLinks, String>
|
||||
typealias JSONEntity<Description: ResourceObjectDescription> = JSONAPI.ResourceObject<Description, NoMetadata, NoLinks, String>
|
||||
|
||||
// Similarly, we create a typealias for unidentified entities. JSON:API
|
||||
// only allows unidentified entities (i.e. no "id" field) for client
|
||||
// requests that create new entities. In these situations, the server
|
||||
// is expected to assign the new entity a unique ID.
|
||||
typealias UnidentifiedJSONEntity<Description: EntityDescription> = JSONAPI.Entity<Description, NoMetadata, NoLinks, Unidentified>
|
||||
typealias UnidentifiedJSONEntity<Description: ResourceObjectDescription> = JSONAPI.ResourceObject<Description, NoMetadata, NoLinks, Unidentified>
|
||||
|
||||
// We create typealiases given that we do not expect JSON:API Relationships
|
||||
// for this particular API to have Metadata or Links associated
|
||||
@@ -40,7 +40,7 @@ typealias Document<PrimaryResourceBody: JSONAPI.ResourceBody, IncludeType: JSONA
|
||||
|
||||
// MARK: Entity Definitions
|
||||
|
||||
enum AuthorDescription: EntityDescription {
|
||||
enum AuthorDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "authors" }
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
@@ -52,7 +52,7 @@ enum AuthorDescription: EntityDescription {
|
||||
|
||||
typealias Author = JSONEntity<AuthorDescription>
|
||||
|
||||
enum ArticleDescription: EntityDescription {
|
||||
enum ArticleDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "articles" }
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
@@ -95,7 +95,7 @@ func articleDocument(includeAuthor: Bool) -> Either<SingleArticleDocument, Singl
|
||||
links: .none)
|
||||
|
||||
let document = SingleArticleDocument(apiDescription: .none,
|
||||
body: .init(entity: article),
|
||||
body: .init(resourceObject: article),
|
||||
includes: .none,
|
||||
meta: .none,
|
||||
links: .none)
|
||||
|
||||
+5
-5
@@ -64,7 +64,7 @@ struct ToManyRelationshipLinks: JSONAPI.Links {
|
||||
}
|
||||
|
||||
/// Description of an Author entity.
|
||||
enum AuthorDescription: EntityDescription {
|
||||
enum AuthorDescription: ResourceObjectDescription {
|
||||
static var jsonType: String { return "authors" }
|
||||
|
||||
struct Attributes: JSONAPI.Attributes {
|
||||
@@ -76,10 +76,10 @@ enum AuthorDescription: EntityDescription {
|
||||
}
|
||||
}
|
||||
|
||||
typealias Author = JSONAPI.Entity<AuthorDescription, EntityMetadata, EntityLinks, String>
|
||||
typealias Author = JSONAPI.ResourceObject<AuthorDescription, EntityMetadata, EntityLinks, String>
|
||||
|
||||
/// Description of an Article entity.
|
||||
enum ArticleDescription: EntityDescription {
|
||||
enum ArticleDescription: ResourceObjectDescription {
|
||||
static var jsonType: String { return "articles" }
|
||||
|
||||
struct Attributes: JSONAPI.Attributes {
|
||||
@@ -96,7 +96,7 @@ enum ArticleDescription: EntityDescription {
|
||||
}
|
||||
}
|
||||
|
||||
typealias Article = JSONAPI.Entity<ArticleDescription, EntityMetadata, EntityLinks, String>
|
||||
typealias Article = JSONAPI.ResourceObject<ArticleDescription, EntityMetadata, EntityLinks, String>
|
||||
|
||||
/// Metadata associated with the API Description
|
||||
struct APIDescriptionMetadata: JSONAPI.Meta {
|
||||
@@ -196,7 +196,7 @@ let documentLinks = SingleArticleDocumentLinks(otherArticlesByPrimaryAuthor: .in
|
||||
meta: .init(expiry: tomorrow)))
|
||||
|
||||
let singleArticleDocument = SingleArticleDocument(apiDescription: apiDescription,
|
||||
body: .init(entity: article),
|
||||
body: .init(resourceObject: article),
|
||||
includes: .init(values: [.init(author1), .init(author2), .init(author3)]),
|
||||
meta: documentMetadata,
|
||||
links: documentLinks)
|
||||
|
||||
@@ -11,7 +11,7 @@ Please enjoy these examples, but allow me the forced casting and the lack of err
|
||||
// MARK: - Create a request or response body with one Dog in it
|
||||
let dogFromCode = try! Dog(name: "Buddy", owner: nil)
|
||||
|
||||
let singleDogDocument = SingleDogDocument(apiDescription: .none, body: .init(entity: dogFromCode), includes: .none, meta: .none, links: .none)
|
||||
let singleDogDocument = SingleDogDocument(apiDescription: .none, body: .init(resourceObject: dogFromCode), includes: .none, meta: .none, links: .none)
|
||||
|
||||
let singleDogData = try! JSONEncoder().encode(singleDogDocument)
|
||||
|
||||
@@ -33,7 +33,7 @@ let houses = [House(attributes: .none, relationships: .none, meta: .none, links:
|
||||
let people = try! [Person(id: personIds[0], name: ["Gary", "Doe"], favoriteColor: "Orange-Red", friends: [], dogs: [dogs[0], dogs[1]], home: houses[0]), Person(id: personIds[1], name: ["Elise", "Joy"], favoriteColor: "Red", friends: [], dogs: [dogs[2]], home: houses[1])]
|
||||
|
||||
let includes = dogs.map { BatchPeopleDocument.Include($0) } + houses.map { BatchPeopleDocument.Include($0) }
|
||||
let batchPeopleDocument = BatchPeopleDocument(apiDescription: .none, body: .init(entities: people), includes: .init(values: includes), meta: .none, links: .none)
|
||||
let batchPeopleDocument = BatchPeopleDocument(apiDescription: .none, body: .init(resourceObjects: people), includes: .init(values: includes), meta: .none, links: .none)
|
||||
let batchPeopleData = try! JSONEncoder().encode(batchPeopleDocument)
|
||||
|
||||
// MARK: - Parse a request or response body with multiple people in it and dogs and houses included
|
||||
|
||||
@@ -24,12 +24,12 @@ extension String: CreatableRawIdType {
|
||||
}
|
||||
|
||||
// MARK: - typealiases for convenience
|
||||
public typealias ExampleEntity<Description: EntityDescription> = Entity<Description, NoMetadata, NoLinks, String>
|
||||
public typealias ExampleEntity<Description: ResourceObjectDescription> = ResourceObject<Description, NoMetadata, NoLinks, String>
|
||||
public typealias ToOne<E: Identifiable> = ToOneRelationship<E, NoMetadata, NoLinks>
|
||||
public typealias ToMany<E: Relatable> = ToManyRelationship<E, NoMetadata, NoLinks>
|
||||
|
||||
// MARK: - A few resource objects (entities)
|
||||
public enum PersonDescription: EntityDescription {
|
||||
public enum PersonDescription: ResourceObjectDescription {
|
||||
|
||||
public static var jsonType: String { return "people" }
|
||||
|
||||
@@ -62,13 +62,13 @@ public enum PersonDescription: EntityDescription {
|
||||
|
||||
public typealias Person = ExampleEntity<PersonDescription>
|
||||
|
||||
public extension Entity where Description == PersonDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
||||
public extension ResourceObject where Description == PersonDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
||||
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(resourceObjects: friends), dogs: .init(resourceObjects: dogs), home: .init(resourceObject: home)), meta: .none, links: .none)
|
||||
}
|
||||
}
|
||||
|
||||
public enum DogDescription: EntityDescription {
|
||||
public enum DogDescription: ResourceObjectDescription {
|
||||
|
||||
public static var jsonType: String { return "dogs" }
|
||||
|
||||
@@ -91,7 +91,7 @@ public enum DogDescription: EntityDescription {
|
||||
|
||||
public typealias Dog = ExampleEntity<DogDescription>
|
||||
|
||||
public enum AlternativeDogDescription: EntityDescription {
|
||||
public enum AlternativeDogDescription: ResourceObjectDescription {
|
||||
|
||||
public static var jsonType: String { return "dogs" }
|
||||
|
||||
@@ -119,9 +119,9 @@ public enum AlternativeDogDescription: EntityDescription {
|
||||
|
||||
public typealias AlternativeDog = ExampleEntity<AlternativeDogDescription>
|
||||
|
||||
public extension Entity where Description == DogDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
||||
public extension ResourceObject where Description == DogDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String {
|
||||
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(resourceObject: owner)), meta: .none, links: .none)
|
||||
}
|
||||
|
||||
init(name: String, owner: Person.Id) throws {
|
||||
@@ -129,7 +129,7 @@ public extension Entity where Description == DogDescription, MetaType == NoMetad
|
||||
}
|
||||
}
|
||||
|
||||
public enum HouseDescription: EntityDescription {
|
||||
public enum HouseDescription: ResourceObjectDescription {
|
||||
|
||||
public static var jsonType: String { return "houses" }
|
||||
|
||||
|
||||
+2
-3
@@ -16,7 +16,7 @@ Pod::Spec.new do |spec|
|
||||
#
|
||||
|
||||
spec.name = "JSONAPI"
|
||||
spec.version = "0.20.0"
|
||||
spec.version = "0.31.1"
|
||||
spec.summary = "Swift Codable JSON API framework."
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
@@ -93,7 +93,7 @@ See the JSON API Spec here: https://jsonapi.org/format/
|
||||
# Not including the public_header_files will make all headers public.
|
||||
#
|
||||
|
||||
spec.source_files = "Sources", "Sources/**/*.{swift}"
|
||||
spec.source_files = "Sources/JSONAPI/**/*.{swift}"
|
||||
# spec.exclude_files = "Classes/Exclude"
|
||||
|
||||
# spec.public_header_files = "Classes/**/*.h"
|
||||
@@ -119,7 +119,6 @@ See the JSON API Spec here: https://jsonapi.org/format/
|
||||
# the lib prefix of their name.
|
||||
#
|
||||
|
||||
spec.framework = "Poly"
|
||||
# spec.frameworks = "SomeFramework", "AnotherFramework"
|
||||
|
||||
# spec.library = "iconv"
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
"repositoryURL": "https://github.com/mattpolzin/Poly.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "d24d4c1214dd05f89eb1182a46592856dd0a0645",
|
||||
"version": "2.0.0"
|
||||
"revision": "38051821d7ef49e590e26e819a2fe447e50be9ff",
|
||||
"version": "2.0.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ let package = Package(
|
||||
targets: ["JSONAPITesting"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/mattpolzin/Poly.git", from: "2.0.0"),
|
||||
.package(url: "https://github.com/mattpolzin/Poly.git", .upToNextMajor(from: "2.0.0")),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
||||
@@ -30,20 +30,20 @@ public func +<R: AppendableResourceBody>(_ left: R, right: R) -> R {
|
||||
public struct SingleResourceBody<Entity: JSONAPI.MaybePrimaryResource>: ResourceBody {
|
||||
public let value: Entity
|
||||
|
||||
public init(entity: Entity) {
|
||||
self.value = entity
|
||||
public init(resourceObject: Entity) {
|
||||
self.value = resourceObject
|
||||
}
|
||||
}
|
||||
|
||||
public struct ManyResourceBody<Entity: JSONAPI.PrimaryResource>: AppendableResourceBody {
|
||||
public let values: [Entity]
|
||||
|
||||
public init(entities: [Entity]) {
|
||||
values = entities
|
||||
public init(resourceObjects: [Entity]) {
|
||||
values = resourceObjects
|
||||
}
|
||||
|
||||
public func appending(_ other: ManyResourceBody) -> ManyResourceBody {
|
||||
return ManyResourceBody(entities: values + other.values)
|
||||
return ManyResourceBody(resourceObjects: values + other.values)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
//
|
||||
// EmptyObjectDecoder.swift
|
||||
// JSONAPI
|
||||
//
|
||||
// Created by Mathew Polzin on 7/2/19.
|
||||
//
|
||||
|
||||
/// `EmptyObjectDecoder` exists internally for the sole purpose of
|
||||
/// allowing certain fallback logic paths to attempt to create `Decodable`
|
||||
/// types from empty containers (specifically in a way that is agnostic
|
||||
/// of any given encoding). In other words, this serves the same purpose
|
||||
/// as `JSONDecoder().decode(Thing.self, from: "{}".data(using: .utf8)!)`
|
||||
/// without needing to use a third party or `Foundation` library decoder.
|
||||
struct EmptyObjectDecoder: Decoder {
|
||||
|
||||
var codingPath: [CodingKey] = []
|
||||
|
||||
var userInfo: [CodingUserInfoKey : Any] = [:]
|
||||
|
||||
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
|
||||
return KeyedDecodingContainer(EmptyKeyedContainer())
|
||||
}
|
||||
|
||||
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
|
||||
return EmptyUnkeyedContainer()
|
||||
}
|
||||
|
||||
func singleValueContainer() throws -> SingleValueDecodingContainer {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeSingleValue
|
||||
}
|
||||
}
|
||||
|
||||
enum EmptyObjectDecodingError: Swift.Error {
|
||||
case emptyObjectCannotBeSingleValue
|
||||
case emptyObjectCannotBeUnkeyedValues
|
||||
case emptyObjectCannotHaveKeyedValues
|
||||
case emptyObjectCannotHaveNestedContainers
|
||||
case emptyObjectCannotHaveSuper
|
||||
}
|
||||
|
||||
struct EmptyUnkeyedContainer: UnkeyedDecodingContainer {
|
||||
var codingPath: [CodingKey] { return [] }
|
||||
|
||||
var count: Int? { return 0 }
|
||||
|
||||
var isAtEnd: Bool { return true }
|
||||
|
||||
var currentIndex: Int { return 0 }
|
||||
|
||||
mutating func decodeNil() throws -> Bool {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Bool.Type) throws -> Bool {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: String.Type) throws -> String {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Double.Type) throws -> Double {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Float.Type) throws -> Float {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Int.Type) throws -> Int {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Int8.Type) throws -> Int8 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Int16.Type) throws -> Int16 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Int32.Type) throws -> Int32 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: Int64.Type) throws -> Int64 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: UInt.Type) throws -> UInt {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: UInt8.Type) throws -> UInt8 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: UInt16.Type) throws -> UInt16 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: UInt32.Type) throws -> UInt32 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode(_ type: UInt64.Type) throws -> UInt64 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotBeUnkeyedValues
|
||||
}
|
||||
|
||||
mutating func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveNestedContainers
|
||||
}
|
||||
|
||||
mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveNestedContainers
|
||||
}
|
||||
|
||||
mutating func superDecoder() throws -> Decoder {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveSuper
|
||||
}
|
||||
}
|
||||
|
||||
struct EmptyKeyedContainer<Key: CodingKey>: KeyedDecodingContainerProtocol {
|
||||
var codingPath: [CodingKey] { return [] }
|
||||
|
||||
var allKeys: [Key] { return [] }
|
||||
|
||||
func contains(_ key: Key) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func decodeNil(forKey key: Key) throws -> Bool {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: String.Type, forKey key: Key) throws -> String {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveKeyedValues
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveNestedContainers
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveNestedContainers
|
||||
}
|
||||
|
||||
func superDecoder() throws -> Decoder {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveSuper
|
||||
}
|
||||
|
||||
func superDecoder(forKey key: Key) throws -> Decoder {
|
||||
throw EmptyObjectDecodingError.emptyObjectCannotHaveSuper
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public protocol CreatableIdType: IdType {
|
||||
init()
|
||||
}
|
||||
|
||||
/// An Entity ID. These IDs can be encoded to or decoded from
|
||||
/// An ResourceObject ID. These IDs can be encoded to or decoded from
|
||||
/// JSON API IDs.
|
||||
public struct Id<RawType: MaybeRawId, IdentifiableType: JSONAPI.JSONTyped>: Equatable, OptionalId {
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ public protocol RelationshipType {
|
||||
var meta: MetaType { get }
|
||||
}
|
||||
|
||||
/// An Entity relationship that can be encoded to or decoded from
|
||||
/// An ResourceObject relationship that can be encoded to or decoded from
|
||||
/// a JSON API "Resource Linkage."
|
||||
/// See https://jsonapi.org/format/#document-resource-object-linkage
|
||||
/// A convenient typealias might make your code much more legible: `One<EntityDescription>`
|
||||
/// A convenient typealias might make your code much more legible: `One<ResourceObjectDescription>`
|
||||
public struct ToOneRelationship<Identifiable: JSONAPI.Identifiable, MetaType: JSONAPI.Meta, LinksType: JSONAPI.Links>: RelationshipType, Equatable {
|
||||
|
||||
public let id: Identifiable.Identifier
|
||||
@@ -38,33 +38,33 @@ extension ToOneRelationship where MetaType == NoMetadata, LinksType == NoLinks {
|
||||
}
|
||||
|
||||
extension ToOneRelationship {
|
||||
public init<E: EntityType>(entity: E, meta: MetaType, links: LinksType) where E.Id == Identifiable.Identifier {
|
||||
self.init(id: entity.id, meta: meta, links: links)
|
||||
public init<T: ResourceObjectType>(resourceObject: T, meta: MetaType, links: LinksType) where T.Id == Identifiable.Identifier {
|
||||
self.init(id: resourceObject.id, meta: meta, links: links)
|
||||
}
|
||||
}
|
||||
|
||||
extension ToOneRelationship where MetaType == NoMetadata, LinksType == NoLinks {
|
||||
public init<E: EntityType>(entity: E) where E.Id == Identifiable.Identifier {
|
||||
self.init(id: entity.id, meta: .none, links: .none)
|
||||
public init<T: ResourceObjectType>(resourceObject: T) where T.Id == Identifiable.Identifier {
|
||||
self.init(id: resourceObject.id, meta: .none, links: .none)
|
||||
}
|
||||
}
|
||||
|
||||
extension ToOneRelationship where Identifiable: OptionalRelatable {
|
||||
public init<E: EntityType>(entity: E?, meta: MetaType, links: LinksType) where E.Id == Identifiable.Wrapped.Identifier {
|
||||
self.init(id: entity?.id, meta: meta, links: links)
|
||||
public init<T: ResourceObjectType>(resourceObject: T?, meta: MetaType, links: LinksType) where T.Id == Identifiable.Wrapped.Identifier {
|
||||
self.init(id: resourceObject?.id, meta: meta, links: links)
|
||||
}
|
||||
}
|
||||
|
||||
extension ToOneRelationship where Identifiable: OptionalRelatable, MetaType == NoMetadata, LinksType == NoLinks {
|
||||
public init<E: EntityType>(entity: E?) where E.Id == Identifiable.Wrapped.Identifier {
|
||||
self.init(id: entity?.id, meta: .none, links: .none)
|
||||
public init<T: ResourceObjectType>(resourceObject: T?) where T.Id == Identifiable.Wrapped.Identifier {
|
||||
self.init(id: resourceObject?.id, meta: .none, links: .none)
|
||||
}
|
||||
}
|
||||
|
||||
/// An Entity relationship that can be encoded to or decoded from
|
||||
/// An ResourceObject relationship that can be encoded to or decoded from
|
||||
/// a JSON API "Resource Linkage."
|
||||
/// See https://jsonapi.org/format/#document-resource-object-linkage
|
||||
/// A convenient typealias might make your code much more legible: `Many<EntityDescription>`
|
||||
/// A convenient typealias might make your code much more legible: `Many<ResourceObjectDescription>`
|
||||
public struct ToManyRelationship<Relatable: JSONAPI.Relatable, MetaType: JSONAPI.Meta, LinksType: JSONAPI.Links>: RelationshipType, Equatable {
|
||||
|
||||
public let ids: [Relatable.Identifier]
|
||||
@@ -84,8 +84,8 @@ public struct ToManyRelationship<Relatable: JSONAPI.Relatable, MetaType: JSONAPI
|
||||
self.links = links
|
||||
}
|
||||
|
||||
public init<E: EntityType>(entities: [E], meta: MetaType, links: LinksType) where E.Id == Relatable.Identifier {
|
||||
self.init(ids: entities.map { $0.id }, meta: meta, links: links)
|
||||
public init<T: ResourceObjectType>(resourceObjects: [T], meta: MetaType, links: LinksType) where T.Id == Relatable.Identifier {
|
||||
self.init(ids: resourceObjects.map { $0.id }, meta: meta, links: links)
|
||||
}
|
||||
|
||||
private init(meta: MetaType, links: LinksType) {
|
||||
@@ -111,8 +111,8 @@ extension ToManyRelationship where MetaType == NoMetadata, LinksType == NoLinks
|
||||
return .none(withMeta: .none, links: .none)
|
||||
}
|
||||
|
||||
public init<E: EntityType>(entities: [E]) where E.Id == Relatable.Identifier {
|
||||
self.init(entities: entities, meta: .none, links: .none)
|
||||
public init<T: ResourceObjectType>(resourceObjects: [T]) where T.Id == Relatable.Identifier {
|
||||
self.init(resourceObjects: resourceObjects, meta: .none, links: .none)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+144
-139
File diff suppressed because it is too large
Load Diff
+8
-8
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// EntityCheck.swift
|
||||
// ResourceObjectCheck.swift
|
||||
// JSONAPITesting
|
||||
//
|
||||
// Created by Mathew Polzin on 11/27/18.
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import JSONAPI
|
||||
|
||||
public enum EntityCheckError: Swift.Error {
|
||||
public enum ResourceObjectCheckError: Swift.Error {
|
||||
/// The attributes should live in a struct, not
|
||||
/// another type class.
|
||||
case attributesNotStruct
|
||||
@@ -29,8 +29,8 @@ public enum EntityCheckError: Swift.Error {
|
||||
case nullArray(named: String)
|
||||
}
|
||||
|
||||
public struct EntityCheckErrors: Swift.Error {
|
||||
let problems: [EntityCheckError]
|
||||
public struct ResourceObjectCheckErrors: Swift.Error {
|
||||
let problems: [ResourceObjectCheckError]
|
||||
}
|
||||
|
||||
private protocol OptionalAttributeType {}
|
||||
@@ -54,9 +54,9 @@ private protocol _AttributeType {}
|
||||
extension TransformedAttribute: _AttributeType {}
|
||||
extension Attribute: _AttributeType {}
|
||||
|
||||
public extension Entity {
|
||||
static func check(_ entity: Entity) throws {
|
||||
var problems = [EntityCheckError]()
|
||||
public extension ResourceObject {
|
||||
static func check(_ entity: ResourceObject) throws {
|
||||
var problems = [ResourceObjectCheckError]()
|
||||
|
||||
let attributesMirror = Mirror(reflecting: entity.attributes)
|
||||
|
||||
@@ -88,7 +88,7 @@ public extension Entity {
|
||||
}
|
||||
|
||||
guard problems.count == 0 else {
|
||||
throw EntityCheckErrors(problems: problems)
|
||||
throw ResourceObjectCheckErrors(problems: problems)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ class EntityCheckTests: XCTestCase {
|
||||
|
||||
// MARK: - Test types
|
||||
extension EntityCheckTests {
|
||||
enum OkDescription: EntityDescription {
|
||||
enum OkDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "hello" }
|
||||
|
||||
public typealias Attributes = NoAttributes
|
||||
@@ -49,7 +49,7 @@ extension EntityCheckTests {
|
||||
|
||||
public typealias OkEntity = BasicEntity<OkDescription>
|
||||
|
||||
enum OtherOkDescription: EntityDescription {
|
||||
enum OtherOkDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "hmm" }
|
||||
|
||||
public typealias Attributes = NoAttributes
|
||||
@@ -58,7 +58,7 @@ extension EntityCheckTests {
|
||||
|
||||
public typealias OtherOkEntity = BasicEntity<OtherOkDescription>
|
||||
|
||||
enum EnumAttributesDescription: EntityDescription {
|
||||
enum EnumAttributesDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "hello" }
|
||||
|
||||
public enum Attributes: JSONAPI.Attributes {
|
||||
@@ -77,7 +77,7 @@ extension EntityCheckTests {
|
||||
|
||||
public typealias EnumAttributesEntity = BasicEntity<EnumAttributesDescription>
|
||||
|
||||
enum EnumRelationshipsDescription: EntityDescription {
|
||||
enum EnumRelationshipsDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "hello" }
|
||||
|
||||
public typealias Attributes = NoAttributes
|
||||
@@ -96,7 +96,7 @@ extension EntityCheckTests {
|
||||
|
||||
public typealias EnumRelationshipsEntity = BasicEntity<EnumRelationshipsDescription>
|
||||
|
||||
enum BadAttributeDescription: EntityDescription {
|
||||
enum BadAttributeDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "hello" }
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
@@ -109,7 +109,7 @@ extension EntityCheckTests {
|
||||
|
||||
public typealias BadAttributeEntity = BasicEntity<BadAttributeDescription>
|
||||
|
||||
enum BadRelationshipDescription: EntityDescription {
|
||||
enum BadRelationshipDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "hello" }
|
||||
|
||||
public typealias Attributes = NoAttributes
|
||||
@@ -122,7 +122,7 @@ extension EntityCheckTests {
|
||||
|
||||
public typealias BadRelationshipEntity = BasicEntity<BadRelationshipDescription>
|
||||
|
||||
enum OptionalArrayAttributeDescription: EntityDescription {
|
||||
enum OptionalArrayAttributeDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "hello" }
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
|
||||
@@ -24,7 +24,7 @@ class Id_LiteralTests: XCTestCase {
|
||||
|
||||
// MARK: - Test types
|
||||
extension Id_LiteralTests {
|
||||
enum TestDescription: EntityDescription {
|
||||
enum TestDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "test" }
|
||||
|
||||
public typealias Attributes = NoAttributes
|
||||
|
||||
@@ -27,7 +27,7 @@ class Relationship_LiteralTests: XCTestCase {
|
||||
|
||||
// MARK: - Test types
|
||||
extension Relationship_LiteralTests {
|
||||
enum TestDescription: EntityDescription {
|
||||
enum TestDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "test" }
|
||||
|
||||
public typealias Attributes = NoAttributes
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
import JSONAPI
|
||||
|
||||
public typealias Entity<Description: JSONAPI.EntityDescription, Meta: JSONAPI.Meta, Links: JSONAPI.Links> = JSONAPI.Entity<Description, Meta, Links, String>
|
||||
public typealias Entity<Description: JSONAPI.ResourceObjectDescription, Meta: JSONAPI.Meta, Links: JSONAPI.Links> = JSONAPI.ResourceObject<Description, Meta, Links, String>
|
||||
|
||||
public typealias BasicEntity<Description: JSONAPI.EntityDescription> = Entity<Description, NoMetadata, NoLinks>
|
||||
public typealias BasicEntity<Description: JSONAPI.ResourceObjectDescription> = Entity<Description, NoMetadata, NoLinks>
|
||||
|
||||
public typealias NewEntity<Description: JSONAPI.EntityDescription, Meta: JSONAPI.Meta, Links: JSONAPI.Links> = JSONAPI.Entity<Description, Meta, Links, Unidentified>
|
||||
public typealias NewEntity<Description: JSONAPI.ResourceObjectDescription, Meta: JSONAPI.Meta, Links: JSONAPI.Links> = JSONAPI.ResourceObject<Description, Meta, Links, Unidentified>
|
||||
|
||||
@@ -37,7 +37,7 @@ class Attribute_FunctorTests: XCTestCase {
|
||||
|
||||
// MARK: Test types
|
||||
extension Attribute_FunctorTests {
|
||||
enum TestTypeDescription: EntityDescription {
|
||||
enum TestTypeDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "test" }
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
|
||||
@@ -27,13 +27,13 @@ class ComputedPropertiesTests: XCTestCase {
|
||||
let entity = decoded(type: TestType.self, data: computed_property_attribute)
|
||||
|
||||
XCTAssertEqual(entity[\.computed], "Sarah2")
|
||||
XCTAssertEqual(entity[\.secretsOut], "shhhh")
|
||||
XCTAssertEqual(entity[direct: \.directSecretsOut], "shhhh")
|
||||
}
|
||||
|
||||
func test_ComputedNonAttributeAccess() {
|
||||
let entity = decoded(type: TestType.self, data: computed_property_attribute)
|
||||
|
||||
XCTAssertEqual(entity[\.computed2], "Sarah2")
|
||||
XCTAssertEqual(entity[direct: \.directComputed], "Sarah2")
|
||||
}
|
||||
|
||||
func test_ComputedRelationshipAccess() {
|
||||
@@ -45,7 +45,7 @@ class ComputedPropertiesTests: XCTestCase {
|
||||
|
||||
// MARK: Test types
|
||||
extension ComputedPropertiesTests {
|
||||
public enum TestTypeDescription: EntityDescription {
|
||||
public enum TestTypeDescription: ResourceObjectDescription {
|
||||
public static var jsonType: String { return "test" }
|
||||
|
||||
public struct Attributes: JSONAPI.Attributes {
|
||||
@@ -56,11 +56,11 @@ extension ComputedPropertiesTests {
|
||||
return name.map { $0 + "2" }
|
||||
}
|
||||
|
||||
public var computed2: String {
|
||||
public var directComputed: String {
|
||||
return computed.value
|
||||
}
|
||||
|
||||
public var secretsOut: String {
|
||||
public var directSecretsOut: String {
|
||||
return secret.value
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user