diff --git a/README.md b/README.md index 8860c59..4a29612 100644 --- a/README.md +++ b/README.md @@ -40,22 +40,22 @@ The primary goals of this framework are: ### Encoding #### Document - [ ] `data` -- [ ] `included` +- [x] `included` - [ ] `errors` - [ ] `meta` - [ ] `jsonapi` - [ ] `links` #### Resource Object -- [x] `id` (untested) -- [x] `type` (untested) -- [x] `attributes` (untested) -- [x] `relationships` (untested) +- [x] `id` +- [x] `type` +- [x] `attributes` +- [x] `relationships` - [ ] `links` - [ ] `meta` #### Relationship Object -- [x] `data` (untested) +- [x] `data` - [ ] `links` - [ ] `meta` diff --git a/Sources/JSONAPI/Document/Includes.swift b/Sources/JSONAPI/Document/Includes.swift index 40ee3fa..5ccaac7 100644 --- a/Sources/JSONAPI/Document/Includes.swift +++ b/Sources/JSONAPI/Document/Includes.swift @@ -7,9 +7,9 @@ import Result -public protocol IncludeDecoder: Decodable {} +public protocol IncludeDecoder: Codable, Equatable {} -public struct Includes: Decodable { +public struct Includes: Codable, Equatable { public static var none: Includes { return .init(values: []) } let values: [I] @@ -34,6 +34,18 @@ public struct Includes: Decodable { values = valueAggregator } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + + guard I.self != NoIncludes.self else { + throw JSONAPIEncodingError.illegalEncoding("Attempting to encode Include0, which should be represented by the absense of an 'included' entry altogether.") + } + + for value in values { + try container.encode(value) + } + } public var count: Int { return values.count @@ -64,6 +76,10 @@ public struct Include0: _Include0 { public init(from decoder: Decoder) throws { } + + public func encode(to encoder: Encoder) throws { + throw JSONAPIEncodingError.illegalEncoding("Attempted to encode Include0, which should be represented by the absence of an 'included' entry altogether.") + } } public typealias NoIncludes = Include0 @@ -85,6 +101,15 @@ public enum Include1: _Include1 { self = .a(try container.decode(A.self)) } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + switch self { + case .a(let a): + try container.encode(a) + } + } } extension Includes where I: _Include1 { @@ -129,6 +154,17 @@ public enum Include2: _Include2 { self = val } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + switch self { + case .a(let a): + try container.encode(a) + case .b(let b): + try container.encode(b) + } + } } extension Includes where I: _Include2 { @@ -180,6 +216,19 @@ public enum Include3: _Include3 { self = val } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + switch self { + case .a(let a): + try container.encode(a) + case .b(let b): + try container.encode(b) + case .c(let c): + try container.encode(c) + } + } } extension Includes where I: _Include3 { @@ -238,6 +287,21 @@ public enum Include4 self = val } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + switch self { + case .a(let a): + try container.encode(a) + case .b(let b): + try container.encode(b) + case .c(let c): + try container.encode(c) + case .d(let d): + try container.encode(d) + } + } } extension Includes where I: _Include4 { @@ -303,6 +367,23 @@ public enum Include5.self, + data: two_same_type_includes))) + } func test_OneInclude() { let includes = decoded(type: Includes>.self, @@ -19,6 +24,11 @@ class IncludedTests: XCTestCase { XCTAssertEqual(includes[TestEntity.self].count, 1) } + + func test_OneInclude_encode() { + test_DecodeEncodeEquality(type: Includes>.self, + data: one_include) + } func test_TwoSameIncludes() { let includes = decoded(type: Includes>.self, @@ -26,6 +36,11 @@ class IncludedTests: XCTestCase { XCTAssertEqual(includes[TestEntity.self].count, 2) } + + func test_TwoSameIncludes_encode() { + test_DecodeEncodeEquality(type: Includes>.self, + data: two_same_type_includes) + } func test_TwoDifferentIncludes() { let includes = decoded(type: Includes>.self, @@ -34,6 +49,11 @@ class IncludedTests: XCTestCase { XCTAssertEqual(includes[TestEntity.self].count, 1) XCTAssertEqual(includes[TestEntity2.self].count, 1) } + + func test_TwoDifferentIncludes_encode() { + test_DecodeEncodeEquality(type: Includes>.self, + data: two_different_type_includes) + } func test_ThreeDifferentIncludes() { let includes = decoded(type: Includes>.self, @@ -43,6 +63,11 @@ class IncludedTests: XCTestCase { XCTAssertEqual(includes[TestEntity2.self].count, 1) XCTAssertEqual(includes[TestEntity4.self].count, 1) } + + func test_ThreeDifferentIncludes_encode() { + test_DecodeEncodeEquality(type: Includes>.self, + data: three_different_type_includes) + } func test_FourDifferentIncludes() { let includes = decoded(type: Includes>.self, @@ -53,6 +78,11 @@ class IncludedTests: XCTestCase { XCTAssertEqual(includes[TestEntity4.self].count, 1) XCTAssertEqual(includes[TestEntity6.self].count, 1) } + + func test_FourDifferentIncludes_encode() { + test_DecodeEncodeEquality(type: Includes>.self, + data: four_different_type_includes) + } func test_FiveDifferentIncludes() { let includes = decoded(type: Includes>.self, @@ -64,6 +94,11 @@ class IncludedTests: XCTestCase { XCTAssertEqual(includes[TestEntity4.self].count, 1) XCTAssertEqual(includes[TestEntity6.self].count, 1) } + + func test_FiveDifferentIncludes_encode() { + test_DecodeEncodeEquality(type: Includes>.self, + data: five_different_type_includes) + } func test_SixDifferentIncludes() { let includes = decoded(type: Includes>.self, @@ -76,6 +111,11 @@ class IncludedTests: XCTestCase { XCTAssertEqual(includes[TestEntity5.self].count, 1) XCTAssertEqual(includes[TestEntity6.self].count, 1) } + + func test_SixDifferentIncludes_encode() { + test_DecodeEncodeEquality(type: Includes>.self, + data: six_different_type_includes) + } } extension IncludedTests { diff --git a/Tests/JSONAPITests/XCTestManifests.swift b/Tests/JSONAPITests/XCTestManifests.swift index 41d9caf..374386b 100644 --- a/Tests/JSONAPITests/XCTestManifests.swift +++ b/Tests/JSONAPITests/XCTestManifests.swift @@ -12,33 +12,63 @@ extension DocumentTests { extension EntityTests { static let __allTests = [ ("test_entityAllAttribute", test_entityAllAttribute), + ("test_entityAllAttribute_encode", test_entityAllAttribute_encode), ("test_entityBrokenNullableOmittedAttribute", test_entityBrokenNullableOmittedAttribute), ("test_EntityNoRelationshipsNoAttributes", test_EntityNoRelationshipsNoAttributes), + ("test_EntityNoRelationshipsNoAttributes_encode", test_EntityNoRelationshipsNoAttributes_encode), ("test_EntityNoRelationshipsSomeAttributes", test_EntityNoRelationshipsSomeAttributes), + ("test_EntityNoRelationshipsSomeAttributes_encode", test_EntityNoRelationshipsSomeAttributes_encode), ("test_entityOneNullAndOneOmittedAttribute", test_entityOneNullAndOneOmittedAttribute), + ("test_entityOneNullAndOneOmittedAttribute_encode", test_entityOneNullAndOneOmittedAttribute_encode), ("test_entityOneNullAttribute", test_entityOneNullAttribute), + ("test_entityOneNullAttribute_encode", test_entityOneNullAttribute_encode), ("test_entityOneOmittedAttribute", test_entityOneOmittedAttribute), + ("test_entityOneOmittedAttribute_encode", test_entityOneOmittedAttribute_encode), ("test_EntitySomeRelationshipsNoAttributes", test_EntitySomeRelationshipsNoAttributes), + ("test_EntitySomeRelationshipsNoAttributes_encode", test_EntitySomeRelationshipsNoAttributes_encode), ("test_EntitySomeRelationshipsSomeAttributes", test_EntitySomeRelationshipsSomeAttributes), + ("test_EntitySomeRelationshipsSomeAttributes_encode", test_EntitySomeRelationshipsSomeAttributes_encode), ("test_IntToString", test_IntToString), + ("test_IntToString_encode", test_IntToString_encode), ("test_NonNullOptionalNullableAttribute", test_NonNullOptionalNullableAttribute), + ("test_NonNullOptionalNullableAttribute_encode", test_NonNullOptionalNullableAttribute_encode), + ("test_nullableRelationshipIsNull", test_nullableRelationshipIsNull), + ("test_nullableRelationshipIsNull_encode", test_nullableRelationshipIsNull_encode), + ("test_nullableRelationshipNotNull", test_nullableRelationshipNotNull), + ("test_nullableRelationshipNotNull_encode", test_nullableRelationshipNotNull_encode), ("test_NullOptionalNullableAttribute", test_NullOptionalNullableAttribute), + ("test_NullOptionalNullableAttribute_encode", test_NullOptionalNullableAttribute_encode), ("test_relationship_access", test_relationship_access), ("test_relationship_operator_access", test_relationship_operator_access), ("test_relationshipIds", test_relationshipIds), + ("test_RleationshipsOfSameType", test_RleationshipsOfSameType), + ("test_RleationshipsOfSameType_encode", test_RleationshipsOfSameType_encode), ("test_toMany_relationship_operator_access", test_toMany_relationship_operator_access), + ("test_UnidentifiedEntity", test_UnidentifiedEntity), + ("test_UnidentifiedEntity_encode", test_UnidentifiedEntity_encode), + ("test_UnidentifiedEntityWithAttributes", test_UnidentifiedEntityWithAttributes), + ("test_UnidentifiedEntityWithAttributes_encode", test_UnidentifiedEntityWithAttributes_encode), ] } extension IncludedTests { static let __allTests = [ ("test_FiveDifferentIncludes", test_FiveDifferentIncludes), + ("test_FiveDifferentIncludes_encode", test_FiveDifferentIncludes_encode), ("test_FourDifferentIncludes", test_FourDifferentIncludes), + ("test_FourDifferentIncludes_encode", test_FourDifferentIncludes_encode), ("test_OneInclude", test_OneInclude), + ("test_OneInclude_encode", test_OneInclude_encode), ("test_SixDifferentIncludes", test_SixDifferentIncludes), + ("test_SixDifferentIncludes_encode", test_SixDifferentIncludes_encode), ("test_ThreeDifferentIncludes", test_ThreeDifferentIncludes), + ("test_ThreeDifferentIncludes_encode", test_ThreeDifferentIncludes_encode), ("test_TwoDifferentIncludes", test_TwoDifferentIncludes), + ("test_TwoDifferentIncludes_encode", test_TwoDifferentIncludes_encode), ("test_TwoSameIncludes", test_TwoSameIncludes), + ("test_TwoSameIncludes_encode", test_TwoSameIncludes_encode), + ("test_zeroIncludes", test_zeroIncludes), + ("test_zeroIncludes_encode", test_zeroIncludes_encode), ] } @@ -47,14 +77,20 @@ extension RelationshipTests { ("test_initToManyWithEntities", test_initToManyWithEntities), ("test_initToManyWithRelationships", test_initToManyWithRelationships), ("test_ToManyRelationship", test_ToManyRelationship), + ("test_ToManyRelationship_encode", test_ToManyRelationship_encode), ("test_ToOneRelationship", test_ToOneRelationship), + ("test_ToOneRelationship_encode", test_ToOneRelationship_encode), ] } extension ResourceBodyTests { static let __allTests = [ ("test_manyResourceBody", test_manyResourceBody), + ("test_manyResourceBody_encode", test_manyResourceBody_encode), + ("test_manyResourceBodyEmpty", test_manyResourceBodyEmpty), + ("test_manyResourceBodyEmpty_encode", test_manyResourceBodyEmpty_encode), ("test_singleResourceBody", test_singleResourceBody), + ("test_singleResourceBody_encode", test_singleResourceBody_encode), ] }