use pretty_assertions::assert_eq;
use sea_query::{tests_cfg::*, *};
use sea_query_clickhouse::*;

// ============================================================================
// DateTime functions
// ============================================================================

#[test]
fn func_to_date_time() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_date_time(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDateTime(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_date_time64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_date_time64(
                Expr::col(Char::Character),
                Expr::val(3)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDateTime64(`character`, 3) FROM `character`"#
    );
}

#[test]
fn func_to_date() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_date(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDate(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_date32() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_date32(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDate32(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_year() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_year(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toYear(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_month() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_month(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toMonth(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_day_of_month() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_day_of_month(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDayOfMonth(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_hour() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_hour(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toHour(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_minute() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_minute(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toMinute(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_second() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_second(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toSecond(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_start_of_day() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_start_of_day(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toStartOfDay(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_start_of_month() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_start_of_month(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toStartOfMonth(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_start_of_year() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_start_of_year(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toStartOfYear(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_start_of_week() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_start_of_week(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toStartOfWeek(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_start_of_hour() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_start_of_hour(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toStartOfHour(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_start_of_minute() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_start_of_minute(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toStartOfMinute(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_start_of_interval() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_start_of_interval(
                Expr::col(Char::Character),
                Expr::cust("INTERVAL 1 HOUR")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toStartOfInterval(`character`, INTERVAL 1 HOUR) FROM `character`"#
    );
}

#[test]
fn func_date_diff() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::date_diff(
                Expr::val("day"),
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT dateDiff('day', `size_w`, `size_h`) FROM `character`"#
    );
}

#[test]
fn func_date_add() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::date_add(
                Expr::val("day"),
                Expr::val(5),
                Expr::col(Char::Character)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT dateAdd('day', 5, `character`) FROM `character`"#
    );
}

#[test]
fn func_date_sub() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::date_sub(
                Expr::val("day"),
                Expr::val(5),
                Expr::col(Char::Character)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT dateSub('day', 5, `character`) FROM `character`"#
    );
}

#[test]
fn func_format_date_time() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::format_date_time(
                Expr::col(Char::Character),
                Expr::val("%Y-%m-%d")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT formatDateTime(`character`, '%Y-%m-%d') FROM `character`"#
    );
}

#[test]
fn func_parse_date_time() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::parse_date_time(
                Expr::col(Char::Character),
                Expr::val("%Y-%m-%d")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT parseDateTime(`character`, '%Y-%m-%d') FROM `character`"#
    );
}

#[test]
fn func_now() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::now())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT now()"#
    );
}

#[test]
fn func_now64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::now64())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT now64()"#
    );
}

#[test]
fn func_today() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::today())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT today()"#
    );
}

#[test]
fn func_yesterday() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::yesterday())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT yesterday()"#
    );
}

#[test]
fn func_to_unix_timestamp() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_unix_timestamp(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toUnixTimestamp(`character`) FROM `character`"#
    );
}

#[test]
fn func_from_unix_timestamp() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::from_unix_timestamp(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT fromUnixTimestamp(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_yyyymm() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_yyyymm(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toYYYYMM(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_yyyymmdd() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_yyyymmdd(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toYYYYMMDD(`character`) FROM `character`"#
    );
}

// ============================================================================
// Array functions
// ============================================================================

#[test]
fn func_array_join() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_join(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayJoin(`character`) FROM `character`"#
    );
}

#[test]
fn func_group_array() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::group_array(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT groupArray(`character`) FROM `character`"#
    );
}

#[test]
fn func_group_uniq_array() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::group_uniq_array(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT groupUniqArray(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_map() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_map(
                Expr::col(Char::Character),
                Expr::col(Char::SizeW)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayMap(`character`, `size_w`) FROM `character`"#
    );
}

#[test]
fn func_array_filter() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_filter(
                Expr::col(Char::Character),
                Expr::col(Char::SizeW)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayFilter(`character`, `size_w`) FROM `character`"#
    );
}

#[test]
fn func_array_sort() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_sort(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arraySort(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_reverse_sort() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_reverse_sort(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayReverseSort(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_reverse() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_reverse(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayReverse(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_flatten() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_flatten(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayFlatten(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_compact() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_compact(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayCompact(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_distinct() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_distinct(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayDistinct(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_concat() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_concat([
                Expr::col(Char::Character),
                Expr::col(Char::SizeW)
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayConcat(`character`, `size_w`) FROM `character`"#
    );
}

#[test]
fn func_array_slice() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_slice(
                Expr::col(Char::Character),
                Expr::val(1),
                Expr::val(10)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arraySlice(`character`, 1, 10) FROM `character`"#
    );
}

#[test]
fn func_has() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::has(Expr::col(Char::Character), Expr::val("a")))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT has(`character`, 'a') FROM `character`"#
    );
}

#[test]
fn func_has_all() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::has_all(Expr::col(Char::Character), Expr::val("a")))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT hasAll(`character`, 'a') FROM `character`"#
    );
}

#[test]
fn func_has_any() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::has_any(Expr::col(Char::Character), Expr::val("a")))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT hasAny(`character`, 'a') FROM `character`"#
    );
}

#[test]
fn func_index_of() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::index_of(Expr::col(Char::Character), Expr::val("a")))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT indexOf(`character`, 'a') FROM `character`"#
    );
}

#[test]
fn func_array_count() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_count(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayCount(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_sum() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_sum(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arraySum(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_avg() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_avg(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayAvg(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_min() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_min(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayMin(`character`) FROM `character`"#
    );
}

#[test]
fn func_array_max() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::array_max(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT arrayMax(`character`) FROM `character`"#
    );
}

#[test]
fn func_length() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::length(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT length(`character`) FROM `character`"#
    );
}

// ============================================================================
// String functions
// ============================================================================

#[test]
fn func_to_string() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_string(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toString(`character`) FROM `character`"#
    );
}

#[test]
fn func_split_by_char() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::split_by_char(
                Expr::val(","),
                Expr::col(Char::Character)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT splitByChar(',', `character`) FROM `character`"#
    );
}

#[test]
fn func_split_by_string() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::split_by_string(
                Expr::val("sep"),
                Expr::col(Char::Character)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT splitByString('sep', `character`) FROM `character`"#
    );
}

#[test]
fn func_replace_all() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::replace_all(
                Expr::col(Char::Character),
                Expr::val("old"),
                Expr::val("new")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT replaceAll(`character`, 'old', 'new') FROM `character`"#
    );
}

#[test]
fn func_replace_one() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::replace_one(
                Expr::col(Char::Character),
                Expr::val("old"),
                Expr::val("new")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT replaceOne(`character`, 'old', 'new') FROM `character`"#
    );
}

#[test]
fn func_concat() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::concat([
                Expr::col(Char::Character),
                Expr::col(Char::SizeW)
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT concat(`character`, `size_w`) FROM `character`"#
    );
}

#[test]
fn func_concat_with_separator() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::concat_with_separator(
                Expr::val(","),
                Expr::col(Char::Character),
                Expr::col(Char::SizeW)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT concatWithSeparator(',', `character`, `size_w`) FROM `character`"#
    );
}

#[test]
fn func_substring() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::substring(
                Expr::col(Char::Character),
                Expr::val(1),
                Expr::val(10)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT substring(`character`, 1, 10) FROM `character`"#
    );
}

#[test]
fn func_trim_both() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::trim_both(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT trimBoth(`character`) FROM `character`"#
    );
}

#[test]
fn func_trim_left() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::trim_left(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT trimLeft(`character`) FROM `character`"#
    );
}

#[test]
fn func_trim_right() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::trim_right(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT trimRight(`character`) FROM `character`"#
    );
}

#[test]
fn func_base64_encode() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::base64_encode(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT base64Encode(`character`) FROM `character`"#
    );
}

#[test]
fn func_base64_decode() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::base64_decode(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT base64Decode(`character`) FROM `character`"#
    );
}

#[test]
fn func_length_utf8() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::length_utf8(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT lengthUTF8(`character`) FROM `character`"#
    );
}

#[test]
fn func_reverse() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::reverse(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT reverse(`character`) FROM `character`"#
    );
}

#[test]
fn func_extract_all() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::extract_all(
                Expr::col(Char::Character),
                Expr::val("\\d+")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT extractAll(`character`, '\\d+') FROM `character`"#
    );
}

#[test]
fn func_match_func() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::match_func(
                Expr::col(Char::Character),
                Expr::val("pattern")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT match(`character`, 'pattern') FROM `character`"#
    );
}

#[test]
fn func_like_func() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::like_func(
                Expr::col(Char::Character),
                Expr::val("%test%")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT like(`character`, '%test%') FROM `character`"#
    );
}

#[test]
fn func_not_like() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::not_like(
                Expr::col(Char::Character),
                Expr::val("%test%")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT notLike(`character`, '%test%') FROM `character`"#
    );
}

#[test]
fn func_multi_search_any() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::multi_search_any(
                Expr::col(Char::Character),
                Expr::val("a")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT multiSearchAny(`character`, 'a') FROM `character`"#
    );
}

#[test]
fn func_position() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::position(
                Expr::col(Char::Character),
                Expr::val("needle")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT position(`character`, 'needle') FROM `character`"#
    );
}

// ============================================================================
// Type conversion functions
// ============================================================================

#[test]
fn func_to_uint8() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_uint8(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toUInt8(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_uint16() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_uint16(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toUInt16(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_uint32() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_uint32(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toUInt32(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_uint64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_uint64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toUInt64(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_int8() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_int8(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toInt8(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_int16() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_int16(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toInt16(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_int32() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_int32(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toInt32(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_int64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_int64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toInt64(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_float32() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_float32(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toFloat32(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_float64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_float64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toFloat64(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_decimal32() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_decimal32(
                Expr::col(Char::Character),
                Expr::val(2)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDecimal32(`character`, 2) FROM `character`"#
    );
}

#[test]
fn func_to_decimal64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_decimal64(
                Expr::col(Char::Character),
                Expr::val(3)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDecimal64(`character`, 3) FROM `character`"#
    );
}

#[test]
fn func_to_decimal128() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_decimal128(
                Expr::col(Char::Character),
                Expr::val(4)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toDecimal128(`character`, 4) FROM `character`"#
    );
}

#[test]
fn func_to_fixed_string() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_fixed_string(
                Expr::col(Char::Character),
                Expr::val(10)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toFixedString(`character`, 10) FROM `character`"#
    );
}

#[test]
fn func_to_uuid() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_uuid(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toUUID(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_ipv4() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_ipv4(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toIPv4(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_ipv6() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_ipv6(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toIPv6(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_type_name() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_type_name(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toTypeName(`character`) FROM `character`"#
    );
}

#[test]
fn func_reinterpret_as_string() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::reinterpret_as_string(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT reinterpretAsString(`character`) FROM `character`"#
    );
}

#[test]
fn func_reinterpret_as_uint64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::reinterpret_as_uint64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT reinterpretAsUInt64(`character`) FROM `character`"#
    );
}

#[test]
fn func_cast() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::cast(
                Expr::col(Char::Character),
                Expr::val("String")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT CAST(`character`, 'String') FROM `character`"#
    );
}

// ============================================================================
// Hash functions
// ============================================================================

#[test]
fn func_sip_hash64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::sip_hash64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT sipHash64(`character`) FROM `character`"#
    );
}

#[test]
fn func_sip_hash128() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::sip_hash128(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT sipHash128(`character`) FROM `character`"#
    );
}

#[test]
fn func_city_hash64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::city_hash64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT cityHash64(`character`) FROM `character`"#
    );
}

#[test]
fn func_xx_hash64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::xx_hash64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT xxHash64(`character`) FROM `character`"#
    );
}

#[test]
fn func_murmur3_64() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::murmur3_64(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT murmurHash3_64(`character`) FROM `character`"#
    );
}

#[test]
fn func_md5_ch() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::md5(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT MD5(`character`) FROM `character`"#
    );
}

#[test]
fn func_sha256() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::sha256(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT SHA256(`character`) FROM `character`"#
    );
}

#[test]
fn func_half_md5() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::half_md5(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT halfMD5(`character`) FROM `character`"#
    );
}

// ============================================================================
// Aggregate functions
// ============================================================================

#[test]
fn func_uniq() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::uniq(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT uniq(`character`) FROM `character`"#
    );
}

#[test]
fn func_uniq_exact() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::uniq_exact(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT uniqExact(`character`) FROM `character`"#
    );
}

#[test]
fn func_uniq_combined() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::uniq_combined(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT uniqCombined(`character`) FROM `character`"#
    );
}

#[test]
fn func_uniq_hll12() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::uniq_hll12(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT uniqHLL12(`character`) FROM `character`"#
    );
}

#[test]
fn func_arg_min() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::arg_min(
                Expr::col(Char::Character),
                Expr::col(Char::SizeW)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT argMin(`character`, `size_w`) FROM `character`"#
    );
}

#[test]
fn func_arg_max() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::arg_max(
                Expr::col(Char::Character),
                Expr::col(Char::SizeW)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT argMax(`character`, `size_w`) FROM `character`"#
    );
}

#[test]
fn func_quantile() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::quantile(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT quantile(`character`) FROM `character`"#
    );
}

#[test]
fn func_quantile_exact() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::quantile_exact(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT quantileExact(`character`) FROM `character`"#
    );
}

#[test]
fn func_quantiles() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::quantiles([Expr::val(0.5), Expr::val(0.9)]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT quantiles(0.5, 0.9) FROM `character`"#
    );
}

#[test]
fn func_top_k() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::top_k(Expr::val(10)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT topK(10) FROM `character`"#
    );
}

#[test]
fn func_sum_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::sum_if(
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH).gt(10)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT sumIf(`size_w`, `size_h` > 10) FROM `character`"#
    );
}

#[test]
fn func_count_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::count_if(Expr::col(Char::SizeW).gt(5)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT countIf(`size_w` > 5) FROM `character`"#
    );
}

#[test]
fn func_avg_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::avg_if(
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH).gt(10)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT avgIf(`size_w`, `size_h` > 10) FROM `character`"#
    );
}

#[test]
fn func_min_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::min_if(
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH).gt(10)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT minIf(`size_w`, `size_h` > 10) FROM `character`"#
    );
}

#[test]
fn func_max_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::max_if(
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH).gt(10)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT maxIf(`size_w`, `size_h` > 10) FROM `character`"#
    );
}

#[test]
fn func_any_func() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::any_func(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT any(`character`) FROM `character`"#
    );
}

#[test]
fn func_any_last() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::any_last(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT anyLast(`character`) FROM `character`"#
    );
}

#[test]
fn func_group_bit_and() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::group_bit_and(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT groupBitAnd(`character`) FROM `character`"#
    );
}

#[test]
fn func_group_bit_or() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::group_bit_or(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT groupBitOr(`character`) FROM `character`"#
    );
}

#[test]
fn func_group_bit_xor() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::group_bit_xor(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT groupBitXor(`character`) FROM `character`"#
    );
}

#[test]
fn func_median() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::median(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT median(`character`) FROM `character`"#
    );
}

// ============================================================================
// Conditional functions
// ============================================================================

#[test]
fn func_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::r#if(
                Expr::col(Char::SizeW).gt(10),
                Expr::val("big"),
                Expr::val("small")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT if(`size_w` > 10, 'big', 'small') FROM `character`"#
    );
}

#[test]
fn func_multi_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::multi_if([
                Expr::col(Char::SizeW).gt(10),
                Expr::val("big"),
                Expr::col(Char::SizeW).gt(5),
                Expr::val("medium"),
                Expr::val("small"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT multiIf(`size_w` > 10, 'big', `size_w` > 5, 'medium', 'small') FROM `character`"#
    );
}

// ============================================================================
// URL functions
// ============================================================================

#[test]
fn func_domain() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::domain(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT domain(`character`) FROM `character`"#
    );
}

#[test]
fn func_top_level_domain() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::top_level_domain(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT topLevelDomain(`character`) FROM `character`"#
    );
}

#[test]
fn func_path() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::path(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT path(`character`) FROM `character`"#
    );
}

#[test]
fn func_protocol() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::protocol(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT protocol(`character`) FROM `character`"#
    );
}

#[test]
fn func_extract_url_parameter() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::extract_url_parameter(
                Expr::col(Char::Character),
                Expr::val("id")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT extractURLParameter(`character`, 'id') FROM `character`"#
    );
}

// ============================================================================
// JSON functions
// ============================================================================

#[test]
fn func_json_extract() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_extract([
                Expr::col(Char::Character),
                Expr::val("key"),
                Expr::val("String"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONExtract(`character`, 'key', 'String') FROM `character`"#
    );
}

#[test]
fn func_json_extract_string() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_extract_string([
                Expr::col(Char::Character),
                Expr::val("key"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONExtractString(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_extract_uint() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_extract_uint([
                Expr::col(Char::Character),
                Expr::val("key"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONExtractUInt(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_extract_int() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_extract_int([
                Expr::col(Char::Character),
                Expr::val("key"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONExtractInt(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_extract_float() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_extract_float([
                Expr::col(Char::Character),
                Expr::val("key"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONExtractFloat(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_extract_bool() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_extract_bool([
                Expr::col(Char::Character),
                Expr::val("key"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONExtractBool(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_extract_array_raw() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_extract_array_raw([
                Expr::col(Char::Character),
                Expr::val("key"),
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONExtractArrayRaw(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_has() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_has([
                Expr::col(Char::Character),
                Expr::val("key")
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONHas(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_length() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_length([
                Expr::col(Char::Character),
                Expr::val("key")
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONLength(`character`, 'key') FROM `character`"#
    );
}

#[test]
fn func_json_type() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::json_type([
                Expr::col(Char::Character),
                Expr::val("key")
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT JSONType(`character`, 'key') FROM `character`"#
    );
}

// ============================================================================
// Math functions
// ============================================================================

#[test]
fn func_exp() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::exp(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT exp(`character`) FROM `character`"#
    );
}

#[test]
fn func_log() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::log(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT log(`character`) FROM `character`"#
    );
}

#[test]
fn func_log2() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::log2(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT log2(`character`) FROM `character`"#
    );
}

#[test]
fn func_log10() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::log10(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT log10(`character`) FROM `character`"#
    );
}

#[test]
fn func_sqrt() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::sqrt(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT sqrt(`character`) FROM `character`"#
    );
}

#[test]
fn func_cbrt() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::cbrt(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT cbrt(`character`) FROM `character`"#
    );
}

#[test]
fn func_power() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::power(Expr::col(Char::SizeW), Expr::val(2)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT power(`size_w`, 2) FROM `character`"#
    );
}

#[test]
fn func_int_div() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::int_div(
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT intDiv(`size_w`, `size_h`) FROM `character`"#
    );
}

#[test]
fn func_int_div_or_zero() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::int_div_or_zero(
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT intDivOrZero(`size_w`, `size_h`) FROM `character`"#
    );
}

#[test]
fn func_modulo_or_zero() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::modulo_or_zero(
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT moduloOrZero(`size_w`, `size_h`) FROM `character`"#
    );
}

// ============================================================================
// Null functions
// ============================================================================

#[test]
fn func_is_null() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::is_null(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT isNull(`character`) FROM `character`"#
    );
}

#[test]
fn func_is_not_null() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::is_not_null(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT isNotNull(`character`) FROM `character`"#
    );
}

#[test]
fn func_if_null() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::if_null(
                Expr::col(Char::Character),
                Expr::val("default")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT ifNull(`character`, 'default') FROM `character`"#
    );
}

#[test]
fn func_null_if() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::null_if(Expr::col(Char::Character), Expr::val("")))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT nullIf(`character`, '') FROM `character`"#
    );
}

#[test]
fn func_assume_not_null() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::assume_not_null(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT assumeNotNull(`character`) FROM `character`"#
    );
}

#[test]
fn func_to_nullable() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::to_nullable(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT toNullable(`character`) FROM `character`"#
    );
}

// ============================================================================
// Other functions
// ============================================================================

#[test]
fn func_generate_uuid_v4() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::generate_uuid_v4())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT generateUUIDv4()"#
    );
}

#[test]
fn func_running_difference() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::running_difference(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT runningDifference(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_neighbor() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::neighbor(Expr::col(Char::Character), Expr::val(1)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT neighbor(`character`, 1) FROM `character`"#
    );
}

#[test]
fn func_row_number_in_all_blocks() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::row_number_in_all_blocks())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT rowNumberInAllBlocks()"#
    );
}

#[test]
fn func_version() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::version())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT version()"#
    );
}

#[test]
fn func_uptime() {
    assert_eq!(
        Query::select()
            .expr(ChFunc::uptime())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT uptime()"#
    );
}

// ============================================================================
// sea-query built-in Func tests
// ============================================================================

#[test]
fn func_sea_max() {
    assert_eq!(
        Query::select()
            .expr(Func::max(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT MAX(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_min() {
    assert_eq!(
        Query::select()
            .expr(Func::min(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT MIN(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_sum() {
    assert_eq!(
        Query::select()
            .expr(Func::sum(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT SUM(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_avg() {
    assert_eq!(
        Query::select()
            .expr(Func::avg(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT AVG(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_abs() {
    assert_eq!(
        Query::select()
            .expr(Func::abs(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT ABS(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_count() {
    assert_eq!(
        Query::select()
            .expr(Func::count(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT COUNT(`character`) FROM `character`"#
    );
}

#[test]
fn func_sea_count_distinct() {
    assert_eq!(
        Query::select()
            .expr(Func::count_distinct(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT COUNT(DISTINCT `character`) FROM `character`"#
    );
}

#[test]
fn func_sea_char_length() {
    assert_eq!(
        Query::select()
            .expr(Func::char_length(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT CHAR_LENGTH(`character`) FROM `character`"#
    );
}

#[test]
fn func_sea_greatest() {
    assert_eq!(
        Query::select()
            .expr(Func::greatest([
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH)
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT GREATEST(`size_w`, `size_h`) FROM `character`"#
    );
}

#[test]
fn func_sea_least() {
    assert_eq!(
        Query::select()
            .expr(Func::least([
                Expr::col(Char::SizeW),
                Expr::col(Char::SizeH)
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT LEAST(`size_w`, `size_h`) FROM `character`"#
    );
}

#[test]
fn func_sea_if_null() {
    assert_eq!(
        Query::select()
            .expr(Func::if_null(
                Expr::col(Char::Character),
                Expr::val("default")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT ifNull(`character`, 'default') FROM `character`"#
    );
}

#[test]
fn func_sea_cast_as() {
    assert_eq!(
        Query::select()
            .expr(Func::cast_as(
                Expr::col(Char::Character),
                Alias::new("String")
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT CAST(`character` AS String) FROM `character`"#
    );
}

#[test]
fn func_sea_coalesce() {
    assert_eq!(
        Query::select()
            .expr(Func::coalesce([
                Expr::col(Char::Character),
                Expr::val("default")
            ]))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT COALESCE(`character`, 'default') FROM `character`"#
    );
}

#[test]
fn func_sea_lower() {
    assert_eq!(
        Query::select()
            .expr(Func::lower(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT LOWER(`character`) FROM `character`"#
    );
}

#[test]
fn func_sea_upper() {
    assert_eq!(
        Query::select()
            .expr(Func::upper(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT UPPER(`character`) FROM `character`"#
    );
}

#[test]
fn func_sea_bit_and() {
    assert_eq!(
        Query::select()
            .expr(Func::bit_and(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT groupBitAnd(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_bit_or() {
    assert_eq!(
        Query::select()
            .expr(Func::bit_or(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT groupBitOr(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_round() {
    assert_eq!(
        Query::select()
            .expr(Func::round(Expr::col(Char::SizeW)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT ROUND(`size_w`) FROM `character`"#
    );
}

#[test]
fn func_sea_round_with_precision() {
    assert_eq!(
        Query::select()
            .expr(Func::round_with_precision(
                Expr::col(Char::SizeW),
                Expr::val(2)
            ))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT ROUND(`size_w`, 2) FROM `character`"#
    );
}

#[test]
fn func_sea_random() {
    assert_eq!(
        Query::select()
            .expr(Func::random())
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT rand()"#
    );
}

#[test]
fn func_sea_md5() {
    assert_eq!(
        Query::select()
            .expr(Func::md5(Expr::col(Char::Character)))
            .from(Char::Table)
            .to_string(ClickhouseQueryBuilder),
        r#"SELECT MD5(`character`) FROM `character`"#
    );
}
