Skip to content

Commit bbd6db6

Browse files
committed
A bit more test coverage for MetaRelationship and a note at the top of a now-confusingly-named section in the documentation.
1 parent 7c99ab4 commit bbd6db6

3 files changed

Lines changed: 58 additions & 9 deletions

File tree

Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ResourceObjectTests: XCTestCase {
2727

2828
func test_optional_relationship_operator_access() {
2929
let entity1 = TestEntity1(attributes: .none, relationships: .none, meta: .none, links: .none)
30-
let entity = TestEntity9(attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalNullableOne: nil, optionalMany: .init(resourceObjects: [entity1, entity1], meta: .none, links: .none)), meta: .none, links: .none)
30+
let entity = TestEntity9(attributes: .none, relationships: .init(meta: .init(meta: .init(x: "hello", y: 5), links: .none), optionalMeta: nil, one: entity1.pointer, nullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalNullableOne: nil, optionalMany: .init(resourceObjects: [entity1, entity1], meta: .none, links: .none)), meta: .none, links: .none)
3131

3232
XCTAssertEqual(entity ~> \.optionalOne, Optional(entity1.id))
3333
XCTAssertEqual((entity ~> \.optionalOne).rawValue, Optional(entity1.id.rawValue))
@@ -44,7 +44,7 @@ class ResourceObjectTests: XCTestCase {
4444

4545
func test_optionalToMany_relationship_opeartor_access() {
4646
let entity1 = TestEntity1(attributes: .none, relationships: .none, meta: .none, links: .none)
47-
let entity = TestEntity9(attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalOne: nil, optionalNullableOne: nil, optionalMany: .init(resourceObjects: [entity1, entity1], meta: .none, links: .none)), meta: .none, links: .none)
47+
let entity = TestEntity9(attributes: .none, relationships: .init(meta: .init(meta: .init(x: "hello", y: 5), links: .none), optionalMeta: nil, one: entity1.pointer, nullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalOne: nil, optionalNullableOne: nil, optionalMany: .init(resourceObjects: [entity1, entity1], meta: .none, links: .none)), meta: .none, links: .none)
4848

4949
XCTAssertEqual(entity ~> \.optionalMany, [entity1.id, entity1.id])
5050
}
@@ -84,13 +84,13 @@ class ResourceObjectTests: XCTestCase {
8484
let _ = TestEntity6(id: .init(rawValue: "6"), attributes: .init(here: .init(value: "here"), maybeHere: nil, maybeNull: .init(value: nil)), relationships: .none, meta: .none, links: .none)
8585
let _ = TestEntity7(id: .init(rawValue: "7"), attributes: .init(here: .init(value: "hello"), maybeHereMaybeNull: .init(value: "world")), relationships: .none, meta: .none, links: .none)
8686
XCTAssertNoThrow(try TestEntity8(id: .init(rawValue: "8"), attributes: .init(string: .init(value: "hello"), int: .init(value: 10), stringFromInt: .init(rawValue: 20), plus: .init(rawValue: 30), doubleFromInt: .init(rawValue: 32), omitted: nil, nullToString: .init(rawValue: nil)), relationships: .none, meta: .none, links: .none))
87-
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: nil, optionalOne: nil, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
88-
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: .init(resourceObject: nil), optionalOne: nil, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
89-
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: .init(id: nil), optionalOne: nil, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
90-
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalOne: nil, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
91-
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: nil, optionalOne: entity1.pointer, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
92-
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: nil, optionalOne: nil, optionalNullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalMany: nil), meta: .none, links: .none)
93-
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(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)
87+
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: nil, optionalMany: nil), meta: .none, links: .none)
88+
let _ = TestEntity9(id: .init(rawValue: "9"), attributes: .none, relationships: .init(meta: .init(meta: .init(x: "hello", y: 5), links: .none), optionalMeta: .init(meta: .init(x: "hello", y: 5), links: .none), one: entity1.pointer, nullableOne: .init(resourceObject: nil), optionalOne: nil, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
89+
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: .init(id: nil), optionalOne: nil, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
90+
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: .init(resourceObject: entity1, meta: .none, links: .none), optionalOne: nil, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
91+
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: entity1.pointer, optionalNullableOne: nil, optionalMany: nil), meta: .none, links: .none)
92+
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)
93+
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)
9494
let e10id1 = TestEntity10.Identifier(rawValue: "hello")
9595
let e10id2 = TestEntity10.Id(rawValue: "world")
9696
let e10id3: TestEntity10.Id = "!"
@@ -356,6 +356,8 @@ extension ResourceObjectTests {
356356
let entity = decoded(type: TestEntity9.self,
357357
data: entity_optional_not_omitted_relationship)
358358

359+
XCTAssertEqual(entity.relationships.meta.meta, TestEntityMeta(x: "world", y: 5))
360+
XCTAssertEqual(entity.relationships.optionalMeta?.meta, TestEntityMeta(x: "world", y: 5))
359361
XCTAssertEqual((entity ~> \.nullableOne)?.rawValue, "3323")
360362
XCTAssertEqual((entity ~> \.one).rawValue, "4459")
361363
XCTAssertNil(entity ~> \.optionalOne)
@@ -391,6 +393,8 @@ extension ResourceObjectTests {
391393
let entity = decoded(type: TestEntity9.self,
392394
data: entity_optional_nullable_nulled_relationship)
393395

396+
XCTAssertEqual(entity.relationships.meta.meta, TestEntityMeta(x: "world", y: 5))
397+
XCTAssertNil(entity.relationships.optionalMeta)
394398
XCTAssertEqual((entity ~> \.nullableOne)?.rawValue, "3323")
395399
XCTAssertEqual((entity ~> \.one).rawValue, "4459")
396400
XCTAssertNil(entity ~> \.optionalNullableOne)
@@ -786,6 +790,10 @@ extension ResourceObjectTests {
786790
typealias Attributes = NoAttributes
787791

788792
public struct Relationships: JSONAPI.Relationships {
793+
let meta: MetaRelationship<TestEntityMeta, NoLinks>
794+
795+
let optionalMeta: MetaRelationship<TestEntityMeta, NoLinks>?
796+
789797
let one: ToOneRelationship<TestEntity1, NoMetadata, NoLinks>
790798

791799
let nullableOne: ToOneRelationship<TestEntity1?, NoMetadata, NoLinks>
@@ -835,11 +843,14 @@ extension ResourceObjectTests {
835843

836844
public struct Relationships: JSONAPI.Relationships {
837845
public init() {
846+
optionalMeta = nil
838847
optionalOne = nil
839848
optionalNullableOne = nil
840849
optionalMany = nil
841850
}
842851

852+
let optionalMeta: MetaRelationship<TestEntityMeta, NoLinks>?
853+
843854
let optionalOne: ToOneRelationship<TestEntity1, NoMetadata, NoLinks>?
844855

845856
let optionalNullableOne: ToOneRelationship<TestEntity1?, NoMetadata, NoLinks>?

Tests/JSONAPITests/ResourceObject/stubs/ResourceObjectStubs.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,18 @@ let entity_optional_not_omitted_relationship = """
233233
"id": "1",
234234
"type": "ninth_test_entities",
235235
"relationships": {
236+
"meta": {
237+
"meta": {
238+
"x": "world",
239+
"y": 5
240+
}
241+
},
242+
"optionalMeta": {
243+
"meta": {
244+
"x": "world",
245+
"y": 5
246+
}
247+
},
236248
"nullableOne": {
237249
"data": {
238250
"id": "3323",
@@ -260,6 +272,12 @@ let entity_optional_nullable_nulled_relationship = """
260272
"id": "1",
261273
"type": "ninth_test_entities",
262274
"relationships": {
275+
"meta": {
276+
"meta": {
277+
"x": "world",
278+
"y": 5
279+
}
280+
},
263281
"nullableOne": {
264282
"data": {
265283
"id": "3323",
@@ -284,6 +302,12 @@ let entity_omitted_relationship = """
284302
"id": "1",
285303
"type": "ninth_test_entities",
286304
"relationships": {
305+
"meta": {
306+
"meta": {
307+
"x": "world",
308+
"y": 5
309+
}
310+
},
287311
"nullableOne": {
288312
"data": {
289313
"id": "3323",
@@ -305,6 +329,12 @@ let entity_optional_to_many_relationship_not_omitted = """
305329
"id": "1",
306330
"type": "ninth_test_entities",
307331
"relationships": {
332+
"meta": {
333+
"meta": {
334+
"x": "world",
335+
"y": 5
336+
}
337+
},
308338
"nullableOne": {
309339
"data": {
310340
"id": "3323",
@@ -334,6 +364,12 @@ let entity_nulled_relationship = """
334364
"id": "1",
335365
"type": "ninth_test_entities",
336366
"relationships": {
367+
"meta": {
368+
"meta": {
369+
"x": "world",
370+
"y": 5
371+
}
372+
},
337373
"nullableOne": {
338374
"data": null
339375
},

documentation/usage.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,8 @@ let createdAt = user.createdAt
580580
This works because `createdAt` is defined in the form: `var {name}: ({ResourceObject}) -> {Value}` where `{ResourceObject}` is the `JSONAPI.ResourceObject` described by the `ResourceObjectDescription` containing the meta-attribute.
581581

582582
### Meta-Relationships
583+
**NOTE** this section describes an ability to create computed relationships, not to be confused with the similarly named `MetaRelationship` type which is used to create relationships that do not have an `id`/`type` (they only have `links` and/or `meta`).
584+
583585
This advanced feature may not ever be useful, but if you find yourself in the situation of dealing with an API that does not 100% follow the **SPEC** then you might find meta-relationships are just the thing to make your resource objects more natural to work with.
584586

585587
Similarly to Meta-Attributes, Meta-Relationships allow you to represent non-compliant relationships as computed relationship properties. In the following example, a relationship is created from some attributes on the JSON model.

0 commit comments

Comments
 (0)