pub struct GrpcClient { /* private fields */ }Expand description
Async gRPC client for Hyper database.
GrpcClient provides query-only access to Hyper databases via gRPC.
Results are returned in Apache Arrow IPC format.
gRPC transport is always available - no feature flags required.
§Limitations
The gRPC interface is read-only:
- Only SELECT queries are supported
- No INSERT, UPDATE, DELETE, or DDL operations
- No COPY protocol for bulk data insertion
For write operations, use the standard TCP Client.
§Example
use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = GrpcConfig::new("http://localhost:7484")
.database("my_database.hyper");
let mut client = GrpcClient::connect(config).await?;
// Execute a query
let result = client.execute_query("SELECT * FROM users").await?;
let arrow_data = result.arrow_data();
// Process arrow_data with arrow crate...
client.close().await?;
Ok(())
}Implementations§
Source§impl GrpcClient
impl GrpcClient
Sourcepub async fn connect(config: GrpcConfig) -> Result<Self>
pub async fn connect(config: GrpcConfig) -> Result<Self>
Connects to a Hyper server via gRPC.
§Example
use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig};
let config = GrpcConfig::new("http://localhost:7484")
.database("test.hyper");
let client = GrpcClient::connect(config).await?;§Errors
- Returns
ErrorKind::Configifconfig.endpointis not a well-formed URI, or if TLS configuration fails. - Returns
ErrorKind::Connectionif the gRPC transport cannot establish a channel to the endpoint.
Sourcepub fn channel(&self) -> &Channel
pub fn channel(&self) -> &Channel
Returns the underlying gRPC channel.
This can be used for advanced use cases like channel cloning or direct stub access.
Sourcepub fn config(&self) -> &GrpcConfig
pub fn config(&self) -> &GrpcConfig
Returns the client configuration.
Sourcepub async fn execute_query(&mut self, sql: &str) -> Result<GrpcQueryResult>
pub async fn execute_query(&mut self, sql: &str) -> Result<GrpcQueryResult>
Executes a SQL query and returns the result.
Results are returned in Apache Arrow IPC format. Use the arrow_data()
method on the result to get the raw Arrow bytes.
§Example
use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig};
let result = client.execute_query("SELECT * FROM users LIMIT 10").await?;
let arrow_bytes = result.arrow_data();§Errors
Returns an error if:
- The query syntax is invalid
- The referenced tables/columns don’t exist
- A non-SELECT query is executed (gRPC is read-only)
- The connection is lost
Sourcepub async fn execute_query_to_arrow(&mut self, sql: &str) -> Result<Bytes>
pub async fn execute_query_to_arrow(&mut self, sql: &str) -> Result<Bytes>
Executes a query and returns raw Arrow IPC bytes.
This is a convenience method that extracts the Arrow data from the result.
§Example
use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig};
let arrow_bytes = client.execute_query_to_arrow("SELECT * FROM users").await?;
// Parse with arrow crate...§Errors
Same failure modes as Self::execute_query (invalid SQL,
missing tables/columns, non-SELECT mutation attempts, or
connection loss).
Sourcepub async fn execute_query_with_params(
&mut self,
sql: &str,
params: QueryParameters,
style: ParameterStyle,
) -> Result<GrpcQueryResult>
pub async fn execute_query_with_params( &mut self, sql: &str, params: QueryParameters, style: ParameterStyle, ) -> Result<GrpcQueryResult>
Executes a parameterized SQL query.
This provides SQL injection prevention and type safety by separating the query from its parameters.
§Arguments
sql- SQL query with parameter placeholdersparams- Query parameters (JSON or Arrow encoded)style- Parameter style used in the query
§Example
use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig, QueryParameters, ParameterStyle};
// Dollar-numbered parameters (mixed types use from_json_value)
let params = QueryParameters::from_json_value(&serde_json::json!([42, "Alice"]))?;
let result = client.execute_query_with_params(
"SELECT * FROM users WHERE id = $1 AND name = $2",
params,
ParameterStyle::DollarNumbered,
).await?;
// Named parameters
let params = QueryParameters::json_named()
.add("min_age", &18)?
.build();
let result = client.execute_query_with_params(
"SELECT * FROM users WHERE age >= :min_age",
params,
ParameterStyle::Named,
).await?;§Errors
Same failure modes as Self::execute_query, plus any
parameter-related error reported by the server (unknown
placeholder, type coercion failure, shape mismatch between the
SQL placeholders and the supplied parameter set).
Sourcepub async fn execute_query_with_params_to_arrow(
&mut self,
sql: &str,
params: QueryParameters,
style: ParameterStyle,
) -> Result<Bytes>
pub async fn execute_query_with_params_to_arrow( &mut self, sql: &str, params: QueryParameters, style: ParameterStyle, ) -> Result<Bytes>
Executes a parameterized query and returns raw Arrow IPC bytes.
§Example
use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig, QueryParameters, ParameterStyle};
let params = QueryParameters::json_positional(&[&42i64])?;
let arrow_bytes = client.execute_query_with_params_to_arrow(
"SELECT * FROM users WHERE id = $1",
params,
ParameterStyle::DollarNumbered,
).await?;§Errors
Same failure modes as Self::execute_query_with_params.
Sourcepub async fn execute_query_with_params_and_options(
&mut self,
sql: &str,
params: QueryParameters,
style: ParameterStyle,
output_format: OutputFormat,
transfer_mode: TransferMode,
) -> Result<GrpcQueryResult>
pub async fn execute_query_with_params_and_options( &mut self, sql: &str, params: QueryParameters, style: ParameterStyle, output_format: OutputFormat, transfer_mode: TransferMode, ) -> Result<GrpcQueryResult>
Executes a parameterized query with specific options.
This allows full control over the output format and transfer mode.
§Errors
- Returns
ErrorKind::Protocolif the server returns no result chunks and does not signal completion. - Propagates any error from the underlying
GrpcQueryExecutor— auth failure, transport error, or server-side SQL error surfaced astonic::Status.
Sourcepub async fn execute_query_with_options(
&mut self,
sql: &str,
output_format: OutputFormat,
transfer_mode: TransferMode,
) -> Result<GrpcQueryResult>
pub async fn execute_query_with_options( &mut self, sql: &str, output_format: OutputFormat, transfer_mode: TransferMode, ) -> Result<GrpcQueryResult>
Executes a query with specific options.
This allows control over the output format and transfer mode.
§Errors
- Returns
ErrorKind::Protocolif the server returns no result chunks and does not signal completion. - Propagates any error from the underlying
GrpcQueryExecutor— auth failure, transport error, or server-side SQL error surfaced astonic::Status.
Sourcepub async fn execute_query_stream(
&mut self,
sql: &str,
) -> Result<GrpcChunkStream>
pub async fn execute_query_stream( &mut self, sql: &str, ) -> Result<GrpcChunkStream>
Executes a query and returns a streaming chunk producer.
Unlike execute_query, which drains every
result chunk into a single GrpcQueryResult before returning, this
method yields chunks lazily: each call to
GrpcChunkStream::next_chunk pulls just enough from the HTTP/2
stream to produce one Arrow IPC byte chunk. For very large result
sets (hundreds of MB to GB) this keeps client memory bounded by a
single gRPC message (capped at the tonic
max_decoding_message_size, default 64 MB) rather than growing to
the full result size.
Pair this with
hyperdb_api::ArrowRowset::from_stream to
decode batches incrementally and keep peak memory constant regardless
of total row count.
§Errors
Same failure modes as
Self::execute_query_stream_with_options — invalid SQL,
auth failure, transport error, etc.
Sourcepub async fn execute_query_stream_with_options(
&mut self,
sql: &str,
output_format: OutputFormat,
transfer_mode: TransferMode,
) -> Result<GrpcChunkStream>
pub async fn execute_query_stream_with_options( &mut self, sql: &str, output_format: OutputFormat, transfer_mode: TransferMode, ) -> Result<GrpcChunkStream>
Streaming variant of execute_query_with_options.
§Errors
Propagates any error from the initial
GrpcQueryExecutor::execute call — server-side SQL error,
auth failure, or transport-level gRPC error.
Sourcepub async fn cancel_query(&mut self, query_id: &str) -> Result<()>
pub async fn cancel_query(&mut self, query_id: &str) -> Result<()>
Cancels an in-flight gRPC query by its query_id.
This is the gRPC analogue of the PG wire CancelRequest packet: it
tells the server to stop executing a previously-started query. Unlike
PG wire (where the cancel travels on a fresh connection), gRPC
cancels travel as a regular RPC multiplexed over the existing HTTP/2
channel — that’s why this call shares self.channel with normal
query traffic.
§When do you have a query_id?
The server assigns a query_id for queries started in
TransferMode::Async
(long-running queries that the client polls). Grab it from
GrpcQueryResult::query_id
after execute_query_with_options(..., TransferMode::Async) returns.
SYNC-mode queries typically complete before the client needs a
cancel — for those, just drop the in-flight future.
§Query-id lifecycle
Query ids are stable for the lifetime of a query and are
server-assigned — a given id is never silently re-used for a
different query (Hyper generates them as UUID-like opaque tokens,
not sequential counters). The only race a caller needs to
consider is between obtaining the id and calling cancel_query:
- If the query is still running, the cancel lands and the server aborts it.
- If the query has already completed normally between “obtain id”
and “cancel”, the server sees a cancel for an unknown /
completed query and handles it gracefully (the exact shape
depends on server build — see the tests in
hyperdb-api/tests/grpc_cancel_tests.rsfor details). Either way the channel stays healthy.
There is no scenario where a stale id causes a cancel to target the wrong query, because ids are not reassigned.
§Errors
Propagates transport-level errors. A successful cancel returns
Ok(()) even if the query had already completed on the server;
cancellation is best-effort by design.
§Relation to the Cancellable trait
This is the fallible user-facing cancel API: it returns a
Result<()> so explicit callers can observe transport-level
failures and react accordingly.
It is not an implementation of the
Cancellable trait — and cannot
be, because Cancellable::cancel(&self) takes no arguments while
gRPC cancels need a per-query query_id. A GrpcClient can have
many concurrent queries in flight; there is no single “the”
query on it the way there is on a PG wire connection. A future
gRPC streaming result type (when one is introduced) would carry
its query_id in a dedicated handle like
GrpcCancelHandle { client, query_id }, and that handle
would impl Cancellable by wrapping this method and swallowing
errors — same shape as
impl Cancellable for Client.
See the Cancellable trait docs
for the full wrapper pattern.
§Example
use hyperdb_api_core::client::grpc::{GrpcClient, GrpcConfig, OutputFormat, TransferMode};
let result = client
.execute_query_with_options(
"SELECT * FROM very_large_table",
OutputFormat::ArrowIpc,
TransferMode::Async,
)
.await?;
if let Some(query_id) = result.query_id() {
// Some time later, decide to abort:
client.cancel_query(query_id).await?;
}Sourcepub async fn close(self) -> Result<()>
pub async fn close(self) -> Result<()>
Closes the gRPC connection.
This is a no-op as tonic channels are reference-counted and will be closed when the last reference is dropped.
§Errors
Currently infallible — always returns Ok(()). The Result
return type is preserved for API symmetry with
GrpcClientSync::close and for forward compatibility if
future tonic channels expose a fallible shutdown.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for GrpcClient
impl !RefUnwindSafe for GrpcClient
impl Send for GrpcClient
impl Sync for GrpcClient
impl Unpin for GrpcClient
impl UnsafeUnpin for GrpcClient
impl !UnwindSafe for GrpcClient
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request