Skip to content

Commit fae1290

Browse files
readRow with filter as parameter
1 parent 6aab994 commit fae1290

File tree

2 files changed

+162
-32
lines changed

2 files changed

+162
-32
lines changed

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

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.api.gax.rpc.ServerStreamingCallable;
2525
import com.google.api.gax.rpc.UnaryCallable;
2626
import com.google.cloud.bigtable.data.v2.models.BulkMutation;
27+
import com.google.cloud.bigtable.data.v2.models.Filters.Filter;
2728
import com.google.cloud.bigtable.data.v2.models.InstanceName;
2829
import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher;
2930
import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation;
@@ -37,6 +38,7 @@
3738
import com.google.protobuf.ByteString;
3839
import java.io.IOException;
3940
import java.util.List;
41+
import javax.annotation.Nullable;
4042

4143
/**
4244
* Client for reading from and writing to existing Bigtable tables.
@@ -210,10 +212,12 @@ public Row readRow(String tableId, String rowKey) {
210212
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
211213
* String tableId = "[TABLE]";
212214
*
213-
* Query query = Query.create(tableId)
214-
* .rowKey("key");
215+
* // Build the filter expression
216+
* Filter filter = FILTERS.chain()
217+
* .filter(FILTERS.qualifier().regex("prefix.*"))
218+
* .filter(FILTERS.limit().cellsPerRow(10));
215219
*
216-
* Row row = bigtableDataClient.readRow(query);
220+
* Row row = bigtableDataClient.readRow(tableId, "key", filter);
217221
* // Do something with row, for example, display all cells
218222
* if(row != null) {
219223
* System.out.println(row.getKey().toStringUtf8());
@@ -229,8 +233,44 @@ public Row readRow(String tableId, String rowKey) {
229233
*
230234
* @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
231235
*/
232-
public Row readRow(Query query) {
233-
return ApiExceptions.callAndTranslateApiException(readRowAsync(query));
236+
public Row readRow(String tableId, String rowKey, @Nullable Filter filter) {
237+
return readRow(tableId, ByteString.copyFromUtf8(rowKey), filter);
238+
}
239+
240+
/**
241+
* Convenience method for synchronously reading a single row. If the row does not exist, the
242+
* value will be null.
243+
*
244+
* <p>Sample code:
245+
*
246+
* <pre>{@code
247+
* InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
248+
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
249+
* String tableId = "[TABLE]";
250+
*
251+
* // Build the filter expression
252+
* Filter filter = FILTERS.chain()
253+
* .filter(FILTERS.qualifier().regex("prefix.*"))
254+
* .filter(FILTERS.limit().cellsPerRow(10));
255+
*
256+
* Row row = bigtableDataClient.readRow(tableId, ByteString.copyFromUtf8("key"), filter);
257+
* // Do something with row, for example, display all cells
258+
* if(row != null) {
259+
* System.out.println(row.getKey().toStringUtf8());
260+
* for(RowCell cell : row.getCells()) {
261+
* System.out.printf("Family: %s Qualifier: %s Value: %s", cell.getFamily(),
262+
* cell.getQualifier().toStringUtf8(), cell.getValue().toStringUtf8());
263+
* }
264+
* }
265+
* } catch(ApiException e) {
266+
* e.printStackTrace();
267+
* }
268+
* }</pre>
269+
*
270+
* @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
271+
*/
272+
public Row readRow(String tableId, ByteString rowKey, @Nullable Filter filter) {
273+
return ApiExceptions.callAndTranslateApiException(readRowAsync(tableId, rowKey, filter));
234274
}
235275

236276
/**
@@ -312,10 +352,12 @@ public ApiFuture<Row> readRowAsync(String tableId, ByteString rowKey) {
312352
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
313353
* String tableId = "[TABLE]";
314354
*
315-
* Query query = Query.create(tableId)
316-
* .rowKey("key");
355+
* // Build the filter expression
356+
* Filters.Filter filter = FILTERS.chain()
357+
* .filter(FILTERS.qualifier().regex("prefix.*"))
358+
* .filter(FILTERS.limit().cellsPerRow(10));
317359
*
318-
* ApiFuture<Row> futureResult = bigtableDataClient.readRowAsync(query);
360+
* ApiFuture<Row> futureResult = bigtableDataClient.readRowAsync(tableId, "key", filter);
319361
*
320362
* ApiFutures.addCallback(futureResult, new ApiFutureCallback<Row>() {
321363
* public void onFailure(Throwable t) {
@@ -334,10 +376,50 @@ public ApiFuture<Row> readRowAsync(String tableId, ByteString rowKey) {
334376
* }
335377
* }</pre>
336378
*/
337-
public ApiFuture<Row> readRowAsync(Query query) {
338-
return readRowsCallable().first().futureCall(query);
379+
public ApiFuture<Row> readRowAsync(String tableId, String rowKey, @Nullable Filter filter) {
380+
return readRowAsync(tableId, ByteString.copyFromUtf8(rowKey), filter);
339381
}
340382

383+
/**
384+
* Convenience method for asynchronously reading a single row. If the row does not exist, the
385+
* future's value will be null.
386+
*
387+
* <p>Sample code:
388+
*
389+
* <pre>{@code
390+
* InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
391+
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
392+
* String tableId = "[TABLE]";
393+
*
394+
* // Build the filter expression
395+
* Filters.Filter filter = FILTERS.chain()
396+
* .filter(FILTERS.qualifier().regex("prefix.*"))
397+
* .filter(FILTERS.limit().cellsPerRow(10));
398+
*
399+
* ApiFuture<Row> futureResult = bigtableDataClient.readRowAsync(tableId, ByteString.copyFromUtf8("key"), filter);
400+
*
401+
* ApiFutures.addCallback(futureResult, new ApiFutureCallback<Row>() {
402+
* public void onFailure(Throwable t) {
403+
* if (t instanceof NotFoundException) {
404+
* System.out.println("Tried to read a non-existent table");
405+
* } else {
406+
* t.printStackTrace();
407+
* }
408+
* }
409+
* public void onSuccess(Row row) {
410+
* if (result != null) {
411+
* System.out.println("Got row: " + result);
412+
* }
413+
* }
414+
* }, MoreExecutors.directExecutor());
415+
* }
416+
* }</pre>
417+
*/
418+
public ApiFuture<Row> readRowAsync(String tableId, ByteString rowKey, @Nullable Filter filter) {
419+
return readRowsCallable().first().futureCall(Query.create(tableId).rowKey(rowKey).filter(filter));
420+
}
421+
422+
341423
/**
342424
* Convenience method for synchronous streaming the results of a {@link Query}.
343425
*

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

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.google.cloud.bigtable.data.v2;
1717

18+
import static com.google.cloud.bigtable.data.v2.models.Filters.FILTERS;
1819
import static com.google.common.truth.Truth.assertThat;
1920
import static org.mockito.Matchers.any;
2021

@@ -33,6 +34,7 @@
3334
import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher;
3435
import com.google.cloud.bigtable.data.v2.models.BulkMutationBatcher.BulkMutationFailure;
3536
import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation;
37+
import com.google.cloud.bigtable.data.v2.models.Filters.Filter;
3638
import com.google.cloud.bigtable.data.v2.models.InstanceName;
3739
import com.google.cloud.bigtable.data.v2.models.KeyOffset;
3840
import com.google.cloud.bigtable.data.v2.models.Mutation;
@@ -138,22 +140,43 @@ public void proxyReadRowStrAsyncTest() {
138140
}
139141

140142
@Test
141-
public void readRowQueryAsyncTest() {
142-
Query query = Query.create("fake-table").rowKey("fake-row-key");
143-
bigtableDataClient.readRowAsync(query);
143+
public void readRowFilterAsyncTest() {
144+
// Build the filter expression
145+
Filter filter = FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
146+
.filter(FILTERS.limit().cellsPerRow(10));
147+
bigtableDataClient.readRowAsync("fake-table", ByteString.copyFromUtf8("fake-row-key"), filter);
144148
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
145149
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
146150

147151
RequestContext ctx =
148152
RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
149153
// NOTE: limit(1) is added by the mocked first() call, so it's not tested here
150-
assertThat(requestCaptor.getValue().toProto(ctx))
151-
.isEqualTo(
152-
ReadRowsRequest.newBuilder()
153-
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
154-
.setAppProfileId("fake-profile")
155-
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
156-
.build());
154+
assertThat(requestCaptor.getValue().toProto(ctx)).isEqualTo(ReadRowsRequest.newBuilder()
155+
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
156+
.setAppProfileId("fake-profile")
157+
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key"))).setFilter(
158+
FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
159+
.filter(FILTERS.limit().cellsPerRow(10)).toProto()).build());
160+
}
161+
162+
@Test
163+
public void readRowFilterStrAsyncTest() {
164+
// Build the filter expression
165+
Filter filter = FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
166+
.filter(FILTERS.limit().cellsPerRow(10));
167+
bigtableDataClient.readRowAsync("fake-table", "fake-row-key", filter);
168+
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
169+
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
170+
171+
RequestContext ctx =
172+
RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
173+
// NOTE: limit(1) is added by the mocked first() call, so it's not tested here
174+
assertThat(requestCaptor.getValue().toProto(ctx)).isEqualTo(ReadRowsRequest.newBuilder()
175+
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
176+
.setAppProfileId("fake-profile")
177+
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key"))).setFilter(
178+
FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
179+
.filter(FILTERS.limit().cellsPerRow(10)).toProto()).build());
157180
}
158181

159182
@Test
@@ -201,26 +224,51 @@ public void readRowStrTest() {
201224
}
202225

203226
@Test
204-
public void readRowQueryTest() {
205-
Query query = Query.create("fake-table").rowKey("fake-row-key");
206-
Mockito.when(mockReadRowsCallable.first().futureCall(any(Query.class)))
207-
.thenReturn(ApiFutures.immediateFuture(
227+
public void readRowFilterTest() {
228+
// Build the filter expression
229+
Filter filter = FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
230+
.filter(FILTERS.limit().cellsPerRow(10));
231+
Mockito.when(mockReadRowsCallable.first().futureCall(any(Query.class))).thenReturn(ApiFutures
232+
.immediateFuture(
208233
Row.create(ByteString.copyFromUtf8("fake-row-key"), Collections.<RowCell>emptyList())));
209-
bigtableDataClient.readRow(query);
234+
bigtableDataClient.readRow("fake-table", ByteString.copyFromUtf8("fake-row-key"), filter);
210235

211236
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
212237
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
213238

214239
RequestContext ctx =
215240
RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
216241
// NOTE: limit(1) is added by the mocked first() call, so it's not tested here
217-
assertThat(requestCaptor.getValue().toProto(ctx))
218-
.isEqualTo(
219-
ReadRowsRequest.newBuilder()
220-
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
221-
.setAppProfileId("fake-profile")
222-
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key")))
223-
.build());
242+
assertThat(requestCaptor.getValue().toProto(ctx)).isEqualTo(ReadRowsRequest.newBuilder()
243+
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
244+
.setAppProfileId("fake-profile")
245+
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key"))).setFilter(
246+
FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
247+
.filter(FILTERS.limit().cellsPerRow(10)).toProto()).build());
248+
}
249+
250+
@Test
251+
public void readRowStrFilterTest() {
252+
// Build the filter expression
253+
Filter filter = FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
254+
.filter(FILTERS.limit().cellsPerRow(10));
255+
Mockito.when(mockReadRowsCallable.first().futureCall(any(Query.class))).thenReturn(ApiFutures
256+
.immediateFuture(
257+
Row.create(ByteString.copyFromUtf8("fake-row-key"), Collections.<RowCell>emptyList())));
258+
bigtableDataClient.readRow("fake-table", "fake-row-key", filter);
259+
260+
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
261+
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
262+
263+
RequestContext ctx =
264+
RequestContext.create(InstanceName.of("fake-project", "fake-instance"), "fake-profile");
265+
// NOTE: limit(1) is added by the mocked first() call, so it's not tested here
266+
assertThat(requestCaptor.getValue().toProto(ctx)).isEqualTo(ReadRowsRequest.newBuilder()
267+
.setTableName("projects/fake-project/instances/fake-instance/tables/fake-table")
268+
.setAppProfileId("fake-profile")
269+
.setRows(RowSet.newBuilder().addRowKeys(ByteString.copyFromUtf8("fake-row-key"))).setFilter(
270+
FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
271+
.filter(FILTERS.limit().cellsPerRow(10)).toProto()).build());
224272
}
225273

226274
@Test

0 commit comments

Comments
 (0)