@@ -143,9 +143,9 @@ public final class ValkeyClusterClient: Sendable {
143143 /// - Other errors if the command execution or parsing fails
144144 @inlinable
145145 public func execute< Command: ValkeyCommand > ( _ command: Command ) async throws -> Command . Response {
146- let hashSlots = command . keysAffected . map { HashSlot ( key : $0 ) }
146+ let hashSlot = try self . hashSlot ( for : command . keysAffected )
147147 var clientSelector : ( ) async throws -> ValkeyNodeClient = {
148- try await self . nodeClient ( for: hashSlots )
148+ try await self . nodeClient ( for: hashSlot . map { [ $0 ] } ?? [ ] )
149149 }
150150
151151 while !Task. isCancelled {
@@ -178,8 +178,8 @@ public final class ValkeyClusterClient: Sendable {
178178 isolation: isolated ( any Actor ) ? = #isolation,
179179 operation: ( ValkeyConnection ) async throws -> sending Value
180180 ) async throws -> Value {
181- let hashSlots = keys . map { HashSlot ( key : $0 ) }
182- let node = try await self . nodeClient ( for: hashSlots )
181+ let hashSlot = try self . hashSlot ( for : keys )
182+ let node = try await self . nodeClient ( for: hashSlot . map { [ $0 ] } ?? [ ] )
183183 return try await node. withConnection ( isolation: isolation, operation: operation)
184184 }
185185
@@ -234,6 +234,20 @@ public final class ValkeyClusterClient: Sendable {
234234
235235 // MARK: - Private methods -
236236
237+ /// Return HashSlot for collection of keys.
238+ ///
239+ /// If collection is empty return `nil`
240+ /// If collection of keys use a variety of hash slot then throw an error
241+ @usableFromInline
242+ /* private */ func hashSlot( for keys: some Collection < ValkeyKey > ) throws -> HashSlot ? {
243+ guard let firstKey = keys. first else { return nil }
244+ let hashSlot = HashSlot ( key: firstKey)
245+ for key in keys. dropFirst ( ) {
246+ guard hashSlot == HashSlot ( key: key) else { throw ValkeyClusterError . keysInCommandRequireMultipleHashSlots }
247+ }
248+ return hashSlot
249+ }
250+
237251 private func queueAction( _ action: RunAction ) {
238252 self . actionStreamContinuation. yield ( action)
239253 }
@@ -418,7 +432,7 @@ public final class ValkeyClusterClient: Sendable {
418432 /// - `ValkeyClusterError.clusterIsUnavailable` if no healthy nodes are available
419433 /// - `ValkeyClusterError.clusterIsMissingSlotAssignment` if the slot assignment cannot be determined
420434 @inlinable
421- func nodeClient( for slots: some ( Collection < HashSlot > & Sendable ) ) async throws -> ValkeyNodeClient {
435+ func nodeClient( for slots: [ HashSlot ] ) async throws -> ValkeyNodeClient {
422436 var retries = 0
423437 while retries < 3 {
424438 defer { retries += 1 }
0 commit comments