Skip to content

Commit ff03e19

Browse files
authored
feat(bigquery): add QueryResultsFormat and ArrowSerializationOptions configurations (#13942)
Stacked PR 1 of 3: Exposes the public configuration API surface (`QueryResultsFormat` and `ArrowSerializationOptions`) and binds them to QueryJobConfiguration. Note: The new classes and methods are annotated with `@BetaApi` to indicate that the API surface is experimental while implementation PRs (PR 2 of 3 and PR 3 of 3) are merged. The `@BetaApi` annotation will be removed upon completion of the final PR in the stack. b/540476814
1 parent f35c570 commit ff03e19

7 files changed

Lines changed: 463 additions & 5 deletions

File tree

google-cloud-jar-parent/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
<dependency>
143143
<groupId>com.google.apis</groupId>
144144
<artifactId>google-api-services-bigquery</artifactId>
145-
<version>v2-rev20260612-2.0.0</version>
145+
<version>v2-rev20260707-2.0.0</version>
146146
</dependency>
147147

148148
</dependencies>

java-bigquery/google-cloud-bigquery/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@
204204
<scope>test</scope>
205205
<version>1.102.0-SNAPSHOT</version><!-- {x-version-update:proto-google-cloud-datacatalog-v1:current} -->
206206
</dependency>
207+
<dependency>
208+
<groupId>org.jspecify</groupId>
209+
<artifactId>jspecify</artifactId>
210+
</dependency>
207211

208212
<dependency>
209213
<groupId>io.opentelemetry</groupId>
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright 2026 Google LLC
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.cloud.bigquery;
18+
19+
import static com.google.common.base.Preconditions.checkNotNull;
20+
21+
import com.google.api.core.BetaApi;
22+
import com.google.common.base.MoreObjects;
23+
import java.io.Serializable;
24+
import java.util.Objects;
25+
import org.jspecify.annotations.NullMarked;
26+
import org.jspecify.annotations.Nullable;
27+
28+
/** <b>[Beta]</b> Options specific to the Apache Arrow output format. */
29+
@BetaApi
30+
@NullMarked
31+
public final class ArrowSerializationOptions implements Serializable {
32+
33+
private static final long serialVersionUID = 1L;
34+
35+
/** <b>[Beta]</b> Buffer compression codec for Apache Arrow record batches. */
36+
@BetaApi
37+
public enum CompressionCodec {
38+
UNCOMPRESSED("UNCOMPRESSED"),
39+
LZ4_FRAME("LZ4_FRAME"),
40+
ZSTD("ZSTD");
41+
42+
private final String value;
43+
44+
CompressionCodec(String value) {
45+
this.value = value;
46+
}
47+
48+
public String getValue() {
49+
return value;
50+
}
51+
52+
@Override
53+
public String toString() {
54+
return value;
55+
}
56+
}
57+
58+
/** <b>[Beta]</b> Timestamp precision for Apache Arrow timestamp types. */
59+
@BetaApi
60+
public enum TimestampPrecision {
61+
MICROS("PRECISION_MICROS"),
62+
NANOS("PRECISION_NANOS"),
63+
PICOS("PRECISION_PICOS");
64+
65+
private final String value;
66+
67+
TimestampPrecision(String value) {
68+
this.value = value;
69+
}
70+
71+
public String getValue() {
72+
return value;
73+
}
74+
75+
@Override
76+
public String toString() {
77+
return value;
78+
}
79+
}
80+
81+
private final CompressionCodec bufferCompression;
82+
private final TimestampPrecision picosTimestampPrecision;
83+
84+
private ArrowSerializationOptions(Builder builder) {
85+
this.bufferCompression = builder.bufferCompression;
86+
this.picosTimestampPrecision = builder.picosTimestampPrecision;
87+
}
88+
89+
/**
90+
* <b>[Beta]</b> Returns the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED).
91+
* Defaults to {@link CompressionCodec#UNCOMPRESSED}.
92+
*/
93+
@BetaApi
94+
public CompressionCodec getBufferCompression() {
95+
return bufferCompression;
96+
}
97+
98+
/**
99+
* <b>[Beta]</b> Returns the timestamp precision for Arrow timestamp types. Defaults to {@link
100+
* TimestampPrecision#PRECISION_MICROS}.
101+
*
102+
* <p>Note: Only applies when {@link QueryResultsFormat#ARROW} is enabled. For Arrow result
103+
* streams, this precision setting governs binary Arrow timestamp column types and takes
104+
* precedence over {@link DataFormatOptions.TimestampFormatOptions}, which applies to default
105+
* {@link QueryResultsFormat#STRUCT_ENCODING} JSON results.
106+
*/
107+
@BetaApi
108+
public TimestampPrecision getPicosTimestampPrecision() {
109+
return picosTimestampPrecision;
110+
}
111+
112+
/** <b>[Beta]</b> Returns a new builder for {@link ArrowSerializationOptions}. */
113+
@BetaApi
114+
public static Builder newBuilder() {
115+
return new Builder();
116+
}
117+
118+
@Override
119+
public String toString() {
120+
return MoreObjects.toStringHelper(this)
121+
.add("bufferCompression", bufferCompression)
122+
.add("picosTimestampPrecision", picosTimestampPrecision)
123+
.toString();
124+
}
125+
126+
@Override
127+
public boolean equals(@Nullable Object o) {
128+
if (this == o) {
129+
return true;
130+
}
131+
if (o == null || getClass() != o.getClass()) {
132+
return false;
133+
}
134+
ArrowSerializationOptions that = (ArrowSerializationOptions) o;
135+
return bufferCompression == that.bufferCompression
136+
&& picosTimestampPrecision == that.picosTimestampPrecision;
137+
}
138+
139+
@Override
140+
public int hashCode() {
141+
return Objects.hash(bufferCompression, picosTimestampPrecision);
142+
}
143+
144+
com.google.api.services.bigquery.model.ArrowSerializationOptions toPb() {
145+
return ArrowSerializationOptionsConverter.toPb(this);
146+
}
147+
148+
static ArrowSerializationOptions fromPb(
149+
com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb) {
150+
return ArrowSerializationOptionsConverter.fromPb(optionsPb);
151+
}
152+
153+
/** <b>[Beta]</b> Builder for {@link ArrowSerializationOptions}. */
154+
@BetaApi
155+
public static final class Builder {
156+
private CompressionCodec bufferCompression = CompressionCodec.UNCOMPRESSED;
157+
private TimestampPrecision picosTimestampPrecision = TimestampPrecision.MICROS;
158+
159+
private Builder() {}
160+
161+
/**
162+
* <b>[Beta]</b> Sets the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED).
163+
*/
164+
@BetaApi
165+
public Builder setBufferCompression(CompressionCodec bufferCompression) {
166+
this.bufferCompression = checkNotNull(bufferCompression, "bufferCompression cannot be null");
167+
return this;
168+
}
169+
170+
/**
171+
* <b>[Beta]</b> Sets the timestamp precision for Arrow timestamp types.
172+
*
173+
* <p>Note: Only applies when {@link QueryResultsFormat#ARROW} is enabled. For Arrow result
174+
* streams, this precision setting governs binary Arrow timestamp column types and takes
175+
* precedence over {@link DataFormatOptions.TimestampFormatOptions}, which applies to default
176+
* {@link QueryResultsFormat#STRUCT_ENCODING} JSON results.
177+
*/
178+
@BetaApi
179+
public Builder setPicosTimestampPrecision(TimestampPrecision picosTimestampPrecision) {
180+
this.picosTimestampPrecision =
181+
checkNotNull(picosTimestampPrecision, "picosTimestampPrecision cannot be null");
182+
return this;
183+
}
184+
185+
/** <b>[Beta]</b> Builds a new instance of {@link ArrowSerializationOptions}. */
186+
@BetaApi
187+
public ArrowSerializationOptions build() {
188+
return new ArrowSerializationOptions(this);
189+
}
190+
}
191+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2026 Google LLC
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.cloud.bigquery;
18+
19+
import org.jspecify.annotations.NullMarked;
20+
import org.jspecify.annotations.Nullable;
21+
22+
@NullMarked
23+
final class ArrowSerializationOptionsConverter {
24+
25+
private ArrowSerializationOptionsConverter() {}
26+
27+
static com.google.api.services.bigquery.model.@Nullable ArrowSerializationOptions toPb(
28+
@Nullable ArrowSerializationOptions options) {
29+
if (options == null) {
30+
return null;
31+
}
32+
com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb =
33+
new com.google.api.services.bigquery.model.ArrowSerializationOptions();
34+
optionsPb.setBufferCompression(options.getBufferCompression().getValue());
35+
optionsPb.setPicosTimestampPrecision(options.getPicosTimestampPrecision().getValue());
36+
return optionsPb;
37+
}
38+
39+
static @Nullable ArrowSerializationOptions fromPb(@Nullable Object optionsPbObj) {
40+
if (optionsPbObj == null) {
41+
return null;
42+
}
43+
com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb =
44+
(com.google.api.services.bigquery.model.ArrowSerializationOptions) optionsPbObj;
45+
ArrowSerializationOptions.Builder builder = ArrowSerializationOptions.newBuilder();
46+
if (optionsPb.getBufferCompression() != null) {
47+
for (ArrowSerializationOptions.CompressionCodec codec :
48+
ArrowSerializationOptions.CompressionCodec.values()) {
49+
if (codec.getValue().equalsIgnoreCase(optionsPb.getBufferCompression())) {
50+
builder.setBufferCompression(codec);
51+
break;
52+
}
53+
}
54+
}
55+
if (optionsPb.getPicosTimestampPrecision() != null) {
56+
for (ArrowSerializationOptions.TimestampPrecision precision :
57+
ArrowSerializationOptions.TimestampPrecision.values()) {
58+
if (precision.getValue().equalsIgnoreCase(optionsPb.getPicosTimestampPrecision())) {
59+
builder.setPicosTimestampPrecision(precision);
60+
break;
61+
}
62+
}
63+
}
64+
return builder.build();
65+
}
66+
}

0 commit comments

Comments
 (0)