#![allow(unused_variables)]
use interstellar::gql::{parse, parse_statement, Statement};
use interstellar::prelude::*;
use interstellar::storage::Graph;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
fn create_union_test_graph() -> Arc<Graph> {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alpha"));
graph.add_vertex("TypeA", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Beta"));
graph.add_vertex("TypeA", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Gamma"));
graph.add_vertex("TypeB", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Delta"));
graph.add_vertex("TypeB", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Epsilon"));
graph.add_vertex("TypeA", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Epsilon"));
graph.add_vertex("TypeB", props);
graph
}
fn create_optional_match_test_graph() -> Arc<Graph> {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Michael Jordan"));
let mj = graph.add_vertex("player", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Scottie Pippen"));
let sp = graph.add_vertex("player", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Charles Barkley"));
let cb = graph.add_vertex("player", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Chicago Bulls"));
let bulls = graph.add_vertex("team", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Phoenix Suns"));
let suns = graph.add_vertex("team", props);
let _ = graph.add_edge(mj, bulls, "won_championship_with", HashMap::new());
let _ = graph.add_edge(sp, bulls, "won_championship_with", HashMap::new());
let _ = graph.add_edge(mj, bulls, "played_for", HashMap::new());
let _ = graph.add_edge(sp, bulls, "played_for", HashMap::new());
let _ = graph.add_edge(cb, suns, "played_for", HashMap::new());
graph
}
fn create_test_graph() -> Arc<Graph> {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
props.insert("age".to_string(), Value::from(30i64));
graph.add_vertex("Person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Bob"));
props.insert("age".to_string(), Value::from(25i64));
graph.add_vertex("Person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Carol"));
props.insert("age".to_string(), Value::from(35i64));
graph.add_vertex("Person", props);
graph
}
fn create_graph_with_edges() -> Arc<Graph> {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
let alice = graph.add_vertex("Person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Bob"));
let bob = graph.add_vertex("Person", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Carol"));
let carol = graph.add_vertex("Person", props);
graph.add_edge(alice, bob, "KNOWS", HashMap::new()).unwrap();
graph
.add_edge(alice, carol, "KNOWS", HashMap::new())
.unwrap();
graph.add_edge(bob, carol, "KNOWS", HashMap::new()).unwrap();
graph
}
#[test]
fn test_gql_parse_statement_single_query() {
let stmt = parse_statement("MATCH (n:Person) RETURN n.name").unwrap();
assert!(
matches!(stmt, Statement::Query(_)),
"Single query should parse to Statement::Query"
);
}
#[test]
fn test_gql_parse_statement_union() {
let stmt = parse_statement(
r#"
MATCH (a:TypeA) RETURN a.name
UNION
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
match stmt {
Statement::Union { queries, all } => {
assert_eq!(queries.len(), 2, "UNION should have 2 queries");
assert!(!all, "UNION (not ALL) should have all=false");
}
_ => panic!("Expected Statement::Union"),
}
}
#[test]
fn test_gql_parse_statement_union_all() {
let stmt = parse_statement(
r#"
MATCH (a:TypeA) RETURN a.name
UNION ALL
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
match stmt {
Statement::Union { queries, all } => {
assert_eq!(queries.len(), 2, "UNION ALL should have 2 queries");
assert!(all, "UNION ALL should have all=true");
}
_ => panic!("Expected Statement::Union"),
}
}
#[test]
fn test_gql_parse_statement_multiple_unions() {
let stmt = parse_statement(
r#"
MATCH (a:TypeA) RETURN a.name
UNION
MATCH (b:TypeB) RETURN b.name
UNION
MATCH (c:TypeC) RETURN c.name
"#,
)
.unwrap();
match stmt {
Statement::Union { queries, all } => {
assert_eq!(queries.len(), 3, "Triple UNION should have 3 queries");
assert!(!all, "UNION should have all=false");
}
_ => panic!("Expected Statement::Union"),
}
}
#[test]
fn test_gql_union_basic() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
UNION
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
let names: HashSet<_> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.as_str()),
_ => None,
})
.collect();
assert_eq!(names.len(), 5, "UNION should have 5 unique names");
assert!(names.contains("Alpha"));
assert!(names.contains("Beta"));
assert!(names.contains("Gamma"));
assert!(names.contains("Delta"));
assert!(names.contains("Epsilon"));
}
#[test]
fn test_gql_union_all_keeps_duplicates() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
UNION ALL
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
assert_eq!(
results.len(),
6,
"UNION ALL should have all 6 results including duplicate Epsilon"
);
let epsilon_count = results
.iter()
.filter(|v| matches!(v, Value::String(s) if s == "Epsilon"))
.count();
assert_eq!(epsilon_count, 2, "Epsilon should appear twice in UNION ALL");
}
#[test]
fn test_gql_union_with_where() {
let graph = Arc::new(Graph::new());
let people = vec![
("Alice", "Young", 20i64),
("Bob", "Young", 25i64),
("Carol", "Old", 60i64),
("Dave", "Old", 65i64),
];
for (name, group, age) in people {
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from(name));
props.insert("age".to_string(), Value::from(age));
graph.add_vertex(group, props);
}
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (y:Young) WHERE y.age > 22 RETURN y.name
UNION
MATCH (o:Old) WHERE o.age > 62 RETURN o.name
"#,
)
.unwrap();
let names: HashSet<_> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.as_str()),
_ => None,
})
.collect();
assert_eq!(names.len(), 2);
assert!(names.contains("Bob"));
assert!(names.contains("Dave"));
}
#[test]
fn test_gql_union_combined_single_query_ordering() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name ORDER BY a.name LIMIT 2
UNION
MATCH (b:TypeB) RETURN b.name ORDER BY b.name LIMIT 2
"#,
)
.unwrap();
let names: HashSet<_> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.as_str()),
_ => None,
})
.collect();
assert!(names.len() <= 4, "Should have at most 4 unique names");
assert!(names.contains("Alpha"));
assert!(names.contains("Beta"));
}
#[test]
fn test_gql_union_multiple_columns() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
props.insert("role".to_string(), Value::from("Engineer"));
graph.add_vertex("Employee", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Bob"));
props.insert("role".to_string(), Value::from("Contractor"));
graph.add_vertex("Contractor", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (e:Employee) RETURN e.name AS person, e.role AS type
UNION
MATCH (c:Contractor) RETURN c.name AS person, c.role AS type
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
for result in &results {
if let Value::Map(map) = result {
assert!(map.contains_key("person"), "Should have 'person' key");
assert!(map.contains_key("type"), "Should have 'type' key");
} else {
panic!("Expected Map result");
}
}
}
#[test]
fn test_gql_union_deduplicates_identical_rows() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Shared"));
graph.add_vertex("TypeA", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Shared"));
graph.add_vertex("TypeB", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
UNION
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Shared".to_string()));
}
#[test]
fn test_gql_union_all_keeps_identical_rows() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Shared"));
graph.add_vertex("TypeA", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Shared"));
graph.add_vertex("TypeB", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
UNION ALL
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
assert!(results
.iter()
.all(|v| v == &Value::String("Shared".to_string())));
}
#[test]
fn test_gql_union_empty_first_query() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (x:NonExistent) RETURN x.name
UNION
MATCH (a:TypeA) RETURN a.name
"#,
)
.unwrap();
assert_eq!(results.len(), 3); }
#[test]
fn test_gql_union_empty_second_query() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
UNION
MATCH (x:NonExistent) RETURN x.name
"#,
)
.unwrap();
assert_eq!(results.len(), 3); }
#[test]
fn test_gql_union_both_empty() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (x:NonExistent1) RETURN x.name
UNION
MATCH (y:NonExistent2) RETURN y.name
"#,
)
.unwrap();
assert_eq!(results.len(), 0);
}
#[test]
fn test_gql_triple_union() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("A1"));
graph.add_vertex("TypeA", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("B1"));
graph.add_vertex("TypeB", props);
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("C1"));
graph.add_vertex("TypeC", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
UNION
MATCH (b:TypeB) RETURN b.name
UNION
MATCH (c:TypeC) RETURN c.name
"#,
)
.unwrap();
let names: HashSet<_> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.as_str()),
_ => None,
})
.collect();
assert_eq!(names.len(), 3);
assert!(names.contains("A1"));
assert!(names.contains("B1"));
assert!(names.contains("C1"));
}
#[test]
fn test_gql_union_case_insensitive() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
union
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
assert!(!results.is_empty(), "lowercase 'union' should work");
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
Union
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
assert!(!results.is_empty(), "mixed case 'Union' should work");
}
#[test]
fn test_gql_union_all_case_insensitive() {
let graph = create_union_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:TypeA) RETURN a.name
union all
MATCH (b:TypeB) RETURN b.name
"#,
)
.unwrap();
assert_eq!(results.len(), 6, "lowercase 'union all' should work");
}
#[test]
fn test_gql_parse_optional_match() {
let query = parse(
r#"
MATCH (p:player)
OPTIONAL MATCH (p)-[:won_championship_with]->(t:team)
RETURN p.name, t.name
"#,
)
.unwrap();
assert!(!query.optional_match_clauses.is_empty());
assert_eq!(query.optional_match_clauses.len(), 1);
}
#[test]
fn test_gql_parse_multiple_optional_match() {
let query = parse(
r#"
MATCH (p:player)
OPTIONAL MATCH (p)-[:won_championship_with]->(t:team)
OPTIONAL MATCH (p)-[:played_for]->(t2:team)
RETURN p.name, t.name, t2.name
"#,
)
.unwrap();
assert_eq!(query.optional_match_clauses.len(), 2);
}
#[test]
fn test_gql_optional_match_returns_null() {
let graph = create_optional_match_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:player {name: 'Charles Barkley'})
OPTIONAL MATCH (p)-[:won_championship_with]->(t:team)
RETURN p.name, t.name
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
if let Value::Map(map) = &results[0] {
assert_eq!(
map.get("p.name"),
Some(&Value::String("Charles Barkley".to_string()))
);
assert!(
map.get("t.name").is_none() || map.get("t.name") == Some(&Value::Null),
"Expected null for t.name, got {:?}",
map.get("t.name")
);
} else {
panic!("Expected Map result, got {:?}", results[0]);
}
}
#[test]
fn test_gql_optional_match_returns_value() {
let graph = create_optional_match_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:player {name: 'Michael Jordan'})
OPTIONAL MATCH (p)-[:won_championship_with]->(t:team)
RETURN p.name, t.name
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
if let Value::Map(map) = &results[0] {
assert_eq!(
map.get("p.name"),
Some(&Value::String("Michael Jordan".to_string()))
);
assert_eq!(
map.get("t.name"),
Some(&Value::String("Chicago Bulls".to_string()))
);
} else {
panic!("Expected Map result, got {:?}", results[0]);
}
}
#[test]
fn test_gql_optional_match_mixed_results() {
let graph = create_optional_match_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:player)
OPTIONAL MATCH (p)-[:won_championship_with]->(t:team)
RETURN p.name, t.name
"#,
)
.unwrap();
assert_eq!(results.len(), 3);
let mut with_championship = 0;
let mut without_championship = 0;
for result in &results {
if let Value::Map(map) = result {
if let Some(Value::String(_)) = map.get("t.name") {
with_championship += 1;
} else {
without_championship += 1;
}
}
}
assert_eq!(with_championship, 2, "MJ and Pippen have championships");
assert_eq!(without_championship, 1, "Barkley has no championship");
}
#[test]
fn test_gql_optional_match_case_insensitive() {
let graph = create_optional_match_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:player {name: 'Michael Jordan'})
optional match (p)-[:won_championship_with]->(t:team)
RETURN p.name
"#,
)
.unwrap();
assert!(
!results.is_empty(),
"lowercase 'optional match' should work"
);
let results = graph
.gql(
r#"
MATCH (p:player {name: 'Michael Jordan'})
Optional Match (p)-[:won_championship_with]->(t:team)
RETURN p.name
"#,
)
.unwrap();
assert!(
!results.is_empty(),
"mixed case 'Optional Match' should work"
);
}
#[test]
fn test_gql_optional_match_with_where() {
let graph = create_optional_match_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:player)
OPTIONAL MATCH (p)-[:won_championship_with]->(t:team)
WHERE t.name IS NOT NULL
RETURN p.name, t.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
for result in &results {
if let Value::Map(map) = result {
let name = map.get("p.name");
assert!(
name == Some(&Value::String("Michael Jordan".to_string()))
|| name == Some(&Value::String("Scottie Pippen".to_string())),
"Expected MJ or Pippen, got {:?}",
name
);
}
}
}
#[test]
fn test_gql_optional_match_preserves_base_rows() {
let graph = create_optional_match_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:player)
OPTIONAL MATCH (p)-[:won_championship_with]->(t:team)
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 3);
}
#[test]
fn test_gql_with_path_returns_path() {
let graph = create_graph_with_edges();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person)
WITH PATH
RETURN path()
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
for result in &results {
match result {
Value::List(path_elements) => {
assert!(
path_elements.len() >= 2,
"Path should have at least 2 elements, got {}",
path_elements.len()
);
}
_ => panic!("Expected path() to return a list, got {:?}", result),
}
}
}
#[test]
fn test_gql_path_function_elements() {
let graph = create_graph_with_edges();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})
WITH PATH
RETURN path()
"#,
)
.unwrap();
assert_eq!(
results.len(),
1,
"Should find exactly one path from Alice to Bob"
);
if let Value::List(path_elements) = &results[0] {
assert!(!path_elements.is_empty(), "Path should not be empty");
assert!(
matches!(path_elements.first(), Some(Value::Vertex(_))),
"First path element should be a vertex"
);
} else {
panic!("Expected path() to return a list");
}
}
#[test]
fn test_gql_path_function_multi_hop() {
let graph = create_graph_with_edges();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})-[:KNOWS]->(c:Person {name: 'Carol'})
WITH PATH
RETURN path()
"#,
)
.unwrap();
assert_eq!(
results.len(),
1,
"Should find exactly one path from Alice to Bob to Carol"
);
if let Value::List(path_elements) = &results[0] {
assert!(
path_elements.len() >= 3,
"Multi-hop path should have at least 3 elements, got {}",
path_elements.len()
);
} else {
panic!("Expected path() to return a list");
}
}
#[test]
fn test_gql_unwind_list() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
props.insert(
"hobbies".to_string(),
Value::List(vec![
Value::from("reading"),
Value::from("coding"),
Value::from("gaming"),
]),
);
graph.add_vertex("Person", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
UNWIND p.hobbies AS hobby
RETURN hobby
"#,
)
.unwrap();
assert_eq!(results.len(), 3);
let hobbies: HashSet<String> = results
.into_iter()
.filter_map(|v| match v {
Value::String(s) => Some(s),
_ => None,
})
.collect();
assert!(hobbies.contains("reading"));
assert!(hobbies.contains("coding"));
assert!(hobbies.contains("gaming"));
}
#[test]
fn test_gql_unwind_null_produces_no_rows() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
graph.add_vertex("Person", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
UNWIND p.missing_property AS item
RETURN item
"#,
)
.unwrap();
assert_eq!(results.len(), 0, "UNWIND null should produce no rows");
}
#[test]
fn test_gql_unwind_non_list_wraps() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
props.insert("age".to_string(), Value::from(30i64));
graph.add_vertex("Person", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
UNWIND p.age AS val
RETURN val
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Int(30));
}
#[test]
fn test_gql_multiple_unwind() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
props.insert(
"colors".to_string(),
Value::List(vec![Value::from("red"), Value::from("blue")]),
);
props.insert(
"sizes".to_string(),
Value::List(vec![Value::from("S"), Value::from("M")]),
);
graph.add_vertex("Person", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
UNWIND p.colors AS color
UNWIND p.sizes AS size
RETURN color, size
"#,
)
.unwrap();
assert_eq!(
results.len(),
4,
"Multiple UNWIND should produce cartesian product"
);
let combinations: Vec<(String, String)> = results
.iter()
.filter_map(|v| match v {
Value::Map(map) => {
let color = map.get("color").and_then(|c| match c {
Value::String(s) => Some(s.clone()),
_ => None,
})?;
let size = map.get("size").and_then(|s| match s {
Value::String(s) => Some(s.clone()),
_ => None,
})?;
Some((color, size))
}
_ => None,
})
.collect();
assert_eq!(combinations.len(), 4);
}
#[test]
fn test_gql_unwind_inline_list() {
let graph = create_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
UNWIND [1, 2, 3] AS num
RETURN num
LIMIT 9
"#,
)
.unwrap();
assert_eq!(results.len(), 9);
for result in &results {
match result {
Value::Int(n) => {
assert!(*n >= 1 && *n <= 3, "Expected 1, 2, or 3, got {}", n);
}
_ => panic!("Expected Int, got {:?}", result),
}
}
}
#[test]
fn test_gql_unwind_with_where() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Alice"));
props.insert(
"scores".to_string(),
Value::List(vec![
Value::from(85i64),
Value::from(92i64),
Value::from(78i64),
Value::from(95i64),
]),
);
graph.add_vertex("Person", props);
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
UNWIND p.scores AS score
WHERE score >= 90
RETURN score
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let scores: HashSet<i64> = results
.into_iter()
.filter_map(|v| match v {
Value::Int(n) => Some(n),
_ => None,
})
.collect();
assert!(scores.contains(&92));
assert!(scores.contains(&95));
}