Skip to content

Commit 681e5bc

Browse files
igorbernstein2pongad
authored andcommitted
Bigtable: surface - add syntactic sugar for fetching single rows (#3074)
1 parent 03e216b commit 681e5bc

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.google.cloud.bigtable.data.v2.models.RowAdapter;
3333
import com.google.cloud.bigtable.data.v2.models.RowMutation;
3434
import com.google.cloud.bigtable.data.v2.stub.EnhancedBigtableStub;
35+
import com.google.protobuf.ByteString;
3536
import java.io.IOException;
3637
import java.util.List;
3738

@@ -126,6 +127,42 @@ public static BigtableDataClient create(BigtableDataSettings settings) throws IO
126127
this.stub = stub;
127128
}
128129

130+
/**
131+
* Convenience method for asynchronously reading a single row. If the row does not exist, the
132+
* future's value will be null.
133+
*
134+
* <p>Sample code:
135+
*
136+
* <pre>{@code
137+
* InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
138+
* try (BigtableClient bigtableClient = BigtableClient.create(instanceName)) {
139+
* String tableId = "[TABLE]";
140+
*
141+
* ApiFuture<Row> result = bigtableClient.readRow(tableId, "key");
142+
* }</pre>
143+
*/
144+
public ApiFuture<Row> readRowAsync(String tableId, String rowKey) {
145+
return readRowAsync(tableId, ByteString.copyFromUtf8(rowKey));
146+
}
147+
148+
/**
149+
* Convenience method for asynchronously reading a single row. If the row does not exist, the
150+
* future's value will be null.
151+
*
152+
* <p>Sample code:
153+
*
154+
* <pre>{@code
155+
* InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
156+
* try (BigtableClient bigtableClient = BigtableClient.create(instanceName)) {
157+
* String tableId = "[TABLE]";
158+
*
159+
* ApiFuture<Row> result = bigtableClient.readRow(tableId, ByteString.copyFromUtf8("key"));
160+
* }</pre>
161+
*/
162+
public ApiFuture<Row> readRowAsync(String tableId, ByteString rowKey) {
163+
return readRowsCallable().first().futureCall(Query.create(tableId).rowKey(rowKey));
164+
}
165+
129166
/**
130167
* Convenience method for synchronous streaming the results of a {@link Query}.
131168
*

google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/BigtableDataClientTest.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,29 @@
2424
import com.google.api.gax.rpc.ResponseObserver;
2525
import com.google.api.gax.rpc.ServerStreamingCallable;
2626
import com.google.api.gax.rpc.UnaryCallable;
27+
import com.google.bigtable.v2.ReadRowsRequest;
28+
import com.google.bigtable.v2.RowSet;
29+
import com.google.cloud.bigtable.data.v2.internal.RequestContext;
2730
import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher;
2831
import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher.BulkMutationFailure;
2932
import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation;
33+
import com.google.cloud.bigtable.data.v2.models.InstanceName;
3034
import com.google.cloud.bigtable.data.v2.models.KeyOffset;
3135
import com.google.cloud.bigtable.data.v2.models.Mutation;
3236
import com.google.cloud.bigtable.data.v2.models.Query;
3337
import com.google.cloud.bigtable.data.v2.models.ReadModifyWriteRow;
3438
import com.google.cloud.bigtable.data.v2.models.Row;
3539
import com.google.cloud.bigtable.data.v2.models.RowMutation;
3640
import com.google.cloud.bigtable.data.v2.stub.EnhancedBigtableStub;
41+
import com.google.protobuf.ByteString;
3742
import io.grpc.Status.Code;
3843
import java.util.List;
3944
import java.util.concurrent.TimeoutException;
4045
import org.junit.Before;
4146
import org.junit.Test;
4247
import org.junit.runner.RunWith;
48+
import org.mockito.Answers;
49+
import org.mockito.ArgumentCaptor;
4350
import org.mockito.Mock;
4451
import org.mockito.Mockito;
4552
import org.mockito.runners.MockitoJUnitRunner;
@@ -48,7 +55,10 @@
4855
@RunWith(MockitoJUnitRunner.class)
4956
public class BigtableDataClientTest {
5057
@Mock private EnhancedBigtableStub mockStub;
51-
@Mock private ServerStreamingCallable<Query, Row> mockReadRowsCallable;
58+
59+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
60+
private ServerStreamingCallable<Query, Row> mockReadRowsCallable;
61+
5262
@Mock private UnaryCallable<String, List<KeyOffset>> mockSampleRowKeysCallable;
5363
@Mock private UnaryCallable<RowMutation, Void> mockMutateRowCallable;
5464
@Mock private UnaryCallable<ConditionalRowMutation, Boolean> mockCheckAndMutateRowCallable;
@@ -79,6 +89,44 @@ public void proxyReadRowsCallableTest() {
7989
assertThat(bigtableDataClient.readRowsCallable()).isSameAs(mockReadRowsCallable);
8090
}
8191

92+
@Test
93+
public void proxyReadRowAsyncTest() {
94+
bigtableDataClient.readRowAsync("fake-table", ByteString.copyFromUtf8("fake-row-key"));
95+
96+
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
97+
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
98+
99+
RequestContext ctx =
100+
RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
101+
// NOTE: limit(1) is added by the mocked first() call, so it's not tested here
102+
assertThat(requestCaptor.getValue().toProto(ctx))
103+
.isEqualTo(
104+
ReadRowsRequest.newBuilder()
105+
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
106+
.setAppProfileId("fake-profile")
107+
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
108+
.build());
109+
}
110+
111+
@Test
112+
public void proxyReadRowStrAsyncTest() {
113+
bigtableDataClient.readRowAsync("fake-table", "fake-row-key");
114+
115+
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
116+
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
117+
118+
RequestContext ctx =
119+
RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
120+
// NOTE: limit(1) is added by the mocked first() call, so it's not tested here
121+
assertThat(requestCaptor.getValue().toProto(ctx))
122+
.isEqualTo(
123+
ReadRowsRequest.newBuilder()
124+
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
125+
.setAppProfileId("fake-profile")
126+
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
127+
.build());
128+
}
129+
82130
@Test
83131
public void proxyReadRowsSyncTest() {
84132
Query query = Query.create("fake-table");

0 commit comments

Comments
 (0)