Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 93 additions & 5 deletions src/bigquery/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,64 @@ use google_cloud_bigquery_v2::client::JobService;
use std::sync::Arc;

/// A high-level BigQuery client for executing queries and managing jobs.
///
/// # Configuration
///
/// To configure a `BigQuery` client, use the `with_*` methods on the [`ClientBuilder`] returned
/// by [`BigQuery::builder()`]. The default configuration uses Application Default Credentials (ADC)
/// and connects to the global default endpoint, which works for most applications.
///
/// Common configuration customizations include:
///
/// - [`with_endpoint()`][crate::builder::bigquery::ClientBuilder::with_endpoint]: Overrides the default API endpoint (`https://bigquery.googleapis.com`). Useful when testing against mock servers or running in restricted network environments (for example, with VPC Service Controls).
/// - [`with_credentials()`][crate::builder::bigquery::ClientBuilder::with_credentials]: Overrides the default Application Default Credentials with explicit or custom authentication credentials.
///
/// # Pooling and Cloning
///
/// `BigQuery` holds an internal gRPC/HTTP client and connection pool wrapped in an [`Arc`].
/// You should create a single `BigQuery` client instance upon application initialization and reuse it across multiple tasks or requests.
/// Cloning a `BigQuery` instance is cheap and does not duplicate underlying connections or thread pools, so you do not need to wrap `BigQuery` in an additional `Arc`.
///
/// # Example: Basic Setup and Query Execution
///
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
Comment thread
alvarowolfx marked this conversation as resolved.
Comment thread
alvarowolfx marked this conversation as resolved.
/// let client = BigQuery::builder().build().await?;
/// let mut rows = client
/// .query("SELECT name, count FROM `bigquery-public-data.usa_names.usa_1910_2013` WHERE state = 'WA' ORDER BY count DESC LIMIT 5")
/// .with_project_id("my-project-id")
/// .run()
/// .await?
/// .until_done()
/// .await?
/// .read();
///
/// while let Some(row) = rows.next().await.transpose()? {
/// let name: String = row.get("name");
/// let count: i64 = row.get("count");
/// println!("{name}: {count}");
/// }
/// # Ok(()) }
/// ```
#[derive(Clone, Debug)]
pub struct BigQuery {
#[allow(dead_code)]
pub(crate) job_service: Arc<JobService>,
job_service: Arc<JobService>,
}

impl BigQuery {
/// Convenient entrypoint to return a fresh configuration builder.
/// Returns a new [`ClientBuilder`] for configuring and instantiating a [`BigQuery`] client.
///
/// # Example
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
/// let client = BigQuery::builder()
/// .with_endpoint("https://bigquery.googleapis.com")
/// .build()
/// .await?;
/// # Ok(()) }
/// ```
pub fn builder() -> ClientBuilder {
ClientBuilder::new()
}
Expand Down Expand Up @@ -58,9 +108,47 @@ impl BigQuery {
Ok(BigQuery { job_service })
}

/// Execute a SQL query.
/// Creates a request builder to configure and execute a SQL query.
///
/// This method returns a [`RunQuery`] builder. You can chain additional configuration methods
/// (such as setting the project ID, positional or named parameters, query location, and maximum result buffer sizes)
/// before calling [`RunQuery::run()`].
///
/// The [`RunQuery`] builder automatically decides whether to route your request via the fast path ([`jobs.query`][jobs_query])
/// or the background job creation path ([`jobs.insert`][jobs_insert]). If the query configuration uses only options supported
/// by the fast path, the client library uses [`jobs.query`][jobs_query] for lower latency. If advanced options (such as destination
/// tables or allowing large results) are configured, the client automatically falls back to creating an asynchronous job.
///
/// [jobs_query]: https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query
/// [jobs_insert]: https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/insert
///
/// # Example
///
/// ```
/// # async fn sample() -> anyhow::Result<()> {
/// use google_cloud_bigquery::client::BigQuery;
Comment thread
alvarowolfx marked this conversation as resolved.
///
/// let client = BigQuery::builder().build().await?;
///
/// // Execute a query and read the resulting rows.
/// let mut rows = client
/// .query("SELECT name, count FROM `my-project.my_dataset.stats` LIMIT 50")
/// .with_project_id("my-project-id")
/// .set_location("US")
/// .run()
/// .await?
/// .until_done()
/// .await?
/// .read();
///
/// This builder internally routes to either `jobs.query` (fast path) or `jobs.insert` (job path)
/// while let Some(row) = rows.next().await.transpose()? {
/// let name: String = row.get("name");
/// let count: i64 = row.get("count");
/// println!("{name}: {count}");
/// }
/// # Ok(())
/// # }
/// ```
pub fn query<S: Into<String>>(&self, sql: S) -> RunQuery {
RunQuery::new(self.job_service.clone(), sql.into())
}
Expand Down
90 changes: 85 additions & 5 deletions src/bigquery/src/client_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,19 @@ use gaxi::options::ClientConfig;
use google_cloud_auth::credentials::Credentials;
use google_cloud_gax::client_builder::Result;

/// A builder for creating and configuring a BigQuery client instance.
/// A builder for [`BigQuery`][crate::client::BigQuery].
///
/// # Example
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
/// let builder = BigQuery::builder();
/// let client = builder
/// .with_endpoint("https://bigquery.googleapis.com")
/// .build()
/// .await?;
/// # Ok(()) }
/// ```
#[derive(Clone, Debug)]
pub struct ClientBuilder {
pub(crate) config: ClientConfig,
Expand All @@ -30,7 +42,7 @@ impl Default for ClientBuilder {
}

impl ClientBuilder {
/// Creates a new default `ClientBuilder`.
/// Creates a new default [`ClientBuilder`].
pub fn new() -> Self {
Self {
config: ClientConfig::default(),
Expand All @@ -39,13 +51,46 @@ impl ClientBuilder {

/// Sets the [BigQuery v2] API endpoint.
///
/// # Example
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
/// let client = BigQuery::builder()
/// .with_endpoint("https://private.googleapis.com")
/// .build()
/// .await?;
/// # Ok(()) }
/// ```
///
/// [BigQuery v2]: https://docs.cloud.google.com/bigquery/docs/reference/rest
pub fn with_endpoint<V: Into<String>>(mut self, v: V) -> Self {
self.config.endpoint = Some(v.into());
self
}

/// Sets custom credentials for the client.
/// Configure the authentication credentials.
///
/// Most Google Cloud services require authentication, though some services
/// allow for anonymous access, and some services provide emulators where
/// no authentication is required. More information about valid credentials
/// types can be found in the [google-cloud-auth] crate documentation.
///
/// # Example
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
/// use google_cloud_auth::credentials::mds;
/// let client = BigQuery::builder()
/// .with_credentials(
/// mds::Builder::default()
/// .with_scopes(["https://www.googleapis.com/auth/cloud-platform.read-only"])
/// .build()?)
/// .build()
/// .await?;
/// # Ok(()) }
/// ```
///
/// [google-cloud-auth]: https://docs.rs/google-cloud-auth
pub fn with_credentials<V: Into<Credentials>>(mut self, credentials: V) -> Self {
self.config.cred = Some(credentials.into());
self
Expand All @@ -55,18 +100,53 @@ impl ClientBuilder {
///
/// The universe domain is the default service domain for a given cloud universe.
/// The default value is "googleapis.com".
///
/// # Example
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
/// let client = BigQuery::builder()
/// .with_universe_domain("googleapis.com")
/// .build()
/// .await?;
/// # Ok(()) }
/// ```
pub fn with_universe_domain<V: Into<String>>(mut self, v: V) -> Self {
self.config.universe_domain = Some(v.into());
self
}

/// Enables observability signals for the client.
/// Enables tracing.
///
/// The client libraries can be dynamically instrumented with the Tokio
/// [tracing] framework. Setting this flag enables this instrumentation.
///
/// # Example
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
/// let client = BigQuery::builder()
/// .with_tracing()
/// .build()
/// .await?;
/// # Ok(()) }
/// ```
///
/// [tracing]: https://docs.rs/tracing/latest/tracing/
pub fn with_tracing(mut self) -> Self {
self.config.tracing = true;
self
}

/// Builds the `BigQuery` client instance.
/// Creates a new [`BigQuery`] client.
///
/// # Example
/// ```
/// # use google_cloud_bigquery::client::BigQuery;
/// # async fn sample() -> anyhow::Result<()> {
/// let client = BigQuery::builder().build().await?;
/// # Ok(()) }
/// ```
pub async fn build(self) -> Result<BigQuery> {
BigQuery::new(self).await
}
Expand Down
Loading