Skip to content

Commit 20dfb48

Browse files
committed
Add InsertAllRequest and InsertAllResponse. Add model classes for table data
1 parent 722e4a7 commit 20dfb48

File tree

9 files changed

+1236
-1
lines changed

9 files changed

+1236
-1
lines changed
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package com.google.gcloud.bigquery;
2+
3+
import static com.google.common.base.Preconditions.checkState;
4+
5+
import com.google.api.client.util.Data;
6+
import com.google.api.client.util.Lists;
7+
import com.google.common.base.MoreObjects;
8+
9+
import java.io.Serializable;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Objects;
13+
14+
/**
15+
* Google BigQuery Table Field Value class. Objects of this class represent values of a BigQuery
16+
* Table Field. A list of values forms a {@link TableRow}. Tables rows can be get as the result of
17+
* a query or when listing table data.
18+
*/
19+
public class FieldValue implements Serializable {
20+
21+
private static final int MICROSECONDS = 1000000;
22+
private static final long serialVersionUID = 469098630191710061L;
23+
24+
private final Kind kind;
25+
private final Object value;
26+
27+
/**
28+
* The field value's kind, giving information on the field's content type.
29+
*/
30+
public enum Kind {
31+
/**
32+
* A primitive field value. A {@code FieldValue} has type {@link #PRIMITIVE} when the
33+
* corresponding field has type {@link Field.Type#bool()}, {@link Field.Type#string()}
34+
* {@link Field.Type#floatingPoint()}, {@link Field.Type#integer()},
35+
* {@link Field.Type#timestamp()} or the value is set to {@code null}.
36+
*/
37+
PRIMITIVE,
38+
39+
/**
40+
* A {@code FieldValue} for a field with {@link Field.Mode#REPEATED} mode.
41+
*/
42+
REPEATED,
43+
44+
/**
45+
* A {@code FieldValue} for a field of type {@link Field.Type#record(Field...)}.
46+
*/
47+
RECORD
48+
}
49+
50+
FieldValue(Kind kind, Object value) {
51+
this.kind = kind;
52+
this.value = value;
53+
}
54+
55+
/**
56+
* Returns the kind of this Field Value.
57+
*
58+
* @return {@link Kind#PRIMITIVE} if the value is of primitive type ({@link Field.Type#bool()},
59+
* {@link Field.Type#string()}, {@link Field.Type#floatingPoint()},
60+
* {@link Field.Type#integer()}, {@link Field.Type#timestamp()}) or is {@code null}. Returns
61+
* {@link Kind#REPEATED} if the corresponding field has ({@link Field.Mode#REPEATED}) mode.
62+
* Returns {@link Kind#RECORD} if the corresponding field has
63+
* {@link Field.Type#record(Field...)} type.
64+
*/
65+
public Kind kind() {
66+
return kind;
67+
}
68+
69+
/**
70+
* Return this field's value as an {@link Object}.
71+
*/
72+
public Object value() {
73+
return value;
74+
}
75+
76+
/**
77+
* Return this field's value as an {@link String}.
78+
*/
79+
@SuppressWarnings("unchecked")
80+
public String stringValue() {
81+
return (String) value;
82+
}
83+
84+
/**
85+
* Returns this field's value as a {@link Long}. This method should only be used if the
86+
* corresponding field has {@link Field.Type#integer()} type.
87+
*
88+
* @throws NumberFormatException if the field's value could not be converted to {@link Integer}
89+
*/
90+
@SuppressWarnings("unchecked")
91+
public long longValue() {
92+
return Long.valueOf(stringValue());
93+
}
94+
95+
/**
96+
* Returns this field's value as a {@link Double}. This method should only be used if the
97+
* corresponding field has {@link Field.Type#floatingPoint()} type.
98+
*
99+
* @throws NumberFormatException if the field's value could not be converted to {@link Double}
100+
*/
101+
@SuppressWarnings("unchecked")
102+
public double doubleValue() {
103+
return Double.valueOf(stringValue());
104+
}
105+
106+
/**
107+
* Returns this field's value as a {@link Boolean}. This method should only be used if the
108+
* corresponding field has {@link Field.Type#bool()} type.
109+
*
110+
* @throws IllegalStateException if the field's value could not be converted to {@link Boolean}
111+
*/
112+
@SuppressWarnings("unchecked")
113+
public boolean booleanValue() {
114+
String stringValue = stringValue();
115+
checkState(stringValue.equalsIgnoreCase("true") || stringValue.equalsIgnoreCase("false"),
116+
"Field value is not of boolean type");
117+
return Boolean.parseBoolean(stringValue);
118+
}
119+
120+
/**
121+
* Returns this field's value as a {@link Long}, representing a timestamp in microseconds. This
122+
* method should only be used if the corresponding field has {@link Field.Type#timestamp()} type.
123+
*
124+
* @throws NumberFormatException if the field's value could not be converted to {@link Long}
125+
*/
126+
@SuppressWarnings("unchecked")
127+
public long timestampValue() {
128+
return new Double(((Double.valueOf(stringValue())) * MICROSECONDS)).longValue();
129+
}
130+
131+
/**
132+
* Returns this field's value as a list of {@link FieldValue}. This method should only be used if
133+
* the corresponding field has {@link Field.Mode#REPEATED} mode (i.e. {@link #kind()} is
134+
* {@link Kind#REPEATED}).
135+
*/
136+
@SuppressWarnings("unchecked")
137+
public List<FieldValue> repeatedValue() {
138+
return (List<FieldValue>) value;
139+
}
140+
141+
/**
142+
* Returns this field's value as a list of {@link FieldValue}. This method should only be used if
143+
* the corresponding field has {@link Field.Type#record(Field...)} type (i.e. {@link #kind()} is
144+
* {@link Kind#RECORD}).
145+
*/
146+
@SuppressWarnings("unchecked")
147+
public List<FieldValue> recordValue() {
148+
return (List<FieldValue>) value;
149+
}
150+
151+
@Override
152+
public String toString() {
153+
return MoreObjects.toStringHelper(this)
154+
.add("kind", kind)
155+
.add("value", value)
156+
.toString();
157+
}
158+
159+
@Override
160+
public int hashCode() {
161+
return Objects.hash(kind, value);
162+
}
163+
164+
@Override
165+
public boolean equals(Object obj) {
166+
if (!(obj instanceof FieldValue)) {
167+
return false;
168+
}
169+
FieldValue other = (FieldValue) obj;
170+
return kind == other.kind && Objects.equals(value, other.value);
171+
}
172+
173+
@SuppressWarnings("unchecked")
174+
static FieldValue fromPb(Object cellPb) {
175+
if (Data.isNull(cellPb)) {
176+
return new FieldValue(Kind.PRIMITIVE, null);
177+
}
178+
if (cellPb instanceof String) {
179+
return new FieldValue(Kind.PRIMITIVE, cellPb);
180+
}
181+
if (cellPb instanceof List) {
182+
List<Object> cellsListPb = (List<Object>) cellPb;
183+
List<FieldValue> repeatedCells = Lists.newArrayListWithCapacity(cellsListPb.size());
184+
for (Object repeatedCellPb : cellsListPb) {
185+
repeatedCells.add(FieldValue.fromPb(repeatedCellPb));
186+
}
187+
return new FieldValue(Kind.REPEATED, repeatedCells);
188+
}
189+
if (cellPb instanceof Map) {
190+
Map<String, Object> cellMapPb = (Map<String, Object>) cellPb;
191+
if (cellMapPb.containsKey("f")) {
192+
List<Object> cellsListPb = (List<Object>) cellMapPb.get("f");
193+
List<FieldValue> recordCells = Lists.newArrayListWithCapacity(cellsListPb.size());
194+
for (Object repeatedCellPb : cellsListPb) {
195+
recordCells.add(FieldValue.fromPb(repeatedCellPb));
196+
}
197+
return new FieldValue(Kind.RECORD, recordCells);
198+
}
199+
// This should never be the case when we are processing a first level table field (i.e. a
200+
// row's field, not a record sub-field)
201+
if (cellMapPb.containsKey("v")) {
202+
return FieldValue.fromPb(cellMapPb.get("v"));
203+
}
204+
}
205+
throw new AssertionError("Unexpected table cell format");
206+
}
207+
}

0 commit comments

Comments
 (0)