Skip to content

Commit

Permalink
Merge pull request #202 from ably/13-fix-metadata-type
Browse files Browse the repository at this point in the history
[ECO-4927] Change `Metadata` to use `JSONValue`
  • Loading branch information
lawrence-forooghian authored Dec 18, 2024
2 parents a182876 + 360d7c3 commit 0159c48
Show file tree
Hide file tree
Showing 10 changed files with 14 additions and 62 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Sources/AblyChat/ChatAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 2 additions & 5 deletions Sources/AblyChat/DefaultMessages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion Sources/AblyChat/Message.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
)
}
Expand Down
47 changes: 1 addition & 46 deletions Sources/AblyChat/Metadata.swift
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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]
4 changes: 2 additions & 2 deletions Sources/AblyChat/RoomReactionDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 ?? [:]),
]
}
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/AblyChatTests/ChatAPITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
)
)

Expand Down
2 changes: 1 addition & 1 deletion Tests/AblyChatTests/DefaultRoomReactionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct DefaultRoomReactionsTests {

let sendReactionParams = SendReactionParams(
type: "like",
metadata: ["someMetadataKey": MetadataValue.string("someMetadataValue")],
metadata: ["someMetadataKey": "someMetadataValue"],
headers: ["someHeadersKey": HeadersValue.string("someHeadersValue")]
)

Expand Down
4 changes: 2 additions & 2 deletions Tests/AblyChatTests/IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
)
)
Expand Down Expand Up @@ -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")]
)
)
Expand Down
4 changes: 2 additions & 2 deletions Tests/AblyChatTests/RoomReactionDTOTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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",
Expand Down

0 comments on commit 0159c48

Please sign in to comment.