mod common;
use common::TestStorage;
use linkrs_metrics::StatsManager;
use linkrs_query::optimizer::OptimizerEngine;
use linkrs_query::parser::Parser;
use linkrs_query::pipeline::QueryPipelineManager;
use std::sync::Arc;
#[test]
fn test_create_cypher_node_basic() {
let query = "CREATE (n:Person {name: 'Alice', age: 30})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATEnode: should succeed: {:?}",
result.err()
);
let stmt = result.expect("CREATEstatement: should succeed");
assert_eq!(stmt.ast.stmt.kind(), "CREATE");
}
#[test]
fn test_create_cypher_node_without_props() {
let query = "CREATE (n:Person)";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATEnode: should succeed: {:?}",
result.err()
);
}
#[test]
fn test_create_cypher_node_multiple_labels() {
let query = "CREATE (n:Person:Employee {name: 'Alice', department: 'Engineering'})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATE nodemulti-label: should succeed: {:?}",
result.err()
);
}
#[test]
fn test_create_cypher_node_without_variable() {
let query = "CREATE (:Person {name: 'Bob'})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATE nodewithout variable: should succeed: {:?}",
result.err()
);
}
#[test]
fn test_create_cypher_node_complex_props() {
let query = r#"CREATE (n:Person {
name: 'Charlie',
age: 35,
salary: 50000.50,
is_active: true,
created_at: '2024-01-01T00:00:00'
})"#;
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_cypher_edge_basic() {
let query = "CREATE (a)-[:KNOWS {since: '2020-01-01', degree: 0.8}]->(b)";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATEedge: should succeed: {:?}",
result.err()
);
let stmt = result.expect("CREATEstatement: should succeed");
assert_eq!(stmt.ast.stmt.kind(), "CREATE");
}
#[test]
fn test_create_cypher_edge_without_props() {
let query = "CREATE (a)-[:FRIEND]->(b)";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATEedge: should succeed: {:?}",
result.err()
);
}
#[test]
fn test_create_cypher_edge_bidirectional() {
let query = "CREATE (a)-[:COLLEAGUE]-(b)";
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_cypher_edge_left_to_right() {
let query = "CREATE (a)<-[:FOLLOWS]-(b)";
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_cypher_path_basic() {
let query = "CREATE (a:Person)-[:KNOWS]->(b:Person)";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATEpath: should succeed: {:?}",
result.err()
);
}
#[test]
fn test_create_cypher_path_with_props() {
let query = "CREATE (a:Person {name: 'Alice'})-[:KNOWS {since: '2020-01-01'}]->(b:Person {name: 'Bob'})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATE pathwith properties: should succeed: {:?}",
result.err()
);
}
#[test]
fn test_create_cypher_long_path() {
let query = "CREATE (a:Person)-[:KNOWS]->(b:Person)-[:WORKS_AT]->(c:Company)";
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_cypher_multiple_nodes() {
let query =
"CREATE (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'}), (c:Person {name: 'Charlie'})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Cypher CREATE multiplenode: should succeed: {:?}",
result.err()
);
}
#[test]
fn test_create_cypher_mixed_patterns() {
let query = "CREATE (a:Person {name: 'Alice'}), (a)-[:KNOWS]->(b:Person {name: 'Bob'})";
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_cypher_node_execution() {
let test_storage = TestStorage::new().expect("Failed to create test storage");
let storage = test_storage.storage();
let stats_manager = Arc::new(StatsManager::new());
let schema_manager = test_storage.schema_manager();
let mut pipeline_manager = QueryPipelineManager::with_optimizer(
storage,
stats_manager,
Arc::new(OptimizerEngine::default()),
)
.with_schema_manager(schema_manager);
let create_space = "CREATE SPACE IF NOT EXISTS test_space";
let _ = pipeline_manager.execute_query(create_space);
let use_space = "USE test_space";
let _ = pipeline_manager.execute_query(use_space);
let query = "CREATE (n:Person {name: 'Alice', age: 30})";
let result = pipeline_manager.execute_query(query);
assert_create_data_rejected(result);
}
#[test]
fn test_create_cypher_edge_execution() {
let test_storage = TestStorage::new().expect("Failed to create test storage");
let storage = test_storage.storage();
let stats_manager = Arc::new(StatsManager::new());
let schema_manager = test_storage.schema_manager();
let mut pipeline_manager = QueryPipelineManager::with_optimizer(
storage,
stats_manager,
Arc::new(OptimizerEngine::default()),
)
.with_schema_manager(schema_manager);
let create_space = "CREATE SPACE IF NOT EXISTS test_space";
let _ = pipeline_manager.execute_query(create_space);
let use_space = "USE test_space";
let _ = pipeline_manager.execute_query(use_space);
let query = "CREATE (a:Person {name: 'Alice'})-[:KNOWS {since: '2020-01-01'}]->(b:Person {name: 'Bob'})";
let result = pipeline_manager.execute_query(query);
assert_create_data_rejected(result);
}
fn assert_create_data_rejected(
result: Result<linkrs_query::executor::base::ExecutionResult, linkrs_core::error::DBError>,
) {
match result {
Ok(linkrs_query::executor::base::ExecutionResult::Error(message)) => {
assert!(
message.contains("use INSERT VERTEX / INSERT EDGE"),
"CREATE data should be rejected explicitly, got: {}",
message
);
}
Err(error) => {
assert!(
format!("{:?}", error).contains("use INSERT VERTEX / INSERT EDGE"),
"CREATE data should be rejected explicitly, got: {:?}",
error
);
}
other => panic!("CREATE data should be rejected, got: {:?}", other),
}
}
#[test]
fn test_create_cypher_invalid_syntax() {
let query = "CREATE n:Person {name: 'Alice'}";
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_cypher_empty_label() {
let query = "CREATE (n {})";
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_cypher_nested_props() {
let query = "CREATE (n:Person {address: {city: 'Beijing', street: 'Main St'}})";
let mut parser = Parser::new(query);
let _result = parser.parse();
}
#[test]
fn test_create_parse_only_string_prop() {
let query = "CREATE (n:Person {name: 'Alice'})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(result.is_ok(), "String property parsing should succeed");
}
#[test]
fn test_create_parse_only_int_prop() {
let query = "CREATE (n:Person {age: 30})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(result.is_ok(), "Integer attribute parsing should succeed");
}
#[test]
fn test_create_parse_only_float_prop() {
let query = "CREATE (n:Person {salary: 50000.50})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Floating point attribute parsing should succeed"
);
}
#[test]
fn test_create_parse_only_bool_prop() {
let query = "CREATE (n:Person {is_active: true})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(result.is_ok(), "Boolean attribute parsing should succeed");
}
#[test]
fn test_create_parse_only_mixed_props() {
let query = "CREATE (n:Person {name: 'Alice', age: 30, salary: 50000.50, is_active: true})";
let mut parser = Parser::new(query);
let result = parser.parse();
assert!(
result.is_ok(),
"Mixed type attribute parsing should succeed"
);
}
#[test]
fn test_cypher_vs_ngql_create_node() {
let cypher_query = "CREATE (n:Person {name: 'Alice', age: 30})";
let mut cypher_parser = Parser::new(cypher_query);
let cypher_result = cypher_parser.parse();
let ngql_query = "INSERT VERTEX Person(name, age) VALUES 1:('Alice', 30)";
let mut ngql_parser = Parser::new(ngql_query);
let ngql_result = ngql_parser.parse();
assert!(
cypher_result.is_ok(),
"Cypher syntax should parse successfully"
);
assert!(
ngql_result.is_ok(),
"The NGQL syntax should parse successfully"
);
}
#[test]
fn test_cypher_vs_ngql_create_edge() {
let cypher_query = "CREATE (a)-[:KNOWS {since: '2020-01-01'}]->(b)";
let mut cypher_parser = Parser::new(cypher_query);
let cypher_result = cypher_parser.parse();
let ngql_query = "INSERT EDGE KNOWS(since) VALUES 1 -> 2:('2020-01-01')";
let mut ngql_parser = Parser::new(ngql_query);
let _ = ngql_parser.parse();
assert!(
cypher_result.is_ok(),
"Cypher syntax should parse successfully"
);
}