From 360d7c3c62b263371c416b2a33c408076f4cf2d0 Mon Sep 17 00:00:00 2001 From: Lawrence Forooghian Date: Wed, 18 Dec 2024 10:03:54 -0300 Subject: [PATCH] Change Metadata to use JSONValue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec isn’t explicit about the type (have created [1] for this to be clarified), but from the examples given there, it seems that it can be any JSON `object`. Part of #13. [1] https://github.com/ably/specification/issues/260 --- README.md | 2 +- Sources/AblyChat/ChatAPI.swift | 2 +- Sources/AblyChat/DefaultMessages.swift | 7 +-- Sources/AblyChat/Message.swift | 2 +- Sources/AblyChat/Metadata.swift | 47 +------------------ Sources/AblyChat/RoomReactionDTO.swift | 4 +- Tests/AblyChatTests/ChatAPITests.swift | 2 +- .../DefaultRoomReactionsTests.swift | 2 +- Tests/AblyChatTests/IntegrationTests.swift | 4 +- .../AblyChatTests/RoomReactionDTOTests.swift | 4 +- 10 files changed, 14 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 96abaf3..13ae613 100644 --- a/README.md +++ b/README.md @@ -455,7 +455,7 @@ try await room.reactions.send(params: .init(type: "like")) You can also add any metadata and headers to reactions: ```swift -try await room.reactions.send(params: .init(type: "πŸŽ‰", metadata: ["effect": .string("fireworks")])) +try await room.reactions.send(params: .init(type: "πŸŽ‰", metadata: ["effect": "fireworks"])) ``` ### Subscribing to room reactions diff --git a/Sources/AblyChat/ChatAPI.swift b/Sources/AblyChat/ChatAPI.swift index e439dcc..6404029 100644 --- a/Sources/AblyChat/ChatAPI.swift +++ b/Sources/AblyChat/ChatAPI.swift @@ -37,7 +37,7 @@ internal final class ChatAPI: Sendable { // (CHA-M3b) A message may be sent without metadata or headers. When these are not specified by the user, they must be omitted from the REST payload. if let metadata = params.metadata { - body["metadata"] = .object(metadata.mapValues(\.toJSONValue)) + body["metadata"] = .object(metadata) } if let headers = params.headers { diff --git a/Sources/AblyChat/DefaultMessages.swift b/Sources/AblyChat/DefaultMessages.swift index 012b8ad..8229d3a 100644 --- a/Sources/AblyChat/DefaultMessages.swift +++ b/Sources/AblyChat/DefaultMessages.swift @@ -77,11 +77,8 @@ internal final class DefaultMessages: Messages, EmitsDiscontinuities { throw ARTErrorInfo.create(withCode: 50000, status: 500, message: "Received incoming message without clientId") } - let metadata: Metadata? = if let metadataJSONObject = try data.optionalObjectValueForKey("metadata") { - try metadataJSONObject.mapValues { try MetadataValue(jsonValue: $0) } - } else { - nil - } + let metadata = try data.optionalObjectValueForKey("metadata") + let headers: Headers? = if let headersJSONObject = try extras.optionalObjectValueForKey("headers") { try headersJSONObject.mapValues { try HeadersValue(jsonValue: $0) } } else { diff --git a/Sources/AblyChat/Message.swift b/Sources/AblyChat/Message.swift index d1dc21d..a198796 100644 --- a/Sources/AblyChat/Message.swift +++ b/Sources/AblyChat/Message.swift @@ -98,7 +98,7 @@ extension Message: JSONObjectDecodable { roomID: jsonObject.stringValueForKey("roomId"), text: jsonObject.stringValueForKey("text"), createdAt: jsonObject.optionalAblyProtocolDateValueForKey("createdAt"), - metadata: jsonObject.objectValueForKey("metadata").mapValues { try .init(jsonValue: $0) }, + metadata: jsonObject.objectValueForKey("metadata"), headers: jsonObject.objectValueForKey("headers").mapValues { try .init(jsonValue: $0) } ) } diff --git a/Sources/AblyChat/Metadata.swift b/Sources/AblyChat/Metadata.swift index 591c0a1..0cfeeea 100644 --- a/Sources/AblyChat/Metadata.swift +++ b/Sources/AblyChat/Metadata.swift @@ -1,12 +1,3 @@ -// TODO: https://github.com/ably-labs/ably-chat-swift/issues/13 - try to improve this type - -public enum MetadataValue: Sendable, Equatable { - case string(String) - case number(Double) - case bool(Bool) - case null -} - /** * Metadata is a map of extra information that can be attached to chat * messages. It is not used by Ably and is sent as part of the realtime @@ -17,40 +8,4 @@ public enum MetadataValue: Sendable, Equatable { * Do not use metadata for authoritative information. There is no server-side * validation. When reading the metadata treat it like user input. */ -public typealias Metadata = [String: MetadataValue] - -extension MetadataValue: JSONDecodable { - internal enum JSONDecodingError: Error { - case unsupportedJSONValue(JSONValue) - } - - internal init(jsonValue: JSONValue) throws { - self = switch jsonValue { - case let .string(value): - .string(value) - case let .number(value): - .number(value) - case let .bool(value): - .bool(value) - case .null: - .null - default: - throw JSONDecodingError.unsupportedJSONValue(jsonValue) - } - } -} - -extension MetadataValue: JSONEncodable { - internal var toJSONValue: JSONValue { - switch self { - case let .string(value): - .string(value) - case let .number(value): - .number(Double(value)) - case let .bool(value): - .bool(value) - case .null: - .null - } - } -} +public typealias Metadata = [String: JSONValue] diff --git a/Sources/AblyChat/RoomReactionDTO.swift b/Sources/AblyChat/RoomReactionDTO.swift index f92b5bd..8242d46 100644 --- a/Sources/AblyChat/RoomReactionDTO.swift +++ b/Sources/AblyChat/RoomReactionDTO.swift @@ -42,13 +42,13 @@ extension RoomReactionDTO.Data: JSONObjectCodable { internal init(jsonObject: [String: JSONValue]) throws { type = try jsonObject.stringValueForKey(JSONKey.type.rawValue) - metadata = try jsonObject.optionalObjectValueForKey(JSONKey.metadata.rawValue)?.mapValues { try .init(jsonValue: $0) } + metadata = try jsonObject.optionalObjectValueForKey(JSONKey.metadata.rawValue) } internal var toJSONObject: [String: JSONValue] { [ JSONKey.type.rawValue: .string(type), - JSONKey.metadata.rawValue: .object(metadata?.mapValues(\.toJSONValue) ?? [:]), + JSONKey.metadata.rawValue: .object(metadata ?? [:]), ] } } diff --git a/Tests/AblyChatTests/ChatAPITests.swift b/Tests/AblyChatTests/ChatAPITests.swift index e7aca3a..c77602e 100644 --- a/Tests/AblyChatTests/ChatAPITests.swift +++ b/Tests/AblyChatTests/ChatAPITests.swift @@ -89,7 +89,7 @@ struct ChatAPITests { params: .init( text: "", // arbitrary // The exact value here is arbitrary, just want to check it gets serialized - metadata: ["numberKey": .number(10), "stringKey": .string("hello")] + metadata: ["numberKey": 10, "stringKey": "hello"] ) ) diff --git a/Tests/AblyChatTests/DefaultRoomReactionsTests.swift b/Tests/AblyChatTests/DefaultRoomReactionsTests.swift index 0482cbc..084674a 100644 --- a/Tests/AblyChatTests/DefaultRoomReactionsTests.swift +++ b/Tests/AblyChatTests/DefaultRoomReactionsTests.swift @@ -30,7 +30,7 @@ struct DefaultRoomReactionsTests { let sendReactionParams = SendReactionParams( type: "like", - metadata: ["someMetadataKey": MetadataValue.string("someMetadataValue")], + metadata: ["someMetadataKey": "someMetadataValue"], headers: ["someHeadersKey": HeadersValue.string("someHeadersValue")] ) diff --git a/Tests/AblyChatTests/IntegrationTests.swift b/Tests/AblyChatTests/IntegrationTests.swift index a96fb70..655b678 100644 --- a/Tests/AblyChatTests/IntegrationTests.swift +++ b/Tests/AblyChatTests/IntegrationTests.swift @@ -118,7 +118,7 @@ struct IntegrationTests { let txMessageAfterRxSubscribe = try await txRoom.messages.send( params: .init( text: "Hello from txRoom, after rxRoom subscribe", - metadata: ["someMetadataKey": .number(123), "someOtherMetadataKey": .string("foo")], + metadata: ["someMetadataKey": 123, "someOtherMetadataKey": "foo"], headers: ["someHeadersKey": .number(456), "someOtherHeadersKey": .string("bar")] ) ) @@ -168,7 +168,7 @@ struct IntegrationTests { try await txRoom.reactions.send( params: .init( type: "heart", - metadata: ["someMetadataKey": .number(123), "someOtherMetadataKey": .string("foo")], + metadata: ["someMetadataKey": 123, "someOtherMetadataKey": "foo"], headers: ["someHeadersKey": .number(456), "someOtherHeadersKey": .string("bar")] ) ) diff --git a/Tests/AblyChatTests/RoomReactionDTOTests.swift b/Tests/AblyChatTests/RoomReactionDTOTests.swift index 885ea30..97b8061 100644 --- a/Tests/AblyChatTests/RoomReactionDTOTests.swift +++ b/Tests/AblyChatTests/RoomReactionDTOTests.swift @@ -36,7 +36,7 @@ enum RoomReactionDTOTests { ] ) - #expect(data == .init(type: "someType", metadata: ["someStringKey": .string("someStringValue"), "someNumberKey": .number(123)])) + #expect(data == .init(type: "someType", metadata: ["someStringKey": "someStringValue", "someNumberKey": 123])) } // MARK: - JSONCodable @@ -49,7 +49,7 @@ enum RoomReactionDTOTests { @Test func toJSONValue() { - let data = RoomReactionDTO.Data(type: "someType", metadata: ["someStringKey": .string("someStringValue"), "someNumberKey": .number(123)]) + let data = RoomReactionDTO.Data(type: "someType", metadata: ["someStringKey": "someStringValue", "someNumberKey": 123]) #expect(data.toJSONValue == [ "type": "someType",