#![allow(unused_variables)]
use interstellar::storage::Graph;
use interstellar::traversal::SnapshotLike;
use interstellar::value::{Value, VertexId};
use std::collections::HashMap;
fn create_mixed_type_graph() -> Graph {
let graph = Graph::new();
let mut props = HashMap::new();
props.insert("value".to_string(), Value::Int(10));
graph.add_vertex("item", props);
let mut props = HashMap::new();
props.insert("value".to_string(), Value::Float(5.5));
graph.add_vertex("item", props);
let mut props = HashMap::new();
props.insert("value".to_string(), Value::String("abc".to_string()));
graph.add_vertex("item", props);
let mut props = HashMap::new();
props.insert("value".to_string(), Value::Bool(true));
graph.add_vertex("item", props);
graph
}
fn create_bool_graph() -> Graph {
let graph = Graph::new();
let mut props = HashMap::new();
props.insert("active".to_string(), Value::Bool(false));
graph.add_vertex("flag", props);
let mut props = HashMap::new();
props.insert("active".to_string(), Value::Bool(true));
graph.add_vertex("flag", props);
let mut props = HashMap::new();
props.insert("active".to_string(), Value::Bool(false));
graph.add_vertex("flag", props);
graph
}
fn create_edge_graph() -> Graph {
let graph = Graph::new();
graph.add_vertex("person", HashMap::new());
graph.add_vertex("person", HashMap::new());
graph.add_vertex("person", HashMap::new());
let mut props = HashMap::new();
props.insert("weight".to_string(), Value::Float(0.5));
graph
.add_edge(VertexId(0), VertexId(1), "knows", props)
.unwrap();
let mut props = HashMap::new();
props.insert("weight".to_string(), Value::Float(0.8));
graph
.add_edge(VertexId(1), VertexId(2), "knows", props)
.unwrap();
let mut props = HashMap::new();
props.insert("weight".to_string(), Value::Float(0.2));
graph
.add_edge(VertexId(0), VertexId(2), "knows", props)
.unwrap();
graph
}
fn create_missing_prop_graph() -> Graph {
let graph = Graph::new();
let mut props = HashMap::new();
props.insert("name".to_string(), Value::String("Alice".to_string()));
props.insert("age".to_string(), Value::Int(30));
graph.add_vertex("person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::String("Bob".to_string()));
graph.add_vertex("person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::String("Charlie".to_string()));
props.insert("age".to_string(), Value::Int(25));
graph.add_vertex("person", props);
graph
}
mod mixed_type_sorting {
use super::*;
#[test]
fn order_by_mixed_type_property_asc() {
let graph = create_mixed_type_graph();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.v()
.has_label("item")
.order()
.by_key_asc("value")
.build()
.to_list();
assert_eq!(results.len(), 4);
}
#[test]
fn order_natural_with_mixed_value_types() {
let graph = Graph::new();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.inject([
Value::Bool(true),
Value::String("hello".to_string()),
Value::Int(42),
Value::Float(3.14),
])
.order()
.by_asc()
.build()
.to_list();
assert_eq!(results.len(), 4);
assert!(matches!(results[0], Value::Int(_)));
}
}
mod bool_sorting {
use super::*;
#[test]
fn order_by_bool_property_ascending() {
let graph = create_bool_graph();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.v()
.has_label("flag")
.order()
.by_key_asc("active")
.build()
.to_list();
assert_eq!(results.len(), 3);
if let Value::Vertex(id) = &results[0] {
let vertex = snapshot.storage().get_vertex(*id).unwrap();
assert_eq!(vertex.properties.get("active"), Some(&Value::Bool(false)));
}
}
#[test]
fn order_by_bool_property_descending() {
let graph = create_bool_graph();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.v()
.has_label("flag")
.order()
.by_key_desc("active")
.build()
.to_list();
assert_eq!(results.len(), 3);
if let Value::Vertex(id) = &results[0] {
let vertex = snapshot.storage().get_vertex(*id).unwrap();
assert_eq!(vertex.properties.get("active"), Some(&Value::Bool(true)));
}
}
#[test]
fn order_natural_bools_ascending() {
let graph = Graph::new();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.inject([Value::Bool(true), Value::Bool(false), Value::Bool(true)])
.order()
.by_asc()
.build()
.to_list();
assert_eq!(results.len(), 3);
assert_eq!(results[0], Value::Bool(false));
assert_eq!(results[1], Value::Bool(true));
assert_eq!(results[2], Value::Bool(true));
}
}
mod edge_sorting {
use super::*;
#[test]
fn order_edges_by_property_ascending() {
let graph = create_edge_graph();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g.e().order().by_key_asc("weight").build().to_list();
assert_eq!(results.len(), 3);
let weights: Vec<f64> = results
.iter()
.filter_map(|v| {
if let Value::Edge(id) = v {
snapshot
.storage()
.get_edge(*id)
.and_then(|e| e.properties.get("weight").cloned())
.and_then(|w| {
if let Value::Float(f) = w {
Some(f)
} else {
None
}
})
} else {
None
}
})
.collect();
assert!((weights[0] - 0.2).abs() < 0.001);
assert!((weights[1] - 0.5).abs() < 0.001);
assert!((weights[2] - 0.8).abs() < 0.001);
}
#[test]
fn order_edges_by_property_descending() {
let graph = create_edge_graph();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g.e().order().by_key_desc("weight").build().to_list();
assert_eq!(results.len(), 3);
let weights: Vec<f64> = results
.iter()
.filter_map(|v| {
if let Value::Edge(id) = v {
snapshot
.storage()
.get_edge(*id)
.and_then(|e| e.properties.get("weight").cloned())
.and_then(|w| {
if let Value::Float(f) = w {
Some(f)
} else {
None
}
})
} else {
None
}
})
.collect();
assert!((weights[0] - 0.8).abs() < 0.001);
assert!((weights[1] - 0.5).abs() < 0.001);
assert!((weights[2] - 0.2).abs() < 0.001);
}
}
mod missing_property_sorting {
use super::*;
#[test]
fn order_with_some_missing_properties() {
let graph = create_missing_prop_graph();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.v()
.has_label("person")
.order()
.by_key_asc("age")
.build()
.to_list();
assert_eq!(results.len(), 3);
}
#[test]
fn order_by_nonexistent_property() {
let graph = create_missing_prop_graph();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.v()
.has_label("person")
.order()
.by_key_asc("nonexistent")
.build()
.to_list();
assert_eq!(results.len(), 3);
}
}
mod subtraversal_sorting {
use super::*;
use interstellar::traversal::__;
#[test]
fn order_by_subtraversal_property() {
let graph = Graph::new();
let mut props = HashMap::new();
props.insert("name".to_string(), Value::String("Alice".to_string()));
props.insert("score".to_string(), Value::Int(100));
graph.add_vertex("person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::String("Bob".to_string()));
props.insert("score".to_string(), Value::Int(50));
graph.add_vertex("person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::String("Charlie".to_string()));
props.insert("score".to_string(), Value::Int(75));
graph.add_vertex("person", props);
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let sub = __.values("score");
let results = g
.v()
.has_label("person")
.order()
.by_traversal(sub, true) .build()
.to_list();
assert_eq!(results.len(), 3);
let names: Vec<String> = results
.iter()
.filter_map(|v| {
if let Value::Vertex(id) = v {
snapshot
.storage()
.get_vertex(*id)
.and_then(|v| v.properties.get("name").cloned())
.and_then(|n| {
if let Value::String(s) = n {
Some(s)
} else {
None
}
})
} else {
None
}
})
.collect();
assert_eq!(names[0], "Alice");
assert_eq!(names[1], "Charlie");
assert_eq!(names[2], "Bob");
}
}
mod order_builder_edge_cases {
use super::*;
#[test]
fn order_with_no_by_clause_defaults_to_asc() {
let graph = Graph::new();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.inject([Value::Int(3), Value::Int(1), Value::Int(2)])
.order()
.build()
.to_list();
assert_eq!(results.len(), 3);
assert_eq!(results[0], Value::Int(1));
assert_eq!(results[1], Value::Int(2));
assert_eq!(results[2], Value::Int(3));
}
#[test]
fn order_with_multiple_by_clauses() {
let graph = Graph::new();
let mut props = HashMap::new();
props.insert("first".to_string(), Value::String("Alice".to_string()));
props.insert("last".to_string(), Value::String("Smith".to_string()));
graph.add_vertex("person", props);
let mut props = HashMap::new();
props.insert("first".to_string(), Value::String("Bob".to_string()));
props.insert("last".to_string(), Value::String("Jones".to_string()));
graph.add_vertex("person", props);
let mut props = HashMap::new();
props.insert("first".to_string(), Value::String("Charlie".to_string()));
props.insert("last".to_string(), Value::String("Smith".to_string()));
graph.add_vertex("person", props);
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.v()
.has_label("person")
.order()
.by_key_asc("last")
.by_key_asc("first")
.build()
.to_list();
assert_eq!(results.len(), 3);
let names: Vec<(String, String)> = results
.iter()
.filter_map(|v| {
if let Value::Vertex(id) = v {
let vertex = snapshot.storage().get_vertex(*id)?;
let first = match vertex.properties.get("first")? {
Value::String(s) => s.clone(),
_ => return None,
};
let last = match vertex.properties.get("last")? {
Value::String(s) => s.clone(),
_ => return None,
};
Some((last, first))
} else {
None
}
})
.collect();
assert_eq!(names[0], ("Jones".to_string(), "Bob".to_string()));
assert_eq!(names[1], ("Smith".to_string(), "Alice".to_string()));
assert_eq!(names[2], ("Smith".to_string(), "Charlie".to_string()));
}
}
mod non_element_sorting {
use super::*;
#[test]
fn order_null_values() {
let graph = Graph::new();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.inject([Value::Null, Value::Int(1), Value::Null, Value::Int(2)])
.order()
.by_asc()
.build()
.to_list();
assert_eq!(results.len(), 4);
assert!(matches!(results[0], Value::Int(_)));
assert!(matches!(results[1], Value::Int(_)));
}
#[test]
fn order_list_values() {
let graph = Graph::new();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let results = g
.inject([
Value::List(vec![Value::Int(1), Value::Int(2)]),
Value::Int(5),
Value::List(vec![Value::Int(3)]),
])
.order()
.by_asc()
.build()
.to_list();
assert_eq!(results.len(), 3);
assert!(matches!(results[0], Value::Int(_)));
}
#[test]
fn order_map_values() {
let graph = Graph::new();
let snapshot = graph.snapshot();
let g = snapshot.gremlin();
let mut map1 = ::indexmap::IndexMap::<String, Value>::new();
map1.insert("key".to_string(), Value::Int(1));
let results = g
.inject([Value::Map(map1), Value::Int(5)])
.order()
.by_asc()
.build()
.to_list();
assert_eq!(results.len(), 2);
assert!(matches!(results[0], Value::Int(_)));
}
}