Skip to content

Commit

Permalink
feat(backends): implement ops.Time for sqlalchemy backends
Browse files Browse the repository at this point in the history
  • Loading branch information
cpcloud authored and kszucs committed Mar 3, 2023
1 parent 26d0dde commit 713cd33
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
1 change: 1 addition & 0 deletions ibis/backends/base/sql/alchemy/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ class array_filter(FunctionElement):
ops.ExtractHour: _extract('hour'),
ops.ExtractMinute: _extract('minute'),
ops.ExtractSecond: _extract('second'),
ops.Time: fixed_arity(lambda arg: sa.cast(arg, sa.TIME), 1),
}


Expand Down
8 changes: 8 additions & 0 deletions ibis/backends/polars/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,3 +995,11 @@ def execute_e(op, **kwargs):
@translate.register(ops.Pi)
def execute_pi(op, **kwargs):
return pl.lit(np.pi)


@translate.register(ops.Time)
def execute_time(op, **kwargs):
arg = translate(op.arg, **kwargs)
if op.arg.output_dtype.is_timestamp():
return arg.dt.truncate("1us").cast(pl.Time)
return arg
53 changes: 51 additions & 2 deletions ibis/backends/tests/test_temporal.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pandas as pd
import pandas.testing as tm
import pytest
import sqlalchemy.exc
import sqlalchemy as sa
from pytest import param

import ibis
Expand Down Expand Up @@ -938,6 +938,55 @@ def test_time_literal(con, backend):
assert con.execute(expr.typeof()) == TIME_BACKEND_TYPES[backend_name]


@pytest.mark.notyet(
["clickhouse", "impala", "pyspark"],
raises=com.OperationNotDefinedError,
reason="backend doesn't have a time datatype",
)
@pytest.mark.notyet(
["druid"],
raises=sa.exc.CompileError,
reason="druid sqlalchemy dialect fails to compile datetime types",
)
@pytest.mark.broken(
["sqlite"], raises=AssertionError, reason="SQLite returns Timedelta from execution"
)
@pytest.mark.notimpl(
["dask", "datafusion", "pandas"], raises=com.OperationNotDefinedError
)
@pytest.mark.parametrize(
"microsecond",
[
0,
param(
561021,
marks=[
pytest.mark.notimpl(
["mssql", "mysql"],
raises=AssertionError,
reason="doesn't have enough precision to capture microseconds",
),
pytest.mark.notyet(
["trino"],
raises=AssertionError,
reason="has enough precision, but sqlalchemy dialect drops them",
),
],
),
],
ids=["second", "subsecond"],
)
def test_extract_time_from_timestamp(con, microsecond):
raw_ts = datetime.datetime(2023, 1, 7, 13, 20, 5, microsecond)
ts = ibis.timestamp(raw_ts)
expr = ts.time()

result = con.execute(expr)
expected = raw_ts.time()

assert result == expected


INTERVAL_BACKEND_TYPES = {
'bigquery': "INTERVAL",
'clickhouse': 'IntervalSecond',
Expand All @@ -952,7 +1001,7 @@ def test_time_literal(con, backend):
['snowflake'],
'(snowflake.connector.errors.ProgrammingError) 001007 (22023): SQL compilation error:'
"invalid type [CAST(INTERVAL_LITERAL('second', '1') AS VARIANT)] for parameter 'TO_VARIANT'",
raises=sqlalchemy.exc.ProgrammingError,
raises=sa.exc.ProgrammingError,
)
@pytest.mark.broken(
['impala'],
Expand Down

0 comments on commit 713cd33

Please sign in to comment.