use bincode::{Decode, Encode};
use crate::{
errors::LatticeError,
properties::PropertyHandle,
utils::{
generational_vector::{GenVec, Handle},
values::{Primitive, Value},
},
};
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, Encode, Decode)]
pub enum EdgeDirection {
Outgoing,
Incoming,
}
#[derive(Clone, Copy)]
pub struct NodeHandle(pub(crate) Handle);
pub enum QueryNode {
Union(Vec<NodeHandle>),
Intersect(Vec<NodeHandle>),
Difference(NodeHandle, NodeHandle),
Attribute {
attr: PropertyHandle,
value: Primitive,
},
Edge {
dir: EdgeDirection,
label: PropertyHandle,
target: NodeHandle,
},
SavedQuery(u64),
}
impl QueryNode {
pub fn attribute<V: Value>(attr: PropertyHandle, value: V) -> Self {
Self::Attribute {
attr,
value: value.to_primitive(),
}
}
}
pub struct QueryBuilder {
pub(crate) nodes: GenVec<QueryNode>,
pub(crate) root: Option<NodeHandle>,
}
impl QueryBuilder {
pub fn match_attr<V: Value>(
&mut self,
attr: PropertyHandle,
value: V,
) -> Result<NodeHandle, LatticeError> {
let value = value.to_primitive();
value.verify()?;
let handle = self.nodes.add(QueryNode::Attribute { attr, value });
Ok(NodeHandle(handle))
}
pub fn match_outgoing(
&mut self,
label: PropertyHandle,
subject: NodeHandle,
) -> Result<NodeHandle, LatticeError> {
self.nodes
.get(subject.0)
.ok_or(LatticeError::EdgeNotFound)?;
let handle = self.nodes.add(QueryNode::Edge {
dir: EdgeDirection::Outgoing,
label,
target: subject,
});
Ok(NodeHandle(handle))
}
pub fn match_incoming(
&mut self,
label: PropertyHandle,
target: NodeHandle,
) -> Result<NodeHandle, LatticeError> {
self.nodes.get(target.0).ok_or(LatticeError::EdgeNotFound)?;
let handle = self.nodes.add(QueryNode::Edge {
dir: EdgeDirection::Incoming,
label,
target,
});
Ok(NodeHandle(handle))
}
pub fn group_and(&mut self, children: Vec<NodeHandle>) -> Result<NodeHandle, LatticeError> {
for c in &children {
self.nodes.get(c.0).ok_or(LatticeError::EdgeNotFound)?;
}
let handle = self.nodes.add(QueryNode::Intersect(children));
Ok(NodeHandle(handle))
}
pub fn group_or(&mut self, children: Vec<NodeHandle>) -> Result<NodeHandle, LatticeError> {
for c in &children {
self.nodes.get(c.0).ok_or(LatticeError::EdgeNotFound)?;
}
let handle = self.nodes.add(QueryNode::Union(children));
Ok(NodeHandle(handle))
}
pub fn difference(
&mut self,
include: NodeHandle,
exclude: NodeHandle,
) -> Result<NodeHandle, LatticeError> {
self.nodes
.get(include.0)
.ok_or(LatticeError::EdgeNotFound)?;
self.nodes
.get(exclude.0)
.ok_or(LatticeError::EdgeNotFound)?;
let handle = self.nodes.add(QueryNode::Difference(include, exclude));
Ok(NodeHandle(handle))
}
}
impl Default for QueryBuilder {
fn default() -> Self {
Self::new()
}
}
impl QueryBuilder {
pub fn new() -> Self {
Self {
nodes: GenVec::new(),
root: None,
}
}
pub fn set_root(&mut self, handle: NodeHandle) {
self.root = Some(handle);
}
pub fn get_root(&self) -> Option<NodeHandle> {
self.root
}
}