Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add byte array for list methods on the list name #392

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading