Skip to content

Commit 38c1c34

Browse files
authored
feat: add support of startOffset and endOffset (#430)
* feat: add support of startOffset and endOffset * feat: add support of startOffset and endOffset
1 parent 087d78c commit 38c1c34

File tree

5 files changed

+97
-0
lines changed

5 files changed

+97
-0
lines changed

google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,28 @@ public static BlobListOption delimiter(String delimiter) {
10511051
return new BlobListOption(StorageRpc.Option.DELIMITER, delimiter);
10521052
}
10531053

1054+
/**
1055+
* Returns an option to set a startOffset to filter results to objects whose names are
1056+
* lexicographically equal to or after startOffset. If endOffset is also set, the objects listed
1057+
* have names between startOffset (inclusive) and endOffset (exclusive).
1058+
*
1059+
* @param startOffset startOffset to filter the results
1060+
*/
1061+
public static BlobListOption startOffset(String startOffset) {
1062+
return new BlobListOption(StorageRpc.Option.START_OFF_SET, startOffset);
1063+
}
1064+
1065+
/**
1066+
* Returns an option to set a endOffset to filter results to objects whose names are
1067+
* lexicographically before endOffset. If startOffset is also set, the objects listed have names
1068+
* between startOffset (inclusive) and endOffset (exclusive).
1069+
*
1070+
* @param endOffset endOffset to filter the results
1071+
*/
1072+
public static BlobListOption endOffset(String endOffset) {
1073+
return new BlobListOption(StorageRpc.Option.END_OFF_SET, endOffset);
1074+
}
1075+
10541076
/**
10551077
* Returns an option to define the billing user project. This option is required by buckets with
10561078
* `requester_pays` flag enabled to assign operation costs.

google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ public Tuple<String, Iterable<StorageObject>> list(final String bucket, Map<Opti
354354
.setProjection(DEFAULT_PROJECTION)
355355
.setVersions(Option.VERSIONS.getBoolean(options))
356356
.setDelimiter(Option.DELIMITER.getString(options))
357+
.setStartOffset(Option.START_OFF_SET.getString(options))
358+
.setEndOffset(Option.END_OFF_SET.getString(options))
357359
.setPrefix(Option.PREFIX.getString(options))
358360
.setMaxResults(Option.MAX_RESULTS.getLong(options))
359361
.setPageToken(Option.PAGE_TOKEN.getString(options))

google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ enum Option {
5858
MAX_RESULTS("maxResults"),
5959
PAGE_TOKEN("pageToken"),
6060
DELIMITER("delimiter"),
61+
START_OFF_SET("startOffset"),
62+
END_OFF_SET("endOffset"),
6163
VERSIONS("versions"),
6264
FIELDS("fields"),
6365
CUSTOMER_SUPPLIED_KEY("customerSuppliedKey"),

google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,30 @@ public void testListBlobsDelimiter() {
665665
assertArrayEquals(blobList.toArray(), Iterables.toArray(page.getValues(), Blob.class));
666666
}
667667

668+
@Test
669+
public void testListBlobsWithOffset() {
670+
String cursor = "cursor";
671+
String startOffset = "startOffset";
672+
String endOffset = "endOffset";
673+
Map<StorageRpc.Option, ?> options =
674+
ImmutableMap.of(
675+
StorageRpc.Option.START_OFF_SET, startOffset, StorageRpc.Option.END_OFF_SET, endOffset);
676+
ImmutableList<BlobInfo> blobInfoList = ImmutableList.of(BLOB_INFO1, BLOB_INFO2);
677+
Tuple<String, Iterable<com.google.api.services.storage.model.StorageObject>> result =
678+
Tuple.of(cursor, Iterables.transform(blobInfoList, BlobInfo.INFO_TO_PB_FUNCTION));
679+
EasyMock.expect(storageRpcMock.list(BUCKET_NAME1, options)).andReturn(result);
680+
EasyMock.replay(storageRpcMock);
681+
initializeService();
682+
ImmutableList<Blob> blobList = ImmutableList.of(expectedBlob1, expectedBlob2);
683+
Page<Blob> page =
684+
storage.list(
685+
BUCKET_NAME1,
686+
Storage.BlobListOption.startOffset(startOffset),
687+
Storage.BlobListOption.endOffset(endOffset));
688+
assertEquals(cursor, page.getNextPageToken());
689+
assertArrayEquals(blobList.toArray(), Iterables.toArray(page.getValues(), Blob.class));
690+
}
691+
668692
@Test
669693
public void testUpdateBucket() {
670694
BucketInfo updatedBucketInfo = BUCKET_INFO1.toBuilder().setIndexPage("some-page").build();

google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,53 @@ public void testListBlobsVersioned() throws ExecutionException, InterruptedExcep
993993
}
994994
}
995995

996+
@Test
997+
public void testListBlobsWithOffset() throws ExecutionException, InterruptedException {
998+
String bucketName = RemoteStorageHelper.generateBucketName();
999+
Bucket bucket =
1000+
storage.create(BucketInfo.newBuilder(bucketName).setVersioningEnabled(true).build());
1001+
try {
1002+
List<String> blobNames =
1003+
ImmutableList.of("startOffset_blob1", "startOffset_blob2", "blob3_endOffset");
1004+
BlobInfo blob1 =
1005+
BlobInfo.newBuilder(bucket, blobNames.get(0)).setContentType(CONTENT_TYPE).build();
1006+
BlobInfo blob2 =
1007+
BlobInfo.newBuilder(bucket, blobNames.get(1)).setContentType(CONTENT_TYPE).build();
1008+
BlobInfo blob3 =
1009+
BlobInfo.newBuilder(bucket, blobNames.get(2)).setContentType(CONTENT_TYPE).build();
1010+
1011+
Blob remoteBlob1 = storage.create(blob1);
1012+
Blob remoteBlob2 = storage.create(blob2);
1013+
Blob remoteBlob3 = storage.create(blob3);
1014+
assertNotNull(remoteBlob1);
1015+
assertNotNull(remoteBlob2);
1016+
assertNotNull(remoteBlob3);
1017+
1018+
// Listing blobs without BlobListOptions.
1019+
Page<Blob> page1 = storage.list(bucketName);
1020+
assertEquals(3, Iterators.size(page1.iterateAll().iterator()));
1021+
1022+
// Listing blobs with startOffset.
1023+
Page<Blob> page2 =
1024+
storage.list(bucketName, Storage.BlobListOption.startOffset("startOffset"));
1025+
assertEquals(2, Iterators.size(page2.iterateAll().iterator()));
1026+
1027+
// Listing blobs with endOffset.
1028+
Page<Blob> page3 = storage.list(bucketName, Storage.BlobListOption.endOffset("endOffset"));
1029+
assertEquals(1, Iterators.size(page3.iterateAll().iterator()));
1030+
1031+
// Listing blobs with startOffset and endOffset.
1032+
Page<Blob> page4 =
1033+
storage.list(
1034+
bucketName,
1035+
Storage.BlobListOption.startOffset("startOffset"),
1036+
Storage.BlobListOption.endOffset("endOffset"));
1037+
assertEquals(0, Iterators.size(page4.iterateAll().iterator()));
1038+
} finally {
1039+
RemoteStorageHelper.forceDelete(storage, bucketName, 5, TimeUnit.SECONDS);
1040+
}
1041+
}
1042+
9961043
@Test(timeout = 5000)
9971044
public void testListBlobsCurrentDirectory() throws InterruptedException {
9981045
String directoryName = "test-list-blobs-current-directory/";

0 commit comments

Comments
 (0)