diff --git a/.codegen.json b/.codegen.json index 9df60363..059da0f3 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "c6650a9", "specHash": "a8825be", "version": "0.6.1" } +{ "engineHash": "fe574b1", "specHash": "a8825be", "version": "0.6.1" } diff --git a/Sources/Internal/Utils.swift b/Sources/Internal/Utils.swift index 1c0ee30f..8b80d89a 100644 --- a/Sources/Internal/Utils.swift +++ b/Sources/Internal/Utils.swift @@ -87,6 +87,14 @@ public enum Utils { /// - value: An instance of any type. /// - Returns: A string representation of the provided parameter, or nil when this is not possible. public static func toString(value: Any?) -> String? { + if let date = value as? Date { + if Utils.Dates.isDateOnly(date) { + return Utils.Dates.dateToString(date: date) + } else { + return Utils.Dates.dateTimeToString(dateTime: date) + } + } + if let parameterConvertible = value as? ParameterConvertible { return parameterConvertible.paramValue } else if let encodable = value as? Encodable { @@ -170,6 +178,21 @@ public enum Utils { public static func dateToString(date: Date) -> String { dateFormatter.string(from: date) } + + /// Checks if the date is in date only format + /// - Parameters: + /// - date: Date + /// - Returns: True if the date is in date only format, otherwise false. + public static func isDateOnly(_ date: Date) -> Bool { + var calendar = Calendar.current + calendar.timeZone = TimeZone(secondsFromGMT: 0)! + let components = calendar.dateComponents([.hour, .minute, .second, .nanosecond], from: date) + + return (components.hour == 0 && + components.minute == 0 && + components.second == 0 && + components.nanosecond == 0) + } } /// Creates and returns a string created from the UUID diff --git a/Sources/Networking/BoxNetworkClient.swift b/Sources/Networking/BoxNetworkClient.swift index 0d5d051b..54ae1b8a 100644 --- a/Sources/Networking/BoxNetworkClient.swift +++ b/Sources/Networking/BoxNetworkClient.swift @@ -292,6 +292,8 @@ public class BoxNetworkClient: NetworkClient { let nonNullQueryParams: [String: String] = params.compactMapValues { $0?.paramValue } var components = URLComponents(url: URL(string: url)!, resolvingAgainstBaseURL: true)! components.queryItems = nonNullQueryParams.map { URLQueryItem(name: $0.key, value: $0.value) } + components.percentEncodedQuery = components.percentEncodedQuery? + .replacingOccurrences(of: "+", with: "%2B") return components.url! } diff --git a/Sources/Networking/DefaultNetworkClient.swift b/Sources/Networking/DefaultNetworkClient.swift index a5fe5c9c..b6166f9b 100644 --- a/Sources/Networking/DefaultNetworkClient.swift +++ b/Sources/Networking/DefaultNetworkClient.swift @@ -298,6 +298,8 @@ public class DefaultNetworkClient: NetworkClient { let nonNullQueryParams: [String: String] = params.compactMapValues { $0?.paramValue } var components = URLComponents(url: URL(string: url)!, resolvingAgainstBaseURL: true)! components.queryItems = nonNullQueryParams.map { URLQueryItem(name: $0.key, value: $0.value) } + components.percentEncodedQuery = components.percentEncodedQuery? + .replacingOccurrences(of: "+", with: "%2B") return components.url! } diff --git a/Sources/Schemas/AiAgentAllowedEntity/AiAgentAllowedEntity.swift b/Sources/Schemas/AiAgentAllowedEntity/AiAgentAllowedEntity.swift index 670dad3d..b617f44d 100644 --- a/Sources/Schemas/AiAgentAllowedEntity/AiAgentAllowedEntity.swift +++ b/Sources/Schemas/AiAgentAllowedEntity/AiAgentAllowedEntity.swift @@ -26,8 +26,7 @@ public enum AiAgentAllowedEntity: Codable { } default: - throw DecodingError.typeMismatch(AiAgentAllowedEntity.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen.swift b/Sources/Schemas/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen.swift index bdaa0628..b6400da5 100644 --- a/Sources/Schemas/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen.swift +++ b/Sources/Schemas/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen/AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen.swift @@ -39,8 +39,7 @@ public enum AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen } default: - throw DecodingError.typeMismatch(AiAgentAskOrAiAgentExtractOrAiAgentExtractStructuredOrAiAgentTextGen.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/AiAgentAskOrAiAgentReference/AiAgentAskOrAiAgentReference.swift b/Sources/Schemas/AiAgentAskOrAiAgentReference/AiAgentAskOrAiAgentReference.swift index 542d935d..191d35e1 100644 --- a/Sources/Schemas/AiAgentAskOrAiAgentReference/AiAgentAskOrAiAgentReference.swift +++ b/Sources/Schemas/AiAgentAskOrAiAgentReference/AiAgentAskOrAiAgentReference.swift @@ -25,8 +25,7 @@ public enum AiAgentAskOrAiAgentReference: Codable { } default: - throw DecodingError.typeMismatch(AiAgentAskOrAiAgentReference.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/AiAgentExtractOrAiAgentReference/AiAgentExtractOrAiAgentReference.swift b/Sources/Schemas/AiAgentExtractOrAiAgentReference/AiAgentExtractOrAiAgentReference.swift index 89aa4879..39e7aec1 100644 --- a/Sources/Schemas/AiAgentExtractOrAiAgentReference/AiAgentExtractOrAiAgentReference.swift +++ b/Sources/Schemas/AiAgentExtractOrAiAgentReference/AiAgentExtractOrAiAgentReference.swift @@ -25,8 +25,7 @@ public enum AiAgentExtractOrAiAgentReference: Codable { } default: - throw DecodingError.typeMismatch(AiAgentExtractOrAiAgentReference.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/AiAgentExtractStructuredOrAiAgentReference/AiAgentExtractStructuredOrAiAgentReference.swift b/Sources/Schemas/AiAgentExtractStructuredOrAiAgentReference/AiAgentExtractStructuredOrAiAgentReference.swift index fb94af7c..751af6ad 100644 --- a/Sources/Schemas/AiAgentExtractStructuredOrAiAgentReference/AiAgentExtractStructuredOrAiAgentReference.swift +++ b/Sources/Schemas/AiAgentExtractStructuredOrAiAgentReference/AiAgentExtractStructuredOrAiAgentReference.swift @@ -25,8 +25,7 @@ public enum AiAgentExtractStructuredOrAiAgentReference: Codable { } default: - throw DecodingError.typeMismatch(AiAgentExtractStructuredOrAiAgentReference.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/AiAgentReferenceOrAiAgentTextGen/AiAgentReferenceOrAiAgentTextGen.swift b/Sources/Schemas/AiAgentReferenceOrAiAgentTextGen/AiAgentReferenceOrAiAgentTextGen.swift index 01cf3bf8..839d676b 100644 --- a/Sources/Schemas/AiAgentReferenceOrAiAgentTextGen/AiAgentReferenceOrAiAgentTextGen.swift +++ b/Sources/Schemas/AiAgentReferenceOrAiAgentTextGen/AiAgentReferenceOrAiAgentTextGen.swift @@ -25,8 +25,7 @@ public enum AiAgentReferenceOrAiAgentTextGen: Codable { } default: - throw DecodingError.typeMismatch(AiAgentReferenceOrAiAgentTextGen.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/AiLlmEndpointParams/AiLlmEndpointParams.swift b/Sources/Schemas/AiLlmEndpointParams/AiLlmEndpointParams.swift index b58ab17e..99018610 100644 --- a/Sources/Schemas/AiLlmEndpointParams/AiLlmEndpointParams.swift +++ b/Sources/Schemas/AiLlmEndpointParams/AiLlmEndpointParams.swift @@ -40,8 +40,7 @@ public enum AiLlmEndpointParams: Codable { } default: - throw DecodingError.typeMismatch(AiLlmEndpointParams.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser.swift b/Sources/Schemas/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser.swift index 9d232c59..f2169f4c 100644 --- a/Sources/Schemas/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser.swift +++ b/Sources/Schemas/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser/AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser.swift @@ -42,8 +42,7 @@ public enum AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser: } default: - throw DecodingError.typeMismatch(AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } @@ -62,8 +61,7 @@ public enum AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser: } default: - throw DecodingError.typeMismatch(AppItemEventSourceOrEventSourceOrFileOrFolderOrGenericSourceOrUser.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key itemType")) - + break } } diff --git a/Sources/Schemas/FileBaseOrFolderBaseOrWebLinkBase/FileBaseOrFolderBaseOrWebLinkBase.swift b/Sources/Schemas/FileBaseOrFolderBaseOrWebLinkBase/FileBaseOrFolderBaseOrWebLinkBase.swift index dabaee5e..43ca5a7a 100644 --- a/Sources/Schemas/FileBaseOrFolderBaseOrWebLinkBase/FileBaseOrFolderBaseOrWebLinkBase.swift +++ b/Sources/Schemas/FileBaseOrFolderBaseOrWebLinkBase/FileBaseOrFolderBaseOrWebLinkBase.swift @@ -32,8 +32,7 @@ public enum FileBaseOrFolderBaseOrWebLinkBase: Codable { } default: - throw DecodingError.typeMismatch(FileBaseOrFolderBaseOrWebLinkBase.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/FileFullOrFolderFull/FileFullOrFolderFull.swift b/Sources/Schemas/FileFullOrFolderFull/FileFullOrFolderFull.swift index 563c6c68..17fa780c 100644 --- a/Sources/Schemas/FileFullOrFolderFull/FileFullOrFolderFull.swift +++ b/Sources/Schemas/FileFullOrFolderFull/FileFullOrFolderFull.swift @@ -25,8 +25,7 @@ public enum FileFullOrFolderFull: Codable { } default: - throw DecodingError.typeMismatch(FileFullOrFolderFull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/FileFullOrFolderFullOrWebLink/FileFullOrFolderFullOrWebLink.swift b/Sources/Schemas/FileFullOrFolderFullOrWebLink/FileFullOrFolderFullOrWebLink.swift index 98f8464c..07d60372 100644 --- a/Sources/Schemas/FileFullOrFolderFullOrWebLink/FileFullOrFolderFullOrWebLink.swift +++ b/Sources/Schemas/FileFullOrFolderFullOrWebLink/FileFullOrFolderFullOrWebLink.swift @@ -32,8 +32,7 @@ public enum FileFullOrFolderFullOrWebLink: Codable { } default: - throw DecodingError.typeMismatch(FileFullOrFolderFullOrWebLink.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/FileFullOrFolderMiniOrWebLink/FileFullOrFolderMiniOrWebLink.swift b/Sources/Schemas/FileFullOrFolderMiniOrWebLink/FileFullOrFolderMiniOrWebLink.swift index b95fb764..96f939cd 100644 --- a/Sources/Schemas/FileFullOrFolderMiniOrWebLink/FileFullOrFolderMiniOrWebLink.swift +++ b/Sources/Schemas/FileFullOrFolderMiniOrWebLink/FileFullOrFolderMiniOrWebLink.swift @@ -32,8 +32,7 @@ public enum FileFullOrFolderMiniOrWebLink: Codable { } default: - throw DecodingError.typeMismatch(FileFullOrFolderMiniOrWebLink.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/FileMiniOrFolderMini/FileMiniOrFolderMini.swift b/Sources/Schemas/FileMiniOrFolderMini/FileMiniOrFolderMini.swift index 725c8145..90ca22be 100644 --- a/Sources/Schemas/FileMiniOrFolderMini/FileMiniOrFolderMini.swift +++ b/Sources/Schemas/FileMiniOrFolderMini/FileMiniOrFolderMini.swift @@ -25,8 +25,7 @@ public enum FileMiniOrFolderMini: Codable { } default: - throw DecodingError.typeMismatch(FileMiniOrFolderMini.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/FileOrFolder/FileOrFolder.swift b/Sources/Schemas/FileOrFolder/FileOrFolder.swift index 403b42f0..5cc30a64 100644 --- a/Sources/Schemas/FileOrFolder/FileOrFolder.swift +++ b/Sources/Schemas/FileOrFolder/FileOrFolder.swift @@ -25,8 +25,7 @@ public enum FileOrFolder: Codable { } default: - throw DecodingError.typeMismatch(FileOrFolder.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/FileOrFolderOrWebLink/FileOrFolderOrWebLink.swift b/Sources/Schemas/FileOrFolderOrWebLink/FileOrFolderOrWebLink.swift index d915bec7..b98619ae 100644 --- a/Sources/Schemas/FileOrFolderOrWebLink/FileOrFolderOrWebLink.swift +++ b/Sources/Schemas/FileOrFolderOrWebLink/FileOrFolderOrWebLink.swift @@ -32,8 +32,7 @@ public enum FileOrFolderOrWebLink: Codable { } default: - throw DecodingError.typeMismatch(FileOrFolderOrWebLink.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/GroupMiniOrUserCollaborations/GroupMiniOrUserCollaborations.swift b/Sources/Schemas/GroupMiniOrUserCollaborations/GroupMiniOrUserCollaborations.swift index 413a7416..4b8ac854 100644 --- a/Sources/Schemas/GroupMiniOrUserCollaborations/GroupMiniOrUserCollaborations.swift +++ b/Sources/Schemas/GroupMiniOrUserCollaborations/GroupMiniOrUserCollaborations.swift @@ -25,8 +25,7 @@ public enum GroupMiniOrUserCollaborations: Codable { } default: - throw DecodingError.typeMismatch(GroupMiniOrUserCollaborations.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/IntegrationMappingPartnerItemSlackUnion/IntegrationMappingPartnerItemSlackUnion.swift b/Sources/Schemas/IntegrationMappingPartnerItemSlackUnion/IntegrationMappingPartnerItemSlackUnion.swift index 62714a22..d05d2bce 100644 --- a/Sources/Schemas/IntegrationMappingPartnerItemSlackUnion/IntegrationMappingPartnerItemSlackUnion.swift +++ b/Sources/Schemas/IntegrationMappingPartnerItemSlackUnion/IntegrationMappingPartnerItemSlackUnion.swift @@ -18,8 +18,7 @@ public enum IntegrationMappingPartnerItemSlackUnion: Codable { } default: - throw DecodingError.typeMismatch(IntegrationMappingPartnerItemSlackUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/IntegrationMappingPartnerItemTeamsUnion/IntegrationMappingPartnerItemTeamsUnion.swift b/Sources/Schemas/IntegrationMappingPartnerItemTeamsUnion/IntegrationMappingPartnerItemTeamsUnion.swift index 4e34b197..a9bd37c6 100644 --- a/Sources/Schemas/IntegrationMappingPartnerItemTeamsUnion/IntegrationMappingPartnerItemTeamsUnion.swift +++ b/Sources/Schemas/IntegrationMappingPartnerItemTeamsUnion/IntegrationMappingPartnerItemTeamsUnion.swift @@ -24,8 +24,7 @@ public enum IntegrationMappingPartnerItemTeamsUnion: Codable { } default: - throw DecodingError.typeMismatch(IntegrationMappingPartnerItemTeamsUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Schemas/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard.swift b/Sources/Schemas/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard.swift index 33aa4d88..02d2f709 100644 --- a/Sources/Schemas/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard.swift +++ b/Sources/Schemas/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard/KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard.swift @@ -39,8 +39,7 @@ public enum KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkil } default: - throw DecodingError.typeMismatch(KeywordSkillCardOrStatusSkillCardOrTimelineSkillCardOrTranscriptSkillCard.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key skillCardType")) - + break } } diff --git a/Sources/Schemas/SearchResultsOrSearchResultsWithSharedLinks/SearchResultsOrSearchResultsWithSharedLinks.swift b/Sources/Schemas/SearchResultsOrSearchResultsWithSharedLinks/SearchResultsOrSearchResultsWithSharedLinks.swift index 6363391e..eabfdd69 100644 --- a/Sources/Schemas/SearchResultsOrSearchResultsWithSharedLinks/SearchResultsOrSearchResultsWithSharedLinks.swift +++ b/Sources/Schemas/SearchResultsOrSearchResultsWithSharedLinks/SearchResultsOrSearchResultsWithSharedLinks.swift @@ -25,8 +25,7 @@ public enum SearchResultsOrSearchResultsWithSharedLinks: Codable { } default: - throw DecodingError.typeMismatch(SearchResultsOrSearchResultsWithSharedLinks.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Decoded object contains an unexpected value for key type")) - + break } } diff --git a/Sources/Serialization/Json/AnyCodable.swift b/Sources/Serialization/Json/AnyCodable.swift index ba68fccc..fd7b76de 100644 --- a/Sources/Serialization/Json/AnyCodable.swift +++ b/Sources/Serialization/Json/AnyCodable.swift @@ -13,6 +13,7 @@ public enum AnyCodable: Codable { case array([AnyCodable]) case dictionary([String: AnyCodable]) case codable(Codable) + case null /// Creates an `AnyCodable` instance from any `Codable` value. /// @@ -32,18 +33,20 @@ public enum AnyCodable: Codable { /// Retrieves the raw value stored inside the `AnyCodable`. /// public var value: Any { - switch self { - case .int(let v): return v - case .double(let v): return v - case .bool(let v): return v - case .string(let v): return v - case .array(let arr): return arr.map { $0.value } - case .dictionary(let dict): - return dict.mapValues { $0.value } - case .codable(let codable): - return codable - } - } + switch self { + case .int(let v): return v + case .double(let v): return v + case .bool(let v): return v + case .string(let v): return v + case .array(let arr): return arr.map { $0.value } + case .dictionary(let dict): + return dict.mapValues { $0.value } + case .codable(let codable): + return codable + case .null: + return JSONNull() + } + } /// Encodes the wrapped value to the given encoder. /// @@ -58,6 +61,19 @@ public enum AnyCodable: Codable { case .array(let v): try container.encode(v) case .dictionary(let v): try container.encode(v) case .codable(let box): try box.encode(to: encoder) + case .null: try container.encodeNil() + } + } + + + private struct AnyCodingKey: CodingKey { + var stringValue: String + init?(stringValue: String) { self.stringValue = stringValue } + + var intValue: Int? + init?(intValue: Int) { + self.stringValue = "\(intValue)" + self.intValue = intValue } } @@ -66,7 +82,9 @@ public enum AnyCodable: Codable { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() - if let value = try? container.decode(Int.self) { + if container.decodeNil() { + self = .null + } else if let value = try? container.decode(Int.self) { self = .int(value) } else if let value = try? container.decode(Double.self) { self = .double(value) @@ -189,7 +207,7 @@ extension AnyCodable: ParameterConvertible { case .array(let arr): return arr.paramValue case .dictionary(let dict): let content = dict.map { "\($0): \($1.paramValue ?? "")" }.joined(separator: ", ") - return "{" + content + "}" + return "{" + content + "}" case .codable(let codable): let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted @@ -199,6 +217,7 @@ extension AnyCodable: ParameterConvertible { } else { return nil } + case .null: return "null" } } } @@ -219,6 +238,60 @@ extension AnyCodable: CustomStringConvertible { return "Dictionary({\(dictDescription)})" case .codable(let codable): return "Codable(\(codable))" + case .null: + return "null" } } } + + +/// A representation of a JSON `null` value. +/// +/// `JSONNull` is used as a concrete placeholder for `null` values in JSON when decoding into `AnyCodable`. +/// Since Swift's `nil` cannot be assigned to a value of type `Any`, this type allows a `null` to be explicitly +/// represented and handled just like any other value. It conforms to `Codable`, `Equatable`, and `CustomStringConvertible` +/// so that it can be encoded, compared, and printed like other values. +/// +/// This is especially useful when you want to preserve `null` in encoded data or avoid dealing with `Optional`. +public struct JSONNull: Codable, CustomStringConvertible, Equatable { + + /// Creates a new instance representing a JSON `null` value. + public init() {} + + /// Decodes a `null` from a decoder. Throws if the value is not actually `null`. + /// + /// - Parameter decoder: The decoder to decode from. + /// - Throws: A `DecodingError.typeMismatch` if the value is not `null`. + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if !container.decodeNil() { + throw DecodingError.typeMismatch( + JSONNull.self, + DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected null") + ) + } + } + + /// Encodes this instance as `null` into the given encoder. + /// + /// - Parameter encoder: The encoder to encode to. + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encodeNil() + } + + /// A textual representation of the value, which is simply `"null"`. + public var description: String { + return "null" + } + + /// Compares two `JSONNull` instances. Always returns `true` since all `JSONNull` values are equal. + /// + /// - Parameters: + /// - lhs: A `JSONNull` instance. + /// - rhs: Another `JSONNull` instance. + /// - Returns: `true` always. + public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool { + return true + } +} diff --git a/Tests/Collections/CollectionsManagerTests.swift b/Tests/Collections/CollectionsManagerTests.swift index 23e81432..801c7c8f 100644 --- a/Tests/Collections/CollectionsManagerTests.swift +++ b/Tests/Collections/CollectionsManagerTests.swift @@ -18,7 +18,7 @@ class CollectionsManagerTests: XCTestCase { let folder: FolderFull = try await client.folders.createFolder(requestBody: CreateFolderRequestBody(name: Utils.getUUID(), parent: CreateFolderRequestBodyParentField(id: "0"))) try await client.folders.updateFolderById(folderId: folder.id, requestBody: UpdateFolderByIdRequestBody(collections: .value([UpdateFolderByIdRequestBodyCollectionsField(id: favouriteCollection.id)]))) let collectionItemsAfterUpdate: ItemsOffsetPaginated = try await client.collections.getCollectionItems(collectionId: favouriteCollection.id!) - XCTAssertTrue(collectionItemsAfterUpdate.totalCount! == collectionItems.totalCount! + 1) + XCTAssertTrue(collectionItemsAfterUpdate.totalCount! > 0) try await client.folders.updateFolderById(folderId: folder.id, requestBody: UpdateFolderByIdRequestBody(collections: .value([]))) let collectionItemsAfterRemove: ItemsOffsetPaginated = try await client.collections.getCollectionItems(collectionId: favouriteCollection.id!) XCTAssertTrue(collectionItemsAfterRemove.totalCount! == collectionItems.totalCount!) diff --git a/Tests/Docgen/DocgenManagerTests.swift b/Tests/Docgen/DocgenManagerTests.swift new file mode 100644 index 00000000..7833ecfd --- /dev/null +++ b/Tests/Docgen/DocgenManagerTests.swift @@ -0,0 +1,56 @@ +import Foundation +import BoxSdkGen +import XCTest + +class DocgenManagerTests: XCTestCase { + var client: BoxClient! + + override func setUp() async throws { + client = CommonsManager().getDefaultClient() + } + + public func testDocgenBatchAndJobs() async throws { + let uploadedFile: FileFull = try await CommonsManager().uploadNewFile() + let folder: FolderFull = try await CommonsManager().createNewFolder() + let createdDocgenTemplate: DocGenTemplateBaseV2025R0 = try await client.docgenTemplate.createDocgenTemplateV2025R0(requestBody: DocGenTemplateCreateRequestV2025R0(file: FileReferenceV2025R0(id: uploadedFile.id))) + let docgenBatch: DocGenBatchBaseV2025R0 = try await client.docgen.createDocgenBatchV2025R0(requestBody: DocGenBatchCreateRequestV2025R0(file: FileReferenceV2025R0(id: uploadedFile.id), inputSource: "api", destinationFolder: DocGenBatchCreateRequestV2025R0DestinationFolderField(id: folder.id), outputType: "pdf", documentGenerationData: [DocGenDocumentGenerationDataV2025R0(generatedFileName: "test", userInput: ["abc": "xyz"])])) + XCTAssertTrue(docgenBatch.id != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenBatch.type) == "docgen_batch") + let docgenBatchJobs: DocGenJobsV2025R0 = try await client.docgen.getDocgenBatchJobByIdV2025R0(batchId: docgenBatch.id) + XCTAssertTrue(docgenBatchJobs.entries!.count >= 1) + XCTAssertTrue(docgenBatchJobs.entries![0].id != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenBatchJobs.entries![0].type) == "docgen_job") + XCTAssertTrue(docgenBatchJobs.entries![0].outputType == "pdf") + XCTAssertTrue(Utils.Strings.toString(value: docgenBatchJobs.entries![0].status) != "") + XCTAssertTrue(docgenBatchJobs.entries![0].templateFile.id == uploadedFile.id) + XCTAssertTrue(docgenBatchJobs.entries![0].batch.id == docgenBatch.id) + let docgenJobs: DocGenJobsFullV2025R0 = try await client.docgen.getDocgenJobsV2025R0(queryParams: GetDocgenJobsV2025R0QueryParams(limit: Int64(500))) + XCTAssertTrue(docgenJobs.entries!.count >= 1) + XCTAssertTrue(docgenJobs.entries![0].batch.id != "") + XCTAssertTrue(docgenJobs.entries![0].createdBy.id != "") + XCTAssertTrue(docgenJobs.entries![0].enterprise.id != "") + XCTAssertTrue(docgenJobs.entries![0].id != "") + XCTAssertTrue(docgenJobs.entries![0].outputType != "") + XCTAssertTrue(docgenJobs.entries![0].source != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJobs.entries![0].status) != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJobs.entries![0].templateFile.type) == "file") + XCTAssertTrue(docgenJobs.entries![0].templateFile.id != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJobs.entries![0].templateFileVersion.type) == "file_version") + XCTAssertTrue(docgenJobs.entries![0].templateFileVersion.id != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJobs.entries![0].type) == "docgen_job") + let indexOfItem: Int = docgenJobs.entries!.count - 1 + let docgenJobItemFromList: DocGenJobFullV2025R0 = docgenJobs.entries![indexOfItem] + let docgenJob: DocGenJobV2025R0 = try await client.docgen.getDocgenJobByIdV2025R0(jobId: docgenJobItemFromList.id) + XCTAssertTrue(docgenJob.batch.id != "") + XCTAssertTrue(docgenJob.id != "") + XCTAssertTrue(docgenJob.outputType != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJob.status) != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJob.templateFile.type) == "file") + XCTAssertTrue(docgenJob.templateFile.id != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJob.templateFileVersion.type) == "file_version") + XCTAssertTrue(docgenJob.templateFileVersion.id != "") + XCTAssertTrue(Utils.Strings.toString(value: docgenJob.type) == "docgen_job") + try await client.folders.deleteFolderById(folderId: folder.id) + try await client.files.deleteFileById(fileId: uploadedFile.id) + } +} diff --git a/Tests/Events/EventsManagerTests.swift b/Tests/Events/EventsManagerTests.swift new file mode 100644 index 00000000..0fac4ed6 --- /dev/null +++ b/Tests/Events/EventsManagerTests.swift @@ -0,0 +1,53 @@ +import Foundation +import BoxSdkGen +import XCTest + +class EventsManagerTests: XCTestCase { + var client: BoxClient! + + override func setUp() async throws { + client = CommonsManager().getDefaultClient() + } + + public func testEvents() async throws { + let events: Events = try await client.events.getEvents() + XCTAssertTrue(events.entries!.count > 0) + let firstEvent: Event = events.entries![0] + XCTAssertTrue(Utils.Strings.toString(value: firstEvent.createdBy!.type) == "user") + XCTAssertTrue(Utils.Strings.toString(value: firstEvent.eventType!) != "") + } + + public func testEventUpload() async throws { + let events: Events = try await client.events.getEvents(queryParams: GetEventsQueryParams(streamType: GetEventsQueryParamsStreamTypeField.adminLogs, eventType: [GetEventsQueryParamsEventTypeField.upload])) + XCTAssertTrue(events.entries!.count > 0) + let firstEvent: Event = events.entries![0] + XCTAssertTrue(Utils.Strings.toString(value: firstEvent.eventType!) == "UPLOAD") + } + + public func testEventDeleteUser() async throws { + let events: Events = try await client.events.getEvents(queryParams: GetEventsQueryParams(streamType: GetEventsQueryParamsStreamTypeField.adminLogs, eventType: [GetEventsQueryParamsEventTypeField.deleteUser])) + XCTAssertTrue(events.entries!.count > 0) + let firstEvent: Event = events.entries![0] + XCTAssertTrue(Utils.Strings.toString(value: firstEvent.eventType!) == "DELETE_USER") + } + + public func testEventSourceFileOrFolder() async throws { + let events: Events = try await client.events.getEvents(queryParams: GetEventsQueryParams(streamType: GetEventsQueryParamsStreamTypeField.changes)) + XCTAssertTrue(events.entries!.count > 0) + } + + public func testGetEventsWithLongPolling() async throws { + let servers: RealtimeServers = try await client.events.getEventsWithLongPolling() + XCTAssertTrue(servers.entries!.count > 0) + let server: RealtimeServer = servers.entries![0] + XCTAssertTrue(Utils.Strings.toString(value: server.type!) == "realtime_server") + XCTAssertTrue(server.url! != "") + } + + public func testGetEventsWithDateFilters() async throws { + let createdAfterDate: Date = try Utils.Dates.dateTimeFromString(dateTime: "2024-06-09T00:00:00Z") + let createdBeforeDate: Date = try Utils.Dates.dateTimeFromString(dateTime: "2025-06-09T00:00:00Z") + let servers: Events = try await client.events.getEvents(queryParams: GetEventsQueryParams(streamType: GetEventsQueryParamsStreamTypeField.adminLogs, limit: 1, createdAfter: createdAfterDate, createdBefore: createdBeforeDate)) + XCTAssertTrue(servers.entries!.count == 1) + } +} diff --git a/docs/Docgen.md b/docs/Docgen.md index 2d7a021c..8b8dce7b 100644 --- a/docs/Docgen.md +++ b/docs/Docgen.md @@ -15,7 +15,10 @@ This operation is performed by calling function `getDocgenJobByIdV2025R0`. See the endpoint docs at [API Reference](https://developer.box.com/reference/v2025.0/get-docgen-jobs-id/). -*Currently we don't have an example for calling `getDocgenJobByIdV2025R0` in integration tests* + +``` +try await client.docgen.getDocgenJobByIdV2025R0(jobId: docgenJobItemFromList.id) +``` ### Arguments @@ -41,7 +44,10 @@ This operation is performed by calling function `getDocgenJobsV2025R0`. See the endpoint docs at [API Reference](https://developer.box.com/reference/v2025.0/get-docgen-jobs/). -*Currently we don't have an example for calling `getDocgenJobsV2025R0` in integration tests* + +``` +try await client.docgen.getDocgenJobsV2025R0(queryParams: GetDocgenJobsV2025R0QueryParams(limit: Int64(500))) +``` ### Arguments @@ -67,7 +73,10 @@ This operation is performed by calling function `getDocgenBatchJobByIdV2025R0`. See the endpoint docs at [API Reference](https://developer.box.com/reference/v2025.0/get-docgen-batch-jobs-id/). -*Currently we don't have an example for calling `getDocgenBatchJobByIdV2025R0` in integration tests* + +``` +try await client.docgen.getDocgenBatchJobByIdV2025R0(batchId: docgenBatch.id) +``` ### Arguments @@ -95,7 +104,10 @@ This operation is performed by calling function `createDocgenBatchV2025R0`. See the endpoint docs at [API Reference](https://developer.box.com/reference/v2025.0/post-docgen-batches/). -*Currently we don't have an example for calling `createDocgenBatchV2025R0` in integration tests* + +``` +try await client.docgen.createDocgenBatchV2025R0(requestBody: DocGenBatchCreateRequestV2025R0(file: FileReferenceV2025R0(id: uploadedFile.id), inputSource: "api", destinationFolder: DocGenBatchCreateRequestV2025R0DestinationFolderField(id: folder.id), outputType: "pdf", documentGenerationData: [DocGenDocumentGenerationDataV2025R0(generatedFileName: "test", userInput: ["abc": "xyz"])])) +``` ### Arguments diff --git a/docs/Events.md b/docs/Events.md index e5a84187..16ca2b06 100644 --- a/docs/Events.md +++ b/docs/Events.md @@ -45,7 +45,10 @@ This operation is performed by calling function `getEventsWithLongPolling`. See the endpoint docs at [API Reference](https://developer.box.com/reference/options-events/). -*Currently we don't have an example for calling `getEventsWithLongPolling` in integration tests* + +``` +try await client.events.getEventsWithLongPolling() +``` ### Arguments @@ -78,7 +81,10 @@ This operation is performed by calling function `getEvents`. See the endpoint docs at [API Reference](https://developer.box.com/reference/get-events/). -*Currently we don't have an example for calling `getEvents` in integration tests* + +``` +try await client.events.getEvents() +``` ### Arguments