use interstellar::prelude::*;
use interstellar::traversal::p;
use std::collections::HashMap;
use std::sync::Arc;
fn main() {
let graph = Arc::new(Graph::new());
let alice = graph.add_vertex(
"person",
HashMap::from([
("name".into(), Value::from("Alice")),
("age".into(), Value::from(35i64)),
]),
);
let bob = graph.add_vertex(
"person",
HashMap::from([
("name".into(), Value::from("Bob")),
("age".into(), Value::from(28i64)),
]),
);
let charlie = graph.add_vertex(
"person",
HashMap::from([
("name".into(), Value::from("Charlie")),
("age".into(), Value::from(42i64)),
]),
);
let proj = graph.add_vertex(
"project",
HashMap::from([("name".into(), Value::from("Interstellar"))]),
);
graph
.add_edge(alice, bob, "knows", HashMap::from([("since".into(), Value::from(2020i64))]))
.unwrap();
graph
.add_edge(bob, charlie, "knows", HashMap::from([("since".into(), Value::from(2022i64))]))
.unwrap();
graph
.add_edge(alice, proj, "created", Default::default())
.unwrap();
let snap = graph.snapshot();
let g = snap.gremlin();
println!("=== Example 1: Simple filter ===");
println!("Query: g.V().hasLabel('person').values('name')\n");
let explanation = g.v().has_label("person").values("name").explain();
println!("{explanation}");
println!("=== Example 2: Navigation with predicate ===");
println!("Query: g.V().hasLabel('person').has('age', gt(30)).out('knows').values('name')\n");
let explanation = g
.v()
.has_label("person")
.has_where("age", p::gt(30i64))
.out_labels(&["knows"])
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 3: Traversal with barrier step ===");
println!("Query: g.V().hasLabel('person').out().order().by(asc).values('name')\n");
let explanation = g
.v()
.has_label("person")
.out()
.order()
.by_value_asc()
.build()
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 4: Dedup + limit ===");
println!("Query: g.V().hasLabel('person').out().dedup().limit(10).values('name')\n");
let explanation = g
.v()
.has_label("person")
.out()
.dedup()
.limit(10)
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 5: Edge traversal ===");
println!("Query: g.E().hasLabel('knows').has('since', gte(2021)).inV().values('name')\n");
let explanation = g
.e()
.has_label("knows")
.has_where("since", p::gte(2021i64))
.in_v()
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 6: E() with outV ===");
println!("Query: g.E().hasLabel('knows').outV().dedup().values('name')\n");
let explanation = g
.e()
.has_label("knows")
.out_v()
.dedup()
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 7: Where filter ===");
println!("Query: g.V().hasLabel('person').where(__.out('created')).values('name')\n");
let explanation = g
.v()
.has_label("person")
.where_(__.out_labels(&["created"]))
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 8: Repeat/until ===");
println!("Query: g.V().has('name','Alice').repeat(__.out('knows')).until(__.has('name','Charlie')).times(5).values('name')\n");
let explanation = g
.v()
.has_value("name", Value::from("Alice"))
.repeat(__.out_labels(&["knows"]))
.until(__.has_value("name", Value::from("Charlie")))
.times(5)
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 9: Repeat/times ===");
println!("Query: g.V().has('name','Alice').repeat(__.out('knows')).times(3).values('name')\n");
let explanation = g
.v()
.has_value("name", Value::from("Alice"))
.repeat(__.out_labels(&["knows"]))
.times(3)
.values("name")
.explain();
println!("{explanation}");
println!("=== Example 10: Union branching ===");
println!("Query: g.V().has('name','Alice').union(__.out('knows').values('name'), __.out('created').values('name'))\n");
let explanation = g
.v()
.has_value("name", Value::from("Alice"))
.union(vec![
__.out_labels(&["knows"]).values("name"),
__.out_labels(&["created"]).values("name"),
])
.explain();
println!("{explanation}");
println!("=== Example 11: Anonymous traversal ===");
println!("Query: __.out().hasLabel('person').values('name')\n");
let explanation = __.out().has_label("person").values("name").explain();
println!("{explanation}");
println!("=== Example 12: Explain vs Execute ===");
println!("Query: g.V().hasLabel('person').has('age', gt(30)).values('name')\n");
let explanation = g
.v()
.has_label("person")
.has_where("age", p::gt(30i64))
.values("name")
.explain();
println!("{explanation}");
let results = g
.v()
.has_label("person")
.has_where("age", p::gt(30i64))
.values("name")
.to_list();
println!("Results: {results:?}");
println!("\n=== Example 13: Explain via Gremlin string ===");
let query = "g.V().hasLabel('person').has('age', P.gt(30)).out('knows').values('name').explain()";
println!("Query: {query}\n");
let ast = interstellar::gremlin::parse(query).expect("parse failed");
let compiled = interstellar::gremlin::compile(&ast, &g).expect("compile failed");
let result = compiled.execute();
match result {
interstellar::gremlin::ExecutionResult::Explain(text) => println!("{text}"),
other => println!("Unexpected result: {other:?}"),
}
println!("=== Example 14: Index-aware explain ===");
println!("Creating BTree index on person.age...\n");
use interstellar::index::IndexBuilder;
let spec = IndexBuilder::vertex()
.label("person")
.property("age")
.build()
.expect("build index spec");
graph.create_index(spec).expect("create index");
let snap = graph.snapshot();
let g = interstellar::traversal::GraphTraversalSource::from_snapshot_with_graph(
&snap,
Arc::clone(&graph),
);
println!("Query: g.V().hasLabel('person').has('age', gt(30)).out('knows').values('name')\n");
let explanation = g
.v()
.has_label("person")
.has_where("age", p::gt(30i64))
.out_labels(&["knows"])
.values("name")
.explain();
println!("{explanation}");
println!("Note: The 'has' step on 'age' now shows an index hint!");
#[cfg(feature = "full-text")]
{
use interstellar::storage::text::TextIndexConfig;
println!("\n=== Example 15: Full-text search explain ===");
println!("Creating text index on article.body...\n");
graph
.create_text_index_v("body", TextIndexConfig::default())
.expect("create text index");
graph.add_vertex(
"article",
HashMap::from([
("title".into(), Value::from("Intro to Raft")),
(
"body".into(),
Value::from("Raft is a consensus algorithm for replicated logs"),
),
]),
);
graph.add_vertex(
"article",
HashMap::from([
("title".into(), Value::from("Paxos Made Simple")),
(
"body".into(),
Value::from("Paxos is a family of protocols for consensus"),
),
]),
);
let snap = graph.snapshot();
let g = interstellar::traversal::GraphTraversalSource::from_snapshot_with_graph(
&snap,
Arc::clone(&graph),
);
println!("Query: g.searchText('body', 'consensus', 5).hasLabel('article').values('title')\n");
let explanation = g
.search_text("body", "consensus", 5)
.expect("search_text")
.has_label("article")
.values("title")
.explain();
println!("{explanation}");
println!("Query: g.V().hasLabel('article').has('body').values('title')\n");
let explanation = g
.v()
.has_label("article")
.has("body")
.values("title")
.explain();
println!("{explanation}");
}
}