Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/mountainash_data/backends/ibis/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,9 @@ def table(self, name: str, *, database: str | None = None) -> t.Any:
def table_exists(
self, name: str, database: str | None = None
) -> bool:
tables = self.list_tables()
return name in tables
# ibis exposes no native table_exists; scope the membership check to the
# requested namespace by forwarding database= through list_tables (DEBT-9).
return name in self.list_tables(namespace=database)

def run_sql(
self,
Expand Down
39 changes: 39 additions & 0 deletions tests/test_unit/backends/ibis/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,45 @@ def test_table_exists_returns_bool():
assert backend.table_exists("t") is True


def test_table_exists_honors_database_namespace():
"""table_exists(database=...) must scope the check to that namespace (DEBT-9).

A table living only in a non-default schema must be found via ``database=``
and must NOT be found in the default namespace, and vice versa.
"""
with IbisBackend(dialect="duckdb", database=":memory:") as backend:
raw = backend.ibis_connection()
raw.raw_sql("CREATE SCHEMA tenant_a")
raw.raw_sql("CREATE TABLE tenant_a.sleep (id INTEGER)")
raw.raw_sql("CREATE TABLE main_only (id INTEGER)")

# Table exists only in tenant_a.
assert backend.table_exists("sleep", database="tenant_a") is True
assert backend.table_exists("sleep") is False
# Table exists only in the default namespace.
assert backend.table_exists("main_only") is True
assert backend.table_exists("main_only", database="tenant_a") is False


def test_table_exists_forwards_database_to_introspection(monkeypatch):
"""The ``database`` arg must reach the introspection call, not be dropped.

Guards the swallowed-error path: ``IbisConnection.list_tables`` returns ``[]``
on failure, so a test asserting only a bool return can pass on a version that
never forwards ``database``. Assert the forwarding directly.
"""
with IbisBackend(dialect="sqlite", database=":memory:") as backend:
seen: dict[str, str | None] = {}

def fake_list_tables(namespace=None):
seen["namespace"] = namespace
return ["sleep"]

monkeypatch.setattr(backend, "list_tables", fake_list_tables)
assert backend.table_exists("sleep", database="tenant_a") is True
assert seen == {"namespace": "tenant_a"}


def test_fluent_chaining():
"""Multiple fluent calls can be chained."""
with IbisBackend(dialect="sqlite", database=":memory:") as backend:
Expand Down
Loading