use std::sync::Arc;
use super::actor::{TransitionCtx, TransitionError};
use super::context::RequestCtx;
use super::directory::Entry;
use super::node::Node;
use super::resource::{ResourceCtx, ResourceError, ResourceSnapshot, TransitionOutcome};
use super::transition::TransitionInput;
use crate::query::{self as query_eval};
#[derive(Clone)]
pub struct NodeHandle {
node: Arc<Node>,
}
impl NodeHandle {
pub fn new(node: Arc<Node>) -> Self {
Self { node }
}
pub fn node(&self) -> &Arc<Node> {
&self.node
}
pub(crate) async fn resource(&self, id: &str) -> Option<ResourceProxy> {
let entry = {
let dir = self.node.directory_read().await;
dir.get_by_id(id)
}?;
Some(ResourceProxy::new(entry, self.node.clone()))
}
pub async fn query(&self, ql: &str) -> Result<Vec<ResourceProxy>, NodeHandleError> {
let parsed =
crate::caql::parse(ql).map_err(|e| NodeHandleError::QueryParse(e.to_string()))?;
let entries = {
let dir = self.node.directory_read().await;
dir.entries().to_vec()
};
let mut matches = Vec::new();
for entry in entries {
let ctx = ResourceCtx::new_test();
let snap = match entry.snapshot(ctx, self.node.id()).await {
Ok(snap) => snap,
Err(_) => continue,
};
let v = snap.to_query_value();
if query_eval::matches(&parsed, &v).unwrap_or(false) {
matches.push(ResourceProxy::new(entry.clone(), self.node.clone()));
}
}
Ok(matches)
}
}
#[derive(Debug)]
pub enum NodeHandleError {
QueryParse(String),
Internal(String),
}
#[derive(Clone)]
pub struct ResourceProxy {
entry: Arc<Entry>,
node: Arc<Node>,
}
impl ResourceProxy {
pub(crate) fn new(entry: Arc<Entry>, node: Arc<Node>) -> Self {
Self { entry, node }
}
pub fn id(&self) -> &str {
&self.entry.id
}
pub fn kind(&self) -> &str {
&self.entry.kind
}
pub async fn snapshot(&self) -> Result<ResourceSnapshot, ResourceError> {
let ctx = ResourceCtx::new_test();
self.entry.snapshot(ctx, self.node.id()).await
}
pub async fn transition(
&self,
name: &str,
input: TransitionInput,
) -> Result<TransitionOutcome, TransitionError> {
let ctx = TransitionCtx::with_node(RequestCtx::default(), self.node.clone());
self.entry
.handle
.transition_with_ctx(ctx, name, input)
.await
}
pub async fn transition_with_ctx(
&self,
ctx: TransitionCtx,
name: &str,
input: TransitionInput,
) -> Result<TransitionOutcome, TransitionError> {
self.entry
.handle
.transition_with_ctx(ctx, name, input)
.await
}
}
pub type ActorProxy = ResourceProxy;