From 1caf6dea3bafc6cc100cb10936db75546cf0d87e Mon Sep 17 00:00:00 2001 From: Mark Needham Date: Thu, 29 Feb 2024 16:36:45 +0000 Subject: [PATCH] fix(clickhouse): make arrays non nullable (#8501) --- .../clickhouse/tests/test_datatypes.py | 19 ++++++++++++++++++- ibis/backends/sql/datatypes.py | 2 +- ibis/backends/tests/test_array.py | 8 ++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/ibis/backends/clickhouse/tests/test_datatypes.py b/ibis/backends/clickhouse/tests/test_datatypes.py index ae85290cde98..b784ceb224ef 100644 --- a/ibis/backends/clickhouse/tests/test_datatypes.py +++ b/ibis/backends/clickhouse/tests/test_datatypes.py @@ -3,6 +3,7 @@ import hypothesis as h import hypothesis.strategies as st import pytest +import sqlglot.expressions as sge from pytest import param import ibis @@ -278,7 +279,7 @@ def test_parse_type(ch_type, ibis_type): | its.date_dtype() | its.time_dtype() | its.timestamp_dtype(scale=st.integers(0, 9)) - | its.array_dtypes(roundtrippable_types) + | its.array_dtypes(roundtrippable_types, nullable=false) | its.map_dtypes(map_key_types, roundtrippable_types, nullable=false) ) ) @@ -289,3 +290,19 @@ def test_type_roundtrip(ibis_type): type_string = ClickHouseType.to_string(ibis_type) parsed_ibis_type = ClickHouseType.from_string(type_string) assert parsed_ibis_type == ibis_type + + +def test_arrays_nullable(): + # if dtype.nullable and not (dtype.is_map() or dtype.is_array()): + sge_type = ClickHouseType.from_ibis(dt.Array("float")) + typecode = sge.DataType.Type + + assert sge_type == sge.DataType( + this=typecode.ARRAY, + expressions=[ + sge.DataType( + this=typecode.NULLABLE, expressions=[sge.DataType(this=typecode.DOUBLE)] + ) + ], + nested=True, + ) diff --git a/ibis/backends/sql/datatypes.py b/ibis/backends/sql/datatypes.py index 9fe2f6f72ef9..6b8687513849 100644 --- a/ibis/backends/sql/datatypes.py +++ b/ibis/backends/sql/datatypes.py @@ -966,7 +966,7 @@ class ClickHouseType(SqlglotType): def from_ibis(cls, dtype: dt.DataType) -> sge.DataType: """Convert a sqlglot type to an ibis type.""" typ = super().from_ibis(dtype) - if dtype.nullable and not dtype.is_map(): + if dtype.nullable and not (dtype.is_map() or dtype.is_array()): # map cannot be nullable in clickhouse return sge.DataType(this=typecode.NULLABLE, expressions=[typ]) else: diff --git a/ibis/backends/tests/test_array.py b/ibis/backends/tests/test_array.py index 584c4ac3e60f..156c31bda8d5 100644 --- a/ibis/backends/tests/test_array.py +++ b/ibis/backends/tests/test_array.py @@ -938,8 +938,8 @@ def flatten_data(): marks=[ pytest.mark.notyet( ["clickhouse"], - reason="doesn't support nullable array elements", - raises=ClickHouseDatabaseError, + reason="Arrays are never nullable", + raises=AssertionError, ) ], ), @@ -950,8 +950,8 @@ def flatten_data(): marks=[ pytest.mark.notyet( ["clickhouse"], - reason="doesn't support nullable array elements", - raises=ClickHouseDatabaseError, + reason="Arrays are never nullable", + raises=AssertionError, ) ], ),