diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java
index 3b287594f..40d9f70ca 100644
--- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java
+++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java
@@ -15,7 +15,11 @@
*/
package com.google.cloud.bigtable.data.v2;
+import static com.google.cloud.bigtable.data.v2.models.Filters.FILTERS;
+
+import com.google.api.core.ApiFunction;
import com.google.api.core.ApiFuture;
+import com.google.api.core.ApiFutures;
import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.api.gax.batching.Batcher;
@@ -36,6 +40,7 @@
import com.google.cloud.bigtable.data.v2.models.RowMutation;
import com.google.cloud.bigtable.data.v2.models.RowMutationEntry;
import com.google.cloud.bigtable.data.v2.stub.EnhancedBigtableStub;
+import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.util.List;
@@ -159,6 +164,135 @@ public static BigtableDataClient create(BigtableDataSettings settings) throws IO
this.stub = stub;
}
+ /**
+ * Confirms synchronously if given row key exists or not.
+ *
+ *
Sample code:
+ *
+ *
{@code
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create("[PROJECT]", "[INSTANCE]")) {
+ * String tableId = "[TABLE]";
+ * String key = "key";
+ *
+ * boolean isRowPresent = bigtableDataClient.exists(tableId, key);
+ *
+ * // Do something with result, for example, display a message
+ * if(isRowPresent) {
+ * System.out.println(key + " is present");
+ * }
+ * } catch(ApiException e) {
+ * e.printStackTrace();
+ * }
+ * }
+ *
+ * @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
+ */
+ public boolean exists(String tableId, String rowKey) {
+ return ApiExceptions.callAndTranslateApiException(existsAsync(tableId, rowKey));
+ }
+
+ /**
+ * Confirms synchronously if given row key exists or not.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create("[PROJECT]", "[INSTANCE]")) {
+ * String tableId = "[TABLE]";
+ * ByteString key = ByteString.copyFromUtf8("key");
+ *
+ * boolean isRowPresent = bigtableDataClient.exists(tableId, key);
+ *
+ * // Do something with result, for example, display a message
+ * if(isRowPresent) {
+ * System.out.println(key.toStringUtf8() + " is present");
+ * }
+ * } catch(ApiException e) {
+ * e.printStackTrace();
+ * }
+ * }
+ *
+ * @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
+ */
+ public boolean exists(String tableId, ByteString rowKey) {
+ return ApiExceptions.callAndTranslateApiException(existsAsync(tableId, rowKey));
+ }
+
+ /**
+ * Confirms asynchronously if given row key exists or not.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create("[PROJECT]", "[INSTANCE]")) {
+ * String tableId = "[TABLE]";
+ * final String key = "key";
+ *
+ * ApiFuture futureResult = bigtableDataClient.existsAsync(tableId, key);
+ *
+ * ApiFutures.addCallback(futureResult, new ApiFutureCallback() {
+ * public void onFailure(Throwable t) {
+ * t.printStackTrace();
+ * }
+ * public void onSuccess(Boolean isRowPresent) {
+ * if(isRowPresent) {
+ * System.out.println(key + " is present");
+ * }
+ * }
+ * }, MoreExecutors.directExecutor());
+ * }
+ * }
+ */
+ public ApiFuture existsAsync(String tableId, String rowKey) {
+ return existsAsync(tableId, ByteString.copyFromUtf8(rowKey));
+ }
+
+ /**
+ * Confirms asynchronously if given row key exists or not.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * try (BigtableDataClient bigtableDataClient = BigtableDataClient.create("[PROJECT]", "[INSTANCE]")) {
+ * String tableId = "[TABLE]";
+ * final ByteString key = ByteString.copyFromUtf8("key");
+ *
+ * ApiFuture futureResult = bigtableDataClient.existsAsync(tableId, key);
+ *
+ * ApiFutures.addCallback(futureResult, new ApiFutureCallback() {
+ * public void onFailure(Throwable t) {
+ * t.printStackTrace();
+ * }
+ * public void onSuccess(Boolean isRowPresent) {
+ * if(isRowPresent) {
+ * System.out.println(key.toStringUtf8() + " is present");
+ * }
+ * }
+ * }, MoreExecutors.directExecutor());
+ * }
+ * }
+ */
+ public ApiFuture existsAsync(String tableId, ByteString rowKey) {
+ Query query =
+ Query.create(tableId)
+ .rowKey(rowKey)
+ .filter(
+ FILTERS
+ .chain()
+ .filter(FILTERS.limit().cellsPerRow(1))
+ .filter(FILTERS.value().strip()));
+ ApiFuture resultFuture = stub.readRowCallable().futureCall(query);
+ return ApiFutures.transform(
+ resultFuture,
+ new ApiFunction() {
+ @Override
+ public Boolean apply(Row row) {
+ return row != null;
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+
/**
* Convenience method for synchronously reading a single row. If the row does not exist, the value
* will be null.
diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java
index b83800c56..c3bf52b63 100644
--- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java
+++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java
@@ -92,6 +92,57 @@ public void proxyCloseTest() throws Exception {
Mockito.verify(mockStub).close();
}
+ @Test
+ public void existsTest() {
+ Query expectedQuery =
+ Query.create("fake-table")
+ .rowKey("fake-row-key")
+ .filter(
+ FILTERS
+ .chain()
+ .filter(FILTERS.limit().cellsPerRow(1))
+ .filter(FILTERS.value().strip()));
+ Row row = Row.create(ByteString.copyFromUtf8("fake-row-key"), ImmutableList.of());
+ Mockito.when(mockReadRowCallable.futureCall(expectedQuery))
+ .thenReturn(ApiFutures.immediateFuture(row))
+ .thenReturn(ApiFutures.immediateFuture(null));
+
+ boolean result = bigtableDataClient.exists("fake-table", "fake-row-key");
+ boolean anotherResult =
+ bigtableDataClient.exists("fake-table", ByteString.copyFromUtf8("fake-row-key"));
+
+ assertThat(result).isTrue();
+ assertThat(anotherResult).isFalse();
+
+ Mockito.verify(mockReadRowCallable, Mockito.times(2)).futureCall(expectedQuery);
+ }
+
+ @Test
+ public void existsAsyncTest() throws Exception {
+ Query expectedQuery =
+ Query.create("fake-table")
+ .rowKey("fake-row-key")
+ .filter(
+ FILTERS
+ .chain()
+ .filter(FILTERS.limit().cellsPerRow(1))
+ .filter(FILTERS.value().strip()));
+ Row row = Row.create(ByteString.copyFromUtf8("fake-row-key"), ImmutableList.of());
+
+ Mockito.when(mockReadRowCallable.futureCall(expectedQuery))
+ .thenReturn(ApiFutures.immediateFuture(row))
+ .thenReturn(ApiFutures.immediateFuture(null));
+
+ ApiFuture result =
+ bigtableDataClient.existsAsync("fake-table", ByteString.copyFromUtf8("fake-row-key"));
+ assertThat(result.get()).isTrue();
+
+ ApiFuture anotherResult = bigtableDataClient.existsAsync("fake-table", "fake-row-key");
+ assertThat(anotherResult.get()).isFalse();
+
+ Mockito.verify(mockReadRowCallable, Mockito.times(2)).futureCall(expectedQuery);
+ }
+
@Test
public void proxyReadRowsCallableTest() {
assertThat(bigtableDataClient.readRowsCallable()).isSameInstanceAs(mockReadRowsCallable);
diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/ReadIT.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/ReadIT.java
index 0e4a5f37a..4d7fdcdb1 100644
--- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/ReadIT.java
+++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/ReadIT.java
@@ -57,6 +57,26 @@ public void setUp() {
prefix = UUID.randomUUID().toString();
}
+ @Test
+ public void isRowExists() throws Exception {
+ String rowKey = prefix + "-test-row-key";
+ String tableId = testEnvRule.env().getTableId();
+ testEnvRule
+ .env()
+ .getDataClient()
+ .mutateRow(
+ RowMutation.create(tableId, rowKey)
+ .setCell(testEnvRule.env().getFamilyId(), "qualifier", "value"));
+
+ assertThat(testEnvRule.env().getDataClient().exists(tableId, rowKey)).isTrue();
+
+ String nonExistingKey = prefix + "non-existing-key";
+ assertThat(testEnvRule.env().getDataClient().exists(tableId, nonExistingKey)).isFalse();
+
+ // Async
+ assertThat(testEnvRule.env().getDataClient().existsAsync(tableId, rowKey).get()).isTrue();
+ }
+
@Test
public void readEmpty() throws Throwable {
String uniqueKey = prefix + "-readEmpty";