Skip to content

Commit

Permalink
Merge pull request #43 from momentohq/add-list-collection
Browse files Browse the repository at this point in the history
feat: add list collection
  • Loading branch information
pratik151192 authored Jan 12, 2024
2 parents 357c115 + a08c050 commit 3b57e7d
Show file tree
Hide file tree
Showing 20 changed files with 3,285 additions and 13 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

213 changes: 213 additions & 0 deletions src/commonMain/kotlin/software/momento/kotlin/sdk/CacheClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@ import software.momento.kotlin.sdk.auth.CredentialProvider
import software.momento.kotlin.sdk.config.Configuration
import software.momento.kotlin.sdk.internal.InternalControlClient
import software.momento.kotlin.sdk.internal.InternalDataClient
import software.momento.kotlin.sdk.requests.CollectionTtl
import software.momento.kotlin.sdk.responses.cache.DeleteResponse
import software.momento.kotlin.sdk.responses.cache.GetResponse
import software.momento.kotlin.sdk.responses.cache.SetResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheCreateResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheDeleteResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheListResponse
import software.momento.kotlin.sdk.responses.cache.list.ListConcatenateBackResponse
import software.momento.kotlin.sdk.responses.cache.list.ListConcatenateFrontResponse
import software.momento.kotlin.sdk.responses.cache.list.ListFetchResponse
import software.momento.kotlin.sdk.responses.cache.list.ListLengthResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPopBackResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPopFrontResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPushBackResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPushFrontResponse
import software.momento.kotlin.sdk.responses.cache.list.ListRemoveValueResponse
import software.momento.kotlin.sdk.responses.cache.list.ListRetainResponse
import kotlin.time.Duration

/**
Expand Down Expand Up @@ -171,6 +182,208 @@ public class CacheClient(
return dataClient.delete(cacheName, key)
}

/**
* Appends a list of string values to the back of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to append to.
* @param values The list of string values to append.
* @param truncateFrontToSize Optional parameter to truncate the list from the front to a certain size after the append operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the concatenate back operation: [ListConcatenateBackResponse.Success] or [ListConcatenateBackResponse.Error].
*/
public suspend fun listConcatenateBack(cacheName: String, listName: String, values: Iterable<String>, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null
): ListConcatenateBackResponse {
return dataClient.listConcatenateBack(cacheName, listName, values, truncateFrontToSize, ttl)
}

/**
* Appends a list of byte array values to the back of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to append to.
* @param values The list of byte array values to append.
* @param truncateFrontToSize Optional parameter to truncate the list from the front to a certain size after the append operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the concatenate back operation: [ListConcatenateBackResponse.Success] or [ListConcatenateBackResponse.Error].
*/
public suspend fun listConcatenateBackByteArray(cacheName: String, listName: String, values: Iterable<ByteArray>, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null
): ListConcatenateBackResponse {
return dataClient.listConcatenateBackByteArray(cacheName, listName, values, truncateFrontToSize, ttl)
}

/**
* Prepends a list of string values to the front of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to prepend to.
* @param values The list of string values to prepend.
* @param truncateBackToSize Optional parameter to truncate the list from the back to a certain size after the prepend operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the concatenate front operation: [ListConcatenateFrontResponse.Success] or [ListConcatenateFrontResponse.Error].
*/
public suspend fun listConcatenateFront(cacheName: String, listName: String, values: Iterable<String>, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null
): ListConcatenateFrontResponse {
return dataClient.listConcatenateFront(cacheName, listName, values, truncateBackToSize, ttl)
}

/**
* Prepends a list of byte array values to the front of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to prepend to.
* @param values The list of byte array values to prepend.
* @param truncateBackToSize Optional parameter to truncate the list from the back to a certain size after the prepend operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the concatenate front operation: [ListConcatenateFrontResponse.Success] or [ListConcatenateFrontResponse.Error].
*/
public suspend fun listConcatenateFrontByteArray(cacheName: String, listName: String, values: Iterable<ByteArray>, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null
): ListConcatenateFrontResponse {
return dataClient.listConcatenateFrontByteArray(cacheName, listName, values, truncateBackToSize, ttl)
}

/**
* Retrieves a range of elements from an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to fetch from.
* @param startIndex The starting index of the range (inclusive).
* @param endIndex The ending index of the range (exclusive).
* @return The result of the list fetch operation: [ListFetchResponse.Hit] or [ListFetchResponse.Miss] or [ListFetchResponse.Error].
*/
public suspend fun listFetch(cacheName: String, listName: String, startIndex: Int? = null, endIndex: Int? = null): ListFetchResponse {
return dataClient.listFetch(cacheName, listName, startIndex, endIndex)
}

/**
* Retrieves the length of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to measure.
* @return The result of the list length operation: [ListLengthResponse.Hit] or [ListLengthResponse.Miss] or [ListLengthResponse.Error].
*/
public suspend fun listLength(cacheName: String, listName: String): ListLengthResponse {
return dataClient.listLength(cacheName, listName)
}

/**
* Adds a value to the back of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to append to.
* @param value The value to add.
* @param truncateFrontToSize Optional parameter to truncate the list from the front to a certain size after the append operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the push back operation: [ListPushBackResponse.Success] or [ListPushBackResponse.Error].
*/
public suspend fun listPushBack(cacheName: String, listName: String, value: String, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null): ListPushBackResponse {
return dataClient.listPushBack(cacheName, listName, value, truncateFrontToSize, ttl)
}

/**
* Adds a value to the back of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to append to.
* @param value The value to add.
* @param truncateFrontToSize Optional parameter to truncate the list from the front to a certain size after the append operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the push back operation: [ListPushBackResponse.Success] or [ListPushBackResponse.Error].
*/
public suspend fun listPushBack(cacheName: String, listName: String, value: ByteArray, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null): ListPushBackResponse {
return dataClient.listPushBack(cacheName, listName, value, truncateFrontToSize, ttl)
}

/**
* Adds a value to the front of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to prepend to.
* @param value The value to add.
* @param truncateBackToSize Optional parameter to truncate the list from the back to a certain size after the prepend operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the push front operation: [ListPushFrontResponse.Success] or [ListPushFrontResponse.Error].
*/
public suspend fun listPushFront(cacheName: String, listName: String, value: String, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null): ListPushFrontResponse {
return dataClient.listPushFront(cacheName, listName, value, truncateBackToSize, ttl)
}

/**
* Adds a value to the front of an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to prepend to.
* @param value The value to add.
* @param truncateBackToSize Optional parameter to truncate the list from the back to a certain size after the prepend operation.
* @param ttl Optional CollectionTtl for the list.
* @return The result of the push front operation: [ListPushFrontResponse.Success] or [ListPushFrontResponse.Error].
*/
public suspend fun listPushFront(cacheName: String, listName: String, value: ByteArray, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null): ListPushFrontResponse {
return dataClient.listPushFront(cacheName, listName, value, truncateBackToSize, ttl)
}

/**
* Removes the last value from an existing list in the cache and returns it.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to pop from.
* @return The result of the pop back operation: [ListPopBackResponse.Hit] with the value if the list is not empty,
* [ListPopBackResponse.Miss] if the list is empty, or [ListPopBackResponse.Error].
*/
public suspend fun listPopBack(cacheName: String, listName: String): ListPopBackResponse {
return dataClient.listPopBack(cacheName, listName)
}

/**
* Removes the first value from an existing list in the cache and returns it.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to pop from.
* @return The result of the pop front operation: [ListPopFrontResponse.Hit] with the value if the list is not empty,
* [ListPopFrontResponse.Miss] if the list is empty, or [ListPopFrontResponse.Error].
*/
public suspend fun listPopFront(cacheName: String, listName: String): ListPopFrontResponse {
return dataClient.listPopFront(cacheName, listName)
}

/**
* Removes a specific value from an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to remove the value from.
* @param value The string value to be removed.
* @return The result of the remove value operation: [ListRemoveValueResponse.Success] or [ListRemoveValueResponse.Error].
*/
public suspend fun listRemoveValue(cacheName: String, listName: String, value: String): ListRemoveValueResponse {
return dataClient.listRemoveValue(cacheName, listName, value)
}

/**
* Removes a specific value from an existing list in the cache.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to remove the value from.
* @param value The byte array value to be removed.
* @return The result of the remove value operation: [ListRemoveValueResponse.Success] or [ListRemoveValueResponse.Error].
*/
public suspend fun listRemoveValue(cacheName: String, listName: String, value: ByteArray): ListRemoveValueResponse {
return dataClient.listRemoveValue(cacheName, listName, value)
}

/**
* Retains a specific range of elements in an existing list in the cache by slicing it.
*
* @param cacheName The name of the cache containing the list.
* @param listName The name of the list to retain elements in.
* @param startIndex The starting index of the range to retain (inclusive).
* @param endIndex The ending index of the range to retain (exclusive).
* @param ttl Optional CollectionTtl for the list.
* @return The result of the retain operation: [ListRetainResponse.Success] or [ListRetainResponse.Error].
*/
public suspend fun listRetain(cacheName: String, listName: String, startIndex: Int? = null, endIndex: Int? = null, ttl: CollectionTtl? = null): ListRetainResponse {
return dataClient.listRetain(cacheName, listName, startIndex, endIndex, ttl)
}

override fun close() {
dataClient.close()
controlClient.close()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@ package software.momento.kotlin.sdk.internal

import software.momento.kotlin.sdk.auth.CredentialProvider
import software.momento.kotlin.sdk.config.Configuration
import software.momento.kotlin.sdk.requests.CollectionTtl
import software.momento.kotlin.sdk.responses.cache.DeleteResponse
import software.momento.kotlin.sdk.responses.cache.GetResponse
import software.momento.kotlin.sdk.responses.cache.SetResponse
import software.momento.kotlin.sdk.responses.cache.list.ListConcatenateBackResponse
import software.momento.kotlin.sdk.responses.cache.list.ListConcatenateFrontResponse
import software.momento.kotlin.sdk.responses.cache.list.ListFetchResponse
import software.momento.kotlin.sdk.responses.cache.list.ListLengthResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPopBackResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPopFrontResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPushBackResponse
import software.momento.kotlin.sdk.responses.cache.list.ListPushFrontResponse
import software.momento.kotlin.sdk.responses.cache.list.ListRemoveValueResponse
import software.momento.kotlin.sdk.responses.cache.list.ListRetainResponse
import kotlin.time.Duration

internal expect class InternalDataClient(
Expand All @@ -28,4 +39,34 @@ internal expect class InternalDataClient(
internal suspend fun delete(cacheName: String, key: String): DeleteResponse

internal suspend fun delete(cacheName: String, key: ByteArray): DeleteResponse

internal suspend fun listConcatenateBack(cacheName: String, listName: String, values: Iterable<String>, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null): ListConcatenateBackResponse

internal suspend fun listConcatenateBackByteArray(cacheName: String, listName: String, values: Iterable<ByteArray>, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null): ListConcatenateBackResponse

internal suspend fun listConcatenateFront(cacheName: String, listName: String, values: Iterable<String>, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null): ListConcatenateFrontResponse

internal suspend fun listConcatenateFrontByteArray(cacheName: String, listName: String, values: Iterable<ByteArray>, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null): ListConcatenateFrontResponse

internal suspend fun listFetch(cacheName: String, listName: String, startIndex: Int?, endIndex: Int?): ListFetchResponse

internal suspend fun listLength(cacheName: String, listName: String): ListLengthResponse

internal suspend fun listPushBack(cacheName: String, listName: String, value: String, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null): ListPushBackResponse

internal suspend fun listPushBack(cacheName: String, listName: String, value: ByteArray, truncateFrontToSize: Int? = null, ttl: CollectionTtl? = null): ListPushBackResponse

internal suspend fun listPushFront(cacheName: String, listName: String, value: String, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null): ListPushFrontResponse

internal suspend fun listPushFront(cacheName: String, listName: String, value: ByteArray, truncateBackToSize: Int? = null, ttl: CollectionTtl? = null): ListPushFrontResponse

internal suspend fun listPopBack(cacheName: String, listName: String): ListPopBackResponse

internal suspend fun listPopFront(cacheName: String, listName: String): ListPopFrontResponse

internal suspend fun listRemoveValue(cacheName: String, listName: String, value: String): ListRemoveValueResponse

internal suspend fun listRemoveValue(cacheName: String, listName: String, value: ByteArray): ListRemoveValueResponse

internal suspend fun listRetain(cacheName: String, listName: String, startIndex: Int?, endIndex: Int?, ttl: CollectionTtl? = null): ListRetainResponse
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
package software.momento.kotlin.sdk.internal.utils

import software.momento.kotlin.sdk.exceptions.InvalidArgumentException
import kotlin.time.Duration

/**
* Client-side validation methods. While we should rely on server for all validations, there are
* some that cannot be delegated and instead fail in grpc client, like providing a negative ttl.
*/
public object ValidationUtils {
private const val REQUEST_DEADLINE_MUST_BE_POSITIVE = "Request deadline must be positive"
private const val CACHE_ITEM_TTL_MUST_BE_POSITIVE = "Cache item TTL must be positive"
private const val CACHE_NAME_IS_REQUIRED = "Non-empty cache name is required"

/**
* Throws an [InvalidArgumentException] if the deadline is null or not positive.
*
* @param deadline The deadline to validate.
*/
internal fun requireValidDeadline(deadline: Duration) {
require(deadline.isPositive()) { REQUEST_DEADLINE_MUST_BE_POSITIVE }
}
private const val LIST_NAME_IS_REQUIRED = "List name is required and cannot be null"
private const val TRUNCATE_TO_SIZE_MUST_BE_POSITIVE = "Truncate to size must be positive"
private const val A_NON_NULL_VALUE_IS_REQUIRED = "A non-null value is required"
private const val INDEX_RANGE_INVALID = "End index must be greater than start index"

internal fun requireValidCacheName(cacheName: String) {
require(cacheName.isNotBlank()) { CACHE_NAME_IS_REQUIRED }
Expand All @@ -28,4 +21,14 @@ public object ValidationUtils {
internal fun requireValidTtl(ttl: Duration) {
require(ttl.isPositive()) { CACHE_ITEM_TTL_MUST_BE_POSITIVE }
}

internal fun requireValidTruncateToSize(truncateToSize: Int?) {
require(truncateToSize == null || truncateToSize > 0) { TRUNCATE_TO_SIZE_MUST_BE_POSITIVE }
}

internal fun requireIndexRangeValid(startIndex: Int?, endIndex: Int?) {
if (startIndex == null || endIndex == null) return

require(endIndex > startIndex) { INDEX_RANGE_INVALID }
}
}
Loading

0 comments on commit 3b57e7d

Please sign in to comment.