Skip to content

Commit 7dfca8e

Browse files
committed
Merge pull request #443 from mziccard/bigquery
Add InsertAllRequest, InsertAllResponse and model classes for table data
2 parents a88e0da + aacc383 commit 7dfca8e

File tree

7 files changed

+1197
-1
lines changed

7 files changed

+1197
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
/*
2+
* Copyright 2015 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.bigquery;
18+
19+
import static com.google.common.base.Preconditions.checkNotNull;
20+
import static com.google.common.base.Preconditions.checkState;
21+
22+
import com.google.api.client.util.Data;
23+
import com.google.api.client.util.Lists;
24+
import com.google.common.base.Function;
25+
import com.google.common.base.MoreObjects;
26+
27+
import java.io.Serializable;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.Objects;
31+
32+
/**
33+
* Google BigQuery Table Field Value class. Objects of this class represent values of a BigQuery
34+
* Table Field. A list of values forms a table row. Tables rows can be gotten as the result of a
35+
* query or when listing table data.
36+
*/
37+
public class FieldValue implements Serializable {
38+
39+
static final Function<Object, FieldValue> FROM_PB_FUNCTION = new Function<Object, FieldValue>() {
40+
@Override
41+
public FieldValue apply(Object pb) {
42+
return FieldValue.fromPb(pb);
43+
}
44+
};
45+
private static final int MICROSECONDS = 1000000;
46+
private static final long serialVersionUID = 469098630191710061L;
47+
48+
private final Attribute attribute;
49+
private final Object value;
50+
51+
/**
52+
* The field value's attribute, giving information on the field's content type.
53+
*/
54+
public enum Attribute {
55+
/**
56+
* A primitive field value. A {@code FieldValue} is primitive when the corresponding field has
57+
* type {@link Field.Type#bool()}, {@link Field.Type#string()},
58+
* {@link Field.Type#floatingPoint()}, {@link Field.Type#integer()},
59+
* {@link Field.Type#timestamp()} or the value is set to {@code null}.
60+
*/
61+
PRIMITIVE,
62+
63+
/**
64+
* A {@code FieldValue} for a field with {@link Field.Mode#REPEATED} mode.
65+
*/
66+
REPEATED,
67+
68+
/**
69+
* A {@code FieldValue} for a field of type {@link Field.Type#record(Field...)}.
70+
*/
71+
RECORD
72+
}
73+
74+
FieldValue(Attribute attribute, Object value) {
75+
this.attribute = attribute;
76+
this.value = value;
77+
}
78+
79+
/**
80+
* Returns the attribute of this Field Value.
81+
*
82+
* @return {@link Attribute#PRIMITIVE} if the field is a primitive type
83+
* ({@link Field.Type#bool()}, {@link Field.Type#string()},
84+
* {@link Field.Type#floatingPoint()}, {@link Field.Type#integer()},
85+
* {@link Field.Type#timestamp()}) or is {@code null}. Returns {@link Attribute#REPEATED} if
86+
* the corresponding field has ({@link Field.Mode#REPEATED}) mode. Returns
87+
* {@link Attribute#RECORD} if the corresponding field is a
88+
* {@link Field.Type#record(Field...)} type.
89+
*/
90+
public Attribute attribute() {
91+
return attribute;
92+
}
93+
94+
/**
95+
* Returns {@code true} if this field's value is {@code null}, {@code false} otherwise.
96+
*/
97+
public boolean isNull() {
98+
return value == null;
99+
}
100+
101+
/**
102+
* Returns this field's value as an {@link Object}. If {@link #isNull()} is {@code true} this
103+
* method returns {@code null}.
104+
*/
105+
public Object value() {
106+
return value;
107+
}
108+
109+
/**
110+
* Returns this field's value as a {@link String}. This method should only be used if the
111+
* corresponding field has primitive type ({@link Field.Type#bool()}, {@link Field.Type#string()},
112+
* {@link Field.Type#floatingPoint()}, {@link Field.Type#integer()},
113+
* {@link Field.Type#timestamp()}).
114+
*
115+
* @throws ClassCastException if the field is not a primitive type
116+
* @throws NullPointerException if {@link #isNull()} returns {@code true}
117+
*/
118+
@SuppressWarnings("unchecked")
119+
public String stringValue() {
120+
checkNotNull(value);
121+
return (String) value;
122+
}
123+
124+
/**
125+
* Returns this field's value as a {@code long}. This method should only be used if the
126+
* corresponding field has {@link Field.Type#integer()} type.
127+
*
128+
* @throws ClassCastException if the field is not a primitive type
129+
* @throws NumberFormatException if the field's value could not be converted to {@link Integer}
130+
* @throws NullPointerException if {@link #isNull()} returns {@code true}
131+
*/
132+
@SuppressWarnings("unchecked")
133+
public long longValue() {
134+
return Long.parseLong(stringValue());
135+
}
136+
137+
/**
138+
* Returns this field's value as a {@link Double}. This method should only be used if the
139+
* corresponding field has {@link Field.Type#floatingPoint()} type.
140+
*
141+
* @throws ClassCastException if the field is not a primitive type
142+
* @throws NumberFormatException if the field's value could not be converted to {@link Double}
143+
* @throws NullPointerException if {@link #isNull()} returns {@code true}
144+
*/
145+
@SuppressWarnings("unchecked")
146+
public double doubleValue() {
147+
return Double.parseDouble(stringValue());
148+
}
149+
150+
/**
151+
* Returns this field's value as a {@link Boolean}. This method should only be used if the
152+
* corresponding field has {@link Field.Type#bool()} type.
153+
*
154+
* @throws ClassCastException if the field is not a primitive type
155+
* @throws IllegalStateException if the field's value could not be converted to {@link Boolean}
156+
* @throws NullPointerException if {@link #isNull()} returns {@code true}
157+
*/
158+
@SuppressWarnings("unchecked")
159+
public boolean booleanValue() {
160+
String stringValue = stringValue();
161+
checkState(stringValue.equalsIgnoreCase("true") || stringValue.equalsIgnoreCase("false"),
162+
"Field value is not of boolean type");
163+
return Boolean.parseBoolean(stringValue);
164+
}
165+
166+
/**
167+
* Returns this field's value as a {@code long}, representing a timestamp in microseconds since
168+
* epoch (UNIX time). This method should only be used if the corresponding field has
169+
* {@link Field.Type#timestamp()} type.
170+
*
171+
* @throws ClassCastException if the field is not a primitive type
172+
* @throws NumberFormatException if the field's value could not be converted to {@link Long}
173+
* @throws NullPointerException if {@link #isNull()} returns {@code true}
174+
*/
175+
@SuppressWarnings("unchecked")
176+
public long timestampValue() {
177+
// timestamps are encoded in the format 1408452095.22 where the integer part is seconds since
178+
// epoch (e.g. 1408452095.22 == 2014-08-19 07:41:35.220 -05:00)
179+
return new Double(((Double.valueOf(stringValue())) * MICROSECONDS)).longValue();
180+
}
181+
182+
/**
183+
* Returns this field's value as a list of {@link FieldValue}. This method should only be used if
184+
* the corresponding field has {@link Field.Mode#REPEATED} mode (i.e. {@link #attribute()} is
185+
* {@link Attribute#REPEATED}).
186+
*
187+
* @throws ClassCastException if the field has not {@link Field.Mode#REPEATED} mode
188+
* @throws NullPointerException if {@link #isNull()} returns {@code true}
189+
*/
190+
@SuppressWarnings("unchecked")
191+
public List<FieldValue> repeatedValue() {
192+
checkNotNull(value);
193+
return (List<FieldValue>) value;
194+
}
195+
196+
/**
197+
* Returns this field's value as a list of {@link FieldValue}. This method should only be used if
198+
* the corresponding field has {@link Field.Type#record(Field...)} type (i.e. {@link #attribute()}
199+
* is {@link Attribute#RECORD}).
200+
*
201+
* @throws ClassCastException if the field is not a {@link Field.Type#record(Field...)} type
202+
* @throws NullPointerException if {@link #isNull()} returns {@code true}
203+
*/
204+
@SuppressWarnings("unchecked")
205+
public List<FieldValue> recordValue() {
206+
checkNotNull(value);
207+
return (List<FieldValue>) value;
208+
}
209+
210+
@Override
211+
public String toString() {
212+
return MoreObjects.toStringHelper(this)
213+
.add("attribute", attribute)
214+
.add("value", value)
215+
.toString();
216+
}
217+
218+
@Override
219+
public int hashCode() {
220+
return Objects.hash(attribute, value);
221+
}
222+
223+
@Override
224+
public boolean equals(Object obj) {
225+
if (!(obj instanceof FieldValue)) {
226+
return false;
227+
}
228+
FieldValue other = (FieldValue) obj;
229+
return attribute == other.attribute && Objects.equals(value, other.value);
230+
}
231+
232+
@SuppressWarnings("unchecked")
233+
static FieldValue fromPb(Object cellPb) {
234+
if (Data.isNull(cellPb)) {
235+
return new FieldValue(Attribute.PRIMITIVE, null);
236+
}
237+
if (cellPb instanceof String) {
238+
return new FieldValue(Attribute.PRIMITIVE, cellPb);
239+
}
240+
if (cellPb instanceof List) {
241+
List<Object> cellsListPb = (List<Object>) cellPb;
242+
List<FieldValue> repeatedCells = Lists.newArrayListWithCapacity(cellsListPb.size());
243+
for (Object repeatedCellPb : cellsListPb) {
244+
repeatedCells.add(FieldValue.fromPb(repeatedCellPb));
245+
}
246+
return new FieldValue(Attribute.REPEATED, repeatedCells);
247+
}
248+
if (cellPb instanceof Map) {
249+
Map<String, Object> cellMapPb = (Map<String, Object>) cellPb;
250+
if (cellMapPb.containsKey("f")) {
251+
List<Object> cellsListPb = (List<Object>) cellMapPb.get("f");
252+
List<FieldValue> recordCells = Lists.newArrayListWithCapacity(cellsListPb.size());
253+
for (Object repeatedCellPb : cellsListPb) {
254+
recordCells.add(FieldValue.fromPb(repeatedCellPb));
255+
}
256+
return new FieldValue(Attribute.RECORD, recordCells);
257+
}
258+
// This should never be the case when we are processing a first level table field (i.e. a
259+
// row's field, not a record sub-field)
260+
if (cellMapPb.containsKey("v")) {
261+
return FieldValue.fromPb(cellMapPb.get("v"));
262+
}
263+
}
264+
throw new AssertionError("Unexpected table cell format");
265+
}
266+
}

0 commit comments

Comments
 (0)