Skip to main content

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}