From 83cf5bba875b44e927b11ae47938f3a4e88666a3 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 30 Apr 2024 09:31:36 -0500 Subject: [PATCH 1/3] allow optional metadata to be omitted as well as nulled out. --- Sources/JSONAPI/Resource/Relationship.swift | 3 --- .../Resource Object/ResourceObject.swift | 12 +++++++++- .../ResourceObject/ResourceObjectTests.swift | 22 +++++++++++++++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Sources/JSONAPI/Resource/Relationship.swift b/Sources/JSONAPI/Resource/Relationship.swift index fc03c4e..4a2c3fa 100644 --- a/Sources/JSONAPI/Resource/Relationship.swift +++ b/Sources/JSONAPI/Resource/Relationship.swift @@ -263,9 +263,6 @@ extension MetaRelationship: Codable { } } -fileprivate protocol _Optional {} -extension Optional: _Optional {} - extension ToOneRelationship: Codable where Identifiable.ID: OptionalId { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ResourceLinkageCodingKeys.self) diff --git a/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift b/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift index 77d367e..1b4308b 100644 --- a/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift +++ b/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift @@ -447,7 +447,17 @@ public extension ResourceObject { ) } - meta = try (NoMetadata() as? MetaType) ?? container.decode(MetaType.self, forKey: .meta) + do { + meta = try (NoMetadata() as? MetaType) ?? container.decode(MetaType.self, forKey: .meta) + } catch let decodingError as DecodingError { + let anyNil: Any? = nil + + guard case .keyNotFound = decodingError, + let omittedMeta = anyNil as? MetaType else { + throw decodingError + } + meta = omittedMeta + } links = try (NoLinks() as? LinksType) ?? container.decode(LinksType.self, forKey: .links) } diff --git a/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift b/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift index d492b18..77a75c7 100644 --- a/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift +++ b/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift @@ -151,6 +151,11 @@ extension ResourceObjectTests { data: entity_no_relationships_no_attributes) } + func test_EntityNoMetaDecodesAsOptionalMeta() { + let _ = decoded(type: TestEntityOptionalMeta.self, + data: entity_no_relationships_no_attributes) + } + func test_EntityNoRelationshipsSomeAttributes() { let entity = decoded(type: TestEntity5.self, data: entity_no_relationships_some_attributes) @@ -861,13 +866,13 @@ extension ResourceObjectTests { public struct Relationships: JSONAPI.Relationships { public init() { - optionalMeta = nil + optionalMeta = nil optionalOne = nil optionalNullableOne = nil optionalMany = nil } - let optionalMeta: MetaRelationship? + let optionalMeta: MetaRelationship? let optionalOne: ToOneRelationship? @@ -879,6 +884,19 @@ extension ResourceObjectTests { typealias TestEntity12 = BasicEntity + enum TestEntityOptionalMetaType: JSONAPI.ResourceObjectDescription { + public static var jsonType: String { return "test_entities" } + + typealias Attributes = NoAttributes + typealias Relationships = NoRelationships + } + + struct UnimportantMeta: JSONAPI.Meta { + let property1: String + } + + typealias TestEntityOptionalMeta = JSONAPI.ResourceObject + enum UnidentifiedTestEntityType: ResourceObjectDescription { public static var jsonType: String { return "unidentified_test_entities" } From 457ac3df7557bdb87d820d0efc3a4c1776363860 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 30 Apr 2024 11:10:33 -0500 Subject: [PATCH 2/3] fix test for latest MacOS Swift versions --- .../SparseFields/SparseFieldEncoderTests.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Tests/JSONAPITests/SparseFields/SparseFieldEncoderTests.swift b/Tests/JSONAPITests/SparseFields/SparseFieldEncoderTests.swift index 9d5bba5..2625989 100644 --- a/Tests/JSONAPITests/SparseFields/SparseFieldEncoderTests.swift +++ b/Tests/JSONAPITests/SparseFields/SparseFieldEncoderTests.swift @@ -43,13 +43,9 @@ class SparseFieldEncoderTests: XCTestCase { XCTAssertEqual(allThingsOnDeserialized["bool"] as? Bool, true) XCTAssertEqual(allThingsOnDeserialized["double"] as? Double, 10.5) XCTAssertEqual(allThingsOnDeserialized["string"] as? String, "hello") - #if os(Linux) - // There's some bug with Linux where it won't case the value to a float. - // It does exist and it is == 1.2 + // For latest versions of MacOS and all versions of Linux, floats + // decode as doubles. XCTAssertEqual(allThingsOnDeserialized["float"] as? Double, 1.2) - #else - XCTAssertEqual(allThingsOnDeserialized["float"] as? Float, 1.2) - #endif XCTAssertEqual(allThingsOnDeserialized["int"] as? Int, 3) XCTAssertEqual(allThingsOnDeserialized["int8"] as? Int8, 4) XCTAssertEqual(allThingsOnDeserialized["int16"] as? Int16, 5) From 6f8e133d7d9c43c7a6d5a87b1a978dc2d014599f Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 30 Apr 2024 11:26:41 -0500 Subject: [PATCH 3/3] Fix decoding error support for newer MacOS Swift versions --- Sources/JSONAPI/Document/DocumentDecodingError.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/JSONAPI/Document/DocumentDecodingError.swift b/Sources/JSONAPI/Document/DocumentDecodingError.swift index 92e9ade..8a96054 100644 --- a/Sources/JSONAPI/Document/DocumentDecodingError.swift +++ b/Sources/JSONAPI/Document/DocumentDecodingError.swift @@ -33,6 +33,10 @@ public enum DocumentDecodingError: Swift.Error, Equatable { self = .primaryResourceMissing case .valueNotFound(let type, let context) where Location(context) == .data && type == UnkeyedDecodingContainer.self: self = .primaryResourcesMissing + case .valueNotFound(let type, let context) where Location(context) == .data && type is _ArrayType.Type && context.debugDescription.hasSuffix("found null value instead"): + self = .primaryResourcesMissing + case .valueNotFound(_, let context) where Location(context) == .data && context.debugDescription.hasSuffix("found null value instead"): + self = .primaryResourceMissing case .typeMismatch(let type, let context) where Location(context) == .data && type is _ArrayType.Type && context.debugDescription.hasSuffix("but found null instead."): self = .primaryResourcesMissing case .typeMismatch(_, let context) where Location(context) == .data && context.debugDescription.hasSuffix("but found null instead."):