use crate::velesql::ast::{
CompareOp, Condition, CreateCollectionKind, DdlStatement, DmlStatement, GraphSchemaMode,
SchemaDefinition, Value,
};
use crate::velesql::Parser;
#[test]
fn test_create_vector_collection_basic() {
let query = Parser::parse("CREATE COLLECTION docs (dimension = 768, metric = 'cosine');")
.expect("basic CREATE COLLECTION should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
assert_eq!(create.name, "docs");
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.dimension, 768);
assert_eq!(params.metric, "cosine");
assert!(params.storage.is_none());
assert!(params.m.is_none());
assert!(params.ef_construction.is_none());
}
#[test]
fn test_create_vector_collection_with_storage_in_body() {
let query = Parser::parse(
"CREATE COLLECTION docs (dimension = 768, metric = 'cosine', storage = 'sq8');",
)
.expect("CREATE with storage in body should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.storage.as_deref(), Some("sq8"));
}
#[test]
fn test_create_vector_collection_storage_in_with_propagated() {
let query = Parser::parse(
"CREATE COLLECTION docs (dimension = 768, metric = 'cosine') WITH (storage = 'sq8');",
)
.expect("CREATE with storage in WITH should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.storage.as_deref(), Some("sq8"));
}
#[test]
fn test_create_vector_collection_with_hnsw_params() {
let query = Parser::parse(
"CREATE COLLECTION docs (dimension = 768, metric = 'cosine') WITH (m = 16, ef_construction = 200);",
)
.expect("CREATE with HNSW params should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.m, Some(16));
assert_eq!(params.ef_construction, Some(200));
}
#[test]
fn test_create_vector_collection_metric_euclidean() {
let query = Parser::parse("CREATE COLLECTION vectors (dimension = 128, metric = 'euclidean');")
.expect("euclidean metric should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.metric, "euclidean");
}
#[test]
fn test_create_vector_collection_metric_dotproduct() {
let query =
Parser::parse("CREATE COLLECTION embeddings (dimension = 256, metric = 'dotproduct');")
.expect("dotproduct metric should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.metric, "dotproduct");
}
#[test]
fn test_create_vector_collection_without_semicolon() {
let query = Parser::parse("CREATE COLLECTION docs (dimension = 768, metric = 'cosine')")
.expect("CREATE without semicolon should parse");
assert!(query.ddl.is_some());
}
#[test]
fn test_create_vector_collection_large_dimension() {
let query = Parser::parse("CREATE COLLECTION large (dimension = 4096, metric = 'cosine');")
.expect("large dimension should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.dimension, 4096);
}
#[test]
fn test_create_graph_collection_schemaless_with_embeddings() {
let query = Parser::parse(
"CREATE GRAPH COLLECTION kg (dimension = 768, metric = 'cosine') SCHEMALESS;",
)
.expect("graph schemaless with embeddings should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
assert_eq!(create.name, "kg");
let CreateCollectionKind::Graph(params) = &create.kind else {
panic!("Expected Graph kind");
};
assert_eq!(params.dimension, Some(768));
assert_eq!(params.metric.as_deref(), Some("cosine"));
assert_eq!(params.schema_mode, GraphSchemaMode::Schemaless);
}
#[test]
fn test_create_graph_collection_schemaless_no_embeddings() {
let result = Parser::parse("CREATE GRAPH COLLECTION kg SCHEMALESS;");
if let Ok(query) = result {
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Graph(params) = &create.kind else {
panic!("Expected Graph kind");
};
assert!(params.dimension.is_none());
assert_eq!(params.schema_mode, GraphSchemaMode::Schemaless);
}
}
#[test]
fn test_create_graph_collection_typed_schema() {
let query = Parser::parse(
"CREATE GRAPH COLLECTION kg (dimension = 768, metric = 'cosine') \
WITH SCHEMA (NODE Person (name: STRING, age: INTEGER), EDGE KNOWS FROM Person TO Person);",
)
.expect("typed graph schema should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Graph(params) = &create.kind else {
panic!("Expected Graph kind");
};
let GraphSchemaMode::Typed(defs) = ¶ms.schema_mode else {
panic!("Expected Typed schema mode");
};
assert_eq!(defs.len(), 2);
let SchemaDefinition::Node { name, properties } = &defs[0] else {
panic!("Expected Node definition at index 0");
};
assert_eq!(name, "Person");
assert_eq!(properties.len(), 2);
assert_eq!(properties[0], ("name".to_string(), "STRING".to_string()));
assert_eq!(properties[1], ("age".to_string(), "INTEGER".to_string()));
let SchemaDefinition::Edge {
name,
from_type,
to_type,
} = &defs[1]
else {
panic!("Expected Edge definition at index 1");
};
assert_eq!(name, "KNOWS");
assert_eq!(from_type, "Person");
assert_eq!(to_type, "Person");
}
#[test]
fn test_create_metadata_collection_simple() {
let query = Parser::parse("CREATE METADATA COLLECTION tags;")
.expect("metadata collection should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
assert_eq!(create.name, "tags");
assert!(matches!(create.kind, CreateCollectionKind::Metadata));
}
#[test]
fn test_create_metadata_collection_without_semicolon() {
let query = Parser::parse("CREATE METADATA COLLECTION tags")
.expect("metadata without semicolon should parse");
assert!(query.ddl.is_some());
let ddl = query.ddl.expect("DDL present");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
assert_eq!(create.name, "tags");
assert!(matches!(create.kind, CreateCollectionKind::Metadata));
}
#[test]
fn test_drop_collection_simple() {
let query = Parser::parse("DROP COLLECTION docs;").expect("DROP COLLECTION should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::DropCollection(drop) = ddl else {
panic!("Expected DropCollection variant");
};
assert_eq!(drop.name, "docs");
assert!(!drop.if_exists);
}
#[test]
fn test_drop_collection_if_exists() {
let query =
Parser::parse("DROP COLLECTION IF EXISTS docs;").expect("DROP IF EXISTS should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::DropCollection(drop) = ddl else {
panic!("Expected DropCollection variant");
};
assert_eq!(drop.name, "docs");
assert!(drop.if_exists);
}
#[test]
fn test_insert_edge_basic() {
let query = Parser::parse("INSERT EDGE INTO kg (source = 1, target = 2, label = 'KNOWS');")
.expect("INSERT EDGE should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::InsertEdge(edge) = dml else {
panic!("Expected InsertEdge variant");
};
assert_eq!(edge.collection, "kg");
assert_eq!(edge.source, 1);
assert_eq!(edge.target, 2);
assert_eq!(edge.label, "KNOWS");
assert!(edge.properties.is_empty());
assert!(edge.edge_id.is_none());
}
#[test]
fn test_insert_edge_with_properties() {
let query = Parser::parse(
"INSERT EDGE INTO kg (source = 1, target = 2, label = 'KNOWS') \
WITH PROPERTIES (weight = 0.95, year = 2026);",
)
.expect("INSERT EDGE with properties should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::InsertEdge(edge) = dml else {
panic!("Expected InsertEdge variant");
};
assert_eq!(edge.collection, "kg");
assert_eq!(edge.source, 1);
assert_eq!(edge.target, 2);
assert_eq!(edge.label, "KNOWS");
assert_eq!(edge.properties.len(), 2);
let weight = edge.properties.iter().find(|(k, _)| k == "weight");
assert!(weight.is_some(), "weight property should exist");
let year = edge.properties.iter().find(|(k, _)| k == "year");
assert!(year.is_some(), "year property should exist");
}
#[test]
fn test_delete_from_single_id() {
let query = Parser::parse("DELETE FROM docs WHERE id = 42;")
.expect("DELETE FROM with single ID should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::Delete(delete) = dml else {
panic!("Expected Delete variant");
};
assert_eq!(delete.table, "docs");
let Condition::Comparison(cmp) = &delete.where_clause else {
panic!(
"Expected Comparison condition, got {:?}",
delete.where_clause
);
};
assert_eq!(cmp.column, "id");
assert_eq!(cmp.operator, CompareOp::Eq);
assert_eq!(cmp.value, Value::Integer(42));
}
#[test]
fn test_delete_from_in_clause() {
let query = Parser::parse("DELETE FROM docs WHERE id IN (1, 2, 3);")
.expect("DELETE FROM with IN clause should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::Delete(delete) = dml else {
panic!("Expected Delete variant");
};
assert_eq!(delete.table, "docs");
let Condition::In(in_cond) = &delete.where_clause else {
panic!("Expected In condition, got {:?}", delete.where_clause);
};
assert_eq!(in_cond.column, "id");
assert_eq!(in_cond.values.len(), 3);
assert!(!in_cond.negated);
}
#[test]
fn test_delete_from_string_comparison() {
let query = Parser::parse("DELETE FROM docs WHERE category = 'obsolete';")
.expect("DELETE FROM with string comparison should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::Delete(delete) = dml else {
panic!("Expected Delete variant");
};
assert_eq!(delete.table, "docs");
let Condition::Comparison(cmp) = &delete.where_clause else {
panic!("Expected Comparison condition");
};
assert_eq!(cmp.column, "category");
assert_eq!(cmp.operator, CompareOp::Eq);
assert_eq!(cmp.value, Value::String("obsolete".to_string()));
}
#[test]
fn test_delete_edge_basic() {
let query = Parser::parse("DELETE EDGE 123 FROM kg;").expect("DELETE EDGE should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::DeleteEdge(del_edge) = dml else {
panic!("Expected DeleteEdge variant");
};
assert_eq!(del_edge.collection, "kg");
assert_eq!(del_edge.edge_id, 123);
}
#[test]
fn test_create_vector_without_dimension_fails() {
let result = Parser::parse("CREATE COLLECTION docs (metric = 'cosine');");
assert!(
result.is_err(),
"CREATE COLLECTION without dimension should fail"
);
}
#[test]
fn test_create_vector_without_metric_defaults_to_cosine() {
let query = Parser::parse("CREATE COLLECTION docs (dimension = 768);")
.expect("CREATE COLLECTION without metric should succeed");
let ddl = query.ddl.expect("Expected DDL");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection");
};
let CreateCollectionKind::Vector(params) = create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.metric, "cosine", "metric should default to cosine");
assert_eq!(params.dimension, 768);
}
#[test]
fn test_create_collection_quoted_identifier() {
let query = Parser::parse("CREATE COLLECTION `my-docs` (dimension = 768, metric = 'cosine');")
.expect("quoted identifier should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
assert_eq!(create.name, "my-docs");
}
#[test]
fn test_drop_nonexistent_parses_fine() {
let query = Parser::parse("DROP COLLECTION nonexistent;")
.expect("DROP nonexistent should parse at parser level");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::DropCollection(drop) = ddl else {
panic!("Expected DropCollection variant");
};
assert_eq!(drop.name, "nonexistent");
assert!(!drop.if_exists);
}
#[test]
fn test_delete_from_without_where_fails() {
let result = Parser::parse("DELETE FROM docs;");
assert!(result.is_err(), "DELETE FROM without WHERE should fail");
}
#[test]
fn test_delete_edge_with_non_integer_fails() {
let result = Parser::parse("DELETE EDGE 'abc' FROM kg;");
assert!(
result.is_err(),
"DELETE EDGE with non-integer ID should fail"
);
}
#[test]
fn test_insert_edge_missing_source_fails() {
let result = Parser::parse("INSERT EDGE INTO kg (target = 2, label = 'KNOWS');");
assert!(result.is_err(), "INSERT EDGE without source should fail");
}
#[test]
fn test_insert_edge_missing_target_fails() {
let result = Parser::parse("INSERT EDGE INTO kg (source = 1, label = 'KNOWS');");
assert!(result.is_err(), "INSERT EDGE without target should fail");
}
#[test]
fn test_insert_edge_missing_label_fails() {
let result = Parser::parse("INSERT EDGE INTO kg (source = 1, target = 2);");
assert!(result.is_err(), "INSERT EDGE without label should fail");
}
#[test]
fn test_create_vector_empty_body_fails() {
let result = Parser::parse("CREATE COLLECTION docs;");
assert!(
result.is_err(),
"CREATE COLLECTION with no body should fail for vector (no dimension)"
);
}
#[test]
fn test_create_vector_duplicate_options() {
let result = Parser::parse(
"CREATE COLLECTION docs (dimension = 768, dimension = 512, metric = 'cosine');",
);
if let Ok(query) = result {
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.dimension, 768);
}
}
#[test]
fn test_is_ddl_query_true_for_create() {
let query = Parser::parse("CREATE COLLECTION docs (dimension = 768, metric = 'cosine');")
.expect("should parse");
assert!(query.is_ddl_query());
assert!(!query.is_select_query());
assert!(!query.is_dml_query());
assert!(!query.is_match_query());
assert!(!query.is_train());
}
#[test]
fn test_is_ddl_query_true_for_drop() {
let query = Parser::parse("DROP COLLECTION docs;").expect("should parse");
assert!(query.is_ddl_query());
assert!(!query.is_select_query());
assert!(!query.is_dml_query());
}
#[test]
fn test_is_dml_query_true_for_insert_edge() {
let query = Parser::parse("INSERT EDGE INTO kg (source = 1, target = 2, label = 'KNOWS');")
.expect("should parse");
assert!(query.is_dml_query());
assert!(!query.is_ddl_query());
assert!(!query.is_select_query());
}
#[test]
fn test_is_dml_query_true_for_delete_from() {
let query = Parser::parse("DELETE FROM docs WHERE id = 1;").expect("should parse");
assert!(query.is_dml_query());
assert!(!query.is_ddl_query());
assert!(!query.is_select_query());
}
#[test]
fn test_is_dml_query_true_for_delete_edge() {
let query = Parser::parse("DELETE EDGE 42 FROM kg;").expect("should parse");
assert!(query.is_dml_query());
assert!(!query.is_ddl_query());
assert!(!query.is_select_query());
}
#[test]
fn test_is_ddl_query_false_for_select() {
let query = Parser::parse("SELECT * FROM docs LIMIT 10").expect("should parse");
assert!(!query.is_ddl_query());
assert!(!query.is_dml_query());
assert!(query.is_select_query());
}
#[test]
fn test_ast_create_vector_all_fields() {
let query = Parser::parse(
"CREATE COLLECTION embeddings (dimension = 512, metric = 'euclidean', storage = 'pq') \
WITH (m = 32, ef_construction = 400);",
)
.expect("full vector CREATE should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
assert_eq!(create.name, "embeddings");
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.dimension, 512);
assert_eq!(params.metric, "euclidean");
assert_eq!(params.storage.as_deref(), Some("pq"));
assert_eq!(params.m, Some(32));
assert_eq!(params.ef_construction, Some(400));
}
#[test]
fn test_ast_create_graph_fields() {
let query = Parser::parse(
"CREATE GRAPH COLLECTION social (dimension = 384, metric = 'cosine') SCHEMALESS;",
)
.expect("graph CREATE should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection variant");
};
assert_eq!(create.name, "social");
let CreateCollectionKind::Graph(params) = &create.kind else {
panic!("Expected Graph kind");
};
assert_eq!(params.dimension, Some(384));
assert_eq!(params.metric.as_deref(), Some("cosine"));
assert_eq!(params.schema_mode, GraphSchemaMode::Schemaless);
}
#[test]
fn test_ast_drop_fields() {
let query =
Parser::parse("DROP COLLECTION IF EXISTS legacy;").expect("DROP IF EXISTS should parse");
let ddl = query.ddl.expect("Expected DDL statement");
let DdlStatement::DropCollection(drop) = ddl else {
panic!("Expected DropCollection variant");
};
assert_eq!(drop.name, "legacy");
assert!(drop.if_exists);
}
#[test]
fn test_ast_insert_edge_fields() {
let query = Parser::parse(
"INSERT EDGE INTO social (source = 10, target = 20, label = 'FOLLOWS') \
WITH PROPERTIES (since = 2025);",
)
.expect("INSERT EDGE with properties should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::InsertEdge(edge) = dml else {
panic!("Expected InsertEdge variant");
};
assert_eq!(edge.collection, "social");
assert_eq!(edge.source, 10);
assert_eq!(edge.target, 20);
assert_eq!(edge.label, "FOLLOWS");
assert!(edge.edge_id.is_none());
assert!(!edge.properties.is_empty());
let since = edge.properties.iter().find(|(k, _)| k == "since");
assert!(since.is_some(), "since property should exist");
}
#[test]
fn test_ast_delete_from_fields() {
let query =
Parser::parse("DELETE FROM archive WHERE id = 99;").expect("DELETE FROM should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::Delete(delete) = dml else {
panic!("Expected Delete variant");
};
assert_eq!(delete.table, "archive");
let Condition::Comparison(cmp) = &delete.where_clause else {
panic!("Expected Comparison condition");
};
assert_eq!(cmp.column, "id");
assert_eq!(cmp.operator, CompareOp::Eq);
assert_eq!(cmp.value, Value::Integer(99));
}
#[test]
fn test_ast_delete_edge_fields() {
let query =
Parser::parse("DELETE EDGE 999 FROM relationships;").expect("DELETE EDGE should parse");
let dml = query.dml.expect("Expected DML statement");
let DmlStatement::DeleteEdge(del_edge) = dml else {
panic!("Expected DeleteEdge variant");
};
assert_eq!(del_edge.collection, "relationships");
assert_eq!(del_edge.edge_id, 999);
}
#[test]
fn test_create_collection_case_insensitive_keywords() {
let query = Parser::parse("create collection test_coll (dimension = 64, metric = 'cosine');")
.expect("lowercase keywords should parse");
assert!(query.is_ddl_query());
let ddl = query.ddl.expect("Expected DDL");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection");
};
assert_eq!(create.name, "test_coll");
}
#[test]
fn test_drop_collection_case_insensitive() {
let query =
Parser::parse("drop collection IF EXISTS my_coll;").expect("mixed case DROP should parse");
assert!(query.is_ddl_query());
let ddl = query.ddl.expect("Expected DDL");
let DdlStatement::DropCollection(drop) = ddl else {
panic!("Expected DropCollection");
};
assert_eq!(drop.name, "my_coll");
assert!(drop.if_exists);
}
#[test]
fn test_insert_edge_case_insensitive() {
let query = Parser::parse("insert edge into kg (source = 5, target = 6, label = 'LINKED');")
.expect("lowercase INSERT EDGE should parse");
assert!(query.is_dml_query());
}
#[test]
fn test_delete_from_case_insensitive() {
let query = Parser::parse("delete from docs where id = 1;")
.expect("lowercase DELETE FROM should parse");
assert!(query.is_dml_query());
}
#[test]
fn test_delete_edge_case_insensitive() {
let query =
Parser::parse("delete edge 7 from kg;").expect("lowercase DELETE EDGE should parse");
assert!(query.is_dml_query());
}
#[test]
fn test_create_graph_collection_no_body() {
let result = Parser::parse("CREATE GRAPH COLLECTION kg;");
if let Ok(query) = result {
let ddl = query.ddl.expect("Expected DDL");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection");
};
assert_eq!(create.name, "kg");
let CreateCollectionKind::Graph(params) = &create.kind else {
panic!("Expected Graph kind");
};
assert!(params.dimension.is_none());
assert!(params.metric.is_none());
assert_eq!(params.schema_mode, GraphSchemaMode::Schemaless);
}
}
#[test]
fn test_insert_edge_large_ids() {
let query = Parser::parse(
"INSERT EDGE INTO kg (source = 999999999, target = 888888888, label = 'REFS');",
)
.expect("large IDs should parse");
let dml = query.dml.expect("Expected DML");
let DmlStatement::InsertEdge(edge) = dml else {
panic!("Expected InsertEdge");
};
assert_eq!(edge.source, 999_999_999);
assert_eq!(edge.target, 888_888_888);
}
#[test]
fn test_delete_edge_zero_id() {
let query = Parser::parse("DELETE EDGE 0 FROM kg;").expect("edge ID 0 should parse");
let dml = query.dml.expect("Expected DML");
let DmlStatement::DeleteEdge(del_edge) = dml else {
panic!("Expected DeleteEdge");
};
assert_eq!(del_edge.edge_id, 0);
}
#[test]
fn test_create_vector_with_all_with_options() {
let query = Parser::parse(
"CREATE COLLECTION idx (dimension = 128, metric = 'cosine') \
WITH (storage = 'binary', m = 48, ef_construction = 500);",
)
.expect("all WITH options should parse");
let ddl = query.ddl.expect("Expected DDL");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection");
};
let CreateCollectionKind::Vector(params) = &create.kind else {
panic!("Expected Vector kind");
};
assert_eq!(params.dimension, 128);
assert_eq!(params.metric, "cosine");
assert_eq!(params.m, Some(48));
assert_eq!(params.ef_construction, Some(500));
}
#[test]
fn test_drop_collection_without_semicolon() {
let query = Parser::parse("DROP COLLECTION temp").expect("DROP without semicolon should parse");
assert!(query.is_ddl_query());
let ddl = query.ddl.expect("Expected DDL");
let DdlStatement::DropCollection(drop) = ddl else {
panic!("Expected DropCollection");
};
assert_eq!(drop.name, "temp");
}
#[test]
fn test_delete_from_with_and_condition() {
let query = Parser::parse("DELETE FROM docs WHERE category = 'old' AND status = 'archived';")
.expect("DELETE with AND condition should parse");
let dml = query.dml.expect("Expected DML");
let DmlStatement::Delete(delete) = dml else {
panic!("Expected Delete");
};
assert_eq!(delete.table, "docs");
assert!(
matches!(delete.where_clause, Condition::And(_, _)),
"Expected AND condition, got {:?}",
delete.where_clause
);
}
#[test]
fn test_create_graph_typed_schema_multiple_nodes() {
let query = Parser::parse(
"CREATE GRAPH COLLECTION ontology (dimension = 768, metric = 'cosine') \
WITH SCHEMA (\
NODE Person (name: STRING, age: INTEGER), \
NODE Company (name: STRING, founded: INTEGER), \
EDGE WORKS_AT FROM Person TO Company\
);",
)
.expect("multi-node typed schema should parse");
let ddl = query.ddl.expect("Expected DDL");
let DdlStatement::CreateCollection(create) = ddl else {
panic!("Expected CreateCollection");
};
let CreateCollectionKind::Graph(params) = &create.kind else {
panic!("Expected Graph kind");
};
let GraphSchemaMode::Typed(defs) = ¶ms.schema_mode else {
panic!("Expected Typed schema mode");
};
assert_eq!(defs.len(), 3);
assert!(matches!(&defs[0], SchemaDefinition::Node { name, .. } if name == "Person"));
assert!(matches!(&defs[1], SchemaDefinition::Node { name, .. } if name == "Company"));
let SchemaDefinition::Edge {
name,
from_type,
to_type,
} = &defs[2]
else {
panic!("Expected Edge definition");
};
assert_eq!(name, "WORKS_AT");
assert_eq!(from_type, "Person");
assert_eq!(to_type, "Company");
}
#[test]
fn test_invalid_metric_rejected_at_parse_time() {
let result = Parser::parse("CREATE COLLECTION docs (dimension = 768, metric = 'manhattan');");
assert!(result.is_err(), "invalid metric should fail at parse time");
let err = result.unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("Unknown metric 'manhattan'"),
"error should name the invalid metric, got: {msg}"
);
}
#[test]
fn test_valid_metric_aliases_parse_successfully() {
for alias in &[
"cosine",
"euclidean",
"l2",
"dot",
"dotproduct",
"inner",
"ip",
"hamming",
"jaccard",
] {
let sql = format!("CREATE COLLECTION test_m (dimension = 64, metric = '{alias}');");
let result = Parser::parse(&sql);
assert!(
result.is_ok(),
"metric alias '{alias}' should parse, got: {:?}",
result.err()
);
}
}
#[test]
fn test_graph_invalid_metric_rejected_at_parse_time() {
let result = Parser::parse(
"CREATE GRAPH COLLECTION kg (dimension = 128, metric = 'badmetric') SCHEMALESS;",
);
assert!(
result.is_err(),
"invalid metric on graph collection should fail at parse time"
);
}