use crate::velesql::{Condition, Parser};
#[test]
fn test_match_basic() {
let query = Parser::parse("SELECT * FROM docs WHERE content MATCH 'database' LIMIT 10")
.expect("basic MATCH should parse");
assert!(
query.select.where_clause.is_some(),
"WHERE clause must be present"
);
match query.select.where_clause.as_ref() {
Some(Condition::Match(m)) => {
assert_eq!(m.column, "content");
assert_eq!(m.query, "database");
}
other => panic!("Expected Match condition, got {other:?}"),
}
assert_eq!(query.select.limit, Some(10));
}
#[test]
fn test_match_with_vector_near_hybrid() {
let sql = "SELECT * FROM docs WHERE vector NEAR $v AND content MATCH 'vector' LIMIT 10";
let query = Parser::parse(sql).expect("hybrid MATCH + NEAR should parse");
match query.select.where_clause.as_ref() {
Some(Condition::And(left, right)) => {
assert!(
matches!(left.as_ref(), Condition::VectorSearch(_)),
"Left should be VectorSearch, got {left:?}"
);
assert!(
matches!(right.as_ref(), Condition::Match(_)),
"Right should be Match, got {right:?}"
);
}
other => panic!("Expected AND(VectorSearch, Match), got {other:?}"),
}
}
#[test]
fn test_match_with_multiple_and_conditions() {
let sql = "SELECT * FROM docs WHERE vector NEAR $v AND title MATCH 'AI' AND category = 'tech' LIMIT 10";
let query = Parser::parse(sql).expect("MATCH with multiple ANDs should parse");
assert!(query.select.where_clause.is_some());
assert_eq!(query.select.limit, Some(10));
assert!(
matches!(query.select.where_clause, Some(Condition::And(_, _))),
"Root condition should be AND"
);
}
#[test]
fn test_match_on_different_column() {
let query = Parser::parse("SELECT * FROM docs WHERE title MATCH 'neural network' LIMIT 5")
.expect("MATCH on title column should parse");
match query.select.where_clause.as_ref() {
Some(Condition::Match(m)) => {
assert_eq!(m.column, "title");
assert_eq!(m.query, "neural network");
}
other => panic!("Expected Match condition, got {other:?}"),
}
assert_eq!(query.select.limit, Some(5));
}
#[test]
fn test_match_with_order_by_similarity() {
let sql = "SELECT * FROM docs WHERE content MATCH 'search' ORDER BY similarity() DESC LIMIT 10";
let query = Parser::parse(sql).expect("MATCH + ORDER BY similarity() should parse");
assert!(
query.select.where_clause.is_some(),
"WHERE clause must be present"
);
assert!(
query.select.order_by.is_some(),
"ORDER BY clause must be present"
);
assert_eq!(query.select.limit, Some(10));
}
#[test]
fn test_match_with_limit_and_offset() {
let sql = "SELECT * FROM docs WHERE content MATCH 'test' LIMIT 10 OFFSET 20";
let query = Parser::parse(sql).expect("MATCH + LIMIT + OFFSET should parse");
assert!(query.select.where_clause.is_some());
assert_eq!(query.select.limit, Some(10));
assert_eq!(query.select.offset, Some(20));
}
#[test]
fn test_match_with_with_clause() {
let sql = "SELECT * FROM docs WHERE content MATCH 'query' LIMIT 5 WITH (mode = 'accurate')";
let query = Parser::parse(sql).expect("MATCH + WITH clause should parse");
assert!(query.select.where_clause.is_some());
assert_eq!(query.select.limit, Some(5));
let with_clause = query
.select
.with_clause
.as_ref()
.expect("WITH clause should be present");
assert!(
!with_clause.options.is_empty(),
"WITH clause must have options"
);
assert_eq!(
with_clause.get_mode(),
Some("accurate"),
"mode should be 'accurate'"
);
}
#[test]
fn test_match_single_character_query() {
let query = Parser::parse("SELECT * FROM docs WHERE content MATCH 'a' LIMIT 10")
.expect("MATCH with single-char query should parse");
match query.select.where_clause.as_ref() {
Some(Condition::Match(m)) => {
assert_eq!(m.query, "a");
}
other => panic!("Expected Match condition, got {other:?}"),
}
}
#[test]
fn test_match_special_characters() {
let query = Parser::parse("SELECT * FROM docs WHERE content MATCH 'C++' LIMIT 10")
.expect("MATCH with special chars should parse");
match query.select.where_clause.as_ref() {
Some(Condition::Match(m)) => {
assert_eq!(m.query, "C++");
}
other => panic!("Expected Match condition, got {other:?}"),
}
}
#[test]
fn test_match_combined_with_or() {
let sql = "SELECT * FROM docs WHERE content MATCH 'database' OR category = 'tech' LIMIT 10";
let query = Parser::parse(sql).expect("MATCH + OR should parse");
match query.select.where_clause.as_ref() {
Some(Condition::Or(left, right)) => {
assert!(
matches!(left.as_ref(), Condition::Match(_)),
"Left should be Match, got {left:?}"
);
assert!(
matches!(right.as_ref(), Condition::Comparison(_)),
"Right should be Comparison, got {right:?}"
);
}
other => panic!("Expected OR(Match, Comparison), got {other:?}"),
}
}
#[test]
fn test_match_combined_with_not() {
let sql = "SELECT * FROM docs WHERE content MATCH 'AI' AND NOT (category = 'spam') LIMIT 10";
let query = Parser::parse(sql).expect("MATCH + AND NOT should parse");
match query.select.where_clause.as_ref() {
Some(Condition::And(left, right)) => {
assert!(
matches!(left.as_ref(), Condition::Match(_)),
"Left should be Match, got {left:?}"
);
assert!(
matches!(right.as_ref(), Condition::Not(_)),
"Right should be Not, got {right:?}"
);
}
other => panic!("Expected AND(Match, Not), got {other:?}"),
}
}
#[test]
fn test_match_without_string_value_fails() {
let result = Parser::parse("SELECT * FROM docs WHERE content MATCH 123 LIMIT 10");
assert!(
result.is_err(),
"MATCH with integer value should fail to parse"
);
}
#[test]
fn test_match_without_column_fails() {
let result = Parser::parse("SELECT * FROM docs WHERE MATCH 'test' LIMIT 10");
assert!(
result.is_err(),
"MATCH without column name should fail to parse"
);
}