Skip to content

Commit 5c437a2

Browse files
readRow with filter parameter
1 parent 6aab994 commit 5c437a2

File tree

2 files changed

+164
-32
lines changed

2 files changed

+164
-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;
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;
@@ -210,10 +211,12 @@ public Row readRow(String tableId, String rowKey) {
210211
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
211212
* String tableId = "[TABLE]";
212213
*
213-
* Query query = Query.create(tableId)
214-
* .rowKey("key");
214+
* // Build the filter expression
215+
* Filters.Filter filter = FILTERS.chain()
216+
* .filter(FILTERS.qualifier().regex("prefix.*"))
217+
* .filter(FILTERS.limit().cellsPerRow(10));
215218
*
216-
* Row row = bigtableDataClient.readRow(query);
219+
* Row row = bigtableDataClient.readRow(tableId, "key", filter);
217220
* // Do something with row, for example, display all cells
218221
* if(row != null) {
219222
* System.out.println(row.getKey().toStringUtf8());
@@ -229,8 +232,45 @@ public Row readRow(String tableId, String rowKey) {
229232
*
230233
* @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
231234
*/
232-
public Row readRow(Query query) {
233-
return ApiExceptions.callAndTranslateApiException(readRowAsync(query));
235+
public Row readRow(String tableId, String rowKey, Filters.Filter filter) {
236+
return readRow(tableId, ByteString.copyFromUtf8(rowKey), filter);
237+
}
238+
239+
/**
240+
* Convenience method for synchronously reading a single row. If the row does not exist, the
241+
* value will be null.
242+
*
243+
* <p>Sample code:
244+
*
245+
* <pre>{@code
246+
* InstanceName instanceName = InstanceName.of("[PROJECT]", "[INSTANCE]");
247+
* try (BigtableDataClient bigtableDataClient = BigtableDataClient.create(instanceName)) {
248+
* String tableId = "[TABLE]";
249+
*
250+
* // Build the filter expression
251+
* Filters.Filter filter = FILTERS.chain()
252+
* .filter(FILTERS.qualifier().regex("prefix.*"))
253+
* .filter(FILTERS.limit().cellsPerRow(10));
254+
*
255+
* Row row = bigtableDataClient.readRow(tableId, ByteString.copyFromUtf8("key"), filter);
256+
* // Do something with row, for example, display all cells
257+
* if(row != null) {
258+
* System.out.println(row.getKey().toStringUtf8());
259+
* for(RowCell cell : row.getCells()) {
260+
* System.out.printf("Family: %s Qualifier: %s Value: %s", cell.getFamily(),
261+
* cell.getQualifier().toStringUtf8(), cell.getValue().toStringUtf8());
262+
* }
263+
* }
264+
* } catch(ApiException e) {
265+
* e.printStackTrace();
266+
* }
267+
* }</pre>
268+
*
269+
* @throws com.google.api.gax.rpc.ApiException when a serverside error occurs
270+
*/
271+
public Row readRow(String tableId, ByteString rowKey, Filters.Filter filter) {
272+
return ApiExceptions.callAndTranslateApiException(readRowAsync(tableId, rowKey, filter));
273+
234274
}
235275

236276
/**
@@ -312,10 +352,51 @@ 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));
359+
*
360+
* ApiFuture<Row> futureResult = bigtableDataClient.readRowAsync(tableId, "key", filter);
317361
*
318-
* ApiFuture<Row> futureResult = bigtableDataClient.readRowAsync(query);
362+
* ApiFutures.addCallback(futureResult, new ApiFutureCallback<Row>() {
363+
* public void onFailure(Throwable t) {
364+
* if (t instanceof NotFoundException) {
365+
* System.out.println("Tried to read a non-existent table");
366+
* } else {
367+
* t.printStackTrace();
368+
* }
369+
* }
370+
* public void onSuccess(Row row) {
371+
* if (result != null) {
372+
* System.out.println("Got row: " + result);
373+
* }
374+
* }
375+
* }, MoreExecutors.directExecutor());
376+
* }
377+
* }</pre>
378+
*/
379+
public ApiFuture<Row> readRowAsync(String tableId, String rowKey, Filters.Filter filter) {
380+
return readRowAsync(tableId, ByteString.copyFromUtf8(rowKey), filter);
381+
}
382+
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);
319400
*
320401
* ApiFutures.addCallback(futureResult, new ApiFutureCallback<Row>() {
321402
* public void onFailure(Throwable t) {
@@ -334,10 +415,11 @@ public ApiFuture<Row> readRowAsync(String tableId, ByteString rowKey) {
334415
* }
335416
* }</pre>
336417
*/
337-
public ApiFuture<Row> readRowAsync(Query query) {
338-
return readRowsCallable().first().futureCall(query);
418+
public ApiFuture<Row> readRowAsync(String tableId, ByteString rowKey, Filters.Filter filter) {
419+
return readRowsCallable().first().futureCall(Query.create(tableId).rowKey(rowKey).filter(filter));
339420
}
340421

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: 72 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;
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,45 @@ 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+
Filters.Filter filter = FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
146+
.filter(FILTERS.limit().cellsPerRow(10));
147+
148+
bigtableDataClient.readRowAsync("fake-table", ByteString.copyFromUtf8("fake-row-key"), filter);
144149
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
145150
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
146151

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

159184
@Test
@@ -201,26 +226,51 @@ public void readRowStrTest() {
201226
}
202227

203228
@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(
229+
public void readRowFilterTest() {
230+
// Build the filter expression
231+
Filters.Filter filter = FILTERS.chain().filter(FILTERS.qualifier().regex("prefix.*"))
232+
.filter(FILTERS.limit().cellsPerRow(10));
233+
Mockito.when(mockReadRowsCallable.first().futureCall(any(Query.class))).thenReturn(ApiFutures
234+
.immediateFuture(
208235
Row.create(ByteString.copyFromUtf8("fake-row-key"), Collections.<RowCell>emptyList())));
209-
bigtableDataClient.readRow(query);
236+
bigtableDataClient.readRow("fake-table", ByteString.copyFromUtf8("fake-row-key"), filter);
210237

211238
ArgumentCaptor<Query> requestCaptor = ArgumentCaptor.forClass(Query.class);
212239
Mockito.verify(mockReadRowsCallable.first()).futureCall(requestCaptor.capture());
213240

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

226276
@Test

0 commit comments

Comments
 (0)