From fbed3f62e891469f479ba4302ba19f375e761301 Mon Sep 17 00:00:00 2001 From: anitarua Date: Fri, 8 Dec 2023 15:57:07 -0800 Subject: [PATCH] dry up the code --- Sources/Momento/CacheClient.swift | 426 ++++++++++++++++++--------- Sources/Momento/TopicClient.swift | 45 ++- Tests/MomentoTests/configTests.swift | 2 +- Tests/MomentoTests/topicsTests.swift | 10 +- 4 files changed, 338 insertions(+), 145 deletions(-) diff --git a/Sources/Momento/CacheClient.swift b/Sources/Momento/CacheClient.swift index 499d67a..bbf6935 100644 --- a/Sources/Momento/CacheClient.swift +++ b/Sources/Momento/CacheClient.swift @@ -1,20 +1,22 @@ import Foundation -public enum ScalarType { +enum ScalarType { case string(String) case data(Data) } -// The CacheClient interface provides user-friendly, public-facing methods +// The CacheClient class provides user-friendly, public-facing methods // with default values for non-required parameters and overloaded functions // that accept String and Data values directly rather than ScalarTypes +protocol CacheClientProtocol: ControlClientProtocol & DataClientProtocol {} + /** Client to perform operations against Momento Serverless Cache. To learn more, see the [Momento Cache developer documentation](https://docs.momentohq.com/cache) */ @available(macOS 10.15, iOS 13, *) -public class CacheClient { +public class CacheClient: CacheClientProtocol { private let credentialProvider: CredentialProviderProtocol private let configuration: CacheClientConfigurationProtocol private let controlClient: ControlClientProtocol @@ -121,7 +123,7 @@ public class CacheClient { Gets the value stored for the given key. - Parameters: - cacheName: the name of the cache to perform the lookup in - - key: the key to look up + - key: the key to look up as type String - Returns: CacheGetResponse representing the result of the get operation. Pattern matching can be used to operate on the appropriate subtype. ``` @@ -136,24 +138,14 @@ public class CacheClient { ``` */ public func get(cacheName: String, key: String) async -> CacheGetResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateCacheKey(key: ScalarType.string(key)) - } catch let err as SdkError { - return CacheGetError(error: err) - } catch { - return CacheGetError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.get(cacheName: cacheName, key: ScalarType.string(key)) + return await self.get(cacheName: cacheName, key: ScalarType.string(key)) } /** Gets the value stored for the given key. - Parameters: - cacheName: the name of the cache to perform the lookup in - - key: the key to look up + - key: the key to look up as type Data - Returns: CacheGetResponse representing the result of the get operation. Pattern matching can be used to operate on the appropriate subtype. ``` @@ -168,9 +160,13 @@ public class CacheClient { ``` */ public func get(cacheName: String, key: Data) async -> CacheGetResponse { + return await self.get(cacheName: cacheName, key: ScalarType.data(key)) + } + + internal func get(cacheName: String, key: ScalarType) async -> CacheGetResponse { do { try validateCacheName(cacheName: cacheName) - try validateCacheKey(key: ScalarType.data(key)) + try validateCacheKey(key: key) } catch let err as SdkError { return CacheGetError(error: err) } catch { @@ -178,7 +174,7 @@ public class CacheClient { message: "unexpected error: \(error)") ) } - return await self.dataClient.get(cacheName: cacheName, key: ScalarType.data(key)) + return await self.dataClient.get(cacheName: cacheName, key: key) } /** @@ -199,19 +195,13 @@ public class CacheClient { } ``` */ - public func set(cacheName: String, key: String, value: String, ttl: TimeInterval? = nil) async -> CacheSetResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateCacheKey(key: ScalarType.string(key)) - try validateTtl(ttl: ttl) - } catch let err as SdkError { - return CacheSetError(error: err) - } catch { - return CacheSetError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.set( + public func set( + cacheName: String, + key: String, + value: String, + ttl: TimeInterval? = nil + ) async -> CacheSetResponse { + return await set( cacheName: cacheName, key: ScalarType.string(key), value: ScalarType.string(value), @@ -219,19 +209,31 @@ public class CacheClient { ) } - public func set(cacheName: String, key: String, value: Data, ttl: TimeInterval? = nil) async -> CacheSetResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateCacheKey(key: ScalarType.string(key)) - try validateTtl(ttl: ttl) - } catch let err as SdkError { - return CacheSetError(error: err) - } catch { - return CacheSetError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.set( + /** + Associates the given key with the given value. If a value for the key is already present it is replaced with the new value. + - Parameters: + - cacheName: the name of the cache to store the value in + - key: the key to set the value for + - value: the value to associate with the key + - ttl: the time to live for the item in the cache. Uses the client's default TTL if this is not supplied. + - Returns: CacheSetResponse representing the result of the set operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheSetError: + // handle error + case let responseSuccess as CacheSetSuccess: + // handle success + } + ``` + */ + public func set( + cacheName: String, + key: String, + value: Data, + ttl: TimeInterval? = nil + ) async -> CacheSetResponse { + return await set( cacheName: cacheName, key: ScalarType.string(key), value: ScalarType.data(value), @@ -239,19 +241,31 @@ public class CacheClient { ) } - public func set(cacheName: String, key: Data, value: String, ttl: TimeInterval? = nil) async -> CacheSetResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateCacheKey(key: ScalarType.data(key)) - try validateTtl(ttl: ttl) - } catch let err as SdkError { - return CacheSetError(error: err) - } catch { - return CacheSetError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.set( + /** + Associates the given key with the given value. If a value for the key is already present it is replaced with the new value. + - Parameters: + - cacheName: the name of the cache to store the value in + - key: the key to set the value for + - value: the value to associate with the key + - ttl: the time to live for the item in the cache. Uses the client's default TTL if this is not supplied. + - Returns: CacheSetResponse representing the result of the set operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheSetError: + // handle error + case let responseSuccess as CacheSetSuccess: + // handle success + } + ``` + */ + public func set( + cacheName: String, + key: Data, + value: String, + ttl: TimeInterval? = nil + ) async -> CacheSetResponse { + return await set( cacheName: cacheName, key: ScalarType.data(key), value: ScalarType.string(value), @@ -259,10 +273,47 @@ public class CacheClient { ) } - public func set(cacheName: String, key: Data, value: Data, ttl: TimeInterval? = nil) async -> CacheSetResponse { + /** + Associates the given key with the given value. If a value for the key is already present it is replaced with the new value. + - Parameters: + - cacheName: the name of the cache to store the value in + - key: the key to set the value for + - value: the value to associate with the key + - ttl: the time to live for the item in the cache. Uses the client's default TTL if this is not supplied. + - Returns: CacheSetResponse representing the result of the set operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheSetError: + // handle error + case let responseSuccess as CacheSetSuccess: + // handle success + } + ``` + */ + public func set( + cacheName: String, + key: Data, + value: Data, + ttl: TimeInterval? = nil + ) async -> CacheSetResponse { + return await set( + cacheName: cacheName, + key: ScalarType.data(key), + value: ScalarType.data(value), + ttl: ttl + ) + } + + internal func set( + cacheName: String, + key: ScalarType, + value: ScalarType, + ttl: TimeInterval? = nil + ) async -> CacheSetResponse { do { try validateCacheName(cacheName: cacheName) - try validateCacheKey(key: ScalarType.data(key)) + try validateCacheKey(key: key) try validateTtl(ttl: ttl) } catch let err as SdkError { return CacheSetError(error: err) @@ -273,8 +324,8 @@ public class CacheClient { } return await self.dataClient.set( cacheName: cacheName, - key: ScalarType.data(key), - value: ScalarType.data(value), + key: key, + value: value, ttl: ttl ) } @@ -305,20 +356,7 @@ public class CacheClient { truncateFrontToSize: Int? = nil, ttl: CollectionTtl? = nil ) async -> CacheListConcatenateBackResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateListName(listName: listName) - try validateTruncateSize(size: truncateFrontToSize) - try validateTtl(ttl: ttl?.ttlSeconds()) - try validateListSize(list: values.map { ScalarType.string($0) }) - } catch let err as SdkError { - return CacheListConcatenateBackError(error: err) - } catch { - return CacheListConcatenateBackError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.listConcatenateBack( + return await listConcatenateBack( cacheName: cacheName, listName: listName, values: values.map { ScalarType.string($0) }, @@ -327,19 +365,54 @@ public class CacheClient { ) } + /** + Adds multiple elements to the back of the given list. Creates the list if it does not already exist. + - Parameters: + - cacheName: the name of the cache to store the list in + - listName: the list to add to + - values: the elements to add to the list + - truncateFrontToSize: If the list exceeds this length, remove excess from the front of the list. Must be positive. + - ttl: refreshes the list's TTL using the client's default if this is not supplied. + - Returns: CacheListConcatenateBackResponse representing the result of the operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheListConcatenateBackError: + // handle error + case let responseSuccess as CacheListConcatenateBackSuccess: + // handle success + } + ``` + */ public func listConcatenateBack( cacheName: String, listName: String, values: [Data], truncateFrontToSize: Int? = nil, ttl: CollectionTtl? = nil + ) async -> CacheListConcatenateBackResponse { + return await listConcatenateBack( + cacheName: cacheName, + listName: listName, + values: values.map { ScalarType.data($0) }, + truncateFrontToSize: truncateFrontToSize, + ttl: ttl + ) + } + + internal func listConcatenateBack( + cacheName: String, + listName: String, + values: [ScalarType], + truncateFrontToSize: Int? = nil, + ttl: CollectionTtl? = nil ) async -> CacheListConcatenateBackResponse { do { try validateCacheName(cacheName: cacheName) try validateListName(listName: listName) try validateTruncateSize(size: truncateFrontToSize) try validateTtl(ttl: ttl?.ttlSeconds()) - try validateListSize(list: values.map { ScalarType.data($0) }) + try validateListSize(list: values) } catch let err as SdkError { return CacheListConcatenateBackError(error: err) } catch { @@ -350,7 +423,7 @@ public class CacheClient { return await self.dataClient.listConcatenateBack( cacheName: cacheName, listName: listName, - values: values.map { ScalarType.data($0) }, + values: values, truncateFrontToSize: truncateFrontToSize, ttl: ttl ) @@ -382,20 +455,7 @@ public class CacheClient { truncateBackToSize: Int? = nil, ttl: CollectionTtl? = nil ) async -> CacheListConcatenateFrontResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateListName(listName: listName) - try validateTruncateSize(size: truncateBackToSize) - try validateTtl(ttl: ttl?.ttlSeconds()) - try validateListSize(list: values.map { ScalarType.string($0) }) - } catch let err as SdkError { - return CacheListConcatenateFrontError(error: err) - } catch { - return CacheListConcatenateFrontError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.listConcatenateFront( + return await listConcatenateFront( cacheName: cacheName, listName: listName, values: values.map { ScalarType.string($0) }, @@ -404,19 +464,54 @@ public class CacheClient { ) } + /** + Adds multiple elements to the front of the given list. Creates the list if it does not already exist. + - Parameters: + - cacheName: the name of the cache to store the list in + - listName: the list to add to + - values: the elements to add to the list + - truncateBackToSize: If the list exceeds this length, remove excess from the back of the list. Must be positive. + - ttl: refreshes the list's TTL using the client's default if this is not supplied. + - Returns: CacheListConcatenateFrontResponse representing the result of the operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheListConcatenateFrontError: + // handle error + case let responseSuccess as CacheListConcatenateFrontSuccess: + // handle success + } + ``` + */ public func listConcatenateFront( cacheName: String, listName: String, values: [Data], truncateBackToSize: Int? = nil, ttl: CollectionTtl? = nil + ) async -> CacheListConcatenateFrontResponse { + return await listConcatenateFront( + cacheName: cacheName, + listName: listName, + values: values.map { ScalarType.data($0) }, + truncateBackToSize: truncateBackToSize, + ttl: ttl + ) + } + + internal func listConcatenateFront( + cacheName: String, + listName: String, + values: [ScalarType], + truncateBackToSize: Int? = nil, + ttl: CollectionTtl? = nil ) async -> CacheListConcatenateFrontResponse { do { try validateCacheName(cacheName: cacheName) try validateListName(listName: listName) try validateTruncateSize(size: truncateBackToSize) try validateTtl(ttl: ttl?.ttlSeconds()) - try validateListSize(list: values.map { ScalarType.data($0) }) + try validateListSize(list: values) } catch let err as SdkError { return CacheListConcatenateFrontError(error: err) } catch { @@ -427,7 +522,7 @@ public class CacheClient { return await self.dataClient.listConcatenateFront( cacheName: cacheName, listName: listName, - values: values.map { ScalarType.data($0) }, + values: values, truncateBackToSize: truncateBackToSize, ttl: ttl ) @@ -609,19 +704,7 @@ public class CacheClient { truncateFrontToSize: Int? = nil, ttl: CollectionTtl? = nil ) async -> CacheListPushBackResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateListName(listName: listName) - try validateTruncateSize(size: truncateFrontToSize) - try validateTtl(ttl: ttl?.ttlSeconds()) - } catch let err as SdkError { - return CacheListPushBackError(error: err) - } catch { - return CacheListPushBackError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.listPushBack( + return await listPushBack( cacheName: cacheName, listName: listName, value: ScalarType.string(value), @@ -630,12 +713,47 @@ public class CacheClient { ) } + /** + Adds an element to the back of the given list. Creates the list if it does not already exist. + - Parameters: + - cacheName: the name of the cache to store the list in + - listName: the list to add to + - value: the element to add to the list + - truncateFrontToSize: If the list exceeds this length, remove excess from the front of the list. Must be positive. + - ttl: refreshes the list's TTL using the client's default if this is not supplied. + - Returns: CacheListPushBackResponse representing the result of the operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheListPushBackError: + // handle error + case let responseSuccess as CacheListPushBackSuccess: + // handle success + } + ``` + */ public func listPushBack( cacheName: String, listName: String, value: Data, truncateFrontToSize: Int? = nil, ttl: CollectionTtl? = nil + ) async -> CacheListPushBackResponse { + return await listPushBack( + cacheName: cacheName, + listName: listName, + value: ScalarType.data(value), + truncateFrontToSize: truncateFrontToSize, + ttl: ttl + ) + } + + internal func listPushBack( + cacheName: String, + listName: String, + value: ScalarType, + truncateFrontToSize: Int? = nil, + ttl: CollectionTtl? = nil ) async -> CacheListPushBackResponse { do { try validateCacheName(cacheName: cacheName) @@ -652,7 +770,7 @@ public class CacheClient { return await self.dataClient.listPushBack( cacheName: cacheName, listName: listName, - value: ScalarType.data(value), + value: value, truncateFrontToSize: truncateFrontToSize, ttl: ttl ) @@ -684,19 +802,7 @@ public class CacheClient { truncateBackToSize: Int? = nil, ttl: CollectionTtl? = nil ) async -> CacheListPushFrontResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateListName(listName: listName) - try validateTruncateSize(size: truncateBackToSize) - try validateTtl(ttl: ttl?.ttlSeconds()) - } catch let err as SdkError { - return CacheListPushFrontError(error: err) - } catch { - return CacheListPushFrontError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.listPushFront( + return await listPushFront( cacheName: cacheName, listName: listName, value: ScalarType.string(value), @@ -705,12 +811,47 @@ public class CacheClient { ) } + /** + Adds an element to the front of the given list. Creates the list if it does not already exist. + - Parameters: + - cacheName: the name of the cache to store the list in + - listName: the list to add to + - value: the element to add to the list + - truncateBackToSize: If the list exceeds this length, remove excess from the back of the list. Must be positive. + - ttl: refreshes the list's TTL using the client's default if this is not supplied. + - Returns: CacheListPushFrontResponse representing the result of the operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheListPushFrontError: + // handle error + case let responseSuccess as CacheListPushFrontSuccess: + // handle success + } + ``` + */ public func listPushFront( cacheName: String, listName: String, value: Data, truncateBackToSize: Int? = nil, ttl: CollectionTtl? = nil + ) async -> CacheListPushFrontResponse { + return await listPushFront( + cacheName: cacheName, + listName: listName, + value: ScalarType.data(value), + truncateBackToSize: truncateBackToSize, + ttl: ttl + ) + } + + internal func listPushFront( + cacheName: String, + listName: String, + value: ScalarType, + truncateBackToSize: Int? = nil, + ttl: CollectionTtl? = nil ) async -> CacheListPushFrontResponse { do { try validateCacheName(cacheName: cacheName) @@ -727,7 +868,7 @@ public class CacheClient { return await self.dataClient.listPushFront( cacheName: cacheName, listName: listName, - value: ScalarType.data(value), + value: value, truncateBackToSize: truncateBackToSize, ttl: ttl ) @@ -755,27 +896,38 @@ public class CacheClient { listName: String, value: String ) async -> CacheListRemoveValueResponse { - do { - try validateCacheName(cacheName: cacheName) - try validateListName(listName: listName) - } catch let err as SdkError { - return CacheListRemoveValueError(error: err) - } catch { - return CacheListRemoveValueError(error: UnknownError( - message: "unexpected error: \(error)") - ) - } - return await self.dataClient.listRemoveValue( - cacheName: cacheName, - listName: listName, - value: ScalarType.string(value) - ) + return await listRemoveValue(cacheName: cacheName, listName: listName, value: ScalarType.string(value)) } + /** + Removes all elements from the given list equal to the given value. + - Parameters: + - cacheName: the name of the cache containing the list + - listName: the list to remove values from + - value: the value to remove + - Returns: CacheListRemoveValueResponse representing the result of the operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch response { + case let responseError as CacheListRemoveValueError: + // handle error + case let responseSuccess as CacheListRemoveValueSuccess: + // handle success + } + ``` + */ public func listRemoveValue( cacheName: String, listName: String, value: Data + ) async -> CacheListRemoveValueResponse { + return await listRemoveValue(cacheName: cacheName, listName: listName, value: ScalarType.data(value)) + } + + internal func listRemoveValue( + cacheName: String, + listName: String, + value: ScalarType ) async -> CacheListRemoveValueResponse { do { try validateCacheName(cacheName: cacheName) @@ -790,7 +942,7 @@ public class CacheClient { return await self.dataClient.listRemoveValue( cacheName: cacheName, listName: listName, - value: ScalarType.data(value) + value: value ) } diff --git a/Sources/Momento/TopicClient.swift b/Sources/Momento/TopicClient.swift index 89ae3e8..45a2aa9 100644 --- a/Sources/Momento/TopicClient.swift +++ b/Sources/Momento/TopicClient.swift @@ -1,8 +1,16 @@ +import Foundation + public protocol TopicClientProtocol { func publish( cacheName: String, topicName: String, - value: ScalarType + value: String + ) async -> TopicPublishResponse + + func publish( + cacheName: String, + topicName: String, + value: Data ) async -> TopicPublishResponse func subscribe( @@ -44,7 +52,32 @@ public class TopicClient: TopicClientProtocol { - Parameters: - cacheName: name of the cache containing the topic - topicName: name of the topic - - value: the value to be published + - value: the value to be published as String + - Returns: TopicPublishResponse representing the result of the publish operation. + Pattern matching can be used to operate on the appropriate subtype. + ``` + switch publishResponse { + case let publishError as TopicPublishError: + // handle error + case is TopicPublishSuccess: + // handle success + } + ``` + */ + public func publish( + cacheName: String, + topicName: String, + value: String + ) async -> TopicPublishResponse { + return await self.doPublish(cacheName: cacheName, topicName: topicName, value: ScalarType.string(value)) + } + + /** + Publishes a value to a topic + - Parameters: + - cacheName: name of the cache containing the topic + - topicName: name of the topic + - value: the value to be published as Data - Returns: TopicPublishResponse representing the result of the publish operation. Pattern matching can be used to operate on the appropriate subtype. ``` @@ -57,6 +90,14 @@ public class TopicClient: TopicClientProtocol { ``` */ public func publish( + cacheName: String, + topicName: String, + value: Data + ) async -> TopicPublishResponse { + return await self.doPublish(cacheName: cacheName, topicName: topicName, value: ScalarType.data(value)) + } + + internal func doPublish( cacheName: String, topicName: String, value: ScalarType diff --git a/Tests/MomentoTests/configTests.swift b/Tests/MomentoTests/configTests.swift index 3f9cf2b..5474f91 100644 --- a/Tests/MomentoTests/configTests.swift +++ b/Tests/MomentoTests/configTests.swift @@ -50,7 +50,7 @@ final class configTests: XCTestCase { let pubResp = await topicClient.publish( cacheName: self.integrationTestCacheName, topicName: generateStringWithUuid(prefix: "test-topic"), - value: ScalarType.string("test-message") + value: "test-message" ) XCTAssertTrue(pubResp is TopicPublishError) XCTAssertEqual(MomentoErrorCode.TIMEOUT_ERROR, (pubResp as! TopicPublishError).errorCode) diff --git a/Tests/MomentoTests/topicsTests.swift b/Tests/MomentoTests/topicsTests.swift index 0e7eb45..121066e 100644 --- a/Tests/MomentoTests/topicsTests.swift +++ b/Tests/MomentoTests/topicsTests.swift @@ -26,7 +26,7 @@ final class topicsTests: XCTestCase { let invalidCacheNameResp = await self.topicClient.publish( cacheName: "", topicName: topicName, - value: ScalarType.string("test-message") + value: "test-message" ) XCTAssertTrue( invalidCacheNameResp is TopicPublishError, @@ -41,7 +41,7 @@ final class topicsTests: XCTestCase { let invalidTopicNameResp = await self.topicClient.publish( cacheName: self.integrationTestCacheName, topicName: "", - value: ScalarType.string("test-message") + value: "test-message" ) XCTAssertTrue( invalidTopicNameResp is TopicPublishError, @@ -56,7 +56,7 @@ final class topicsTests: XCTestCase { let pubResp = await self.topicClient.publish( cacheName: self.integrationTestCacheName, topicName: topicName, - value: ScalarType.string("test-message") + value: "test-message" ) XCTAssertTrue( pubResp is TopicPublishSuccess, @@ -121,7 +121,7 @@ final class topicsTests: XCTestCase { let pubResp = await self.topicClient.publish( cacheName: self.integrationTestCacheName, topicName: topicName, - value: ScalarType.string("publishing and subscribing!") + value: "publishing and subscribing!" ) XCTAssertTrue( pubResp is TopicPublishSuccess, @@ -158,7 +158,7 @@ final class topicsTests: XCTestCase { let pubResp = await self.topicClient.publish( cacheName: self.integrationTestCacheName, topicName: topicName, - value: ScalarType.data(binaryValue) + value: binaryValue ) XCTAssertTrue( pubResp is TopicPublishSuccess,