From 05f5ae541d73dc27b02e6050b1f196eda102859f Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Mon, 30 Jan 2023 16:22:25 +0100 Subject: [PATCH] feat(clickhouse): implement ops.TimestampFromYMDHMS, ops.DateFromYMD --- ibis/backends/clickhouse/compiler/values.py | 38 +++++++++++++++++++++ ibis/backends/tests/test_generic.py | 5 +-- ibis/backends/tests/test_temporal.py | 8 ++--- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/ibis/backends/clickhouse/compiler/values.py b/ibis/backends/clickhouse/compiler/values.py index 24a76909babd..020a3ea9cb8c 100644 --- a/ibis/backends/clickhouse/compiler/values.py +++ b/ibis/backends/clickhouse/compiler/values.py @@ -561,6 +561,44 @@ def _truncate(op, **kw): return f"{converter}({arg})" +@translate_val.register(ops.DateFromYMD) +def _date_from_ymd(op, **kw): + y = translate_val(op.year, **kw) + m = translate_val(op.month, **kw) + d = translate_val(op.day, **kw) + return ( + f"toDate(concat(" + f"toString({y}), '-', " + f"leftPad(toString({m}), 2, '0'), '-', " + f"leftPad(toString({d}), 2, '0')" + f"))" + ) + + +@translate_val.register(ops.TimestampFromYMDHMS) +def _timestamp_from_ymdhms(op, **kw): + y = translate_val(op.year, **kw) + m = translate_val(op.month, **kw) + d = translate_val(op.day, **kw) + h = translate_val(op.hours, **kw) + min = translate_val(op.minutes, **kw) + s = translate_val(op.seconds, **kw) + timezone_arg = '' + if timezone := op.output_dtype.timezone: + timezone_arg = f', {timezone}' + + return ( + f"toDateTime(" + f"concat(toString({y}), '-', " + f"leftPad(toString({m}), 2, '0'), '-', " + f"leftPad(toString({d}), 2, '0'), ' ', " + f"leftPad(toString({h}), 2, '0'), ':', " + f"leftPad(toString({min}), 2, '0'), ':', " + f"leftPad(toString({s}), 2, '0')" + f"), {timezone_arg})" + ) + + @translate_val.register(ops.ExistsSubquery) @translate_val.register(ops.NotExistsSubquery) def _exists_subquery(op, **kw): diff --git a/ibis/backends/tests/test_generic.py b/ibis/backends/tests/test_generic.py index bc35d33c4856..8519e80227ff 100644 --- a/ibis/backends/tests/test_generic.py +++ b/ibis/backends/tests/test_generic.py @@ -1044,9 +1044,10 @@ def test_exists(batting, awards_players, method_name): id="binary", ), param( - ibis.date(12, 12, 12), + ibis.date(2022, 12, 12), { 'bigquery': "DATE", + 'clickhouse': 'Date', 'snowflake': 'DATE', 'sqlite': "text", 'trino': 'date', @@ -1055,7 +1056,7 @@ def test_exists(batting, awards_players, method_name): }, marks=[ pytest.mark.broken( - ['clickhouse', 'impala'], + ['impala'], "No translation rule for ", raises=com.OperationNotDefinedError, ), diff --git a/ibis/backends/tests/test_temporal.py b/ibis/backends/tests/test_temporal.py index 828fb28c3056..538446b09b4e 100644 --- a/ibis/backends/tests/test_temporal.py +++ b/ibis/backends/tests/test_temporal.py @@ -773,7 +773,7 @@ def test_now_from_projection(alltypes): @pytest.mark.notimpl(["pandas", "datafusion", "mysql", "dask", "pyspark"]) -@pytest.mark.notyet(["clickhouse", "impala"]) +@pytest.mark.notyet(["impala"]) def test_date_literal(con): expr = ibis.date(2022, 2, 4) result = con.execute(expr) @@ -781,7 +781,7 @@ def test_date_literal(con): @pytest.mark.notimpl(["pandas", "datafusion", "mysql", "dask", "pyspark"]) -@pytest.mark.notyet(["clickhouse", "impala"]) +@pytest.mark.notyet(["impala"]) def test_timestamp_literal(con): expr = ibis.timestamp(2022, 2, 4, 16, 20, 0) result = con.execute(expr) @@ -810,7 +810,7 @@ def test_time_literal(con): @pytest.mark.notimpl(["pandas", "datafusion", "mysql", "dask", "pyspark"]) -@pytest.mark.notyet(["clickhouse", "impala"]) +@pytest.mark.notyet(["impala"]) def test_date_column_from_ymd(con, alltypes, df): c = alltypes.timestamp_col expr = ibis.date(c.year(), c.month(), c.day()) @@ -824,7 +824,7 @@ def test_date_column_from_ymd(con, alltypes, df): @pytest.mark.notimpl(["pandas", "datafusion", "mysql", "dask", "pyspark"]) -@pytest.mark.notyet(["clickhouse", "impala"]) +@pytest.mark.notyet(["impala"]) def test_timestamp_column_from_ymdhms(con, alltypes, df): c = alltypes.timestamp_col expr = ibis.timestamp(