use super::*;
use crate::ast::BinaryOp;
fn text(bytes: &[u8]) -> BoundExpr {
BoundExpr::Text(bytes.to_vec())
}
fn collate(operand: BoundExpr, collation: Collation) -> BoundExpr {
apply_collation(operand, collation)
}
fn concat(left: BoundExpr, right: BoundExpr) -> BoundExpr {
BoundExpr::Arithmetic {
op: BinaryOp::Concat,
left: Box::new(left),
right: Box::new(right),
}
}
fn column(collation: Collation) -> BoundExpr {
BoundExpr::Column {
source: 0,
column: 0,
slot: 0,
affinity: Affinity::Text,
collation,
}
}
fn compared_with(left: &BoundExpr, right: &BoundExpr) -> Collation {
comparison_rules(left, right).1
}
#[test]
fn a_collate_inside_a_concatenation_reaches_the_comparison() {
let right = concat(text(b"b"), collate(text(b""), Collation::NoCase));
assert_eq!(compared_with(&text(b"B"), &right), Collation::NoCase);
let left = concat(collate(text(b"a"), Collation::NoCase), text(b"x"));
assert_eq!(compared_with(&left, &text(b"AX")), Collation::NoCase);
}
#[test]
fn the_left_operand_with_a_collate_wins() {
let nocase_first = concat(
collate(text(b"a"), Collation::NoCase),
collate(text(b"b"), Collation::Binary),
);
assert_eq!(nocase_first.explicit_collation(), Some(Collation::NoCase));
let binary_first = concat(
collate(text(b"a"), Collation::Binary),
collate(text(b"b"), Collation::NoCase),
);
assert_eq!(binary_first.explicit_collation(), Some(Collation::Binary));
let nocase_right = concat(collate(text(b"a"), Collation::NoCase), text(b"x"));
let binary_left = collate(text(b"AX"), Collation::Binary);
assert_eq!(
compared_with(&binary_left, &nocase_right),
Collation::Binary
);
}
#[test]
fn a_column_collation_passes_through_cast_and_unary_plus_only() {
let cast = BoundExpr::Cast {
operand: Box::new(column(Collation::NoCase)),
affinity: Affinity::Text,
};
assert_eq!(cast.collation(), Some(Collation::NoCase));
let plus = BoundExpr::Unary {
op: UnaryOp::Identity,
operand: Box::new(column(Collation::NoCase)),
};
assert_eq!(plus.collation(), Some(Collation::NoCase));
let minus = BoundExpr::Unary {
op: UnaryOp::Negate,
operand: Box::new(column(Collation::NoCase)),
};
assert_eq!(minus.collation(), None);
let joined = concat(column(Collation::NoCase), text(b""));
assert_eq!(joined.collation(), None);
assert_eq!(compared_with(&joined, &text(b"A")), Collation::Binary);
}
#[test]
fn an_aggregate_reference_carries_its_arguments_collate() {
let arguments = [text(b","), collate(text(b"s"), Collation::NoCase)];
let explicit = explicit_argument_collation(&arguments);
assert_eq!(explicit, Some(Collation::NoCase));
let aggregate = BoundExpr::Aggregate {
slot: 0,
collation: explicit,
};
assert_eq!(compared_with(&aggregate, &text(b"C")), Collation::NoCase);
let window = BoundExpr::WindowRef {
slot: 0,
collation: None,
};
assert_eq!(
compared_with(&window, &column(Collation::NoCase)),
Collation::NoCase
);
assert_eq!(
explicit_argument_collation(&[column(Collation::NoCase)]),
None
);
}
#[test]
fn an_outer_collate_beats_one_inside_it() {
let inner = concat(collate(text(b"a"), Collation::NoCase), text(b"x"));
let outer = collate(inner, Collation::Binary);
assert_eq!(compared_with(&outer, &text(b"AX")), Collation::Binary);
}