From 9027a7f5e6bbfbc52546b5bfe3f78d7a0ea74895 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 29 May 2020 18:40:48 -0700 Subject: [PATCH 1/5] Had to change course due to type system errors with collision between one protocol's typealias and another's associatedtype --- .../Contents.swift | 4 ++-- .../Contents.swift | 10 +++++----- .../Usage.xcplaygroundpage/Contents.swift | 6 +++--- JSONAPI.playground/Sources/Entities.swift | 8 ++++---- README.md | 4 ++-- Sources/JSONAPI/Resource/Relationship.swift | 12 +++++------ .../Resource Object/ResourceObject.swift | 20 +++++++++---------- .../DocumentCompoundResourceTests.swift | 6 +++--- Tests/JSONAPITests/Poly/PolyProxyTests.swift | 4 ++-- .../ResourceObject/ResourceObjectTests.swift | 4 ++-- documentation/usage.md | 12 +++++------ 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift index 7a83541..280a614 100644 --- a/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift @@ -30,7 +30,7 @@ typealias UnidentifiedJSONEntity = JSONA // Create relationship typealiases because we do not expect // JSON:API Relationships for this particular API to have // Metadata or Links associated with them. -typealias ToOneRelationship = JSONAPI.ToOneRelationship +typealias ToOneRelationship = JSONAPI.ToOneRelationship typealias ToManyRelationship = JSONAPI.ToManyRelationship // Create a typealias for a Document because we do not expect @@ -86,7 +86,7 @@ typealias SingleArticleDocument = Document, NoInclud func articleDocument(includeAuthor: Bool) -> Either { // Let's pretend all of this is coming from a database: - let authorId = Author.ID(rawValue: "1234") + let authorId = Author.Identifier(rawValue: "1234") let article = Article(id: .init(rawValue: "5678"), attributes: .init(title: .init(value: "JSON:API in Swift"), diff --git a/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift index 2628c38..81f985b 100644 --- a/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift @@ -129,9 +129,9 @@ enum ArticleDocumentError: String, JSONAPIError, Codable { typealias SingleArticleDocument = JSONAPI.Document, DocumentMetadata, SingleArticleDocumentLinks, Include1, APIDescription, ArticleDocumentError> // MARK: - Instantiations -let authorId1 = Author.ID() -let authorId2 = Author.ID() -let authorId3 = Author.ID() +let authorId1 = Author.Identifier() +let authorId2 = Author.Identifier() +let authorId3 = Author.Identifier() let now = Date() let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: now)! @@ -155,7 +155,7 @@ let author1Links = EntityLinks(selfLink: .init(url: URL(string: "https://article meta: .init(expiry: tomorrow))) let author1 = Author(id: authorId1, attributes: .init(name: .init(value: "James Kinney")), - relationships: .init(articles: .init(ids: [article.id, Article.ID(), Article.ID()], + relationships: .init(articles: .init(ids: [article.id, Article.Identifier(), Article.Identifier()], meta: .init(pagination: .init(total: 3, limit: 50, offset: 0)), @@ -167,7 +167,7 @@ let author2Links = EntityLinks(selfLink: .init(url: URL(string: "https://article meta: .init(expiry: tomorrow))) let author2 = Author(id: authorId2, attributes: .init(name: .init(value: "James Kinney")), - relationships: .init(articles: .init(ids: [article.id, Article.ID()], + relationships: .init(articles: .init(ids: [article.id, Article.Identifier()], meta: .init(pagination: .init(total: 2, limit: 50, offset: 0)), diff --git a/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift index 48296f0..5917bef 100644 --- a/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift @@ -20,18 +20,18 @@ let singleDogData = try! JSONEncoder().encode(singleDogDocument) // MARK: - Parse a request or response body with one Dog in it let dogResponse = try! JSONDecoder().decode(SingleDogDocument.self, from: singleDogData) let dogFromData = dogResponse.body.primaryResource?.value -let dogOwner: Person.ID? = dogFromData.flatMap { $0 ~> \.owner } +let dogOwner: Person.Identifier? = dogFromData.flatMap { $0 ~> \.owner } // MARK: - Parse a request or response body with one Dog in it using an alternative model typealias AltSingleDogDocument = JSONAPI.Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, BasicJSONAPIError> let altDogResponse = try! JSONDecoder().decode(AltSingleDogDocument.self, from: singleDogData) let altDogFromData = altDogResponse.body.primaryResource?.value -let altDogHuman: Person.ID? = altDogFromData.flatMap { $0 ~> \.human } +let altDogHuman: Person.Identifier? = altDogFromData.flatMap { $0 ~> \.human } // MARK: - Create a request or response with multiple people and dogs and houses included -let personIds = [Person.ID(), Person.ID()] +let personIds = [Person.Identifier(), Person.Identifier()] let dogs = try! [Dog(name: "Buddy", owner: personIds[0]), Dog(name: "Joy", owner: personIds[0]), Dog(name: "Travis", owner: personIds[1])] let houses = [House(attributes: .none, relationships: .none, meta: .none, links: .none), House(attributes: .none, relationships: .none, meta: .none, links: .none)] 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])] diff --git a/JSONAPI.playground/Sources/Entities.swift b/JSONAPI.playground/Sources/Entities.swift index 8b1564a..1bd6109 100644 --- a/JSONAPI.playground/Sources/Entities.swift +++ b/JSONAPI.playground/Sources/Entities.swift @@ -25,7 +25,7 @@ extension String: CreatableRawIdType { // MARK: - typealiases for convenience public typealias ExampleEntity = ResourceObject -public typealias ToOne = ToOneRelationship +public typealias ToOne = ToOneRelationship public typealias ToMany = ToManyRelationship // MARK: - A few resource objects (entities) @@ -63,8 +63,8 @@ public enum PersonDescription: ResourceObjectDescription { public typealias Person = ExampleEntity 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(resourceObjects: friends), dogs: .init(resourceObjects: dogs), home: .init(resourceObject: home)), meta: .none, links: .none) + 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(resourceObjects: friends), dogs: .init(resourceObjects: dogs), home: .init(resourceObject: home)), meta: .none, links: .none) } } @@ -147,7 +147,7 @@ public extension ResourceObject where Description == DogDescription, MetaType == 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 { + 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) } } diff --git a/README.md b/README.md index e735354..d1b28a7 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ typealias UnidentifiedJSONEntity = JSONA // Create relationship typealiases because we do not expect // JSON:API Relationships for this particular API to have // Metadata or Links associated with them. -typealias ToOneRelationship = JSONAPI.ToOneRelationship +typealias ToOneRelationship = JSONAPI.ToOneRelationship typealias ToManyRelationship = JSONAPI.ToManyRelationship // Create a typealias for a Document because we do not expect @@ -220,7 +220,7 @@ typealias SingleArticleDocument = Document, NoInclud func articleDocument(includeAuthor: Bool) -> Either { // Let's pretend all of this is coming from a database: - let authorId = Author.ID(rawValue: "1234") + let authorId = Author.Identifier(rawValue: "1234") let article = Article(id: .init(rawValue: "5678"), attributes: .init(title: .init(value: "JSON:API in Swift"), diff --git a/Sources/JSONAPI/Resource/Relationship.swift b/Sources/JSONAPI/Resource/Relationship.swift index 0ab0dbf..8b44a81 100644 --- a/Sources/JSONAPI/Resource/Relationship.swift +++ b/Sources/JSONAPI/Resource/Relationship.swift @@ -56,25 +56,25 @@ extension ToOneRelationship where MetaType == NoMetadata, LinksType == NoLinks { } extension ToOneRelationship { - public init(resourceObject: T, meta: MetaType, links: LinksType) where T.ID == Identifiable.ID { + public init(resourceObject: T, meta: MetaType, links: LinksType) where T.Id == Identifiable.ID { self.init(id: resourceObject.id, meta: meta, links: links) } } extension ToOneRelationship where MetaType == NoMetadata, LinksType == NoLinks { - public init(resourceObject: T) where T.ID == Identifiable.ID { + public init(resourceObject: T) where T.Id == Identifiable.ID { self.init(id: resourceObject.id, meta: .none, links: .none) } } extension ToOneRelationship where Identifiable: OptionalRelatable { - public init(resourceObject: T?, meta: MetaType, links: LinksType) where T.ID == Identifiable.Wrapped.ID { + public init(resourceObject: T?, meta: MetaType, links: LinksType) where T.Id == Identifiable.Wrapped.ID { self.init(id: resourceObject?.id, meta: meta, links: links) } } extension ToOneRelationship where Identifiable: OptionalRelatable, MetaType == NoMetadata, LinksType == NoLinks { - public init(resourceObject: T?) where T.ID == Identifiable.Wrapped.ID { + public init(resourceObject: T?) where T.Id == Identifiable.Wrapped.ID { self.init(id: resourceObject?.id, meta: .none, links: .none) } } @@ -102,7 +102,7 @@ public struct ToManyRelationship(resourceObjects: [T], meta: MetaType, links: LinksType) where T.ID == Relatable.ID { + public init(resourceObjects: [T], meta: MetaType, links: LinksType) where T.Id == Relatable.ID { self.init(ids: resourceObjects.map(\.id), meta: meta, links: links) } @@ -129,7 +129,7 @@ extension ToManyRelationship where MetaType == NoMetadata, LinksType == NoLinks return .none(withMeta: .none, links: .none) } - public init(resourceObjects: [T]) where T.ID == Relatable.ID { + public init(resourceObjects: [T]) where T.Id == Relatable.ID { self.init(resourceObjects: resourceObjects, meta: .none, links: .none) } } diff --git a/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift b/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift index 88ae539..9ac95d8 100644 --- a/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift +++ b/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift @@ -73,6 +73,8 @@ public protocol ResourceObjectProxy: Equatable, JSONTyped { associatedtype Description: ResourceObjectProxyDescription associatedtype EntityRawIdType: JSONAPI.MaybeRawId + typealias Id = JSONAPI.Id + typealias Attributes = Description.Attributes typealias Relationships = Description.Relationships @@ -80,7 +82,7 @@ public protocol ResourceObjectProxy: Equatable, JSONTyped { /// the entity is being created clientside and the /// server is being asked to create a unique Id. Otherwise, /// this should be of a type conforming to `IdType`. - var id: JSONAPI.Id { get } + var id: Id { get } /// The JSON API compliant attributes of this `Entity`. var attributes: Attributes { get } @@ -89,10 +91,6 @@ public protocol ResourceObjectProxy: Equatable, JSONTyped { var relationships: Relationships { get } } -extension ResourceObjectProxy { - public typealias ID = JSONAPI.Id -} - extension ResourceObjectProxy { /// The JSON API compliant "type" of this `ResourceObject`. public static var jsonType: String { return Description.jsonType } @@ -130,7 +128,7 @@ public struct ResourceObject { switch self { case .a(let a): - return ID(rawValue: a.id.rawValue) + return Id(rawValue: a.id.rawValue) case .b(let b): - return ID(rawValue: b.id.rawValue) + return Id(rawValue: b.id.rawValue) } } diff --git a/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift b/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift index bf4b6be..b7b6dca 100644 --- a/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift +++ b/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift @@ -92,8 +92,8 @@ class ResourceObjectTests: XCTestCase { let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(meta: .init(meta: .init(x: "hello", y: 5), links: .none), optionalMeta: nil, one: entity1.pointer, nullableOne: nil, optionalOne: nil, optionalNullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalMany: nil), meta: .none, links: .none) let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(meta: .init(meta: .init(x: "hello", y: 5), links: .none), optionalMeta: nil, one: entity1.pointer, nullableOne: nil, optionalOne: nil, optionalNullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalMany: .init(resourceObjects: [], meta: .none, links: .none)), meta: .none, links: .none) let e10id1 = TestEntity10.ID(rawValue: "hello") - let e10id2 = TestEntity10.ID(rawValue: "world") - let e10id3: TestEntity10.ID = "!" + let e10id2 = TestEntity10.Id(rawValue: "world") + let e10id3: TestEntity10.Id = "!" let _ = TestEntity10(id: .init(rawValue: "10"), attributes: .none, relationships: .init(selfRef: .init(id: e10id1), selfRefs: .init(ids: [e10id2, e10id3])), meta: .none, links: .none) XCTAssertNoThrow(try TestEntity11(id: .init(rawValue: "11"), attributes: .init(number: .init(rawValue: 11)), relationships: .none, meta: .none, links: .none)) let _ = UnidentifiedTestEntity(attributes: .init(me: .init(value: "hello")), relationships: .none, meta: .none, links: .none) diff --git a/documentation/usage.md b/documentation/usage.md index 7c11597..a295347 100644 --- a/documentation/usage.md +++ b/documentation/usage.md @@ -167,7 +167,7 @@ typealias Relationships = NoRelationships `Relationship` values boil down to `Ids` of other resource objects. To access the `Id` of a related `ResourceObject`, you can use the custom `~>` operator with the `KeyPath` of the `Relationship` from which you want the `Id`. The friends of the above `Person` `ResourceObject` can be accessed as follows (type annotations for clarity): ```swift -let friendIds: [Person.ID] = person ~> \.friends +let friendIds: [Person.Identifier] = person ~> \.friends ``` ### `JSONAPI.Attributes` @@ -244,8 +244,8 @@ If your computed property is wrapped in a `AttributeType` then you can still use ### Copying/Mutating `ResourceObjects` `ResourceObject` is a value type, so copying is its default behavior. There are three common mutations you might want to make when copying a `ResourceObject`: -1. Assigning a new `ID` to the copy of an identified `ResourceObject`. -2. Assigning a new `ID` to the copy of an unidentified `ResourceObject`. +1. Assigning a new `Identifier` to the copy of an identified `ResourceObject`. +2. Assigning a new `Identifier` to the copy of an unidentified `ResourceObject`. 3. Change attribute or relationship values. The first two can be accomplished with code like the following: @@ -595,9 +595,9 @@ enum UserDescription: ResourceObjectDescription { } struct Relationships: JSONAPI.Relationships { - public var friend: (User) -> User.ID { + public var friend: (User) -> User.Identifier { return { user in - return User.ID(rawValue: user.friend_id) + return User.Identifier(rawValue: user.friend_id) } } } @@ -612,4 +612,4 @@ Given a value `user` of the above resource object type, you can access the `frie let friendId = user ~> \.friend ``` -This works because `friend` is defined in the form: `var {name}: ({ResourceObject}) -> {ID}` where `{ResourceObject}` is the `JSONAPI.ResourceObject` described by the `ResourceObjectDescription` containing the meta-relationship. +This works because `friend` is defined in the form: `var {name}: ({ResourceObject}) -> {Identifier}` where `{ResourceObject}` is the `JSONAPI.ResourceObject` described by the `ResourceObjectDescription` containing the meta-relationship. From 540199146c01b3a7514b7ea5ba0df87292c79fb9 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 29 May 2020 18:59:39 -0700 Subject: [PATCH 2/5] re-update documentation --- .../Contents.swift | 2 +- .../Contents.swift | 10 +++++----- .../Pages/Usage.xcplaygroundpage/Contents.swift | 6 +++--- README.md | 4 ++-- documentation/usage.md | 12 ++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift index 280a614..5cc9cef 100644 --- a/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift @@ -86,7 +86,7 @@ typealias SingleArticleDocument = Document, NoInclud func articleDocument(includeAuthor: Bool) -> Either { // Let's pretend all of this is coming from a database: - let authorId = Author.Identifier(rawValue: "1234") + let authorId = Author.Id(rawValue: "1234") let article = Article(id: .init(rawValue: "5678"), attributes: .init(title: .init(value: "JSON:API in Swift"), diff --git a/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift index 81f985b..678296e 100644 --- a/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Full Document Verbose Generation.xcplaygroundpage/Contents.swift @@ -129,9 +129,9 @@ enum ArticleDocumentError: String, JSONAPIError, Codable { typealias SingleArticleDocument = JSONAPI.Document, DocumentMetadata, SingleArticleDocumentLinks, Include1, APIDescription, ArticleDocumentError> // MARK: - Instantiations -let authorId1 = Author.Identifier() -let authorId2 = Author.Identifier() -let authorId3 = Author.Identifier() +let authorId1 = Author.Id() +let authorId2 = Author.Id() +let authorId3 = Author.Id() let now = Date() let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: now)! @@ -155,7 +155,7 @@ let author1Links = EntityLinks(selfLink: .init(url: URL(string: "https://article meta: .init(expiry: tomorrow))) let author1 = Author(id: authorId1, attributes: .init(name: .init(value: "James Kinney")), - relationships: .init(articles: .init(ids: [article.id, Article.Identifier(), Article.Identifier()], + relationships: .init(articles: .init(ids: [article.id, Article.Id(), Article.Id()], meta: .init(pagination: .init(total: 3, limit: 50, offset: 0)), @@ -167,7 +167,7 @@ let author2Links = EntityLinks(selfLink: .init(url: URL(string: "https://article meta: .init(expiry: tomorrow))) let author2 = Author(id: authorId2, attributes: .init(name: .init(value: "James Kinney")), - relationships: .init(articles: .init(ids: [article.id, Article.Identifier()], + relationships: .init(articles: .init(ids: [article.id, Article.Id()], meta: .init(pagination: .init(total: 2, limit: 50, offset: 0)), diff --git a/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift index 5917bef..1d3da07 100644 --- a/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift @@ -20,18 +20,18 @@ let singleDogData = try! JSONEncoder().encode(singleDogDocument) // MARK: - Parse a request or response body with one Dog in it let dogResponse = try! JSONDecoder().decode(SingleDogDocument.self, from: singleDogData) let dogFromData = dogResponse.body.primaryResource?.value -let dogOwner: Person.Identifier? = dogFromData.flatMap { $0 ~> \.owner } +let dogOwner: Person.Id? = dogFromData.flatMap { $0 ~> \.owner } // MARK: - Parse a request or response body with one Dog in it using an alternative model typealias AltSingleDogDocument = JSONAPI.Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, BasicJSONAPIError> let altDogResponse = try! JSONDecoder().decode(AltSingleDogDocument.self, from: singleDogData) let altDogFromData = altDogResponse.body.primaryResource?.value -let altDogHuman: Person.Identifier? = altDogFromData.flatMap { $0 ~> \.human } +let altDogHuman: Person.Id? = altDogFromData.flatMap { $0 ~> \.human } // MARK: - Create a request or response with multiple people and dogs and houses included -let personIds = [Person.Identifier(), Person.Identifier()] +let personIds = [Person.Id(), Person.Id()] let dogs = try! [Dog(name: "Buddy", owner: personIds[0]), Dog(name: "Joy", owner: personIds[0]), Dog(name: "Travis", owner: personIds[1])] let houses = [House(attributes: .none, relationships: .none, meta: .none, links: .none), House(attributes: .none, relationships: .none, meta: .none, links: .none)] 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])] diff --git a/README.md b/README.md index d1b28a7..54a0997 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ extension String: CreatableRawIdType { // Create a typealias because 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. +// with them. We also expect them to have String Ids. typealias JSONEntity = JSONAPI.ResourceObject // Similarly, create a typealias for unidentified entities. JSON:API @@ -220,7 +220,7 @@ typealias SingleArticleDocument = Document, NoInclud func articleDocument(includeAuthor: Bool) -> Either { // Let's pretend all of this is coming from a database: - let authorId = Author.Identifier(rawValue: "1234") + let authorId = Author.Id(rawValue: "1234") let article = Article(id: .init(rawValue: "5678"), attributes: .init(title: .init(value: "JSON:API in Swift"), diff --git a/documentation/usage.md b/documentation/usage.md index a295347..f138cac 100644 --- a/documentation/usage.md +++ b/documentation/usage.md @@ -167,7 +167,7 @@ typealias Relationships = NoRelationships `Relationship` values boil down to `Ids` of other resource objects. To access the `Id` of a related `ResourceObject`, you can use the custom `~>` operator with the `KeyPath` of the `Relationship` from which you want the `Id`. The friends of the above `Person` `ResourceObject` can be accessed as follows (type annotations for clarity): ```swift -let friendIds: [Person.Identifier] = person ~> \.friends +let friendIds: [Person.Id] = person ~> \.friends ``` ### `JSONAPI.Attributes` @@ -244,8 +244,8 @@ If your computed property is wrapped in a `AttributeType` then you can still use ### Copying/Mutating `ResourceObjects` `ResourceObject` is a value type, so copying is its default behavior. There are three common mutations you might want to make when copying a `ResourceObject`: -1. Assigning a new `Identifier` to the copy of an identified `ResourceObject`. -2. Assigning a new `Identifier` to the copy of an unidentified `ResourceObject`. +1. Assigning a new `Id` to the copy of an identified `ResourceObject`. +2. Assigning a new `Id` to the copy of an unidentified `ResourceObject`. 3. Change attribute or relationship values. The first two can be accomplished with code like the following: @@ -595,9 +595,9 @@ enum UserDescription: ResourceObjectDescription { } struct Relationships: JSONAPI.Relationships { - public var friend: (User) -> User.Identifier { + public var friend: (User) -> User.Id { return { user in - return User.Identifier(rawValue: user.friend_id) + return User.Id(rawValue: user.friend_id) } } } @@ -612,4 +612,4 @@ Given a value `user` of the above resource object type, you can access the `frie let friendId = user ~> \.friend ``` -This works because `friend` is defined in the form: `var {name}: ({ResourceObject}) -> {Identifier}` where `{ResourceObject}` is the `JSONAPI.ResourceObject` described by the `ResourceObjectDescription` containing the meta-relationship. +This works because `friend` is defined in the form: `var {name}: ({ResourceObject}) -> {Id}` where `{ResourceObject}` is the `JSONAPI.ResourceObject` described by the `ResourceObjectDescription` containing the meta-relationship. From 43fdde175a2c1ccae4e9f88f53fdb061857b46be Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 29 May 2020 19:02:20 -0700 Subject: [PATCH 3/5] re-fix example playgrounds --- .../Contents.swift | 2 +- JSONAPI.playground/Sources/Entities.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift index 5cc9cef..f7b8052 100644 --- a/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Full Client & Server Example.xcplaygroundpage/Contents.swift @@ -30,7 +30,7 @@ typealias UnidentifiedJSONEntity = JSONA // Create relationship typealiases because we do not expect // JSON:API Relationships for this particular API to have // Metadata or Links associated with them. -typealias ToOneRelationship = JSONAPI.ToOneRelationship +typealias ToOneRelationship = JSONAPI.ToOneRelationship typealias ToManyRelationship = JSONAPI.ToManyRelationship // Create a typealias for a Document because we do not expect diff --git a/JSONAPI.playground/Sources/Entities.swift b/JSONAPI.playground/Sources/Entities.swift index 1bd6109..e64cfbb 100644 --- a/JSONAPI.playground/Sources/Entities.swift +++ b/JSONAPI.playground/Sources/Entities.swift @@ -25,7 +25,7 @@ extension String: CreatableRawIdType { // MARK: - typealiases for convenience public typealias ExampleEntity = ResourceObject -public typealias ToOne = ToOneRelationship +public typealias ToOne = ToOneRelationship public typealias ToMany = ToManyRelationship // MARK: - A few resource objects (entities) From c825eedb0722de2fc6dfd57ac57679bf2303f1ea Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 29 May 2020 19:10:22 -0700 Subject: [PATCH 4/5] A bit more cleanup --- README.md | 2 +- Sources/JSONAPI/Resource/Relationship.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 54a0997..22ebb8f 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ typealias UnidentifiedJSONEntity = JSONA // Create relationship typealiases because we do not expect // JSON:API Relationships for this particular API to have // Metadata or Links associated with them. -typealias ToOneRelationship = JSONAPI.ToOneRelationship +typealias ToOneRelationship = JSONAPI.ToOneRelationship typealias ToManyRelationship = JSONAPI.ToManyRelationship // Create a typealias for a Document because we do not expect diff --git a/Sources/JSONAPI/Resource/Relationship.swift b/Sources/JSONAPI/Resource/Relationship.swift index 8b44a81..88b54d5 100644 --- a/Sources/JSONAPI/Resource/Relationship.swift +++ b/Sources/JSONAPI/Resource/Relationship.swift @@ -96,7 +96,7 @@ public struct ToManyRelationship(pointers: [ToOneRelationship], meta: MetaType, links: LinksType) where T.ID == Relatable.ID { + public init(pointers: [ToOneRelationship], meta: MetaType, links: LinksType) where T.ID == Relatable.ID { ids = pointers.map(\.id) self.meta = meta self.links = links @@ -121,7 +121,7 @@ extension ToManyRelationship where MetaType == NoMetadata, LinksType == NoLinks self.init(ids: ids, meta: .none, links: .none) } - public init(pointers: [ToOneRelationship]) where T.ID == Relatable.ID { + public init(pointers: [ToOneRelationship]) where T.ID == Relatable.ID { self.init(pointers: pointers, meta: .none, links: .none) } From e9b9dbc90961cbd0888c09098516741e83b34d48 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 29 May 2020 19:15:36 -0700 Subject: [PATCH 5/5] sanity check test and note on the insanity --- Tests/JSONAPITests/SwiftIdentifiableTests.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Tests/JSONAPITests/SwiftIdentifiableTests.swift b/Tests/JSONAPITests/SwiftIdentifiableTests.swift index d5de133..70f6738 100644 --- a/Tests/JSONAPITests/SwiftIdentifiableTests.swift +++ b/Tests/JSONAPITests/SwiftIdentifiableTests.swift @@ -25,6 +25,19 @@ final class SwiftIdentifiableTests: XCTestCase { XCTAssertEqual(hash[t1.id], String(describing: t1.id)) XCTAssertEqual(hash[t2.id], String(describing: t2.id)) } + + func test_Id_ID_equivalence() { + // it's not at all great to have both of these names for + // the Id type, but I could not do better than this and + // still have a typealias for the Id type on the + // ResourceObjectProxy protocol. One protocol's typealias + // will collide with anotehr protocol's associatedtype in + // very ugly ways. + + XCTAssert(TestType.ID.self == TestType.Id.self) + + XCTAssertEqual(TestType.ID(rawValue: "hello"), TestType.Id(rawValue: "hello")) + } } fileprivate enum TestDescription: JSONAPI.ResourceObjectDescription {