google_cloud_bigquery/query/client_builder.rs
1// Copyright 2026 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::client::BigQuery;
16use gaxi::options::ClientConfig;
17use google_cloud_auth::credentials::Credentials;
18use google_cloud_gax::client_builder::Result;
19
20/// A builder for [`BigQuery`][crate::client::BigQuery].
21///
22/// # Example
23/// ```
24/// # use google_cloud_bigquery::client::BigQuery;
25/// # async fn sample() -> anyhow::Result<()> {
26/// let builder = BigQuery::builder();
27/// let client = builder
28/// .with_endpoint("https://bigquery.googleapis.com")
29/// .build()
30/// .await?;
31/// # Ok(()) }
32/// ```
33#[derive(Clone, Debug)]
34pub struct ClientBuilder {
35 pub(crate) config: ClientConfig,
36 pub(crate) project_id: Option<String>,
37 pub(crate) storage_read_enabled: bool,
38 pub(crate) storage_read_endpoint: Option<String>,
39}
40
41impl Default for ClientBuilder {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47impl ClientBuilder {
48 /// Creates a new default [`ClientBuilder`].
49 pub fn new() -> Self {
50 Self {
51 config: ClientConfig::default(),
52 project_id: None,
53 storage_read_enabled: false,
54 storage_read_endpoint: None,
55 }
56 }
57
58 /// Sets the default Google Cloud project ID for the client.
59 ///
60 /// # Example
61 /// ```
62 /// # use google_cloud_bigquery::client::BigQuery;
63 /// # async fn sample() -> anyhow::Result<()> {
64 /// let client = BigQuery::builder()
65 /// .with_project_id("my-project-id")
66 /// .build()
67 /// .await?;
68 /// # Ok(()) }
69 /// ```
70 pub fn with_project_id<V: Into<String>>(mut self, project_id: V) -> Self {
71 self.project_id = Some(project_id.into());
72 self
73 }
74
75 /// Sets the [BigQuery v2] API endpoint.
76 ///
77 /// # Example
78 /// ```
79 /// # use google_cloud_bigquery::client::BigQuery;
80 /// # async fn sample() -> anyhow::Result<()> {
81 /// let client = BigQuery::builder()
82 /// .with_endpoint("https://private.googleapis.com")
83 /// .build()
84 /// .await?;
85 /// # Ok(()) }
86 /// ```
87 ///
88 /// [BigQuery v2]: https://docs.cloud.google.com/bigquery/docs/reference/rest
89 pub fn with_endpoint<V: Into<String>>(mut self, v: V) -> Self {
90 self.config.endpoint = Some(v.into());
91 self
92 }
93
94 /// Configure the authentication credentials.
95 ///
96 /// Most Google Cloud services require authentication, though some services
97 /// allow for anonymous access, and some services provide emulators where
98 /// no authentication is required. More information about valid credentials
99 /// types can be found in the [google-cloud-auth] crate documentation.
100 ///
101 /// # Example
102 /// ```
103 /// # use google_cloud_bigquery::client::BigQuery;
104 /// # async fn sample() -> anyhow::Result<()> {
105 /// use google_cloud_auth::credentials::mds;
106 /// let client = BigQuery::builder()
107 /// .with_credentials(
108 /// mds::Builder::default()
109 /// .with_scopes(["https://www.googleapis.com/auth/cloud-platform.read-only"])
110 /// .build()?)
111 /// .build()
112 /// .await?;
113 /// # Ok(()) }
114 /// ```
115 ///
116 /// [google-cloud-auth]: https://docs.rs/google-cloud-auth
117 pub fn with_credentials<V: Into<Credentials>>(mut self, credentials: V) -> Self {
118 self.config.cred = Some(credentials.into());
119 self
120 }
121
122 /// Configure the universe domain.
123 ///
124 /// The universe domain is the default service domain for a given cloud universe.
125 /// The default value is "googleapis.com".
126 ///
127 /// # Example
128 /// ```
129 /// # use google_cloud_bigquery::client::BigQuery;
130 /// # async fn sample() -> anyhow::Result<()> {
131 /// let client = BigQuery::builder()
132 /// .with_universe_domain("googleapis.com")
133 /// .build()
134 /// .await?;
135 /// # Ok(()) }
136 /// ```
137 pub fn with_universe_domain<V: Into<String>>(mut self, v: V) -> Self {
138 self.config.universe_domain = Some(v.into());
139 self
140 }
141
142 /// Enables tracing.
143 ///
144 /// The client libraries can be dynamically instrumented with the Tokio
145 /// [tracing] framework. Setting this flag enables this instrumentation.
146 ///
147 /// # Example
148 /// ```
149 /// # use google_cloud_bigquery::client::BigQuery;
150 /// # async fn sample() -> anyhow::Result<()> {
151 /// let client = BigQuery::builder()
152 /// .with_tracing()
153 /// .build()
154 /// .await?;
155 /// # Ok(()) }
156 /// ```
157 ///
158 /// [tracing]: https://docs.rs/tracing/latest/tracing/
159 pub fn with_tracing(mut self) -> Self {
160 self.config.tracing = true;
161 self
162 }
163
164 /// Configure the retry policy.
165 ///
166 /// The client libraries can automatically retry operations that fail. The
167 /// retry policy controls what errors are considered retryable, sets limits
168 /// on the number of attempts or the time trying to make attempts.
169 ///
170 /// # Example
171 /// ```
172 /// # use google_cloud_bigquery::client::BigQuery;
173 /// # async fn sample() -> anyhow::Result<()> {
174 /// use google_cloud_bigquery::query::retry_policy::RetryableErrors;
175 /// use google_cloud_gax::retry_policy::RetryPolicyExt;
176 /// let client = BigQuery::builder()
177 /// .with_retry_policy(RetryableErrors.with_attempt_limit(3))
178 /// .build()
179 /// .await?;
180 /// # Ok(()) }
181 /// ```
182 pub fn with_retry_policy<V: Into<google_cloud_gax::retry_policy::RetryPolicyArg>>(
183 mut self,
184 v: V,
185 ) -> Self {
186 self.config.retry_policy = Some(v.into().into());
187 self
188 }
189
190 /// Configure the retry backoff policy.
191 ///
192 /// The client libraries can automatically retry operations that fail. The
193 /// backoff policy controls how long to wait in between retry attempts.
194 ///
195 /// # Example
196 /// ```
197 /// # use google_cloud_bigquery::client::BigQuery;
198 /// # async fn sample() -> anyhow::Result<()> {
199 /// use google_cloud_gax::exponential_backoff::ExponentialBackoff;
200 /// use std::time::Duration;
201 /// let policy = ExponentialBackoff::default();
202 /// let client = BigQuery::builder()
203 /// .with_backoff_policy(policy)
204 /// .build()
205 /// .await?;
206 /// # Ok(()) }
207 /// ```
208 pub fn with_backoff_policy<V: Into<google_cloud_gax::backoff_policy::BackoffPolicyArg>>(
209 mut self,
210 v: V,
211 ) -> Self {
212 self.config.backoff_policy = Some(v.into().into());
213 self
214 }
215
216 /// Enables or disables BigQuery Storage Read API acceleration for query result reading.
217 ///
218 /// When enabled, large query result sets will be streamed directly using the high-performance
219 /// gRPC Storage Read API in Arrow format, using the same [`Row`][crate::query::Row] interface.
220 ///
221 /// # Example
222 /// ```
223 /// # use google_cloud_bigquery::client::BigQuery;
224 /// # async fn sample() -> anyhow::Result<()> {
225 /// let client = BigQuery::builder()
226 /// .with_storage_read(true)
227 /// .build()
228 /// .await?;
229 /// # Ok(()) }
230 /// ```
231 #[cfg(google_cloud_unstable_bigquery_storage_read)]
232 pub fn with_storage_read(mut self, enabled: bool) -> Self {
233 self.storage_read_enabled = enabled;
234 self
235 }
236
237 /// Sets the endpoint for the BigQuery Storage Read API.
238 ///
239 /// # Example
240 /// ```
241 /// # use google_cloud_bigquery::client::BigQuery;
242 /// # async fn sample() -> anyhow::Result<()> {
243 /// let client = BigQuery::builder()
244 /// .with_storage_read(true)
245 /// .with_storage_read_endpoint("https://bigquerystorage.googleapis.com")
246 /// .build()
247 /// .await?;
248 /// # Ok(()) }
249 /// ```
250 #[cfg(google_cloud_unstable_bigquery_storage_read)]
251 pub fn with_storage_read_endpoint<V: Into<String>>(mut self, endpoint: V) -> Self {
252 self.storage_read_endpoint = Some(endpoint.into());
253 self
254 }
255
256 /// Creates a new [`BigQuery`] client.
257 ///
258 /// # Example
259 /// ```
260 /// # use google_cloud_bigquery::client::BigQuery;
261 /// # async fn sample() -> anyhow::Result<()> {
262 /// let client = BigQuery::builder().build().await?;
263 /// # Ok(()) }
264 /// ```
265 pub async fn build(self) -> Result<BigQuery> {
266 BigQuery::new(self).await
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273 use crate::query::retry_policy::RetryableErrors;
274 use google_cloud_auth::credentials::anonymous::Builder as Anonymous;
275 use google_cloud_gax::exponential_backoff::ExponentialBackoff;
276
277 #[test]
278 fn defaults() -> anyhow::Result<()> {
279 let builder = ClientBuilder::new();
280 assert!(builder.config.endpoint.is_none(), "{builder:?}");
281 assert!(builder.config.universe_domain.is_none(), "{builder:?}");
282 assert!(builder.config.cred.is_none(), "{builder:?}");
283 assert!(!builder.config.tracing);
284 assert!(builder.config.retry_policy.is_none(), "{builder:?}");
285 assert!(builder.config.backoff_policy.is_none(), "{builder:?}");
286 assert!(builder.project_id.is_none(), "{builder:?}");
287 assert!(!builder.storage_read_enabled, "{builder:?}");
288 assert!(builder.storage_read_endpoint.is_none(), "{builder:?}");
289
290 Ok(())
291 }
292
293 #[tokio::test]
294 async fn setters() -> anyhow::Result<()> {
295 let builder = ClientBuilder::new()
296 .with_project_id("test-project")
297 .with_endpoint("test-endpoint.com")
298 .with_universe_domain("test-universe.com")
299 .with_credentials(Anonymous::new().build())
300 .with_retry_policy(RetryableErrors)
301 .with_backoff_policy(ExponentialBackoff::default())
302 .with_tracing();
303 #[cfg(google_cloud_unstable_bigquery_storage_read)]
304 let builder = builder
305 .with_storage_read(true)
306 .with_storage_read_endpoint("test-storage-endpoint.com");
307
308 assert_eq!(builder.project_id, Some("test-project".to_string()));
309 assert_eq!(
310 builder.config.endpoint,
311 Some("test-endpoint.com".to_string())
312 );
313 assert_eq!(
314 builder.config.universe_domain,
315 Some("test-universe.com".to_string())
316 );
317 assert!(builder.config.cred.is_some(), "{builder:?}");
318 assert!(builder.config.tracing);
319 assert!(builder.config.retry_policy.is_some(), "{builder:?}");
320 assert!(builder.config.backoff_policy.is_some(), "{builder:?}");
321 #[cfg(google_cloud_unstable_bigquery_storage_read)]
322 {
323 assert!(builder.storage_read_enabled);
324 assert_eq!(
325 builder.storage_read_endpoint,
326 Some("test-storage-endpoint.com".to_string())
327 );
328 }
329
330 Ok(())
331 }
332}