Skip to content

Commit d5e0d70

Browse files
authored
Add a merge method to Metadata (#2084)
## Motivation We want to be able to flatten `RPCError`s, and to do so we need to be able to merge the `Metadata` contained in each. ## Modifications This PR adds a helper function to merge one `Metadata` instance into another. ## Result Unblocks #2083 and also provides a potentially useful API for users. **- Note:** Because of the way `Metadata` has been implemented, we can have multiple _identical_ key-value pairs. This isn't ideal, as it's particularly feasible that we'll end up with multiple repeated identical pairs when merging two `Metadata`s. I think we should reconsider the backing data structure (using a set for example) or add a check before inserting to avoid this.
1 parent 74d0848 commit d5e0d70

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

Sources/GRPCCore/Metadata.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ public struct Metadata: Sendable, Hashable {
171171
self.elements.append(.init(key: key, value: value))
172172
}
173173

174+
/// Add the contents of a `Sequence` of key-value pairs to this `Metadata` instance.
175+
///
176+
/// - Parameter other: the `Sequence` whose key-value pairs should be added into this `Metadata` instance.
177+
public mutating func add(contentsOf other: some Sequence<Element>) {
178+
self.elements.append(contentsOf: other.map(KeyValuePair.init))
179+
}
180+
181+
/// Add the contents of another `Metadata` to this instance.
182+
///
183+
/// - Parameter other: the `Metadata` whose key-value pairs should be added into this one.
184+
public mutating func add(contentsOf other: Metadata) {
185+
self.elements.append(contentsOf: other.elements)
186+
}
187+
174188
/// Removes all values associated with the given key.
175189
///
176190
/// - Parameter key: The key for which all values should be removed.

Tests/GRPCCoreTests/MetadataTests.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,66 @@ struct MetadataTests {
252252
#expect(self.metadata == ["key1": "value1", "key3": "value1"])
253253
}
254254
}
255+
256+
@Suite("Merge")
257+
struct Merge {
258+
var metadata: Metadata = [
259+
"key1": "value1-1",
260+
"key2": "value2",
261+
"key3": "value3",
262+
]
263+
var otherMetadata: Metadata = [
264+
"key4": "value4",
265+
"key5": "value5",
266+
]
267+
268+
@Test("Where key is already present with a different value")
269+
mutating func mergeWhereKeyIsAlreadyPresentWithDifferentValue() async throws {
270+
self.otherMetadata.addString("value1-2", forKey: "key1")
271+
self.metadata.add(contentsOf: self.otherMetadata)
272+
273+
#expect(
274+
self.metadata == [
275+
"key1": "value1-1",
276+
"key2": "value2",
277+
"key3": "value3",
278+
"key4": "value4",
279+
"key5": "value5",
280+
"key1": "value1-2",
281+
]
282+
)
283+
}
284+
285+
@Test("Where key is already present with same value")
286+
mutating func mergeWhereKeyIsAlreadyPresentWithSameValue() async throws {
287+
self.otherMetadata.addString("value1-1", forKey: "key1")
288+
self.metadata.add(contentsOf: self.otherMetadata)
289+
290+
#expect(
291+
self.metadata == [
292+
"key1": "value1-1",
293+
"key2": "value2",
294+
"key3": "value3",
295+
"key4": "value4",
296+
"key5": "value5",
297+
"key1": "value1-1",
298+
]
299+
)
300+
}
301+
302+
@Test("Where key is not already present")
303+
mutating func mergeWhereKeyIsNotAlreadyPresent() async throws {
304+
self.metadata.add(contentsOf: self.otherMetadata)
305+
306+
#expect(
307+
self.metadata == [
308+
"key1": "value1-1",
309+
"key2": "value2",
310+
"key3": "value3",
311+
"key4": "value4",
312+
"key5": "value5",
313+
]
314+
)
315+
}
316+
}
255317
}

0 commit comments

Comments
 (0)