diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java index 6e9d085178b7..d1061ac74d11 100644 --- a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java +++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java @@ -26,6 +26,7 @@ import com.google.cloud.bigtable.data.v2.models.BulkMutation; import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher; import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation; +import com.google.cloud.bigtable.data.v2.models.Filters.Filter; import com.google.cloud.bigtable.data.v2.models.InstanceName; import com.google.cloud.bigtable.data.v2.models.KeyOffset; import com.google.cloud.bigtable.data.v2.models.Query; @@ -37,6 +38,7 @@ import com.google.protobuf.ByteString; import java.io.IOException; import java.util.List; +import javax.annotation.Nullable; /** * Client for reading from and writing to existing Bigtable tables. @@ -143,7 +145,7 @@ public static BigtableDataClient create(BigtableDataSettings settings) throws IO * *
Sample code: * - *
{code
+ * {@code
* InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
* String tableId = "[TABLE]";
@@ -153,7 +155,8 @@ public static BigtableDataClient create(BigtableDataSettings settings) throws IO
* if(row != null) {
* System.out.println(row.getKey().toStringUtf8());
* for(RowCell cell : row.getCells()) {
- * System.out.println("Family: " + cell.getFamily() + " Qualifier: " + cell.getQualifier().toStringUtf8() + " Value: " + cell.getValue().toStringUtf8());
+ * System.out.printf("Family: %s Qualifier: %s Value: %s", cell.getFamily(),
+ * cell.getQualifier().toStringUtf8(), cell.getValue().toStringUtf8());
* }
* }
* } catch(ApiException e) {
@@ -164,7 +167,7 @@ public static BigtableDataClient create(BigtableDataSettings settings) throws IO
* @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
*/
public Row readRow(String tableId, ByteString rowKey) {
- return ApiExceptions.callAndTranslateApiException(readRowAsync(tableId, rowKey));
+ return ApiExceptions.callAndTranslateApiException(readRowAsync(tableId, rowKey, null));
}
/**
@@ -173,7 +176,7 @@ public Row readRow(String tableId, ByteString rowKey) {
*
* Sample code:
*
- *
{code
+ * {@code
* InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
* String tableId = "[TABLE]";
@@ -183,7 +186,8 @@ public Row readRow(String tableId, ByteString rowKey) {
* if(row != null) {
* System.out.println(row.getKey().toStringUtf8());
* for(RowCell cell : row.getCells()) {
- * System.out.println("Family: " + cell.getFamily() + " Qualifier: " + cell.getQualifier().toStringUtf8() + " Value: " + cell.getValue().toStringUtf8());
+ * System.out.printf("Family: %s Qualifier: %s Value: %s", cell.getFamily(),
+ * cell.getQualifier().toStringUtf8(), cell.getValue().toStringUtf8());
* }
* }
* } catch(ApiException e) {
@@ -194,7 +198,81 @@ public Row readRow(String tableId, ByteString rowKey) {
* @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
*/
public Row readRow(String tableId, String rowKey) {
- return ApiExceptions.callAndTranslateApiException(readRowAsync(tableId, rowKey));
+ return ApiExceptions.callAndTranslateApiException(
+ readRowAsync(tableId, ByteString.copyFromUtf8(rowKey), null));
+ }
+
+ /**
+ * Convenience method for synchronously reading a single row. If the row does not exist, the value
+ * will be null.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
+ * String tableId = "[TABLE]";
+ *
+ * // Build the filter expression
+ * Filter filter = FILTERS.chain()
+ * .filter(FILTERS.qualifier().regex("prefix.*"))
+ * .filter(FILTERS.limit().cellsPerRow(10));
+ *
+ * Row row = bigtableDataClient.readRow(tableId, "key", filter);
+ * // Do something with row, for example, display all cells
+ * if(row != null) {
+ * System.out.println(row.getKey().toStringUtf8());
+ * for(RowCell cell : row.getCells()) {
+ * System.out.printf("Family: %s Qualifier: %s Value: %s", cell.getFamily(),
+ * cell.getQualifier().toStringUtf8(), cell.getValue().toStringUtf8());
+ * }
+ * }
+ * } catch(ApiException e) {
+ * e.printStackTrace();
+ * }
+ * }
+ *
+ * @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
+ */
+ public Row readRow(String tableId, String rowKey, @Nullable Filter filter) {
+ return ApiExceptions.callAndTranslateApiException(
+ readRowAsync(tableId, ByteString.copyFromUtf8(rowKey), filter));
+ }
+
+ /**
+ * Convenience method for synchronously reading a single row. If the row does not exist, the value
+ * will be null.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
+ * String tableId = "[TABLE]";
+ *
+ * // Build the filter expression
+ * Filter filter = FILTERS.chain()
+ * .filter(FILTERS.qualifier().regex("prefix.*"))
+ * .filter(FILTERS.limit().cellsPerRow(10));
+ *
+ * Row row = bigtableDataClient.readRow(tableId, ByteString.copyFromUtf8("key"), filter);
+ * // Do something with row, for example, display all cells
+ * if(row != null) {
+ * System.out.println(row.getKey().toStringUtf8());
+ * for(RowCell cell : row.getCells()) {
+ * System.out.printf("Family: %s Qualifier: %s Value: %s", cell.getFamily(),
+ * cell.getQualifier().toStringUtf8(), cell.getValue().toStringUtf8());
+ * }
+ * }
+ * } catch(ApiException e) {
+ * e.printStackTrace();
+ * }
+ * }
+ *
+ * @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
+ */
+ public Row readRow(String tableId, ByteString rowKey, @Nullable Filter filter) {
+ return ApiExceptions.callAndTranslateApiException(readRowAsync(tableId, rowKey, filter));
}
/**
@@ -228,7 +306,7 @@ public Row readRow(String tableId, String rowKey) {
* }
*/
public ApiFuture readRowAsync(String tableId, String rowKey) {
- return readRowAsync(tableId, ByteString.copyFromUtf8(rowKey));
+ return readRowAsync(tableId, ByteString.copyFromUtf8(rowKey), null);
}
/**
@@ -262,11 +340,93 @@ public ApiFuture readRowAsync(String tableId, String rowKey) {
* }
*/
public ApiFuture readRowAsync(String tableId, ByteString rowKey) {
- return readRowsCallable().first().futureCall(Query.create(tableId).rowKey(rowKey));
+ return readRowAsync(tableId, rowKey, null);
+ }
+
+ /**
+ * Convenience method for asynchronously reading a single row. If the row does not exist, the
+ * future's value will be null.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
+ * String tableId = "[TABLE]";
+ *
+ * // Build the filter expression
+ * Filters.Filter filter = FILTERS.chain()
+ * .filter(FILTERS.qualifier().regex("prefix.*"))
+ * .filter(FILTERS.limit().cellsPerRow(10));
+ *
+ * ApiFuture futureResult = bigtableDataClient.readRowAsync(tableId, "key", filter);
+ *
+ * ApiFutures.addCallback(futureResult, new ApiFutureCallback() {
+ * public void onFailure(Throwable t) {
+ * if (t instanceof NotFoundException) {
+ * System.out.println("Tried to read a non-existent table");
+ * } else {
+ * t.printStackTrace();
+ * }
+ * }
+ * public void onSuccess(Row row) {
+ * if (result != null) {
+ * System.out.println("Got row: " + result);
+ * }
+ * }
+ * }, MoreExecutors.directExecutor());
+ * }
+ * }
+ */
+ public ApiFuture readRowAsync(String tableId, String rowKey, @Nullable Filter filter) {
+ return readRowAsync(tableId, ByteString.copyFromUtf8(rowKey), filter);
+ }
+
+ /**
+ * Convenience method for asynchronously reading a single row. If the row does not exist, the
+ * future's value will be null.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
+ * String tableId = "[TABLE]";
+ *
+ * // Build the filter expression
+ * Filters.Filter filter = FILTERS.chain()
+ * .filter(FILTERS.qualifier().regex("prefix.*"))
+ * .filter(FILTERS.limit().cellsPerRow(10));
+ *
+ * ApiFuture futureResult = bigtableDataClient.readRowAsync(tableId, ByteString.copyFromUtf8("key"), filter);
+ *
+ * ApiFutures.addCallback(futureResult, new ApiFutureCallback() {
+ * public void onFailure(Throwable t) {
+ * if (t instanceof NotFoundException) {
+ * System.out.println("Tried to read a non-existent table");
+ * } else {
+ * t.printStackTrace();
+ * }
+ * }
+ * public void onSuccess(Row row) {
+ * if (result != null) {
+ * System.out.println("Got row: " + result);
+ * }
+ * }
+ * }, MoreExecutors.directExecutor());
+ * }
+ * }
+ */
+ public ApiFuture readRowAsync(String tableId, ByteString rowKey, @Nullable Filter filter) {
+ Query query = Query.create(tableId).rowKey(rowKey);
+ if (filter != null) {
+ query = query.filter(filter);
+ }
+ return readRowsCallable().first().futureCall(query);
}
/**
- * Convenience method for synchronous streaming the results of a {@link Query}.
+ * Convenience method for synchronously streaming the results of a {@link Query}.
*
* Sample code:
*
@@ -304,7 +464,7 @@ public ServerStream readRows(Query query) {
}
/**
- * Convenience method for asynchronous streaming the results of a {@link Query}.
+ * Convenience method for asynchronously streaming the results of a {@link Query}.
*
* Sample code:
*
diff --git a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java
index 622c8f308263..be6cb2b965c5 100644
--- a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java
+++ b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java
@@ -15,6 +15,7 @@
*/
package com.google.cloud.bigtable.data.v2;
+import static com.google.cloud.bigtable.data.v2.models.Filters.FILTERS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
@@ -33,6 +34,7 @@
import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher;
import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher.BulkMutationFailure;
import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation;
+import com.google.cloud.bigtable.data.v2.models.Filters.Filter;
import com.google.cloud.bigtable.data.v2.models.InstanceName;
import com.google.cloud.bigtable.data.v2.models.KeyOffset;
import com.google.cloud.bigtable.data.v2.models.Mutation;
@@ -137,6 +139,66 @@ public void proxyReadRowStrAsyncTest() {
.build());
}
+ @Test
+ public void readRowFilterAsyncTest() {
+ // Build the filter expression
+ Filter filter =
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10));
+ bigtableDataClient.readRowAsync("fake-table", ByteString.copyFromUtf8("fake-row-key"), filter);
+ ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Query.class);
+ Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
+
+ RequestContext ctx =
+ RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
+ // NOTE: limit(1) is added by the mocked first() call, so it's not tested here
+ assertThat(requestCaptor.getValue().toProto(ctx))
+ .isEqualTo(
+ ReadRowsRequest.newBuilder()
+ .setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
+ .setAppProfileId("fake-profile")
+ .setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
+ .setFilter(
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10))
+ .toProto())
+ .build());
+ }
+
+ @Test
+ public void readRowFilterStrAsyncTest() {
+ // Build the filter expression
+ Filter filter =
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10));
+ bigtableDataClient.readRowAsync("fake-table", "fake-row-key", filter);
+ ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Query.class);
+ Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
+
+ RequestContext ctx =
+ RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
+ // NOTE: limit(1) is added by the mocked first() call, so it's not tested here
+ assertThat(requestCaptor.getValue().toProto(ctx))
+ .isEqualTo(
+ ReadRowsRequest.newBuilder()
+ .setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
+ .setAppProfileId("fake-profile")
+ .setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
+ .setFilter(
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10))
+ .toProto())
+ .build());
+ }
+
@Test
public void readRowTest() {
Mockito.when(mockReadRowsCallable.first().futureCall(any(Query.class)))
@@ -185,6 +247,78 @@ public void readRowStrTest() {
.build());
}
+ @Test
+ public void readRowFilterTest() {
+ // Build the filter expression
+ Filter filter =
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10));
+ Mockito.when(mockReadRowsCallable.first().futureCall(any(Query.class)))
+ .thenReturn(
+ ApiFutures.immediateFuture(
+ Row.create(
+ ByteString.copyFromUtf8("fake-row-key"), Collections.emptyList())));
+ bigtableDataClient.readRow("fake-table", ByteString.copyFromUtf8("fake-row-key"), filter);
+
+ ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Query.class);
+ Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
+
+ RequestContext ctx =
+ RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
+ // NOTE: limit(1) is added by the mocked first() call, so it's not tested here
+ assertThat(requestCaptor.getValue().toProto(ctx))
+ .isEqualTo(
+ ReadRowsRequest.newBuilder()
+ .setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
+ .setAppProfileId("fake-profile")
+ .setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
+ .setFilter(
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10))
+ .toProto())
+ .build());
+ }
+
+ @Test
+ public void readRowStrFilterTest() {
+ // Build the filter expression
+ Filter filter =
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10));
+ Mockito.when(mockReadRowsCallable.first().futureCall(any(Query.class)))
+ .thenReturn(
+ ApiFutures.immediateFuture(
+ Row.create(
+ ByteString.copyFromUtf8("fake-row-key"), Collections.emptyList())));
+ bigtableDataClient.readRow("fake-table", "fake-row-key", filter);
+
+ ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Query.class);
+ Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
+
+ RequestContext ctx =
+ RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
+ // NOTE: limit(1) is added by the mocked first() call, so it's not tested here
+ assertThat(requestCaptor.getValue().toProto(ctx))
+ .isEqualTo(
+ ReadRowsRequest.newBuilder()
+ .setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
+ .setAppProfileId("fake-profile")
+ .setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
+ .setFilter(
+ FILTERS
+ .chain()
+ .filter(FILTERS.qualifier().regex("prefix.*"))
+ .filter(FILTERS.limit().cellsPerRow(10))
+ .toProto())
+ .build());
+ }
+
@Test
public void proxyReadRowsSyncTest() {
Query query = Query.create("fake-table");