hyperdb_api_core/client/mod.rs
1// Copyright (c) 2026, Salesforce, Inc. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4#![allow(
5 missing_docs,
6 reason = "internal crate; not published to crates.io. Docs are contributor-facing, covered in DEVELOPMENT.md."
7)]
8
9//! Client library for Hyper database.
10//!
11//! This crate provides both synchronous and asynchronous PostgreSQL-wire-protocol clients
12//! specifically for Hyper database servers, with support for `HyperBinary`
13//! data format, gRPC transport, and Salesforce Data Cloud authentication.
14//!
15//! # Features
16//!
17//! ## Core Client Features
18//! - **Dual architecture**: `AsyncClient` for async applications, `Client` for sync
19//! - Thread-safe clients (can be shared between threads/tasks)
20//! - Multiple authentication methods: cleartext, MD5, SCRAM-SHA-256
21//! - Simple query protocol for ad-hoc queries
22//! - Extended query protocol for prepared statements
23//! - COPY protocol for high-performance bulk insertion
24//! - Optional TLS support (rustls)
25//!
26//! ## Advanced Transport Features
27//! - **gRPC transport**: Query-only access with Arrow IPC format
28//! - **Salesforce authentication**: OAuth 2.0 and JWT Bearer Token flows
29//! - **Connection pooling**: Async connection pooling via deadpool
30//!
31//! # Quick Start
32//!
33//! ## Synchronous Client
34//!
35//! ```no_run
36//! use hyperdb_api_core::client::{Client, Config};
37//!
38//! fn main() -> hyperdb_api_core::client::Result<()> {
39//! let config = Config::new()
40//! .with_host("localhost")
41//! .with_port(7483)
42//! .with_database("test.hyper");
43//!
44//! let client = Client::connect(&config)?;
45//!
46//! let rows = client.query("SELECT 1 as value")?;
47//! for row in rows {
48//! println!("value: {:?}", row.get_i32(0));
49//! }
50//!
51//! client.close()?;
52//! Ok(())
53//! }
54//! ```
55//!
56//! ## Asynchronous Client
57//!
58//! ```no_run
59//! use hyperdb_api_core::client::{AsyncClient, Config};
60//!
61//! #[tokio::main]
62//! async fn main() -> hyperdb_api_core::client::Result<()> {
63//! let config = Config::new()
64//! .with_host("localhost")
65//! .with_port(7483)
66//! .with_database("test.hyper");
67//!
68//! let client = AsyncClient::connect(&config).await?;
69//! let rows = client.query("SELECT 1").await?;
70//! client.close().await?;
71//! Ok(())
72//! }
73//! ```
74//!
75//! ## gRPC Client
76//!
77//! ```no_run
78//! use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig};
79//!
80//! #[tokio::main]
81//! async fn main() -> hyperdb_api_core::client::Result<()> {
82//! let config = GrpcConfig::new("http://localhost:7484");
83//! let mut client = GrpcClient::connect(config).await?;
84//!
85//! let result = client.execute_query("SELECT 1").await?;
86//! println!("Query complete: {}", result.is_complete());
87//! Ok(())
88//! }
89//! ```
90//!
91//! ## Salesforce Authentication
92//!
93//! ```ignore
94//! use hyperdb_api_salesforce::{SalesforceAuthConfig, AuthMode, DataCloudTokenProvider};
95//! use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig};
96//!
97//! #[tokio::main]
98//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
99//! let auth_config = SalesforceAuthConfig::new(
100//! "https://login.salesforce.com",
101//! "your-client-id",
102//! )?.auth_mode(AuthMode::password("user@example.com", "password"));
103//!
104//! let mut token_provider = DataCloudTokenProvider::new(auth_config)?;
105//! let token = token_provider.get_token().await?;
106//!
107//! let grpc_config = GrpcConfig::new("https://hyper.data.salesforce.com")
108//! .header("Authorization", token.bearer_token())
109//! .header("audience", token.tenant_url_str());
110//!
111//! let mut client = GrpcClient::connect(grpc_config).await?;
112//! let result = client.execute_query("SELECT 1").await?;
113//! Ok(())
114//! }
115//! ```
116//!
117//! # Authentication Methods
118//!
119//! ## Basic Authentication
120//!
121//! ```no_run
122//! use hyperdb_api_core::client::Config;
123//!
124//! let config = Config::new()
125//! .with_host("localhost")
126//! .with_port(7483)
127//! .with_user("myuser")
128//! .with_password("mypassword")
129//! .with_database("test.hyper");
130//! ```
131//!
132//! Supported methods:
133//! - Trust (no password required)
134//! - Cleartext password
135//! - MD5 password hash
136//! - SCRAM-SHA-256 (most secure)
137//!
138//! ## Salesforce Data Cloud Authentication
139//!
140//! Three authentication modes are supported:
141//!
142//! - **Password**: Username + password + client secret (OAuth password grant)
143//! - **`PrivateKey`**: JWT Bearer Token Flow using RSA private key (recommended for server-to-server)
144//! - **`RefreshToken`**: OAuth refresh token + client secret
145//!
146//! See the Salesforce authentication section above for a complete example.
147//!
148//! # Bulk Insertion with COPY
149//!
150//! ## Synchronous COPY
151//!
152//! ```no_run
153//! use hyperdb_api_core::client::{Client, Config};
154//! use hyperdb_api_core::protocol::copy;
155//!
156//! # fn example() -> hyperdb_api_core::client::Result<()> {
157//! let config = Config::new().with_host("localhost").with_port(7483);
158//! let client = Client::connect(&config)?;
159//!
160//! let mut writer = client.copy_in("\"my_table\"", &["col1", "col2"])?;
161//!
162//! // Build binary data
163//! let mut buf = bytes::BytesMut::new();
164//! copy::write_header(&mut buf);
165//! copy::write_i32(&mut buf, 42);
166//! copy::write_varbinary(&mut buf, b"hello");
167//!
168//! writer.send(&buf)?;
169//! let rows = writer.finish()?;
170//! # Ok(())
171//! # }
172//! ```
173//!
174//! ## Asynchronous COPY
175//!
176//! ```no_run
177//! use hyperdb_api_core::client::{AsyncClient, Config};
178//! use hyperdb_api_core::protocol::copy;
179//!
180//! #[tokio::main]
181//! async fn example() -> hyperdb_api_core::client::Result<()> {
182//! let config = Config::new().with_host("localhost").with_port(7483);
183//! let client = AsyncClient::connect(&config).await?;
184//!
185//! let mut writer = client.copy_in("\"my_table\"", &["col1", "col2"]).await?;
186//!
187//! // Build binary data
188//! let mut buf = bytes::BytesMut::new();
189//! copy::write_header(&mut buf);
190//! copy::write_i32(&mut buf, 42);
191//! copy::write_varbinary(&mut buf, b"hello");
192//!
193//! writer.send(&buf).await?;
194//! let rows = writer.finish().await?;
195//! Ok(())
196//! }
197//! ```
198//!
199//! # gRPC Transport Details
200//!
201//! The gRPC transport provides read-only access to Hyper databases with the following benefits:
202//!
203//! - Better support for load balancing
204//! - Built-in streaming for large result sets
205//! - HTTP/2 multiplexing
206//! - Easier integration with service meshes
207//! - Arrow IPC format for efficient data transfer
208//!
209//! ## gRPC Limitations
210//!
211//! The gRPC interface is **read-only**:
212//! - Only SELECT queries are supported
213//! - No INSERT, UPDATE, DELETE, or DDL operations
214//! - No COPY protocol for bulk data insertion
215//!
216//! For write operations, use the standard TCP connection.
217//!
218//! ## gRPC Parameterized Queries
219//!
220//! ```no_run
221//! use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig, QueryParameters, ParameterStyle};
222//!
223//! #[tokio::main]
224//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
225//! let config = GrpcConfig::new("http://localhost:7484");
226//! let mut client = GrpcClient::connect(config).await?;
227//!
228//! // Dollar-numbered parameters ($1, $2, ...) - use serde_json::json! for mixed types
229//! let params = QueryParameters::from_json_value(&serde_json::json!([42, "Alice"]))?;
230//! let result = client.execute_query_with_params(
231//! "SELECT * FROM users WHERE id = $1 AND name = $2",
232//! params,
233//! ParameterStyle::DollarNumbered,
234//! ).await?;
235//!
236//! // Named parameters using builder pattern
237//! let params = QueryParameters::json_named()
238//! .add("id", &42i64)?
239//! .add("name", &"Alice")?
240//! .build();
241//! let result = client.execute_query_with_params(
242//! "SELECT * FROM users WHERE id = :id AND name = :name",
243//! params,
244//! ParameterStyle::Named,
245//! ).await?;
246//!
247//! Ok(())
248//! }
249//! ```
250//!
251//! # Feature Flags
252//!
253//! - **`salesforce-auth`**: Salesforce Data Cloud OAuth authentication (via `hyperdb-api-salesforce` crate)
254//!
255//! **Always Available (no feature flags required):**
256//! - TLS support (rustls)
257//! - gRPC transport with Arrow IPC format
258//! - Async client (`AsyncClient`)
259//!
260//! # Attribution
261//!
262//! The `hyper-client` crate code was inspired by the design patterns and API
263//! structure of the [`libpq`](https://crates.io/crates/libpq) Rust crate (MIT License).
264//! While `hyper-client` does not depend on the `libpq` crate, its connection
265//! management patterns served as valuable inspiration during development.
266//!
267//! **libpq crate:**
268//! - Repository: <https://crates.io/crates/libpq>
269//! - License: MIT License
270//! - Note: The `libpq` crate is not a dependency of this project.
271
272#![warn(missing_docs, rust_2018_idioms, clippy::all)]
273
274pub mod auth;
275pub mod cancel;
276#[allow(
277 clippy::module_inception,
278 reason = "preserved submodule name after collapsing the old hyper-client crate into hyperdb-api-core/src/client/"
279)]
280pub mod client;
281pub mod config;
282pub mod connection;
283pub mod endpoint;
284pub mod error;
285pub mod notice;
286pub mod prepare;
287pub mod prepared_stream;
288pub mod row;
289pub mod statement;
290pub mod sync_stream;
291
292// Async modules
293pub mod async_client;
294pub mod async_connection;
295pub mod async_prepared_stream;
296pub mod async_stream;
297pub mod async_stream_query;
298
299pub mod tls;
300
301pub mod grpc;
302
303// Re-exports - Sync client
304pub use async_client::AsyncPreparedStatement;
305pub use cancel::Cancellable;
306pub use client::{Client, CopyInWriter, QueryStream};
307pub use config::Config;
308pub use endpoint::ConnectionEndpoint;
309pub use error::{Error, ErrorKind, Result};
310pub use notice::{Notice, NoticeReceiver};
311pub use prepare::{OwnedPreparedStatement, PreparedStatement, SqlParam};
312pub use row::{BatchRow, FromBinaryValue, Row, StreamRow};
313pub use statement::{Column, ColumnFormat};
314
315// Re-exports - Async client
316pub use async_client::{AsyncClient, AsyncCopyInWriter, AsyncCopyInWriterOwned};
317pub use async_connection::AsyncRawConnection;
318pub use async_prepared_stream::AsyncPreparedQueryStream;
319pub use async_stream::AsyncStream;
320pub use async_stream_query::AsyncQueryStream;
321pub use prepared_stream::PreparedQueryStream;
322pub use sync_stream::SyncStream;
323
324// gRPC types (always available)
325pub use grpc::{GrpcClient, GrpcConfig, GrpcError, GrpcQueryResult, GrpcResultChunk};
326
327// Re-exports of the sibling submodules, so existing `use crate::client::{protocol, types}`
328// paths (from when these were separate crates) still resolve.
329pub use crate::{protocol, types};