use std::collections::HashMap;
use std::time::Duration;
use crate::errors::{YdbError, YdbResult};
use crate::grpc_wrapper::raw_query_service::stream::ExecuteQueryStream;
use crate::result::ResultSet;
use crate::types::Value;
use super::exec::{
apply_stream_tx_id, resolve_commit_tx, transaction_finish_committed_via_query, CallOptions,
};
use super::internal::ExecCoreRef;
#[must_use = "QueryStream must be fully consumed; call close() when using with_commit(true)"]
pub struct QueryStream<'a> {
pub(crate) core: ExecCoreRef<'a>,
pub(crate) stream: ExecuteQueryStream,
pub(crate) commit_tx: bool,
}
impl Drop for QueryStream<'_> {
fn drop(&mut self) {
if let Some(tx_id) = self.stream.take_captured_tx_id() {
if let ExecCoreRef::Transaction(ctx) = &mut self.core {
apply_stream_tx_id(ctx, Some(tx_id));
}
}
self.stream.cancel();
if let ExecCoreRef::Transaction(ctx) = &mut self.core {
if let Some(lease) = &mut ctx.pooled_lease {
lease.end_use();
}
}
}
}
impl QueryStream<'_> {
pub async fn next_result_set(&mut self) -> YdbResult<Option<ResultSet>> {
let (raw, tx_id) = match self.stream.next_result_set().await? {
Some(v) => v,
None => return Ok(None),
};
if let ExecCoreRef::Transaction(ctx) = &mut self.core {
apply_stream_tx_id(ctx, tx_id);
}
Ok(Some(ResultSet::try_from(raw)?))
}
pub fn stats(&self) -> Option<QueryStats> {
self.stream
.stats()
.map(|total_duration| QueryStats { total_duration })
}
pub async fn close(mut self) -> YdbResult<()> {
let meta = self.stream.close().await.map_err(YdbError::from)?;
if let ExecCoreRef::Transaction(ctx) = &mut self.core {
apply_stream_tx_id(ctx, meta.tx_id);
if self.commit_tx {
transaction_finish_committed_via_query(ctx).await;
}
}
Ok(())
}
}
pub(crate) async fn materialize_query(
core: &mut ExecCoreRef<'_>,
text: String,
params: HashMap<String, Value>,
opts: CallOptions,
) -> YdbResult<Vec<ResultSet>> {
let commit_tx = resolve_commit_tx(core, &opts);
let result: YdbResult<Vec<ResultSet>> = async {
let mut stream = core.begin_stream(text, params, opts, true).await?;
let raw_sets = stream
.materialize_all_result_sets()
.await
.map_err(YdbError::from)?;
let mut sets = Vec::with_capacity(raw_sets.len());
for raw in raw_sets {
sets.push(ResultSet::try_from(raw)?);
}
let meta = stream.close().await.map_err(YdbError::from)?;
if let ExecCoreRef::Transaction(ctx) = core {
apply_stream_tx_id(ctx, meta.tx_id);
if commit_tx {
transaction_finish_committed_via_query(ctx).await;
}
}
Ok(sets)
}
.await;
if let ExecCoreRef::Transaction(ctx) = core {
if let Some(lease) = &mut ctx.pooled_lease {
lease.end_use();
}
}
result
}
#[derive(Debug, Default)]
pub struct QueryStats {
pub total_duration: Duration,
}