Skip to content

Commit

Permalink
feat: add byte array for list methods on the list name (#392)
Browse files Browse the repository at this point in the history
Adds various overloads for cache `listFetch`,
`listConcatenateFrontByteArray`, and `listRetain` for the `listName`
as a byte array.
  • Loading branch information
malandis committed Sep 4, 2024
1 parent 87a6119 commit 41ba4b5
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 2 deletions.
91 changes: 89 additions & 2 deletions momento-sdk/src/intTest/java/momento/sdk/ListTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package momento.sdk;

import static momento.sdk.TestUtils.randomBytes;
import static momento.sdk.TestUtils.randomString;
import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -443,6 +444,63 @@ public void listConcatenateFrontStringHappyPath() {
.containsExactlyElementsOf(newExpectedList));
}

@Test
public void listConcatenateFrontByteArrayListNameByteArrayHappyPath() {
final byte[] listName = randomBytes();
final List<byte[]> oldValues =
Arrays.asList("val1".getBytes(), "val2".getBytes(), "val3".getBytes());
final List<byte[]> newValues =
Arrays.asList("val4".getBytes(), "val5".getBytes(), "val6".getBytes());

assertThat(cacheClient.listFetch(cacheName, listName))
.succeedsWithin(FIVE_SECONDS)
.isInstanceOf(ListFetchResponse.Miss.class);

assertThat(
cacheClient.listConcatenateFrontByteArray(
cacheName, listName, oldValues, null, CollectionTtl.fromCacheTtl()))
.succeedsWithin(FIVE_SECONDS)
.isInstanceOf(ListConcatenateFrontResponse.Success.class);

assertThat(cacheClient.listFetch(cacheName, listName))
.succeedsWithin(FIVE_SECONDS)
.asInstanceOf(InstanceOfAssertFactories.type(ListFetchResponse.Hit.class))
.satisfies(
hit ->
assertThat(hit.valueListByteArray())
.hasSize(3)
.containsExactlyElementsOf(oldValues));

assertThat(cacheClient.listConcatenateFrontByteArray(cacheName, listName, newValues))
.succeedsWithin(FIVE_SECONDS)
.isInstanceOf(ListConcatenateFrontResponse.Success.class);

final Iterable<byte[]> expectedList = Iterables.concat(newValues, oldValues);
assertThat(cacheClient.listFetch(cacheName, listName))
.succeedsWithin(FIVE_SECONDS)
.asInstanceOf(InstanceOfAssertFactories.type(ListFetchResponse.Hit.class))
.satisfies(
hit ->
assertThat(hit.valueListByteArray())
.hasSize(6)
.containsExactlyElementsOf(expectedList));

// Add the original values again and truncate the list to 6 items
assertThat(cacheClient.listConcatenateFrontByteArray(cacheName, listName, oldValues, 6))
.succeedsWithin(FIVE_SECONDS)
.isInstanceOf(ListConcatenateFrontResponse.Success.class);

final Iterable<byte[]> newExpectedList = Iterables.concat(oldValues, newValues);
assertThat(cacheClient.listFetch(cacheName, listName))
.succeedsWithin(FIVE_SECONDS)
.asInstanceOf(InstanceOfAssertFactories.type(ListFetchResponse.Hit.class))
.satisfies(
hit ->
assertThat(hit.valueListByteArray())
.hasSize(6)
.containsExactlyElementsOf(newExpectedList));
}

@Test
public void listConcatenateFrontByteArrayHappyPath() {
final String listName = randomString();
Expand Down Expand Up @@ -563,13 +621,14 @@ public void shouldFailListConcatenateFrontWhenNullListName() {
// With ttl specified in method signature
assertThat(
cacheClient.listConcatenateFrontByteArray(
cacheName, null, byteArrayValues, 0, CollectionTtl.fromCacheTtl()))
cacheName, (String) null, byteArrayValues, 0, CollectionTtl.fromCacheTtl()))
.succeedsWithin(FIVE_SECONDS)
.asInstanceOf(InstanceOfAssertFactories.type(ListConcatenateFrontResponse.Error.class))
.satisfies(error -> assertThat(error).hasCauseInstanceOf(InvalidArgumentException.class));

// Without ttl specified in method signature
assertThat(cacheClient.listConcatenateFrontByteArray(cacheName, null, byteArrayValues, 0))
assertThat(
cacheClient.listConcatenateFrontByteArray(cacheName, (String) null, byteArrayValues, 0))
.succeedsWithin(FIVE_SECONDS)
.asInstanceOf(InstanceOfAssertFactories.type(ListConcatenateFrontResponse.Error.class))
.satisfies(error -> assertThat(error).hasCauseInstanceOf(InvalidArgumentException.class));
Expand Down Expand Up @@ -1280,6 +1339,34 @@ public void shouldFailListRemoveValueWhenNullElement() {
.satisfies(error -> assertThat(error).hasCauseInstanceOf(InvalidArgumentException.class));
}

@Test
public void shouldRetainAllValuesWhenListRetainListNameByteArrayWithPositiveStartEndIndices() {
final String listName = randomString();
final byte[] listNameByteArray = listName.getBytes();
final List<String> stringValues = Arrays.asList("val1", "val2", "val3", "val4");

assertThat(
cacheClient.listConcatenateFront(
cacheName, listName, stringValues, null, CollectionTtl.fromCacheTtl()))
.succeedsWithin(FIVE_SECONDS)
.isInstanceOf(ListConcatenateFrontResponse.Success.class);

assertThat(cacheClient.listFetch(cacheName, listNameByteArray, null, null))
.succeedsWithin(FIVE_SECONDS)
.asInstanceOf(InstanceOfAssertFactories.type(ListFetchResponse.Hit.class))
.satisfies(hit -> assertThat(hit.valueListString()).hasSize(4).containsAll(stringValues));

assertThat(cacheClient.listRetain(cacheName, listNameByteArray, 1, 3))
.succeedsWithin(FIVE_SECONDS)
.isInstanceOf(ListRetainResponse.Success.class);

List<String> expectedList = Arrays.asList("val2", "val3");
assertThat(cacheClient.listFetch(cacheName, listNameByteArray, null, null))
.succeedsWithin(FIVE_SECONDS)
.asInstanceOf(InstanceOfAssertFactories.type(ListFetchResponse.Hit.class))
.satisfies(hit -> assertThat(hit.valueListString()).hasSize(2).containsAll(expectedList));
}

@Test
public void shouldRetainAllValuesWhenListRetainWithPositiveStartEndIndices() {
final String listName = randomString();
Expand Down
109 changes: 109 additions & 0 deletions momento-sdk/src/main/java/momento/sdk/CacheClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,28 @@ public CompletableFuture<ListConcatenateFrontResponse> listConcatenateFront(
return scsDataClient.listConcatenateFront(cacheName, listName, values, null, null);
}

/**
* Adds the given values to the front of a list.
*
* @param cacheName The cache containing the list.
* @param listName The list in which to add the values.
* @param values The values to add to the list.
* @param truncateBackToSize If the list exceeds this length, remove excess from the front of the
* list. Must be positive. Will not truncate if not provided.
* @param ttl TTL for the set in cache. This TTL takes precedence over the TTL used when
* initializing a cache client. Defaults to the client's TTL if not provided.
* @return Future containing the result of the list concatenate front operation: {@link
* ListConcatenateFrontResponse.Success} or {@link ListConcatenateFrontResponse.Error}.
*/
public CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteArray(
@Nonnull String cacheName,
@Nonnull byte[] listName,
@Nonnull Iterable<byte[]> values,
@Nullable Integer truncateBackToSize,
@Nullable CollectionTtl ttl) {
return scsDataClient.listConcatenateFrontByteArray(
cacheName, listName, values, truncateBackToSize, ttl);
}
/**
* Adds the given values to the front of a list.
*
Expand All @@ -1628,6 +1650,26 @@ public CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteA
cacheName, listName, values, truncateBackToSize, ttl);
}

/**
* Adds the given values to the front of a list. Refreshes the list with the client's default TTL.
*
* @param cacheName The cache containing the list.
* @param listName The list in which to add the values.
* @param values The values to add to the list.
* @param truncateBackToSize If the list exceeds this length, remove excess from the front of the
* list. Must be positive. Will not truncate if not provided.
* @return Future containing the result of the list concatenate front operation: {@link
* ListConcatenateFrontResponse.Success} or {@link ListConcatenateFrontResponse.Error}.
*/
public CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteArray(
@Nonnull String cacheName,
@Nonnull byte[] listName,
@Nonnull Iterable<byte[]> values,
@Nullable Integer truncateBackToSize) {
return scsDataClient.listConcatenateFrontByteArray(
cacheName, listName, values, truncateBackToSize, null);
}

/**
* Adds the given values to the front of a list. Refreshes the list with the client's default TTL.
*
Expand All @@ -1648,6 +1690,20 @@ public CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteA
cacheName, listName, values, truncateBackToSize, null);
}

/**
* Adds the given values to the front of a list. Refreshes the list with the client's default TTL.
*
* @param cacheName The cache containing the list.
* @param listName The list in which to add the values.
* @param values The values to add to the list.
* @return Future containing the result of the list concatenate front operation: {@link
* ListConcatenateFrontResponse.Success} or {@link ListConcatenateFrontResponse.Error}.
*/
public CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteArray(
@Nonnull String cacheName, @Nonnull byte[] listName, @Nonnull Iterable<byte[]> values) {
return scsDataClient.listConcatenateFrontByteArray(cacheName, listName, values, null, null);
}

/**
* Adds the given values to the front of a list. Refreshes the list with the client's default TTL.
*
Expand All @@ -1662,6 +1718,27 @@ public CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteA
return scsDataClient.listConcatenateFrontByteArray(cacheName, listName, values, null, null);
}

/**
* Fetches all elements of a list between the given indices.
*
* @param cacheName The cache containing the list.
* @param listName The list to fetch.
* @param startIndex Start index (inclusive) for the fetch operation. Defaults to 0 if not
* provided.
* @param endIndex End index (exclusive) for the fetch operation. Defaults to the end of the list
* if not provided.
* @return Future containing the result of the list fetch operation: {@link ListFetchResponse.Hit}
* containing the fetched data, {@link ListFetchResponse.Miss} if no data was found, or {@link
* ListFetchResponse.Error}.
*/
public CompletableFuture<ListFetchResponse> listFetch(
@Nonnull String cacheName,
@Nonnull byte[] listName,
@Nullable Integer startIndex,
@Nullable Integer endIndex) {
return scsDataClient.listFetch(cacheName, listName, startIndex, endIndex);
}

/**
* Fetches all elements of a list between the given indices.
*
Expand All @@ -1683,6 +1760,20 @@ public CompletableFuture<ListFetchResponse> listFetch(
return scsDataClient.listFetch(cacheName, listName, startIndex, endIndex);
}

/**
* Fetches all elements of a list between the given indices.
*
* @param cacheName The cache containing the list.
* @param listName The list to fetch.
* @return Future containing the result of the list fetch operation: {@link ListFetchResponse.Hit}
* containing the fetched data, {@link ListFetchResponse.Miss} if no data was found, or {@link
* ListFetchResponse.Error}.
*/
public CompletableFuture<ListFetchResponse> listFetch(
@Nonnull String cacheName, @Nonnull byte[] listName) {
return scsDataClient.listFetch(cacheName, listName, null, null);
}

/**
* Fetches all elements of a list between the given indices.
*
Expand Down Expand Up @@ -1987,6 +2078,24 @@ public CompletableFuture<ListRemoveValueResponse> listRemoveValue(
return scsDataClient.listRemoveValue(cacheName, listName, value);
}

/**
* Retains only the elements of a list that are between the given indices.
*
* @param cacheName The cache containing the list.
* @param listName The list to cut down.
* @param startIndex - Start index (inclusive) for list retain operation.
* @param endIndex - End index (exclusive) for list retain operation.
* @return Future containing the result of the list retain value operation: {@link
* ListRetainResponse.Success} or {@link ListRetainResponse.Error}.
*/
public CompletableFuture<ListRetainResponse> listRetain(
@Nonnull String cacheName,
@Nonnull byte[] listName,
@Nullable Integer startIndex,
@Nullable Integer endIndex) {
return scsDataClient.listRetain(cacheName, listName, startIndex, endIndex);
}

/**
* Retains only the elements of a list that are between the given indices.
*
Expand Down
56 changes: 56 additions & 0 deletions momento-sdk/src/main/java/momento/sdk/ScsDataClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,29 @@ CompletableFuture<ListConcatenateFrontResponse> listConcatenateFront(
}
}

CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteArray(
@Nonnull String cacheName,
@Nonnull byte[] listName,
@Nonnull Iterable<byte[]> values,
@Nullable Integer truncateBackToSize,
@Nullable CollectionTtl ttl) {
try {
checkCacheNameValid(cacheName);
checkListNameValid(listName);
ensureValidValue(values);

if (ttl == null) {
ttl = CollectionTtl.of(itemDefaultTtl);
}

return sendListConcatenateFront(
cacheName, convert(listName), convertByteArrayIterable(values), truncateBackToSize, ttl);
} catch (Exception e) {
return CompletableFuture.completedFuture(
new ListConcatenateFrontResponse.Error(CacheServiceExceptionMapper.convert(e)));
}
}

CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteArray(
@Nonnull String cacheName,
@Nonnull String listName,
Expand All @@ -974,6 +997,22 @@ CompletableFuture<ListConcatenateFrontResponse> listConcatenateFrontByteArray(
}
}

CompletableFuture<ListFetchResponse> listFetch(
@Nonnull String cacheName,
@Nonnull byte[] listName,
@Nullable Integer startIndex,
@Nullable Integer endIndex) {
try {
checkCacheNameValid(cacheName);
checkListNameValid(listName);
checkIndexRangeValid(startIndex, endIndex);
return sendListFetch(cacheName, convert(listName), startIndex, endIndex);
} catch (Exception e) {
return CompletableFuture.completedFuture(
new ListFetchResponse.Error(CacheServiceExceptionMapper.convert(e)));
}
}

CompletableFuture<ListFetchResponse> listFetch(
@Nonnull String cacheName,
@Nonnull String listName,
Expand Down Expand Up @@ -1150,6 +1189,23 @@ CompletableFuture<ListRemoveValueResponse> listRemoveValue(
}
}

CompletableFuture<ListRetainResponse> listRetain(
@Nonnull String cacheName,
@Nonnull byte[] listName,
@Nullable Integer startIndex,
@Nullable Integer endIndex) {
try {
checkCacheNameValid(cacheName);
checkListNameValid(listName);
checkIndexRangeValid(startIndex, endIndex);

return sendListRetain(cacheName, convert(listName), startIndex, endIndex);
} catch (Exception e) {
return CompletableFuture.completedFuture(
new ListRetainResponse.Error(CacheServiceExceptionMapper.convert(e)));
}
}

CompletableFuture<ListRetainResponse> listRetain(
@Nonnull String cacheName,
@Nonnull String listName,
Expand Down
6 changes: 6 additions & 0 deletions momento-sdk/src/main/java/momento/sdk/ValidationUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ static void checkDictionaryNameValid(String dictionaryName) {
}
}

static void checkListNameValid(byte[] listName) {
if (listName == null) {
throw new InvalidArgumentException(LIST_NAME_CANNOT_BE_NULL);
}
}

static void checkListNameValid(String listName) {
if (listName == null) {
throw new InvalidArgumentException(LIST_NAME_CANNOT_BE_NULL);
Expand Down

0 comments on commit 41ba4b5

Please sign in to comment.