use std::sync::Arc;
use futures::StreamExt;
use crate::exec::{
AccessMode, ContextLevel, EvalContext, ExecOperator, ExecutionContext, FlowResult,
OperatorMetrics, PhysicalExpr, ValueBatchStream, monitor_stream,
};
#[derive(Debug, Clone)]
pub struct VersionScope {
pub(crate) inner: Arc<dyn ExecOperator>,
pub(crate) version: Arc<dyn PhysicalExpr>,
pub(crate) metrics: Arc<OperatorMetrics>,
}
impl VersionScope {
pub(crate) fn new(inner: Arc<dyn ExecOperator>, version: Arc<dyn PhysicalExpr>) -> Self {
Self {
inner,
version,
metrics: Arc::new(OperatorMetrics::new()),
}
}
}
impl ExecOperator for VersionScope {
fn name(&self) -> &'static str {
"VersionScope"
}
fn attrs(&self) -> Vec<(String, String)> {
vec![("version".to_string(), self.version.to_sql())]
}
fn required_context(&self) -> ContextLevel {
self.inner.required_context().max(self.version.required_context())
}
fn access_mode(&self) -> AccessMode {
self.inner.access_mode().combine(self.version.access_mode())
}
fn cardinality_hint(&self) -> crate::exec::CardinalityHint {
self.inner.cardinality_hint()
}
fn children(&self) -> Vec<&Arc<dyn ExecOperator>> {
vec![&self.inner]
}
fn metrics(&self) -> Option<&OperatorMetrics> {
Some(&self.metrics)
}
fn is_scalar(&self) -> bool {
self.inner.is_scalar()
}
fn output_ordering(&self) -> crate::exec::OutputOrdering {
self.inner.output_ordering()
}
fn expressions(&self) -> Vec<(&str, &Arc<dyn PhysicalExpr>)> {
vec![("version", &self.version)]
}
fn execute(&self, ctx: &ExecutionContext) -> FlowResult<ValueBatchStream> {
let version_expr = Arc::clone(&self.version);
let inner = Arc::clone(&self.inner);
let ctx = ctx.clone();
let stream = async_stream::try_stream! {
let eval_ctx = EvalContext::from_exec_ctx(&ctx);
let v = version_expr.evaluate(eval_ctx).await?;
let stamp = v
.cast_to::<crate::val::Datetime>()
.map_err(|e| anyhow::anyhow!("{e}"))?
.to_version_stamp(ctx.txn().timestamp_impl().as_ref())?;
let versioned_ctx = ctx.with_version_stamp(Some(stamp));
let inner_stream = inner.execute(&versioned_ctx)?;
futures::pin_mut!(inner_stream);
while let Some(batch) = inner_stream.next().await {
yield batch?;
}
};
Ok(monitor_stream(Box::pin(stream), "VersionScope", &self.metrics))
}
}