Skip to content

Commit 04bd042

Browse files
committed
Added encoding support to Includes and tests
1 parent 9802efd commit 04bd042

5 files changed

Lines changed: 185 additions & 8 deletions

File tree

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,22 @@ The primary goals of this framework are:
4040
### Encoding
4141
#### Document
4242
- [ ] `data`
43-
- [ ] `included`
43+
- [x] `included`
4444
- [ ] `errors`
4545
- [ ] `meta`
4646
- [ ] `jsonapi`
4747
- [ ] `links`
4848

4949
#### Resource Object
50-
- [x] `id` (untested)
51-
- [x] `type` (untested)
52-
- [x] `attributes` (untested)
53-
- [x] `relationships` (untested)
50+
- [x] `id`
51+
- [x] `type`
52+
- [x] `attributes`
53+
- [x] `relationships`
5454
- [ ] `links`
5555
- [ ] `meta`
5656

5757
#### Relationship Object
58-
- [x] `data` (untested)
58+
- [x] `data`
5959
- [ ] `links`
6060
- [ ] `meta`
6161

Sources/JSONAPI/Document/Includes.swift

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
import Result
99

10-
public protocol IncludeDecoder: Decodable {}
10+
public protocol IncludeDecoder: Codable, Equatable {}
1111

12-
public struct Includes<I: IncludeDecoder>: Decodable {
12+
public struct Includes<I: IncludeDecoder>: Codable, Equatable {
1313
public static var none: Includes { return .init(values: []) }
1414

1515
let values: [I]
@@ -34,6 +34,18 @@ public struct Includes<I: IncludeDecoder>: Decodable {
3434

3535
values = valueAggregator
3636
}
37+
38+
public func encode(to encoder: Encoder) throws {
39+
var container = encoder.unkeyedContainer()
40+
41+
guard I.self != NoIncludes.self else {
42+
throw JSONAPIEncodingError.illegalEncoding("Attempting to encode Include0, which should be represented by the absense of an 'included' entry altogether.")
43+
}
44+
45+
for value in values {
46+
try container.encode(value)
47+
}
48+
}
3749

3850
public var count: Int {
3951
return values.count
@@ -64,6 +76,10 @@ public struct Include0: _Include0 {
6476

6577
public init(from decoder: Decoder) throws {
6678
}
79+
80+
public func encode(to encoder: Encoder) throws {
81+
throw JSONAPIEncodingError.illegalEncoding("Attempted to encode Include0, which should be represented by the absence of an 'included' entry altogether.")
82+
}
6783
}
6884
public typealias NoIncludes = Include0
6985

@@ -85,6 +101,15 @@ public enum Include1<A: EntityType>: _Include1 {
85101

86102
self = .a(try container.decode(A.self))
87103
}
104+
105+
public func encode(to encoder: Encoder) throws {
106+
var container = encoder.singleValueContainer()
107+
108+
switch self {
109+
case .a(let a):
110+
try container.encode(a)
111+
}
112+
}
88113
}
89114

90115
extension Includes where I: _Include1 {
@@ -129,6 +154,17 @@ public enum Include2<A: EntityType, B: EntityType>: _Include2 {
129154

130155
self = val
131156
}
157+
158+
public func encode(to encoder: Encoder) throws {
159+
var container = encoder.singleValueContainer()
160+
161+
switch self {
162+
case .a(let a):
163+
try container.encode(a)
164+
case .b(let b):
165+
try container.encode(b)
166+
}
167+
}
132168
}
133169

134170
extension Includes where I: _Include2 {
@@ -180,6 +216,19 @@ public enum Include3<A: EntityType, B: EntityType, C: EntityType>: _Include3 {
180216

181217
self = val
182218
}
219+
220+
public func encode(to encoder: Encoder) throws {
221+
var container = encoder.singleValueContainer()
222+
223+
switch self {
224+
case .a(let a):
225+
try container.encode(a)
226+
case .b(let b):
227+
try container.encode(b)
228+
case .c(let c):
229+
try container.encode(c)
230+
}
231+
}
183232
}
184233

185234
extension Includes where I: _Include3 {
@@ -238,6 +287,21 @@ public enum Include4<A: EntityType, B: EntityType, C: EntityType, D: EntityType>
238287

239288
self = val
240289
}
290+
291+
public func encode(to encoder: Encoder) throws {
292+
var container = encoder.singleValueContainer()
293+
294+
switch self {
295+
case .a(let a):
296+
try container.encode(a)
297+
case .b(let b):
298+
try container.encode(b)
299+
case .c(let c):
300+
try container.encode(c)
301+
case .d(let d):
302+
try container.encode(d)
303+
}
304+
}
241305
}
242306

243307
extension Includes where I: _Include4 {
@@ -303,6 +367,23 @@ public enum Include5<A: EntityType, B: EntityType, C: EntityType, D: EntityType,
303367

304368
self = val
305369
}
370+
371+
public func encode(to encoder: Encoder) throws {
372+
var container = encoder.singleValueContainer()
373+
374+
switch self {
375+
case .a(let a):
376+
try container.encode(a)
377+
case .b(let b):
378+
try container.encode(b)
379+
case .c(let c):
380+
try container.encode(c)
381+
case .d(let d):
382+
try container.encode(d)
383+
case .e(let e):
384+
try container.encode(e)
385+
}
386+
}
306387
}
307388

308389
extension Includes where I: _Include5 {
@@ -375,6 +456,25 @@ public enum Include6<A: EntityType, B: EntityType, C: EntityType, D: EntityType,
375456

376457
self = val
377458
}
459+
460+
public func encode(to encoder: Encoder) throws {
461+
var container = encoder.singleValueContainer()
462+
463+
switch self {
464+
case .a(let a):
465+
try container.encode(a)
466+
case .b(let b):
467+
try container.encode(b)
468+
case .c(let c):
469+
try container.encode(c)
470+
case .d(let d):
471+
try container.encode(d)
472+
case .e(let e):
473+
try container.encode(e)
474+
case .f(let f):
475+
try container.encode(f)
476+
}
477+
}
378478
}
379479

380480
extension Includes where I: _Include6 {

Sources/JSONAPI/Resource/Relationship.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ private enum ResourceIdentifierCodingKeys: String, CodingKey {
9191

9292
public enum JSONAPIEncodingError: Swift.Error {
9393
case typeMismatch(expected: String, found: String)
94+
case illegalEncoding(String)
9495
}
9596

9697
extension ToOneRelationship {

Tests/JSONAPITests/Includes/IncludeTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,35 @@ class IncludedTests: XCTestCase {
1212

1313
XCTAssertEqual(includes.count, 0)
1414
}
15+
16+
func test_zeroIncludes_encode() {
17+
XCTAssertThrowsError(try JSONEncoder().encode(decoded(type: Includes<NoIncludes>.self,
18+
data: two_same_type_includes)))
19+
}
1520

1621
func test_OneInclude() {
1722
let includes = decoded(type: Includes<Include1<TestEntity>>.self,
1823
data: one_include)
1924

2025
XCTAssertEqual(includes[TestEntity.self].count, 1)
2126
}
27+
28+
func test_OneInclude_encode() {
29+
test_DecodeEncodeEquality(type: Includes<Include1<TestEntity>>.self,
30+
data: one_include)
31+
}
2232

2333
func test_TwoSameIncludes() {
2434
let includes = decoded(type: Includes<Include1<TestEntity>>.self,
2535
data: two_same_type_includes)
2636

2737
XCTAssertEqual(includes[TestEntity.self].count, 2)
2838
}
39+
40+
func test_TwoSameIncludes_encode() {
41+
test_DecodeEncodeEquality(type: Includes<Include1<TestEntity>>.self,
42+
data: two_same_type_includes)
43+
}
2944

3045
func test_TwoDifferentIncludes() {
3146
let includes = decoded(type: Includes<Include2<TestEntity, TestEntity2>>.self,
@@ -34,6 +49,11 @@ class IncludedTests: XCTestCase {
3449
XCTAssertEqual(includes[TestEntity.self].count, 1)
3550
XCTAssertEqual(includes[TestEntity2.self].count, 1)
3651
}
52+
53+
func test_TwoDifferentIncludes_encode() {
54+
test_DecodeEncodeEquality(type: Includes<Include2<TestEntity, TestEntity2>>.self,
55+
data: two_different_type_includes)
56+
}
3757

3858
func test_ThreeDifferentIncludes() {
3959
let includes = decoded(type: Includes<Include3<TestEntity, TestEntity2, TestEntity4>>.self,
@@ -43,6 +63,11 @@ class IncludedTests: XCTestCase {
4363
XCTAssertEqual(includes[TestEntity2.self].count, 1)
4464
XCTAssertEqual(includes[TestEntity4.self].count, 1)
4565
}
66+
67+
func test_ThreeDifferentIncludes_encode() {
68+
test_DecodeEncodeEquality(type: Includes<Include3<TestEntity, TestEntity2, TestEntity4>>.self,
69+
data: three_different_type_includes)
70+
}
4671

4772
func test_FourDifferentIncludes() {
4873
let includes = decoded(type: Includes<Include4<TestEntity, TestEntity2, TestEntity4, TestEntity6>>.self,
@@ -53,6 +78,11 @@ class IncludedTests: XCTestCase {
5378
XCTAssertEqual(includes[TestEntity4.self].count, 1)
5479
XCTAssertEqual(includes[TestEntity6.self].count, 1)
5580
}
81+
82+
func test_FourDifferentIncludes_encode() {
83+
test_DecodeEncodeEquality(type: Includes<Include4<TestEntity, TestEntity2, TestEntity4, TestEntity6>>.self,
84+
data: four_different_type_includes)
85+
}
5686

5787
func test_FiveDifferentIncludes() {
5888
let includes = decoded(type: Includes<Include5<TestEntity, TestEntity2, TestEntity3, TestEntity4, TestEntity6>>.self,
@@ -64,6 +94,11 @@ class IncludedTests: XCTestCase {
6494
XCTAssertEqual(includes[TestEntity4.self].count, 1)
6595
XCTAssertEqual(includes[TestEntity6.self].count, 1)
6696
}
97+
98+
func test_FiveDifferentIncludes_encode() {
99+
test_DecodeEncodeEquality(type: Includes<Include5<TestEntity, TestEntity2, TestEntity3, TestEntity4, TestEntity6>>.self,
100+
data: five_different_type_includes)
101+
}
67102

68103
func test_SixDifferentIncludes() {
69104
let includes = decoded(type: Includes<Include6<TestEntity, TestEntity2, TestEntity3, TestEntity4, TestEntity5, TestEntity6>>.self,
@@ -76,6 +111,11 @@ class IncludedTests: XCTestCase {
76111
XCTAssertEqual(includes[TestEntity5.self].count, 1)
77112
XCTAssertEqual(includes[TestEntity6.self].count, 1)
78113
}
114+
115+
func test_SixDifferentIncludes_encode() {
116+
test_DecodeEncodeEquality(type: Includes<Include6<TestEntity, TestEntity2, TestEntity3, TestEntity4, TestEntity5, TestEntity6>>.self,
117+
data: six_different_type_includes)
118+
}
79119
}
80120

81121
extension IncludedTests {

Tests/JSONAPITests/XCTestManifests.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,63 @@ extension DocumentTests {
1212
extension EntityTests {
1313
static let __allTests = [
1414
("test_entityAllAttribute", test_entityAllAttribute),
15+
("test_entityAllAttribute_encode", test_entityAllAttribute_encode),
1516
("test_entityBrokenNullableOmittedAttribute", test_entityBrokenNullableOmittedAttribute),
1617
("test_EntityNoRelationshipsNoAttributes", test_EntityNoRelationshipsNoAttributes),
18+
("test_EntityNoRelationshipsNoAttributes_encode", test_EntityNoRelationshipsNoAttributes_encode),
1719
("test_EntityNoRelationshipsSomeAttributes", test_EntityNoRelationshipsSomeAttributes),
20+
("test_EntityNoRelationshipsSomeAttributes_encode", test_EntityNoRelationshipsSomeAttributes_encode),
1821
("test_entityOneNullAndOneOmittedAttribute", test_entityOneNullAndOneOmittedAttribute),
22+
("test_entityOneNullAndOneOmittedAttribute_encode", test_entityOneNullAndOneOmittedAttribute_encode),
1923
("test_entityOneNullAttribute", test_entityOneNullAttribute),
24+
("test_entityOneNullAttribute_encode", test_entityOneNullAttribute_encode),
2025
("test_entityOneOmittedAttribute", test_entityOneOmittedAttribute),
26+
("test_entityOneOmittedAttribute_encode", test_entityOneOmittedAttribute_encode),
2127
("test_EntitySomeRelationshipsNoAttributes", test_EntitySomeRelationshipsNoAttributes),
28+
("test_EntitySomeRelationshipsNoAttributes_encode", test_EntitySomeRelationshipsNoAttributes_encode),
2229
("test_EntitySomeRelationshipsSomeAttributes", test_EntitySomeRelationshipsSomeAttributes),
30+
("test_EntitySomeRelationshipsSomeAttributes_encode", test_EntitySomeRelationshipsSomeAttributes_encode),
2331
("test_IntToString", test_IntToString),
32+
("test_IntToString_encode", test_IntToString_encode),
2433
("test_NonNullOptionalNullableAttribute", test_NonNullOptionalNullableAttribute),
34+
("test_NonNullOptionalNullableAttribute_encode", test_NonNullOptionalNullableAttribute_encode),
35+
("test_nullableRelationshipIsNull", test_nullableRelationshipIsNull),
36+
("test_nullableRelationshipIsNull_encode", test_nullableRelationshipIsNull_encode),
37+
("test_nullableRelationshipNotNull", test_nullableRelationshipNotNull),
38+
("test_nullableRelationshipNotNull_encode", test_nullableRelationshipNotNull_encode),
2539
("test_NullOptionalNullableAttribute", test_NullOptionalNullableAttribute),
40+
("test_NullOptionalNullableAttribute_encode", test_NullOptionalNullableAttribute_encode),
2641
("test_relationship_access", test_relationship_access),
2742
("test_relationship_operator_access", test_relationship_operator_access),
2843
("test_relationshipIds", test_relationshipIds),
44+
("test_RleationshipsOfSameType", test_RleationshipsOfSameType),
45+
("test_RleationshipsOfSameType_encode", test_RleationshipsOfSameType_encode),
2946
("test_toMany_relationship_operator_access", test_toMany_relationship_operator_access),
47+
("test_UnidentifiedEntity", test_UnidentifiedEntity),
48+
("test_UnidentifiedEntity_encode", test_UnidentifiedEntity_encode),
49+
("test_UnidentifiedEntityWithAttributes", test_UnidentifiedEntityWithAttributes),
50+
("test_UnidentifiedEntityWithAttributes_encode", test_UnidentifiedEntityWithAttributes_encode),
3051
]
3152
}
3253

3354
extension IncludedTests {
3455
static let __allTests = [
3556
("test_FiveDifferentIncludes", test_FiveDifferentIncludes),
57+
("test_FiveDifferentIncludes_encode", test_FiveDifferentIncludes_encode),
3658
("test_FourDifferentIncludes", test_FourDifferentIncludes),
59+
("test_FourDifferentIncludes_encode", test_FourDifferentIncludes_encode),
3760
("test_OneInclude", test_OneInclude),
61+
("test_OneInclude_encode", test_OneInclude_encode),
3862
("test_SixDifferentIncludes", test_SixDifferentIncludes),
63+
("test_SixDifferentIncludes_encode", test_SixDifferentIncludes_encode),
3964
("test_ThreeDifferentIncludes", test_ThreeDifferentIncludes),
65+
("test_ThreeDifferentIncludes_encode", test_ThreeDifferentIncludes_encode),
4066
("test_TwoDifferentIncludes", test_TwoDifferentIncludes),
67+
("test_TwoDifferentIncludes_encode", test_TwoDifferentIncludes_encode),
4168
("test_TwoSameIncludes", test_TwoSameIncludes),
69+
("test_TwoSameIncludes_encode", test_TwoSameIncludes_encode),
70+
("test_zeroIncludes", test_zeroIncludes),
71+
("test_zeroIncludes_encode", test_zeroIncludes_encode),
4272
]
4373
}
4474

@@ -47,14 +77,20 @@ extension RelationshipTests {
4777
("test_initToManyWithEntities", test_initToManyWithEntities),
4878
("test_initToManyWithRelationships", test_initToManyWithRelationships),
4979
("test_ToManyRelationship", test_ToManyRelationship),
80+
("test_ToManyRelationship_encode", test_ToManyRelationship_encode),
5081
("test_ToOneRelationship", test_ToOneRelationship),
82+
("test_ToOneRelationship_encode", test_ToOneRelationship_encode),
5183
]
5284
}
5385

5486
extension ResourceBodyTests {
5587
static let __allTests = [
5688
("test_manyResourceBody", test_manyResourceBody),
89+
("test_manyResourceBody_encode", test_manyResourceBody_encode),
90+
("test_manyResourceBodyEmpty", test_manyResourceBodyEmpty),
91+
("test_manyResourceBodyEmpty_encode", test_manyResourceBodyEmpty_encode),
5792
("test_singleResourceBody", test_singleResourceBody),
93+
("test_singleResourceBody_encode", test_singleResourceBody_encode),
5894
]
5995
}
6096

0 commit comments

Comments
 (0)