use super::{QueryError, QueryValue};
use crate::lifecycle::{QueryControl, QueryError as ControlError};
use crate::property_graph::{GraphGeneration, NodeId, RelId, StoreInstanceId};
pub const MAX_VALUE_WORK: u64 = 8_000_000;
pub const MAX_QUERY_BYTES: usize = 24 * 1024 * 1024;
#[derive(Debug)]
pub struct QueryView {
store: StoreInstanceId,
generation: GraphGeneration,
}
impl QueryView {
pub const fn new(store: StoreInstanceId, generation: GraphGeneration) -> Self {
Self { store, generation }
}
pub const fn node(&self, id: NodeId) -> QueryValue<'_> {
QueryValue::NodeRef(QueryNodeRef { id, view: self })
}
pub const fn relationship(&self, id: RelId) -> QueryValue<'_> {
QueryValue::RelRef(QueryRelRef { id, view: self })
}
pub const fn store(&self) -> StoreInstanceId {
self.store
}
pub const fn generation(&self) -> GraphGeneration {
self.generation
}
}
pub struct ValueContext<'a> {
pub(super) view: &'a QueryView,
control: &'a QueryControl,
limit: u64,
work: u64,
produced_bytes: u64,
retained: Option<&'a dyn super::runtime::RetainedView>,
}
impl<'a> ValueContext<'a> {
pub const fn control(&self) -> &'a QueryControl {
self.control
}
pub const fn retained_view(&self) -> Option<&'a dyn super::runtime::RetainedView> {
self.retained
}
pub fn new(
view: &'a QueryView,
control: &'a QueryControl,
limit: u64,
) -> Result<Self, QueryError> {
if limit > MAX_VALUE_WORK {
return Err(QueryError::WorkLimit);
}
let result = Self {
view,
control,
limit,
work: 0,
produced_bytes: 0,
retained: None,
};
result.checkpoint()?;
Ok(result)
}
pub(super) fn retained(
view: &'a dyn super::runtime::RetainedView,
control: &'a QueryControl,
limit: u64,
) -> Result<Self, QueryError> {
view.check_active()?;
let mut result = Self::new(view.query_view(), control, limit)?;
result.retained = Some(view);
result.checkpoint()?;
Ok(result)
}
pub const fn work(&self) -> u64 {
self.work
}
pub const fn produced_bytes(&self) -> u64 {
self.produced_bytes
}
pub(super) fn output(&mut self, bytes: u64) -> Result<(), QueryError> {
self.produced_bytes = self
.produced_bytes
.checked_add(bytes)
.ok_or(QueryError::WorkLimit)?;
Ok(())
}
pub(super) fn step(&mut self) -> Result<(), QueryError> {
self.checkpoint()?;
if self.work >= self.limit {
return Err(QueryError::WorkLimit);
}
self.work += 1;
Ok(())
}
pub(super) fn checkpoint(&self) -> Result<(), QueryError> {
if let Some(retained) = self.retained {
retained.check_active()?;
if !std::ptr::eq(retained.query_view(), self.view) {
return Err(QueryError::ForeignView);
}
}
self.control.checkpoint().map_err(|error| match error {
ControlError::Timeout { .. } => QueryError::Timeout,
ControlError::Cancelled { .. } => QueryError::Cancelled,
_ => QueryError::Control,
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct QueryNodeRef<'a> {
pub(super) id: NodeId,
pub(super) view: &'a QueryView,
}
impl QueryNodeRef<'_> {
pub const fn id(self) -> NodeId {
self.id
}
}
#[derive(Clone, Copy, Debug)]
pub struct QueryRelRef<'a> {
pub(super) id: RelId,
pub(super) view: &'a QueryView,
}
impl QueryRelRef<'_> {
pub const fn id(self) -> RelId {
self.id
}
}