ruvector-graph 2.0.6

Distributed Neo4j-compatible hypergraph database with SIMD optimization
Documentation
//! Cypher query parser tests
//!
//! Tests for parsing valid and invalid Cypher queries to ensure syntax correctness.

use ruvector_graph::cypher::parse_cypher;

// ============================================================================
// Valid Cypher Queries
// ============================================================================

#[test]
fn test_parse_simple_match() {
    let result = parse_cypher("MATCH (n) RETURN n");
    assert!(result.is_ok(), "Parse failed: {:?}", result.err());
}

#[test]
fn test_parse_match_with_label() {
    let result = parse_cypher("MATCH (n:Person) RETURN n");
    assert!(result.is_ok());
}

#[test]
fn test_parse_match_with_properties() {
    let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) RETURN n");
    assert!(result.is_ok());
}

#[test]
fn test_parse_match_relationship() {
    let result = parse_cypher("MATCH (a)-[r:KNOWS]->(b) RETURN a, r, b");
    assert!(result.is_ok());
}

#[test]
fn test_parse_match_undirected_relationship() {
    let result = parse_cypher("MATCH (a)-[r:FRIEND]-(b) RETURN a, b");
    assert!(result.is_ok(), "Parse failed: {:?}", result.err());
}

#[test]
fn test_parse_match_path() {
    let result = parse_cypher("MATCH p = (a)-[:KNOWS*1..3]->(b) RETURN p");
    assert!(result.is_ok());
}

#[test]
fn test_parse_create_node() {
    let result = parse_cypher("CREATE (n:Person {name: 'Bob', age: 30})");
    assert!(result.is_ok());
}

#[test]
fn test_parse_create_relationship() {
    let result =
        parse_cypher("CREATE (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})");
    assert!(result.is_ok());
}

#[test]
fn test_parse_merge() {
    let result = parse_cypher("MERGE (n:Person {name: 'Charlie'})");
    assert!(result.is_ok());
}

#[test]
fn test_parse_delete() {
    let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) DELETE n");
    assert!(result.is_ok());
}

#[test]
fn test_parse_set_property() {
    let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) SET n.age = 31");
    assert!(result.is_ok());
}

#[test]
fn test_parse_remove_property() {
    let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) REMOVE n.age");
    assert!(result.is_ok(), "Parse failed: {:?}", result.err());
}

#[test]
fn test_parse_where_clause() {
    let result = parse_cypher("MATCH (n:Person) WHERE n.age > 25 RETURN n");
    assert!(result.is_ok());
}

#[test]
fn test_parse_order_by() {
    let result = parse_cypher("MATCH (n:Person) RETURN n ORDER BY n.age DESC");
    assert!(result.is_ok());
}

#[test]
fn test_parse_limit() {
    let result = parse_cypher("MATCH (n:Person) RETURN n LIMIT 10");
    assert!(result.is_ok());
}

#[test]
fn test_parse_skip() {
    let result = parse_cypher("MATCH (n:Person) RETURN n SKIP 5 LIMIT 10");
    assert!(result.is_ok());
}

#[test]
fn test_parse_aggregate_count() {
    let result = parse_cypher("MATCH (n:Person) RETURN COUNT(n)");
    assert!(result.is_ok());
}

#[test]
fn test_parse_aggregate_sum() {
    let result = parse_cypher("MATCH (n:Person) RETURN SUM(n.age)");
    assert!(result.is_ok());
}

#[test]
fn test_parse_aggregate_avg() {
    let result = parse_cypher("MATCH (n:Person) RETURN AVG(n.age)");
    assert!(result.is_ok());
}

#[test]
fn test_parse_with_clause() {
    let result = parse_cypher("MATCH (n:Person) WITH n.age AS age WHERE age > 25 RETURN age");
    assert!(result.is_ok());
}

#[test]
fn test_parse_optional_match() {
    let result = parse_cypher("OPTIONAL MATCH (n:Person)-[r:KNOWS]->(m) RETURN n, m");
    assert!(result.is_ok());
}

// ============================================================================
// Complex Query Tests
// ============================================================================

#[test]
#[ignore = "Complex multi-direction patterns with <- not yet fully implemented"]
fn test_parse_complex_graph_pattern() {
    let result = parse_cypher(
        "
        MATCH (user:User)-[:PURCHASED]->(product:Product)<-[:PURCHASED]-(other:User)
        WHERE other.id <> 123
        WITH other, COUNT(*) AS commonProducts
        WHERE commonProducts > 3
        RETURN other.name
        ORDER BY commonProducts DESC
        LIMIT 10
    ",
    );
    assert!(result.is_ok());
}

#[test]
fn test_parse_variable_length_path() {
    let result =
        parse_cypher("MATCH (a:Person)-[:KNOWS*1..5]->(b:Person) WHERE a.name = 'Alice' RETURN b");
    assert!(result.is_ok());
}

#[test]
fn test_parse_multiple_patterns() {
    let result = parse_cypher(
        "
        MATCH (a:Person)-[:KNOWS]->(b:Person)
        MATCH (b)-[:WORKS_AT]->(c:Company)
        RETURN a.name, b.name, c.name
    ",
    );
    assert!(result.is_ok());
}

#[test]
fn test_parse_collect_aggregation() {
    let result = parse_cypher(
        "MATCH (p:Person)-[:KNOWS]->(f:Person) RETURN p.name, COLLECT(f.name) AS friends",
    );
    assert!(result.is_ok());
}

// ============================================================================
// Edge Cases
// ============================================================================

#[test]
#[ignore = "Empty query validation not yet implemented"]
fn test_parse_empty_query() {
    let result = parse_cypher("");
    // Empty query should fail
    assert!(result.is_err());
}

#[test]
#[ignore = "Whitespace-only query validation not yet implemented"]
fn test_parse_whitespace_only() {
    let result = parse_cypher("   \n\t  ");
    // Whitespace only should fail
    assert!(result.is_err());
}

#[test]
fn test_parse_parameters() {
    let result = parse_cypher("MATCH (n:Person {name: $name, age: $age}) RETURN n");
    assert!(result.is_ok());
}

#[test]
fn test_parse_list_literal() {
    let result = parse_cypher("RETURN [1, 2, 3, 4, 5] AS numbers");
    assert!(result.is_ok());
}

#[test]
#[ignore = "Map literal in RETURN not yet implemented"]
fn test_parse_map_literal() {
    let result = parse_cypher("RETURN {name: 'Alice', age: 30} AS person");
    assert!(result.is_ok());
}