#[cfg(test)]
mod multi_edge_integration_test {
use crate::{
api::Graph,
gremlin::{traversal::TraversalBuilder, value::Value},
types::StoreError,
};
fn setup_multi_edge_graph(path: &std::path::Path) -> Graph {
let options = crate::schema::GraphOptions {
mode: crate::schema::SchemaMode::Auto,
edge_mode: crate::schema::EdgeMode::Multi,
};
let graph = Graph::open_with_options(path, options).unwrap();
{
let schema_arc = graph.schema();
let mut schema = schema_arc.write().unwrap();
schema.register_vertex_label("person").unwrap();
schema.register_edge_label("purchased").unwrap();
schema.register_edge_label("reviewed").unwrap();
schema.register_edge_label("knows").unwrap();
}
graph
}
#[test]
fn test_multi_edge_mode_explicit_rank() {
let dir = tempfile::tempdir().unwrap();
let graph = setup_multi_edge_graph(dir.path());
let mut tx = graph.begin();
tx.g().addV("person").property("id", 10i64).next().unwrap();
tx.g().addV("person").property("id", 20i64).next().unwrap();
tx.g().addE("purchased").from(10).to(20).property("since", "morning").next().unwrap();
tx.g().addE("purchased").from(10).to(20).property("rank", 1i32).property("since", "evening").next().unwrap();
tx.g().addE("purchased").from(10).to(20).property("rank", 2i64).property("since", "night").next().unwrap();
let dup_res = tx.g().addE("purchased").from(10).to(20).property("rank", 1i32).next();
assert!(matches!(dup_res, Err(StoreError::DuplicateEdge(_))));
tx.commit().unwrap();
let mut read = graph.read();
let edges = read.g().V([10]).outE(["purchased"]).to_list().unwrap();
assert_eq!(edges.len(), 3);
let values = read.g().V([10]).outE(["purchased"]).values(["since"]).to_list().unwrap();
assert_eq!(values.len(), 3);
assert!(values.contains(&Value::String("morning".into())));
assert!(values.contains(&Value::String("evening".into())));
assert!(values.contains(&Value::String("night".into())));
let ranks = read.g().V([10]).outE(["purchased"]).rank().to_list().unwrap();
assert_eq!(ranks.len(), 3);
assert!(ranks.contains(&Value::UInt16(0)));
assert!(ranks.contains(&Value::UInt16(1)));
assert!(ranks.contains(&Value::UInt16(2)));
let evening_edge_count = read.g().V([10]).outE(["purchased"]).hasRank(1u16).count().next().unwrap().unwrap();
assert_eq!(evening_edge_count, Value::Int64(1));
let evening_since =
read.g().V([10]).outE(["purchased"]).hasRank(1u16).values(["since"]).next().unwrap().unwrap();
assert_eq!(evening_since, Value::String("evening".into()));
}
#[test]
fn test_multi_edge_distinct_labels() {
let dir = tempfile::tempdir().unwrap();
let graph = setup_multi_edge_graph(dir.path());
let mut tx = graph.begin();
tx.g().addV("person").property("id", 1i64).next().unwrap();
tx.g().addV("person").property("id", 2i64).next().unwrap();
tx.g().addE("purchased").from(1).to(2).property("rank", 0i32).property("item", "book").next().unwrap();
tx.g().addE("purchased").from(1).to(2).property("rank", 1i32).property("item", "pen").next().unwrap();
tx.g().addE("reviewed").from(1).to(2).property("rank", 0i32).property("rating", 5i32).next().unwrap();
tx.g().addE("reviewed").from(1).to(2).property("rank", 1i32).property("rating", 4i32).next().unwrap();
tx.commit().unwrap();
let mut read = graph.read();
assert_eq!(read.g().V([1]).outE(["purchased"]).count().next().unwrap().unwrap(), Value::Int64(2));
assert_eq!(read.g().V([1]).outE(["reviewed"]).count().next().unwrap().unwrap(), Value::Int64(2));
let items = read.g().V([1]).outE(["purchased"]).values(["item"]).to_list().unwrap();
assert_eq!(items.len(), 2);
assert!(items.contains(&Value::String("book".into())));
assert!(items.contains(&Value::String("pen".into())));
}
#[test]
fn test_multi_edge_property_updates_on_specific_rank() {
let dir = tempfile::tempdir().unwrap();
let graph = setup_multi_edge_graph(dir.path());
let mut tx = graph.begin();
tx.g().addV("person").property("id", 1i64).next().unwrap();
tx.g().addV("person").property("id", 2i64).next().unwrap();
tx.g().addE("knows").from(1).to(2).property("rank", 0i32).property("weight", 0.1f64).next().unwrap();
tx.g().addE("knows").from(1).to(2).property("rank", 1i32).property("weight", 0.2f64).next().unwrap();
tx.g().V([1]).outE(["knows"]).hasRank(1u16).property("weight", 0.9f64).next().unwrap();
tx.commit().unwrap();
let mut read = graph.read();
let w0 = read.g().V([1]).outE(["knows"]).hasRank(0u16).values(["weight"]).next().unwrap().unwrap();
let w1 = read.g().V([1]).outE(["knows"]).hasRank(1u16).values(["weight"]).next().unwrap().unwrap();
assert_eq!(w0, Value::Float64(0.1));
assert_eq!(w1, Value::Float64(0.9));
}
#[test]
fn test_multi_edge_path_tracking() {
let dir = tempfile::tempdir().unwrap();
let graph = setup_multi_edge_graph(dir.path());
let mut tx = graph.begin();
tx.g().addV("person").property("id", 1i64).next().unwrap();
tx.g().addV("person").property("id", 2i64).next().unwrap();
tx.g().addE("knows").from(1).to(2).property("rank", 5i32).next().unwrap();
tx.commit().unwrap();
let mut read = graph.read();
let paths = read.g().V([1]).outE(["knows"]).inV().path().to_list().unwrap();
assert_eq!(paths.len(), 1);
if let Value::Path(path) = &paths[0] {
assert_eq!(path.objects.len(), 3); if let Value::Edge(edge) = &path.objects[1] {
assert_eq!(edge.out_v, 1);
assert_eq!(edge.in_v, 2);
assert_eq!(edge.rank, 5);
assert_eq!(edge.label, "knows");
} else {
panic!("Expected Edge in path segment");
}
} else {
panic!("Expected Path object");
}
}
#[test]
fn test_multi_edge_deletion_of_specific_rank() {
let dir = tempfile::tempdir().unwrap();
let graph = setup_multi_edge_graph(dir.path());
let mut tx = graph.begin();
tx.g().addV("person").property("id", 1i64).next().unwrap();
tx.g().addV("person").property("id", 2i64).next().unwrap();
tx.g().addE("knows").from(1).to(2).property("rank", 0i32).next().unwrap();
tx.g().addE("knows").from(1).to(2).property("rank", 1i32).next().unwrap();
tx.g().addE("knows").from(1).to(2).property("rank", 2i32).next().unwrap();
tx.commit().unwrap();
{
let mut read = graph.read();
let counts = read.g().V([1]).outE(["knows"]).count().next().unwrap().unwrap();
assert_eq!(counts, Value::Int64(3));
}
let mut tx2 = graph.begin();
tx2.g().V([1]).outE(["knows"]).hasRank(1u16).drop().next().unwrap();
tx2.commit().unwrap();
let mut read2 = graph.read();
let remaining_ranks = read2.g().V([1]).outE(["knows"]).rank().to_list().unwrap();
assert_eq!(remaining_ranks.len(), 2);
assert!(remaining_ranks.contains(&Value::UInt16(0)));
assert!(remaining_ranks.contains(&Value::UInt16(2)));
assert!(!remaining_ranks.contains(&Value::UInt16(1)));
let final_counts = read2.g().V([1]).outE(["knows"]).count().next().unwrap().unwrap();
assert_eq!(final_counts, Value::Int64(2));
}
}