Skip to content

Commit e9028cb

Browse files
fvaleyertyler
authored andcommitted
feat(typed-builder): migrate builder to use TypedBuilder in catalog-unity crate
Signed-off-by: Florian Valeye <florian.valeye@gmail.com>
1 parent 7064361 commit e9028cb

7 files changed

Lines changed: 85 additions & 207 deletions

File tree

crates/aws/src/constants.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,7 @@ pub static CONDITION_DELETE_INCOMPLETE: LazyLock<String> = LazyLock::new(|| {
162162

163163
pub const CONDITION_UPDATE_INCOMPLETE: &str = "complete = :f";
164164
pub const DEFAULT_COMMIT_ENTRY_EXPIRATION_DELAY: Duration = Duration::from_secs(86_400);
165+
166+
pub const DEFAULT_S3_POOL_IDLE_TIMEOUT_SECONDS: u64 = 15;
167+
pub const DEFAULT_STS_POOL_IDLE_TIMEOUT_SECONDS: u64 = 10;
168+
pub const DEFAULT_S3_GET_INTERNAL_SERVER_ERROR_RETRIES: usize = 10;

crates/aws/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,6 @@ impl TryFrom<&HashMap<String, AttributeValue>> for CommitEntry {
608608
.map(epoch_to_system_time);
609609
let complete = extract_required_string_field(item, constants::ATTR_COMPLETE)? == "true";
610610

611-
// Construct directly to avoid TypedBuilder's type state issues with conditional fields
612611
Ok(Self {
613612
version,
614613
temp_path,

crates/aws/src/storage.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,15 @@ use tracing::log::*;
2525
use typed_builder::TypedBuilder;
2626
use url::Url;
2727

28-
use crate::constants;
28+
use crate::constants::{
29+
self, DEFAULT_S3_GET_INTERNAL_SERVER_ERROR_RETRIES, DEFAULT_S3_POOL_IDLE_TIMEOUT_SECONDS,
30+
DEFAULT_STS_POOL_IDLE_TIMEOUT_SECONDS,
31+
};
2932
use crate::credentials::AWSForObjectStore;
3033
use crate::errors::DynamoDbConfigError;
3134

3235
const STORE_NAME: &str = "DeltaS3ObjectStore";
3336

34-
// Default values for S3StorageOptions
35-
const DEFAULT_S3_POOL_IDLE_TIMEOUT_SECONDS: u64 = 15;
36-
const DEFAULT_STS_POOL_IDLE_TIMEOUT_SECONDS: u64 = 10;
37-
const DEFAULT_S3_GET_INTERNAL_SERVER_ERROR_RETRIES: usize = 10;
38-
3937
#[derive(Clone, Default, Debug)]
4038
pub struct S3ObjectStoreFactory {}
4139

crates/catalog-unity/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ thiserror.workspace = true
2020
futures.workspace = true
2121
chrono.workspace = true
2222
tracing.workspace = true
23+
typed-builder = { workspace = true }
2324
deltalake-core = { version = "0.29.0", path = "../core" }
2425
deltalake-aws = { version = "0.12.0", path = "../aws", optional = true }
2526
deltalake-azure = { version = "0.12.0", path = "../azure", optional = true }

crates/catalog-unity/src/client/mod.rs

Lines changed: 34 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use reqwest::{ClientBuilder, Proxy};
1414
use reqwest_middleware::ClientWithMiddleware;
1515
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
1616
use std::time::Duration;
17+
use typed_builder::TypedBuilder;
1718

1819
fn map_client_error(e: reqwest::Error) -> super::DataCatalogError {
1920
super::DataCatalogError::Generic {
@@ -25,154 +26,57 @@ fn map_client_error(e: reqwest::Error) -> super::DataCatalogError {
2526
static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
2627

2728
/// HTTP client configuration for remote catalogs
28-
#[derive(Debug, Clone, Default)]
29+
#[derive(Debug, Clone, Default, TypedBuilder)]
30+
#[builder(doc)]
2931
pub struct ClientOptions {
32+
/// User-Agent header to use for requests
33+
#[builder(default, setter(strip_option))]
3034
user_agent: Option<HeaderValue>,
35+
/// Default headers for every request
36+
#[builder(default, setter(strip_option))]
3137
default_headers: Option<HeaderMap>,
38+
/// HTTP proxy URL
39+
#[builder(default, setter(strip_option, into))]
3240
proxy_url: Option<String>,
33-
allow_http: bool,
41+
/// Allow HTTP connections (default: false)
42+
#[builder(default)]
43+
pub(crate) allow_http: bool,
44+
/// Allow invalid SSL certificates (default: false)
45+
#[builder(default)]
3446
allow_insecure: bool,
47+
/// Request timeout
48+
#[builder(default, setter(strip_option))]
3549
timeout: Option<Duration>,
50+
/// Connect timeout
51+
#[builder(default, setter(strip_option))]
3652
connect_timeout: Option<Duration>,
53+
/// Pool idle timeout
54+
#[builder(default, setter(strip_option))]
3755
pool_idle_timeout: Option<Duration>,
56+
/// Maximum number of idle connections per host
57+
#[builder(default, setter(strip_option))]
3858
pool_max_idle_per_host: Option<usize>,
59+
/// HTTP2 keep alive interval
60+
#[builder(default, setter(strip_option))]
3961
http2_keep_alive_interval: Option<Duration>,
62+
/// HTTP2 keep alive timeout
63+
#[builder(default, setter(strip_option))]
4064
http2_keep_alive_timeout: Option<Duration>,
65+
/// Enable HTTP2 keep alive while idle
66+
#[builder(default)]
4167
http2_keep_alive_while_idle: bool,
68+
/// Only use HTTP1
69+
#[builder(default)]
4270
http1_only: bool,
71+
/// Only use HTTP2
72+
#[builder(default)]
4373
http2_only: bool,
74+
/// Retry configuration
75+
#[builder(default, setter(strip_option))]
4476
retry_config: Option<RetryConfig>,
4577
}
4678

4779
impl ClientOptions {
48-
/// Create a new [`ClientOptions`] with default values
49-
pub fn new() -> Self {
50-
Default::default()
51-
}
52-
53-
/// Sets the User-Agent header to be used by this client
54-
///
55-
/// Default is based on the version of this crate
56-
pub fn with_user_agent(mut self, agent: HeaderValue) -> Self {
57-
self.user_agent = Some(agent);
58-
self
59-
}
60-
61-
/// Sets the default headers for every request
62-
pub fn with_default_headers(mut self, headers: HeaderMap) -> Self {
63-
self.default_headers = Some(headers);
64-
self
65-
}
66-
67-
/// Sets what protocol is allowed. If `allow_http` is :
68-
/// * false (default): Only HTTPS are allowed
69-
/// * true: HTTP and HTTPS are allowed
70-
pub fn with_allow_http(mut self, allow_http: bool) -> Self {
71-
self.allow_http = allow_http;
72-
self
73-
}
74-
/// Allows connections to invalid SSL certificates
75-
/// * false (default): Only valid HTTPS certificates are allowed
76-
/// * true: All HTTPS certificates are allowed
77-
///
78-
/// # Warning
79-
///
80-
/// You should think very carefully before using this method. If
81-
/// invalid certificates are trusted, *any* certificate for *any* site
82-
/// will be trusted for use. This includes expired certificates. This
83-
/// introduces significant vulnerabilities, and should only be used
84-
/// as a last resort or for testing
85-
pub fn with_allow_invalid_certificates(mut self, allow_insecure: bool) -> Self {
86-
self.allow_insecure = allow_insecure;
87-
self
88-
}
89-
90-
/// Only use http1 connections
91-
pub fn with_http1_only(mut self) -> Self {
92-
self.http1_only = true;
93-
self
94-
}
95-
96-
/// Only use http2 connections
97-
pub fn with_http2_only(mut self) -> Self {
98-
self.http2_only = true;
99-
self
100-
}
101-
102-
/// Set an HTTP proxy to use for requests
103-
pub fn with_proxy_url(mut self, proxy_url: impl Into<String>) -> Self {
104-
self.proxy_url = Some(proxy_url.into());
105-
self
106-
}
107-
108-
/// Set a request timeout
109-
///
110-
/// The timeout is applied from when the request starts connecting until the
111-
/// response body has finished
112-
pub fn with_timeout(mut self, timeout: Duration) -> Self {
113-
self.timeout = Some(timeout);
114-
self
115-
}
116-
117-
/// Set a timeout for only the connect phase of a Client
118-
pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
119-
self.connect_timeout = Some(timeout);
120-
self
121-
}
122-
123-
/// Set the pool max idle timeout
124-
///
125-
/// This is the length of time an idle connection will be kept alive
126-
///
127-
/// Default is 90 seconds
128-
pub fn with_pool_idle_timeout(mut self, timeout: Duration) -> Self {
129-
self.pool_idle_timeout = Some(timeout);
130-
self
131-
}
132-
133-
/// Set the maximum number of idle connections per host
134-
///
135-
/// Default is no limit
136-
pub fn with_pool_max_idle_per_host(mut self, max: usize) -> Self {
137-
self.pool_max_idle_per_host = Some(max);
138-
self
139-
}
140-
141-
/// Sets an interval for HTTP2 Ping frames should be sent to keep a connection alive.
142-
///
143-
/// Default is disabled
144-
pub fn with_http2_keep_alive_interval(mut self, interval: Duration) -> Self {
145-
self.http2_keep_alive_interval = Some(interval);
146-
self
147-
}
148-
149-
/// Sets a timeout for receiving an acknowledgement of the keep-alive ping.
150-
///
151-
/// If the ping is not acknowledged within the timeout, the connection will be closed.
152-
/// Does nothing if http2_keep_alive_interval is disabled.
153-
///
154-
/// Default is disabled
155-
pub fn with_http2_keep_alive_timeout(mut self, interval: Duration) -> Self {
156-
self.http2_keep_alive_timeout = Some(interval);
157-
self
158-
}
159-
160-
/// Enable HTTP2 keep alive pings for idle connections
161-
///
162-
/// If disabled, keep-alive pings are only sent while there are open request/response
163-
/// streams. If enabled, pings are also sent when no streams are active
164-
///
165-
/// Default is disabled
166-
pub fn with_http2_keep_alive_while_idle(mut self) -> Self {
167-
self.http2_keep_alive_while_idle = true;
168-
self
169-
}
170-
171-
pub fn with_retry_config(mut self, cfg: RetryConfig) -> Self {
172-
self.retry_config = Some(cfg);
173-
self
174-
}
175-
17680
pub(crate) fn client(&self) -> DataCatalogResult<ClientWithMiddleware> {
17781
let mut builder = ClientBuilder::new();
17882

0 commit comments

Comments
 (0)