use super::super::ast::Clause;
use crate::graph::core::pattern_matching::PatternElement;
use std::collections::HashMap;
use std::sync::Arc;
pub(super) struct VectorScoreFilterSpec {
pub(super) variable: String,
pub(super) prop_name: String,
pub(super) query_vec: Vec<f32>,
pub(super) scorer: crate::graph::algorithms::vector::Scorer,
pub(super) threshold: f64,
pub(super) greater_than: bool,
pub(super) inclusive: bool,
}
pub(super) struct DistanceFilterSpec {
pub(super) variable: String,
pub(super) lat_prop: String,
pub(super) lon_prop: String,
pub(super) center_lat: f64,
pub(super) center_lon: f64,
pub(super) threshold: f64,
pub(super) less_than: bool,
pub(super) inclusive: bool,
}
pub(super) struct ContainsFilterSpec {
pub(super) container_variable: String,
pub(super) contained: ContainsTarget,
pub(super) negated: bool,
}
pub(super) enum ContainsTarget {
ConstantPoint(f64, f64),
Variable { name: String },
}
pub(super) enum ResolvedSpatial {
Point(f64, f64),
Geometry(Arc<geo::Geometry<f64>>, Option<geo::Rect<f64>>),
}
pub(super) type GeomWithBBox = (Arc<geo::Geometry<f64>>, Option<geo::Rect<f64>>);
pub(super) struct NodeSpatialData {
pub(super) geometry: Option<GeomWithBBox>,
pub(super) location: Option<(f64, f64)>,
pub(super) shapes: HashMap<String, GeomWithBBox>,
pub(super) points: HashMap<String, (f64, f64)>,
}
pub(super) struct ScoredRowRef {
pub(super) score: f64,
pub(super) index: usize,
}
impl PartialEq for ScoredRowRef {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl Eq for ScoredRowRef {}
impl PartialOrd for ScoredRowRef {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ScoredRowRef {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other
.score
.partial_cmp(&self.score)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| self.index.cmp(&other.index))
}
}
pub(super) struct VectorScoreCache {
pub(super) prop_name: String,
pub(super) query_vec: Vec<f32>,
pub(super) scorer: crate::graph::algorithms::vector::Scorer,
}
pub fn clause_display_name(clause: &Clause) -> String {
match clause {
Clause::Match(m) => {
let types: Vec<&str> = m
.patterns
.iter()
.flat_map(|p| p.elements.iter())
.filter_map(|e| {
if let PatternElement::Node(n) = e {
n.node_type.as_deref()
} else {
None
}
})
.collect();
if types.is_empty() {
"Match".into()
} else {
format!("Match :{}", types.join(", :"))
}
}
Clause::OptionalMatch(m) => {
let types: Vec<&str> = m
.patterns
.iter()
.flat_map(|p| p.elements.iter())
.filter_map(|e| {
if let PatternElement::Node(n) = e {
n.node_type.as_deref()
} else {
None
}
})
.collect();
if types.is_empty() {
"OptionalMatch".into()
} else {
format!("OptionalMatch :{}", types.join(", :"))
}
}
Clause::Where(_) => "Where".into(),
Clause::Return(_) => "Return".into(),
Clause::With(_) => "With".into(),
Clause::OrderBy(_) => "OrderBy".into(),
Clause::Skip(_) => "Skip".into(),
Clause::Limit(_) => "Limit".into(),
Clause::Unwind(_) => "Unwind".into(),
Clause::Union(_) => "Union".into(),
Clause::Create(_) => "Create".into(),
Clause::Set(_) => "Set".into(),
Clause::Delete(_) => "Delete".into(),
Clause::Remove(_) => "Remove".into(),
Clause::Merge(_) => "Merge".into(),
Clause::Foreach { .. } => "Foreach".into(),
Clause::Call(_) => "Call".into(),
Clause::CallSubquery { .. } => "CallSubquery".into(),
Clause::FusedOptionalMatchAggregate { .. } => "FusedOptionalMatchAggregate".into(),
Clause::FusedVectorScoreTopK { .. } => "FusedVectorScoreTopK".into(),
Clause::FusedMatchReturnAggregate { .. } => "FusedMatchReturnAggregate".into(),
Clause::FusedMatchWithAggregate { .. } => "FusedMatchWithAggregate".into(),
Clause::FusedOrderByTopK { .. } => "FusedOrderByTopK".into(),
Clause::FusedCountAll { .. } => "FusedCountAll".into(),
Clause::FusedCountAllEdges { .. } => "FusedCountAllEdges".into(),
Clause::FusedCountByType { .. } => "FusedCountByType".into(),
Clause::FusedCountEdgesByType { .. } => "FusedCountEdgesByType".into(),
Clause::FusedCountTypedNode { node_type, .. } => {
format!("FusedCountTypedNode :{node_type}")
}
Clause::FusedCountTypedEdge { edge_type, .. } => {
format!("FusedCountTypedEdge :{edge_type}")
}
Clause::FusedCountAnchoredEdges {
anchor_idx,
anchor_direction,
edge_type,
..
} => {
let arrow = match anchor_direction {
petgraph::Direction::Outgoing => "→",
petgraph::Direction::Incoming => "←",
};
let t = edge_type.as_deref().unwrap_or("*");
format!("FusedCountAnchoredEdges (anchor#{anchor_idx} {arrow} :{t})")
}
Clause::FusedNodeScanAggregate { .. } => "FusedNodeScanAggregate".into(),
Clause::FusedNodeScanTopK { limit, .. } => format!("FusedNodeScanTopK (k={limit})"),
Clause::SpatialJoin {
container_type,
probe_type,
..
} => format!("SpatialJoin :{container_type} ⊇ :{probe_type}"),
}
}