#![allow(unused_variables)]
use interstellar::prelude::*;
use interstellar::storage::Graph;
use std::collections::HashMap;
use std::sync::Arc;
fn create_exists_test_graph() -> Arc<Graph> {
let graph = Arc::new(Graph::new());
let mut mj_props = HashMap::new();
mj_props.insert("name".to_string(), Value::from("Michael Jordan"));
mj_props.insert("position".to_string(), Value::from("Shooting Guard"));
let mj_id = graph.add_vertex("player", mj_props);
let mut kobe_props = HashMap::new();
kobe_props.insert("name".to_string(), Value::from("Kobe Bryant"));
kobe_props.insert("position".to_string(), Value::from("Shooting Guard"));
let kobe_id = graph.add_vertex("player", kobe_props);
let mut barkley_props = HashMap::new();
barkley_props.insert("name".to_string(), Value::from("Charles Barkley"));
barkley_props.insert("position".to_string(), Value::from("Power Forward"));
let barkley_id = graph.add_vertex("player", barkley_props);
let mut nash_props = HashMap::new();
nash_props.insert("name".to_string(), Value::from("Steve Nash"));
nash_props.insert("position".to_string(), Value::from("Point Guard"));
let nash_id = graph.add_vertex("player", nash_props);
let mut bulls_props = HashMap::new();
bulls_props.insert("name".to_string(), Value::from("Chicago Bulls"));
bulls_props.insert("championships".to_string(), Value::Int(6));
let bulls_id = graph.add_vertex("team", bulls_props);
let mut lakers_props = HashMap::new();
lakers_props.insert("name".to_string(), Value::from("Los Angeles Lakers"));
lakers_props.insert("championships".to_string(), Value::Int(17));
let lakers_id = graph.add_vertex("team", lakers_props);
let mut suns_props = HashMap::new();
suns_props.insert("name".to_string(), Value::from("Phoenix Suns"));
suns_props.insert("championships".to_string(), Value::Int(0));
let suns_id = graph.add_vertex("team", suns_props);
let mut ring_props = HashMap::new();
ring_props.insert("years".to_string(), Value::from("1991-1993,1996-1998"));
let _ = graph.add_edge(mj_id, bulls_id, "won_championship_with", ring_props.clone());
ring_props.insert("years".to_string(), Value::from("2000-2002,2009-2010"));
let _ = graph.add_edge(kobe_id, lakers_id, "won_championship_with", ring_props);
let played_props = HashMap::new();
let _ = graph.add_edge(mj_id, bulls_id, "played_for", played_props.clone());
let _ = graph.add_edge(kobe_id, lakers_id, "played_for", played_props.clone());
let _ = graph.add_edge(barkley_id, suns_id, "played_for", played_props.clone());
let _ = graph.add_edge(nash_id, suns_id, "played_for", played_props);
graph
}
#[test]
fn test_gql_exists_basic() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Michael Jordan".to_string()));
assert!(names.contains(&"Kobe Bryant".to_string()));
}
#[test]
fn test_gql_not_exists() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE NOT EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Charles Barkley".to_string()));
assert!(names.contains(&"Steve Nash".to_string()));
}
#[test]
fn test_gql_exists_with_target_label() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:played_for]->(t:team) }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 4);
}
#[test]
fn test_gql_exists_combined_with_and() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE p.position = 'Shooting Guard' AND EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
}
#[test]
fn test_gql_exists_combined_with_or() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE p.position = 'Point Guard' OR EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 3);
}
#[test]
fn test_gql_exists_no_match() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:nonexistent_relationship]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 0);
}
#[test]
fn test_gql_exists_with_count() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN count(*)
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Int(2));
}
#[test]
fn test_gql_parse_exists_expression() {
use interstellar::gql::parse;
let ast = parse(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert!(ast.where_clause.is_some());
let where_clause = ast.where_clause.unwrap();
match where_clause.expression {
interstellar::gql::Expression::Exists {
negated, pattern, ..
} => {
assert!(!negated);
assert!(!pattern.elements.is_empty());
}
_ => panic!("Expected EXISTS expression"),
}
}
#[test]
fn test_gql_parse_not_exists_expression() {
use interstellar::gql::parse;
let ast = parse(
r#"
MATCH (p:player)
WHERE NOT EXISTS { (p)-[:knows]->() }
RETURN p.name
"#,
)
.unwrap();
assert!(ast.where_clause.is_some());
let where_clause = ast.where_clause.unwrap();
match where_clause.expression {
interstellar::gql::Expression::UnaryOp { op, expr } => {
assert!(matches!(op, interstellar::gql::UnaryOperator::Not));
match *expr {
interstellar::gql::Expression::Exists {
negated, pattern, ..
} => {
assert!(!negated);
assert!(!pattern.elements.is_empty());
}
_ => panic!("Expected EXISTS expression inside NOT"),
}
}
interstellar::gql::Expression::Exists {
negated, pattern, ..
} => {
assert!(negated);
assert!(!pattern.elements.is_empty());
}
_ => panic!("Expected NOT(EXISTS) or EXISTS(negated=true) expression"),
}
}
#[test]
fn test_gql_exists_incoming_edge() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (t:team)
WHERE EXISTS { (t)<-[:played_for]-() }
RETURN t.name
"#,
)
.unwrap();
assert_eq!(results.len(), 3);
}
#[test]
fn test_gql_exists_bidirectional() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (n)
WHERE EXISTS { (n)-[:played_for]-() }
RETURN n
"#,
)
.unwrap();
assert_eq!(results.len(), 7);
}
#[test]
fn test_gql_exists_with_property_filter() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:played_for]->(t:team {championships: 6}) }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Michael Jordan".to_string()));
}
#[test]
fn test_gql_exists_with_target_property_filter_multiple_results() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:played_for]->(t:team {championships: 0}) }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Charles Barkley".to_string()));
assert!(names.contains(&"Steve Nash".to_string()));
}
#[test]
fn test_gql_exists_multiple_conditions_complex() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE p.position = 'Shooting Guard' AND NOT EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 0);
}
#[test]
fn test_gql_exists_with_order_by() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
ORDER BY p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
assert_eq!(results[0], Value::String("Kobe Bryant".to_string()));
assert_eq!(results[1], Value::String("Michael Jordan".to_string()));
}
#[test]
fn test_gql_exists_with_limit() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE NOT EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
LIMIT 1
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
let name = match &results[0] {
Value::String(s) => s.clone(),
_ => panic!("Expected string"),
};
assert!(name == "Charles Barkley" || name == "Steve Nash");
}
#[test]
fn test_gql_exists_nested_not() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE NOT NOT EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Michael Jordan".to_string()));
assert!(names.contains(&"Kobe Bryant".to_string()));
}
#[test]
fn test_gql_exists_with_distinct() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN DISTINCT p.position
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Shooting Guard".to_string()));
}
#[test]
fn test_gql_exists_return_multiple_properties() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name AS name, p.position AS pos
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
for result in &results {
if let Value::Map(map) = result {
assert!(map.contains_key("name"));
assert!(map.contains_key("pos"));
assert_eq!(
map.get("pos"),
Some(&Value::String("Shooting Guard".to_string()))
);
} else {
panic!("Expected map result");
}
}
}
#[test]
fn test_gql_exists_empty_graph() {
let graph = Arc::new(Graph::new());
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 0);
}
#[test]
fn test_gql_exists_no_edges() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Lonely Player"));
graph.add_vertex("player", props);
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:any_relationship]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 0);
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE NOT EXISTS { (p)-[:any_relationship]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Lonely Player".to_string()));
}
#[test]
fn test_gql_exists_self_loop() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from("Narcissist"));
let id = graph.add_vertex("player", props);
let _ = graph.add_edge(id, id, "admires", HashMap::new());
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:admires]->(p) }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Narcissist".to_string()));
}
#[test]
fn test_gql_exists_aggregate_over_filtered() {
let graph = create_exists_test_graph();
let snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { (p)-[:won_championship_with]->() }
RETURN count(*) AS total, collect(p.name) AS winners
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
if let Value::Map(map) = &results[0] {
assert_eq!(map.get("total"), Some(&Value::Int(2)));
if let Some(Value::List(winners)) = map.get("winners") {
assert_eq!(winners.len(), 2);
assert!(winners.contains(&Value::String("Michael Jordan".to_string())));
assert!(winners.contains(&Value::String("Kobe Bryant".to_string())));
} else {
panic!("Expected list for winners");
}
} else {
panic!("Expected map result");
}
}
#[test]
fn test_gql_exists_subquery_match_form() {
let graph = create_exists_test_graph();
let _snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { MATCH (p)-[:won_championship_with]->() }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Michael Jordan".to_string()));
assert!(names.contains(&"Kobe Bryant".to_string()));
}
#[test]
fn test_gql_exists_subquery_with_where_filters_inner_pattern() {
let graph = create_exists_test_graph();
let _snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { MATCH (p)-[:played_for]->(t:team) WHERE t.championships >= 6 }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Michael Jordan".to_string()));
assert!(names.contains(&"Kobe Bryant".to_string()));
assert!(!names.contains(&"Charles Barkley".to_string()));
assert!(!names.contains(&"Steve Nash".to_string()));
}
#[test]
fn test_gql_not_exists_subquery_with_where() {
let graph = create_exists_test_graph();
let _snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE NOT EXISTS { MATCH (p)-[:played_for]->(t:team) WHERE t.championships >= 6 }
RETURN p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 2);
let names: Vec<String> = results
.iter()
.filter_map(|v| match v {
Value::String(s) => Some(s.clone()),
_ => None,
})
.collect();
assert!(names.contains(&"Charles Barkley".to_string()));
assert!(names.contains(&"Steve Nash".to_string()));
}
#[test]
fn test_gql_exists_subquery_where_no_matches() {
let graph = create_exists_test_graph();
let _snapshot = graph.snapshot();
let results: Vec<_> = graph
.gql(
r#"
MATCH (p:player)
WHERE EXISTS { MATCH (p)-[:played_for]->(t:team) WHERE t.championships > 100 }
RETURN p.name
"#,
)
.unwrap();
assert!(results.is_empty(), "expected no players, got {:?}", results);
}
fn create_coalesce_test_graph() -> Arc<Graph> {
let graph = Arc::new(Graph::new());
let mut alice_props = HashMap::new();
alice_props.insert("name".to_string(), Value::from("Alice"));
alice_props.insert("nickname".to_string(), Value::from("Ali"));
graph.add_vertex("Person", alice_props);
let mut bob_props = HashMap::new();
bob_props.insert("name".to_string(), Value::from("Bob"));
graph.add_vertex("Person", bob_props);
let mut carol_props = HashMap::new();
carol_props.insert("nickname".to_string(), Value::from("Carol the Great"));
graph.add_vertex("Person", carol_props);
graph
}
#[test]
fn test_gql_coalesce_first_value() {
let graph = create_coalesce_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) WHERE p.name = 'Alice' RETURN coalesce(p.nickname, p.name)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Ali".to_string()));
}
#[test]
fn test_gql_coalesce_fallback() {
let graph = create_coalesce_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) WHERE p.name = 'Bob' RETURN coalesce(p.nickname, p.name)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Bob".to_string()));
}
#[test]
fn test_gql_coalesce_literal_default() {
let graph = create_coalesce_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) WHERE p.name = 'Bob' RETURN coalesce(p.nickname, 'No Nickname')")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("No Nickname".to_string()));
}
#[test]
fn test_gql_coalesce_multiple_args() {
let graph = create_coalesce_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) WHERE p.nickname = 'Carol the Great' RETURN coalesce(p.name, p.nickname, 'Unknown')")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Carol the Great".to_string()));
}
#[test]
fn test_gql_coalesce_case_insensitive() {
let graph = create_coalesce_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) WHERE p.name = 'Bob' RETURN COALESCE(p.nickname, p.name)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Bob".to_string()));
}
fn create_case_test_graph() -> Arc<Graph> {
let graph = Arc::new(Graph::new());
let people = vec![
("Alice", 32i64, 92i64),
("Bob", 25i64, 75i64),
("Carol", 42i64, 88i64),
("Dave", 18i64, 65i64),
("Eve", 55i64, 45i64),
];
for (name, age, score) in people {
let mut props = HashMap::new();
props.insert("name".to_string(), Value::from(name));
props.insert("age".to_string(), Value::from(age));
props.insert("score".to_string(), Value::from(score));
graph.add_vertex("Person", props);
}
graph
}
#[test]
fn test_gql_case_age_category() {
let graph = create_case_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
WHERE p.name = 'Carol'
RETURN CASE
WHEN p.age > 40 THEN 'Senior'
WHEN p.age > 30 THEN 'Middle'
ELSE 'Young'
END
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Senior".to_string()));
}
#[test]
fn test_gql_case_else_branch() {
let graph = create_case_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
WHERE p.name = 'Dave'
RETURN CASE
WHEN p.age > 40 THEN 'Senior'
WHEN p.age > 30 THEN 'Middle'
ELSE 'Young'
END
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Young".to_string()));
}
#[test]
fn test_gql_case_grade() {
let graph = create_case_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
WHERE p.name = 'Alice'
RETURN p.name, CASE
WHEN p.score >= 90 THEN 'A'
WHEN p.score >= 80 THEN 'B'
WHEN p.score >= 70 THEN 'C'
ELSE 'F'
END AS grade
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
if let Value::Map(map) = &results[0] {
assert_eq!(map.get("grade"), Some(&Value::String("A".to_string())));
} else {
panic!("Expected Map result");
}
}
#[test]
fn test_gql_case_no_else_returns_null() {
let graph = create_case_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
WHERE p.name = 'Eve'
RETURN CASE
WHEN p.age < 20 THEN 'Teen'
END
"#,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Null);
}
#[test]
fn test_gql_case_multiple_results() {
let graph = create_case_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql(
r#"
MATCH (p:Person)
RETURN p.name, CASE
WHEN p.age > 40 THEN 'Senior'
WHEN p.age > 25 THEN 'Adult'
ELSE 'Young'
END AS category
ORDER BY p.name
"#,
)
.unwrap();
assert_eq!(results.len(), 5);
let categories: Vec<_> = results
.iter()
.filter_map(|v| {
if let Value::Map(map) = v {
let name = map.get("p.name").cloned();
let category = map.get("category").cloned();
Some((name, category))
} else {
None
}
})
.collect();
assert!(categories.contains(&(
Some(Value::String("Alice".to_string())),
Some(Value::String("Adult".to_string()))
)));
assert!(categories.contains(&(
Some(Value::String("Carol".to_string())),
Some(Value::String("Senior".to_string()))
)));
assert!(categories.contains(&(
Some(Value::String("Dave".to_string())),
Some(Value::String("Young".to_string()))
)));
}
fn create_type_conversion_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));
props.insert("score".to_string(), Value::from(95.5));
props.insert("active".to_string(), Value::from(true));
props.insert("count_str".to_string(), Value::from("42"));
props.insert("float_str".to_string(), Value::from("3.15"));
props.insert("bool_str".to_string(), Value::from("true"));
graph.add_vertex("Person", props);
graph
}
#[test]
fn test_gql_tostring_integer() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toString(p.age)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("30".to_string()));
}
#[test]
fn test_gql_tostring_float() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toString(p.score)")
.unwrap();
assert_eq!(results.len(), 1);
if let Value::String(s) = &results[0] {
assert!(s.starts_with("95.5"), "Expected '95.5...' got '{}'", s);
} else {
panic!("Expected String result");
}
}
#[test]
fn test_gql_tostring_boolean() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toString(p.active)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("true".to_string()));
}
#[test]
fn test_gql_tointeger_string() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toInteger(p.count_str)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Int(42));
}
#[test]
fn test_gql_tointeger_float() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toInteger(p.score)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Int(95));
}
#[test]
fn test_gql_tointeger_invalid_string() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toInteger(p.name)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Null);
}
#[test]
fn test_gql_tofloat_integer() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (p:Person) RETURN toFloat(p.age)").unwrap();
assert_eq!(results.len(), 1);
if let Value::Float(f) = results[0] {
assert!((f - 30.0).abs() < 0.0001, "Expected 30.0, got {}", f);
} else {
panic!("Expected Float result");
}
}
#[test]
fn test_gql_tofloat_string() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toFloat(p.float_str)")
.unwrap();
assert_eq!(results.len(), 1);
if let Value::Float(f) = results[0] {
assert!((f - 3.15).abs() < 0.0001, "Expected 3.15, got {}", f);
} else {
panic!("Expected Float result");
}
}
#[test]
fn test_gql_toboolean_string_true() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toBoolean(p.bool_str)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Bool(true));
}
#[test]
fn test_gql_toboolean_integer() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN toBoolean(p.age)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Bool(true));
}
#[test]
fn test_gql_toboolean_string_false() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("status".to_string(), Value::from("false"));
graph.add_vertex("Test", props);
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (t:Test) RETURN toBoolean(t.status)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Bool(false));
}
#[test]
fn test_gql_upper_function() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (p:Person) RETURN upper(p.name)").unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("ALICE".to_string()));
}
#[test]
fn test_gql_lower_function() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (p:Person) RETURN lower(p.name)").unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("alice".to_string()));
}
#[test]
fn test_gql_length_string() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (p:Person) RETURN length(p.name)").unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Int(5)); }
#[test]
fn test_gql_abs_function() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("balance".to_string(), Value::from(-100i64));
graph.add_vertex("Account", props);
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (a:Account) RETURN abs(a.balance)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::Int(100));
}
#[test]
fn test_gql_trim_function() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("text".to_string(), Value::from(" hello world "));
graph.add_vertex("Test", props);
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (t:Test) RETURN trim(t.text)").unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("hello world".to_string()));
}
#[test]
fn test_gql_round_function() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (p:Person) RETURN round(p.score)").unwrap();
assert_eq!(results.len(), 1);
if let Value::Float(f) = results[0] {
assert!((f - 96.0).abs() < 0.0001, "Expected 96.0, got {}", f);
} else {
panic!("Expected Float result");
}
}
#[test]
fn test_gql_floor_function() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (p:Person) RETURN floor(p.score)").unwrap();
assert_eq!(results.len(), 1);
if let Value::Float(f) = results[0] {
assert!((f - 95.0).abs() < 0.0001, "Expected 95.0, got {}", f);
} else {
panic!("Expected Float result");
}
}
#[test]
fn test_gql_ceil_function() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph.gql("MATCH (p:Person) RETURN ceil(p.score)").unwrap();
assert_eq!(results.len(), 1);
if let Value::Float(f) = results[0] {
assert!((f - 96.0).abs() < 0.0001, "Expected 96.0, got {}", f);
} else {
panic!("Expected Float result");
}
}
#[test]
fn test_gql_substring_function() {
let graph = create_type_conversion_test_graph();
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (p:Person) RETURN substring(p.name, 0, 3)")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("Ali".to_string()));
}
#[test]
fn test_gql_replace_function() {
let graph = Arc::new(Graph::new());
let mut props = HashMap::new();
props.insert("text".to_string(), Value::from("hello world"));
graph.add_vertex("Test", props);
let snapshot = graph.snapshot();
let results = graph
.gql("MATCH (t:Test) RETURN replace(t.text, 'world', 'there')")
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], Value::String("hello there".to_string()));
}