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}
38
39impl Default for ClientBuilder {
40    fn default() -> Self {
41        Self::new()
42    }
43}
44
45impl ClientBuilder {
46    /// Creates a new default [`ClientBuilder`].
47    pub fn new() -> Self {
48        Self {
49            config: ClientConfig::default(),
50            project_id: None,
51        }
52    }
53
54    /// Sets the default Google Cloud project ID for the client.
55    ///
56    /// # Example
57    /// ```
58    /// # use google_cloud_bigquery::client::BigQuery;
59    /// # async fn sample() -> anyhow::Result<()> {
60    /// let client = BigQuery::builder()
61    ///     .with_project_id("my-project-id")
62    ///     .build()
63    ///     .await?;
64    /// # Ok(()) }
65    /// ```
66    pub fn with_project_id<V: Into<String>>(mut self, project_id: V) -> Self {
67        self.project_id = Some(project_id.into());
68        self
69    }
70
71    /// Sets the [BigQuery v2] API endpoint.
72    ///
73    /// # Example
74    /// ```
75    /// # use google_cloud_bigquery::client::BigQuery;
76    /// # async fn sample() -> anyhow::Result<()> {
77    /// let client = BigQuery::builder()
78    ///     .with_endpoint("https://private.googleapis.com")
79    ///     .build()
80    ///     .await?;
81    /// # Ok(()) }
82    /// ```
83    ///
84    /// [BigQuery v2]: https://docs.cloud.google.com/bigquery/docs/reference/rest
85    pub fn with_endpoint<V: Into<String>>(mut self, v: V) -> Self {
86        self.config.endpoint = Some(v.into());
87        self
88    }
89
90    /// Configure the authentication credentials.
91    ///
92    /// Most Google Cloud services require authentication, though some services
93    /// allow for anonymous access, and some services provide emulators where
94    /// no authentication is required. More information about valid credentials
95    /// types can be found in the [google-cloud-auth] crate documentation.
96    ///
97    /// # Example
98    /// ```
99    /// # use google_cloud_bigquery::client::BigQuery;
100    /// # async fn sample() -> anyhow::Result<()> {
101    /// use google_cloud_auth::credentials::mds;
102    /// let client = BigQuery::builder()
103    ///     .with_credentials(
104    ///         mds::Builder::default()
105    ///             .with_scopes(["https://www.googleapis.com/auth/cloud-platform.read-only"])
106    ///             .build()?)
107    ///     .build()
108    ///     .await?;
109    /// # Ok(()) }
110    /// ```
111    ///
112    /// [google-cloud-auth]: https://docs.rs/google-cloud-auth
113    pub fn with_credentials<V: Into<Credentials>>(mut self, credentials: V) -> Self {
114        self.config.cred = Some(credentials.into());
115        self
116    }
117
118    /// Configure the universe domain.
119    ///
120    /// The universe domain is the default service domain for a given cloud universe.
121    /// The default value is "googleapis.com".
122    ///
123    /// # Example
124    /// ```
125    /// # use google_cloud_bigquery::client::BigQuery;
126    /// # async fn sample() -> anyhow::Result<()> {
127    /// let client = BigQuery::builder()
128    ///     .with_universe_domain("googleapis.com")
129    ///     .build()
130    ///     .await?;
131    /// # Ok(()) }
132    /// ```
133    pub fn with_universe_domain<V: Into<String>>(mut self, v: V) -> Self {
134        self.config.universe_domain = Some(v.into());
135        self
136    }
137
138    /// Enables tracing.
139    ///
140    /// The client libraries can be dynamically instrumented with the Tokio
141    /// [tracing] framework. Setting this flag enables this instrumentation.
142    ///
143    /// # Example
144    /// ```
145    /// # use google_cloud_bigquery::client::BigQuery;
146    /// # async fn sample() -> anyhow::Result<()> {
147    /// let client = BigQuery::builder()
148    ///     .with_tracing()
149    ///     .build()
150    ///     .await?;
151    /// # Ok(()) }
152    /// ```
153    ///
154    /// [tracing]: https://docs.rs/tracing/latest/tracing/
155    pub fn with_tracing(mut self) -> Self {
156        self.config.tracing = true;
157        self
158    }
159
160    /// Configure the retry policy.
161    ///
162    /// The client libraries can automatically retry operations that fail. The
163    /// retry policy controls what errors are considered retryable, sets limits
164    /// on the number of attempts or the time trying to make attempts.
165    ///
166    /// # Example
167    /// ```
168    /// # use google_cloud_bigquery::client::BigQuery;
169    /// # async fn sample() -> anyhow::Result<()> {
170    /// use google_cloud_bigquery::query::retry_policy::RetryableErrors;
171    /// use google_cloud_gax::retry_policy::RetryPolicyExt;
172    /// let client = BigQuery::builder()
173    ///     .with_retry_policy(RetryableErrors.with_attempt_limit(3))
174    ///     .build()
175    ///     .await?;
176    /// # Ok(()) }
177    /// ```
178    pub fn with_retry_policy<V: Into<google_cloud_gax::retry_policy::RetryPolicyArg>>(
179        mut self,
180        v: V,
181    ) -> Self {
182        self.config.retry_policy = Some(v.into().into());
183        self
184    }
185
186    /// Configure the retry backoff policy.
187    ///
188    /// The client libraries can automatically retry operations that fail. The
189    /// backoff policy controls how long to wait in between retry attempts.
190    ///
191    /// # Example
192    /// ```
193    /// # use google_cloud_bigquery::client::BigQuery;
194    /// # async fn sample() -> anyhow::Result<()> {
195    /// use google_cloud_gax::exponential_backoff::ExponentialBackoff;
196    /// use std::time::Duration;
197    /// let policy = ExponentialBackoff::default();
198    /// let client = BigQuery::builder()
199    ///     .with_backoff_policy(policy)
200    ///     .build()
201    ///     .await?;
202    /// # Ok(()) }
203    /// ```
204    pub fn with_backoff_policy<V: Into<google_cloud_gax::backoff_policy::BackoffPolicyArg>>(
205        mut self,
206        v: V,
207    ) -> Self {
208        self.config.backoff_policy = Some(v.into().into());
209        self
210    }
211
212    /// Creates a new [`BigQuery`] client.
213    ///
214    /// # Example
215    /// ```
216    /// # use google_cloud_bigquery::client::BigQuery;
217    /// # async fn sample() -> anyhow::Result<()> {
218    /// let client = BigQuery::builder().build().await?;
219    /// # Ok(()) }
220    /// ```
221    pub async fn build(self) -> Result<BigQuery> {
222        BigQuery::new(self).await
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229    use crate::query::retry_policy::RetryableErrors;
230    use google_cloud_auth::credentials::anonymous::Builder as Anonymous;
231    use google_cloud_gax::exponential_backoff::ExponentialBackoff;
232
233    #[test]
234    fn defaults() -> anyhow::Result<()> {
235        let builder = ClientBuilder::new();
236        assert!(builder.config.endpoint.is_none(), "{builder:?}");
237        assert!(builder.config.universe_domain.is_none(), "{builder:?}");
238        assert!(builder.config.cred.is_none(), "{builder:?}");
239        assert!(!builder.config.tracing);
240        assert!(builder.config.retry_policy.is_none(), "{builder:?}");
241        assert!(builder.config.backoff_policy.is_none(), "{builder:?}");
242        assert!(builder.project_id.is_none(), "{builder:?}");
243
244        Ok(())
245    }
246
247    #[tokio::test]
248    async fn setters() -> anyhow::Result<()> {
249        let builder = ClientBuilder::new()
250            .with_project_id("test-project")
251            .with_endpoint("test-endpoint.com")
252            .with_universe_domain("test-universe.com")
253            .with_credentials(Anonymous::new().build())
254            .with_retry_policy(RetryableErrors)
255            .with_backoff_policy(ExponentialBackoff::default())
256            .with_tracing();
257
258        assert_eq!(builder.project_id, Some("test-project".to_string()));
259        assert_eq!(
260            builder.config.endpoint,
261            Some("test-endpoint.com".to_string())
262        );
263        assert_eq!(
264            builder.config.universe_domain,
265            Some("test-universe.com".to_string())
266        );
267        assert!(builder.config.cred.is_some(), "{builder:?}");
268        assert!(builder.config.tracing);
269        assert!(builder.config.retry_policy.is_some(), "{builder:?}");
270        assert!(builder.config.backoff_policy.is_some(), "{builder:?}");
271
272        Ok(())
273    }
274}