Skip to content

Commit 4b1a4fd

Browse files
committed
Merge pull request #807 from mziccard/field-selector
Add common interface for field selectors
2 parents a248465 + 8db4b9b commit 4b1a4fd

File tree

16 files changed

+444
-209
lines changed

16 files changed

+444
-209
lines changed

gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/BigQuery.java

+25-42
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,15 @@
1919
import static com.google.common.base.Preconditions.checkArgument;
2020

2121
import com.google.common.base.Function;
22-
import com.google.common.base.Joiner;
2322
import com.google.common.collect.ImmutableList;
2423
import com.google.common.collect.Lists;
25-
import com.google.common.collect.Sets;
24+
import com.google.gcloud.FieldSelector;
25+
import com.google.gcloud.FieldSelector.Helper;
2626
import com.google.gcloud.Page;
2727
import com.google.gcloud.Service;
2828
import com.google.gcloud.bigquery.spi.BigQueryRpc;
2929

3030
import java.util.List;
31-
import java.util.Set;
3231

3332
/**
3433
* An interface for Google Cloud BigQuery.
@@ -43,7 +42,7 @@ public interface BigQuery extends Service<BigQueryOptions> {
4342
* @see <a href="https://cloud.google.com/bigquery/docs/reference/v2/datasets#resource">Dataset
4443
* Resource</a>
4544
*/
46-
enum DatasetField {
45+
enum DatasetField implements FieldSelector {
4746
ACCESS("access"),
4847
CREATION_TIME("creationTime"),
4948
DATASET_REFERENCE("datasetReference"),
@@ -56,24 +55,19 @@ enum DatasetField {
5655
LOCATION("location"),
5756
SELF_LINK("selfLink");
5857

58+
static final List<? extends FieldSelector> REQUIRED_FIELDS =
59+
ImmutableList.of(DATASET_REFERENCE);
60+
5961
private final String selector;
6062

6163
DatasetField(String selector) {
6264
this.selector = selector;
6365
}
6466

67+
@Override
6568
public String selector() {
6669
return selector;
6770
}
68-
69-
static String selector(DatasetField... fields) {
70-
Set<String> fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1);
71-
fieldStrings.add(DATASET_REFERENCE.selector());
72-
for (DatasetField field : fields) {
73-
fieldStrings.add(field.selector());
74-
}
75-
return Joiner.on(',').join(fieldStrings);
76-
}
7771
}
7872

7973
/**
@@ -82,7 +76,7 @@ static String selector(DatasetField... fields) {
8276
* @see <a href="https://cloud.google.com/bigquery/docs/reference/v2/tables#resource">Table
8377
* Resource</a>
8478
*/
85-
enum TableField {
79+
enum TableField implements FieldSelector {
8680
CREATION_TIME("creationTime"),
8781
DESCRIPTION("description"),
8882
ETAG("etag"),
@@ -101,25 +95,19 @@ enum TableField {
10195
TYPE("type"),
10296
VIEW("view");
10397

98+
static final List<? extends FieldSelector> REQUIRED_FIELDS =
99+
ImmutableList.of(TABLE_REFERENCE, TYPE);
100+
104101
private final String selector;
105102

106103
TableField(String selector) {
107104
this.selector = selector;
108105
}
109106

107+
@Override
110108
public String selector() {
111109
return selector;
112110
}
113-
114-
static String selector(TableField... fields) {
115-
Set<String> fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 2);
116-
fieldStrings.add(TABLE_REFERENCE.selector());
117-
fieldStrings.add(TYPE.selector());
118-
for (TableField field : fields) {
119-
fieldStrings.add(field.selector());
120-
}
121-
return Joiner.on(',').join(fieldStrings);
122-
}
123111
}
124112

125113
/**
@@ -128,7 +116,7 @@ static String selector(TableField... fields) {
128116
* @see <a href="https://cloud.google.com/bigquery/docs/reference/v2/jobs#resource">Job Resource
129117
* </a>
130118
*/
131-
enum JobField {
119+
enum JobField implements FieldSelector {
132120
CONFIGURATION("configuration"),
133121
ETAG("etag"),
134122
ID("id"),
@@ -138,25 +126,19 @@ enum JobField {
138126
STATUS("status"),
139127
USER_EMAIL("user_email");
140128

129+
static final List<? extends FieldSelector> REQUIRED_FIELDS =
130+
ImmutableList.of(JOB_REFERENCE, CONFIGURATION);
131+
141132
private final String selector;
142133

143134
JobField(String selector) {
144135
this.selector = selector;
145136
}
146137

138+
@Override
147139
public String selector() {
148140
return selector;
149141
}
150-
151-
static String selector(JobField... fields) {
152-
Set<String> fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 2);
153-
fieldStrings.add(JOB_REFERENCE.selector());
154-
fieldStrings.add(CONFIGURATION.selector());
155-
for (JobField field : fields) {
156-
fieldStrings.add(field.selector());
157-
}
158-
return Joiner.on(',').join(fieldStrings);
159-
}
160142
}
161143

162144
/**
@@ -210,7 +192,8 @@ private DatasetOption(BigQueryRpc.Option option, Object value) {
210192
* returned, even if not specified.
211193
*/
212194
public static DatasetOption fields(DatasetField... fields) {
213-
return new DatasetOption(BigQueryRpc.Option.FIELDS, DatasetField.selector(fields));
195+
return new DatasetOption(BigQueryRpc.Option.FIELDS,
196+
Helper.selector(DatasetField.REQUIRED_FIELDS, fields));
214197
}
215198
}
216199

@@ -279,7 +262,8 @@ private TableOption(BigQueryRpc.Option option, Object value) {
279262
* of {@link Table#definition()}) are always returned, even if not specified.
280263
*/
281264
public static TableOption fields(TableField... fields) {
282-
return new TableOption(BigQueryRpc.Option.FIELDS, TableField.selector(fields));
265+
return new TableOption(BigQueryRpc.Option.FIELDS,
266+
Helper.selector(TableField.REQUIRED_FIELDS, fields));
283267
}
284268
}
285269

@@ -376,10 +360,8 @@ public static JobListOption pageToken(String pageToken) {
376360
* listing jobs.
377361
*/
378362
public static JobListOption fields(JobField... fields) {
379-
String selector = JobField.selector(fields);
380-
StringBuilder builder = new StringBuilder();
381-
builder.append("etag,jobs(").append(selector).append(",state,errorResult),nextPageToken");
382-
return new JobListOption(BigQueryRpc.Option.FIELDS, builder.toString());
363+
return new JobListOption(BigQueryRpc.Option.FIELDS,
364+
Helper.listSelector("jobs", JobField.REQUIRED_FIELDS, fields, "state", "errorResult"));
383365
}
384366
}
385367

@@ -402,7 +384,8 @@ private JobOption(BigQueryRpc.Option option, Object value) {
402384
* returned, even if not specified.
403385
*/
404386
public static JobOption fields(JobField... fields) {
405-
return new JobOption(BigQueryRpc.Option.FIELDS, JobField.selector(fields));
387+
return new JobOption(BigQueryRpc.Option.FIELDS,
388+
Helper.selector(JobField.REQUIRED_FIELDS, fields));
406389
}
407390
}
408391

gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/Option.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
/**
2828
* Base class for BigQuery operation option.
2929
*/
30-
class Option implements Serializable {
30+
abstract class Option implements Serializable {
3131

3232
private static final long serialVersionUID = -6647817677804099207L;
3333

@@ -53,8 +53,7 @@ public boolean equals(Object obj) {
5353
return false;
5454
}
5555
Option other = (Option) obj;
56-
return Objects.equals(rpcOption, other.rpcOption)
57-
&& Objects.equals(value, other.value);
56+
return Objects.equals(rpcOption, other.rpcOption) && Objects.equals(value, other.value);
5857
}
5958

6059
@Override

gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/BigQueryImplTest.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -886,12 +886,14 @@ public com.google.api.services.bigquery.model.Job apply(Job job) {
886886
assertEquals(cursor, page.nextPageCursor());
887887
assertArrayEquals(jobList.toArray(), Iterables.toArray(page.values(), Job.class));
888888
String selector = (String) capturedOptions.getValue().get(JOB_OPTION_FIELDS.rpcOption());
889-
assertTrue(selector.contains("etag,jobs("));
889+
assertTrue(selector.contains("nextPageToken,jobs("));
890890
assertTrue(selector.contains("configuration"));
891891
assertTrue(selector.contains("jobReference"));
892892
assertTrue(selector.contains("statistics"));
893-
assertTrue(selector.contains("state,errorResult),nextPageToken"));
894-
assertEquals(80, selector.length());
893+
assertTrue(selector.contains("state"));
894+
assertTrue(selector.contains("errorResult"));
895+
assertTrue(selector.contains(")"));
896+
assertEquals(75, selector.length());
895897
}
896898

897899
@Test

gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/OptionTest.java

+34-7
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,49 @@
1717
package com.google.gcloud.bigquery;
1818

1919
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertNotEquals;
21+
import static org.junit.Assert.assertNull;
2022

2123
import com.google.gcloud.bigquery.spi.BigQueryRpc;
2224

25+
import org.junit.Rule;
2326
import org.junit.Test;
27+
import org.junit.rules.ExpectedException;
2428

2529
public class OptionTest {
2630

31+
private static final BigQueryRpc.Option RPC_OPTION = BigQueryRpc.Option.PAGE_TOKEN;
32+
private static final BigQueryRpc.Option ANOTHER_RPC_OPTION = BigQueryRpc.Option.FIELDS;
33+
private static final String VALUE = "some value";
34+
private static final String OTHER_VALUE = "another value";
35+
private static final Option OPTION = new Option(RPC_OPTION, VALUE) {};
36+
private static final Option OPTION_EQUALS = new Option(RPC_OPTION, VALUE) {};
37+
private static final Option OPTION_NOT_EQUALS1 = new Option(RPC_OPTION, OTHER_VALUE) {};
38+
private static final Option OPTION_NOT_EQUALS2 = new Option(ANOTHER_RPC_OPTION, VALUE) {};
39+
40+
@Rule
41+
public ExpectedException thrown = ExpectedException.none();
42+
43+
@Test
44+
public void testEquals() {
45+
assertEquals(OPTION, OPTION_EQUALS);
46+
assertNotEquals(OPTION, OPTION_NOT_EQUALS1);
47+
assertNotEquals(OPTION, OPTION_NOT_EQUALS2);
48+
}
49+
2750
@Test
28-
public void testOption() {
29-
Option option = new Option(BigQueryRpc.Option.PAGE_TOKEN, "token");
30-
assertEquals(BigQueryRpc.Option.PAGE_TOKEN, option.rpcOption());
31-
assertEquals("token", option.value());
51+
public void testHashCode() {
52+
assertEquals(OPTION.hashCode(), OPTION_EQUALS.hashCode());
3253
}
3354

34-
@Test(expected = NullPointerException.class)
35-
public void testNullRpcOption() {
36-
new Option(null, "token");
55+
@Test
56+
public void testConstructor() {
57+
assertEquals(RPC_OPTION, OPTION.rpcOption());
58+
assertEquals(VALUE, OPTION.value());
59+
Option option = new Option(RPC_OPTION, null) {};
60+
assertEquals(RPC_OPTION, option.rpcOption());
61+
assertNull(option.value());
62+
thrown.expect(NullPointerException.class);
63+
new Option(null, VALUE) {};
3764
}
3865
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.gcloud;
18+
19+
import com.google.common.base.Function;
20+
import com.google.common.base.Joiner;
21+
import com.google.common.collect.Lists;
22+
import com.google.common.collect.Sets;
23+
24+
import java.util.Arrays;
25+
import java.util.List;
26+
import java.util.Set;
27+
28+
/**
29+
* Interface for Google Cloud resource's fields. Implementations of this interface can be used to
30+
* select only desired fields from a returned Google Cloud resource.
31+
*/
32+
public interface FieldSelector {
33+
34+
/**
35+
* Returns a string selector. This selector is passed to a Google Cloud service (possibly with
36+
* other field selectors) to specify which resource fields should be returned by an API call.
37+
*/
38+
String selector();
39+
40+
/**
41+
* A helper class used to build composite selectors given a number of fields. This class is not
42+
* supposed to be used directly by users.
43+
*/
44+
class Helper {
45+
46+
private Helper() {}
47+
48+
private static final Function<FieldSelector, String> FIELD_TO_STRING_FUNCTION =
49+
new Function<FieldSelector, String>() {
50+
@Override
51+
public String apply(FieldSelector fieldSelector) {
52+
return fieldSelector.selector();
53+
}
54+
};
55+
56+
private static String selector(List<? extends FieldSelector> required, FieldSelector[] others,
57+
String... extraResourceFields) {
58+
Set<String> fieldStrings = Sets.newHashSetWithExpectedSize(required.size() + others.length);
59+
fieldStrings.addAll(Lists.transform(required, FIELD_TO_STRING_FUNCTION));
60+
fieldStrings.addAll(Lists.transform(Arrays.asList(others), FIELD_TO_STRING_FUNCTION));
61+
fieldStrings.addAll(Arrays.asList(extraResourceFields));
62+
return Joiner.on(',').join(fieldStrings);
63+
}
64+
65+
/**
66+
* Returns a composite selector given a number of fields. The string selector returned by this
67+
* method can be used for field selection in API calls that return a single resource. This
68+
* method is not supposed to be used directly by users.
69+
*/
70+
public static String selector(List<? extends FieldSelector> required, FieldSelector... others) {
71+
return selector(required, others, new String[]{});
72+
}
73+
74+
/**
75+
* Returns a composite selector given a number of fields and a container name. The string
76+
* selector returned by this method can be used for field selection in API calls that return a
77+
* list of resources. This method is not supposed to be used directly by users.
78+
*/
79+
public static String listSelector(String containerName, List<? extends FieldSelector> required,
80+
FieldSelector... others) {
81+
return "nextPageToken," + containerName + '(' + selector(required, others) + ')';
82+
}
83+
84+
/**
85+
* Returns a composite selector given a number of fields and a container name. This methods also
86+
* takes an {@code extraResourceFields} parameter to specify some extra fields as strings. The
87+
* string selector returned by this method can be used for field selection in API calls that
88+
* return a list of resources. This method is not supposed to be used directly by users.
89+
*/
90+
public static String listSelector(String containerName, List<? extends FieldSelector> required,
91+
FieldSelector[] others, String... extraResourceFields) {
92+
return "nextPageToken," + containerName + '('
93+
+ selector(required, others, extraResourceFields) + ')';
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)