Skip to content

Commit

Permalink
fix: add workaround for NULL map bugs
Browse files Browse the repository at this point in the history
partially addresses ibis-project#8632

postgres started failing these new test too,
so had to adjust that visit_Map()
  • Loading branch information
NickCrews committed Mar 19, 2024
1 parent 3e945e9 commit bf3da0e
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 1 deletion.
6 changes: 6 additions & 0 deletions ibis/backends/duckdb/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ def visit_ArrayZip(self, op, *, arg):
any_arg_null = sg.or_(*(arr.is_(NULL) for arr in arg))
return self.if_(any_arg_null, NULL, zipped_arrays)

def visit_Map(self, op, *, keys, values):
# workaround for https://github.com/ibis-project/ibis/issues/8632
regular = self.f.map(keys, values)
either_null = sg.or_(keys.is_(NULL), values.is_(NULL))
return self.if_(either_null, NULL, regular)

def visit_MapGet(self, op, *, arg, key, default):
return self.f.ifnull(
self.f.list_extract(self.f.element_at(arg, key), 1), default
Expand Down
9 changes: 9 additions & 0 deletions ibis/backends/duckdb/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,12 @@ def test_invalid_connect(tmp_path):
url = f"duckdb://{tmp_path}?read_only=invalid_value"
with pytest.raises(ValueError):
ibis.connect(url)


@pytest.mark.xfail(
raises=duckdb.BinderException,
reason="https://github.com/ibis-project/ibis/issues/8632",
)
def test_map_null_workaround_xfail():
conn = duckdb.connect()
conn.sql("SELECT MAP([0, 1, 2], NULL::INT[]);").fetchone()
5 changes: 4 additions & 1 deletion ibis/backends/postgres/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,10 @@ def visit_ToJSONArray(self, op, *, arg):
)

def visit_Map(self, op, *, keys, values):
return self.f.map(self.f.array(*keys), self.f.array(*values))
# map(["a", "b"], NULL) results in {"a": NULL, "b": NULL} in regular postgres,
# so we need to modify it to return NULL instead
regular = self.f.map(keys, values)
return self.if_(values.is_(NULL), NULL, regular)

def visit_MapLength(self, op, *, arg):
return self.f.cardinality(self.f.akeys(arg))
Expand Down
18 changes: 18 additions & 0 deletions ibis/backends/tests/test_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@
]


@pytest.mark.notyet("clickhouse", reason="nested types can't be NULL")
@pytest.mark.broken(["pandas", "dask"], reason="TypeError: iteration over a 0-d array")
@pytest.mark.parametrize(
"kv",
[
param((["a", "b"], None), id="null_values"),
param((None, ["c", "d"]), id="null_keys"),
param((None, None), id="null_both"),
],
)
def test_map_nulls(con, kv):
k, v = kv
k = ibis.literal(k, type="array<string>")
v = ibis.literal(v, type="array<string>")
m = ibis.map(k, v)
assert con.execute(m) is None


@pytest.mark.notimpl(["pandas", "dask"])
def test_map_table(backend):
table = backend.map
Expand Down

0 comments on commit bf3da0e

Please sign in to comment.