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}