fn ilike_scalar_op bool>()

in arrow-string/src/like.rs [454:495]


fn ilike_scalar_op<O: OffsetSizeTrait, F: Fn(bool) -> bool>(
    left: &GenericStringArray<O>,
    right: &str,
    op: F,
) -> Result<BooleanArray, ArrowError> {
    // If not ASCII faster to use case insensitive regex than using to_uppercase
    if right.is_ascii() && left.is_ascii() {
        if !right.contains(is_like_pattern) {
            return Ok(BooleanArray::from_unary(left, |item| {
                op(item.eq_ignore_ascii_case(right))
            }));
        } else if right.ends_with('%')
            && !right.ends_with("\\%")
            && !right[..right.len() - 1].contains(is_like_pattern)
        {
            // fast path, can use starts_with
            let start_str = &right[..right.len() - 1];
            return Ok(BooleanArray::from_unary(left, |item| {
                let end = item.len().min(start_str.len());
                let result = item.is_char_boundary(end)
                    && start_str.eq_ignore_ascii_case(&item[..end]);
                op(result)
            }));
        } else if right.starts_with('%') && !right[1..].contains(is_like_pattern) {
            // fast path, can use ends_with
            let ends_str = &right[1..];
            return Ok(BooleanArray::from_unary(left, |item| {
                let start = item.len().saturating_sub(ends_str.len());
                let result = item.is_char_boundary(start)
                    && ends_str.eq_ignore_ascii_case(&item[start..]);
                op(result)
            }));
        }
    }

    let re_pattern = replace_like_wildcards(right)?;
    let re = Regex::new(&format!("(?is)^{re_pattern}$")).map_err(|e| {
        ArrowError::ComputeError(format!("Unable to build regex from ILIKE pattern: {e}"))
    })?;

    Ok(BooleanArray::from_unary(left, |item| op(re.is_match(item))))
}