use crate::error::TraverserResult;
use crate::graph::GraphStorage;
use crate::traversal::optimizer::path_analysis::{PathAnalysis, PathRequirement};
use crate::traversal::{
AnonymousTraversal, By, ByModulation, ByModulatorCheck, Order, Traverser, TraverserContext,
};
use crate::value::{ElementProperty, TraverserValue, compare_element_property};
type OrderClause<'g, S> = (Option<By<'g, S>>, Order);
pub(crate) struct OrderClauses<'g, S: GraphStorage + 'g> {
clauses: Vec<OrderClause<'g, S>>,
by_check: ByModulatorCheck,
}
impl<'g, S: GraphStorage + 'g> Default for OrderClauses<'g, S> {
fn default() -> Self {
Self {
clauses: Vec::new(),
by_check: ByModulatorCheck::default(),
}
}
}
impl<'g, S: GraphStorage + 'g> Clone for OrderClauses<'g, S> {
fn clone(&self) -> Self {
Self {
clauses: self.clauses.clone(),
by_check: self.by_check.clone(),
}
}
}
impl<'g, S: GraphStorage + 'g> OrderClauses<'g, S> {
pub(crate) fn fmt_clauses(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (by, order) in &self.clauses {
match by {
Some(by) if *order == Order::Asc => write!(f, ".by({by})")?,
Some(by) => write!(f, ".by({by}, {order})")?,
None => write!(f, ".by({order})")?,
}
}
Ok(())
}
pub(crate) fn push_by(&mut self, by: By<'g, S>) -> ByModulation {
self.by_check.observe_sort_key(&by);
match by {
By::Order(order) => match self.clauses.last_mut() {
Some((_, existing_order)) => *existing_order = order,
None => self.clauses.push((None, order)),
},
other => self.clauses.push((Some(other), Order::Asc)),
}
ByModulation::Accepted
}
#[inline]
pub(crate) fn check(&self, step: &str) -> TraverserResult<()> {
self.by_check.check(step)
}
pub(crate) fn keys(
&self,
context: &mut TraverserContext<'_, S>,
traverser: &Traverser<S>,
) -> TraverserResult<Option<Vec<ElementProperty>>> {
let mut keys = Vec::with_capacity(self.clauses.len().max(1));
if self.clauses.is_empty() {
keys.push(traverser.value.into_node_property(context.storage)?);
return Ok(Some(keys));
}
for (by, _) in &self.clauses {
let key = match by {
Some(by) => {
match TraverserValue::fetch_traverser_value_by(
context,
traverser,
&traverser.value,
by,
)? {
Some(value) => value.into_node_property(context.storage)?,
None => return Ok(None),
}
}
None => traverser.value.into_node_property(context.storage)?,
};
keys.push(key);
}
Ok(Some(keys))
}
pub(crate) fn sort<T>(
&self,
keyed: &mut [(Vec<ElementProperty>, T)],
context: &mut TraverserContext<'_, S>,
) {
let natural = [Order::Asc];
let mut orders: Vec<&Order> = if self.clauses.is_empty() {
natural.iter().collect()
} else {
self.clauses.iter().map(|(_, order)| order).collect()
};
let start = match orders.iter().rposition(|order| **order == Order::Shuffle) {
Some(last_shuffle) => {
use rand::seq::SliceRandom;
keyed.shuffle(context.rng());
last_shuffle + 1
}
None => 0,
};
if start >= orders.len() {
return;
}
orders.drain(..start);
keyed.sort_by(|(a_keys, _), (b_keys, _)| {
for ((a, b), order) in a_keys[start..]
.iter()
.zip(b_keys[start..].iter())
.zip(orders.iter())
{
let cmp = compare_element_property(a, b);
let cmp = match order {
Order::Asc => cmp,
Order::Desc => cmp.reverse(),
Order::Shuffle => std::cmp::Ordering::Equal,
};
if cmp != std::cmp::Ordering::Equal {
return cmp;
}
}
std::cmp::Ordering::Equal
});
}
pub(crate) fn traversals_mut(&mut self) -> Vec<&mut AnonymousTraversal<'g, S>> {
self.clauses
.iter_mut()
.filter_map(|(by, _)| by.as_mut().and_then(By::traversal_mut))
.collect()
}
pub(crate) fn analyze_paths(&mut self, analysis: &PathAnalysis) -> PathRequirement {
let mut requirement = PathRequirement::None;
for (by, _) in &mut self.clauses {
if let Some(by) = by {
requirement = requirement.union(by.analyze_paths(analysis));
}
}
requirement
}
}