Skip to content

Commit 96d9f47

Browse files
kesmit13claude
andcommitted
Move table-specific methods from backend to table mixin
- Update _get_table_backend_and_db() to always return resolved database name with optional escape parameter ('identifier', 'literal', or None) - Move optimize_table() implementation to TableExtensionsMixin.optimize() - Move get_table_stats() implementation to TableExtensionsMixin.get_stats() - Simplify get_column_statistics() to use new escape parameter - Remove optimize_table() and get_table_stats() from BackendExtensionsMixin - Update __init__.py docstring to remove backend method reference Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b53da23 commit 96d9f47

File tree

2 files changed

+37
-57
lines changed

2 files changed

+37
-57
lines changed

singlestoredb/ibis_extras/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
>>> # Backend methods
1919
>>> con.get_storage_info()
2020
>>> con.get_workload_metrics()
21-
>>> con.optimize_table("users")
2221
>>>
2322
>>> # Table methods (work on any table from SingleStoreDB)
2423
>>> t = con.table("users")

singlestoredb/ibis_extras/mixins.py

Lines changed: 37 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import annotations
33

44
from typing import Any
5+
from typing import Literal
56
from typing import Protocol
67
from typing import TYPE_CHECKING
78

@@ -48,11 +49,29 @@ def _escape_string_literal(value: str) -> str:
4849

4950
def _get_table_backend_and_db(
5051
table: ir.Table,
51-
) -> tuple[BackendExtensionsMixin, str | None]:
52-
"""Get SingleStoreDB backend and database from table."""
52+
*,
53+
escape: Literal['identifier', 'literal'] | None = None,
54+
) -> tuple[BackendExtensionsMixin, str]:
55+
"""Get SingleStoreDB backend and database from table.
56+
57+
Parameters
58+
----------
59+
table
60+
The Ibis table object.
61+
escape
62+
How to escape the database name:
63+
- None: return unescaped
64+
- 'identifier': escape for SQL identifiers (backticks)
65+
- 'literal': escape for string literals (quotes)
66+
"""
5367
op = table.op()
5468
if hasattr(op, 'source') and op.source.name == 'singlestoredb':
5569
db = getattr(getattr(op, 'namespace', None), 'database', None)
70+
db = db or op.source.current_database
71+
if escape == 'identifier':
72+
db = _quote_identifier(db)
73+
elif escape == 'literal':
74+
db = _escape_string_literal(db)
5675
return op.source, db # type: ignore[return-value]
5776
raise TypeError(
5877
f'This method only works with SingleStoreDB tables, '
@@ -131,52 +150,6 @@ def get_workload_metrics(self) -> ir.Table:
131150
'SELECT * FROM information_schema.mv_workload_management_events',
132151
)
133152

134-
def optimize_table(self, table_name: str, *, database: str | None = None) -> None:
135-
"""Optimize a specific table.
136-
137-
Parameters
138-
----------
139-
table_name
140-
Name of table to optimize.
141-
database
142-
Database name. Defaults to current database.
143-
"""
144-
db = _quote_identifier(database or self.current_database)
145-
table = _quote_identifier(table_name)
146-
with self.raw_sql(f'OPTIMIZE TABLE {db}.{table} FULL'):
147-
pass
148-
149-
def get_table_stats(
150-
self,
151-
table_name: str,
152-
*,
153-
database: str | None = None,
154-
) -> dict[str, Any]:
155-
"""Get statistics for a specific table.
156-
157-
Parameters
158-
----------
159-
table_name
160-
Name of table.
161-
database
162-
Database name. Defaults to current database.
163-
164-
Returns
165-
-------
166-
dict
167-
Table statistics.
168-
"""
169-
db = _escape_string_literal(database or self.current_database)
170-
table = _escape_string_literal(table_name)
171-
# S608: db and table are escaped via _escape_string_literal
172-
result = self.sql(
173-
f"""
174-
SELECT * FROM information_schema.table_statistics
175-
WHERE database_name = '{db}' AND table_name = '{table}'
176-
""", # noqa: S608
177-
).execute()
178-
return result.to_dict(orient='records')[0] if len(result) else {}
179-
180153

181154
class TableExtensionsMixin(_TableBase):
182155
"""Mixin for ir.Table extensions (SingleStoreDB only)."""
@@ -185,13 +158,23 @@ class TableExtensionsMixin(_TableBase):
185158

186159
def optimize(self) -> None:
187160
"""Optimize this table (SingleStoreDB only)."""
188-
backend, db = _get_table_backend_and_db(self)
189-
backend.optimize_table(self.get_name(), database=db)
161+
backend, db = _get_table_backend_and_db(self, escape='identifier')
162+
table = _quote_identifier(self.get_name())
163+
with backend.raw_sql(f'OPTIMIZE TABLE {db}.{table} FULL'):
164+
pass
190165

191166
def get_stats(self) -> dict[str, Any]:
192167
"""Get statistics for this table (SingleStoreDB only)."""
193-
backend, db = _get_table_backend_and_db(self)
194-
return backend.get_table_stats(self.get_name(), database=db)
168+
backend, db = _get_table_backend_and_db(self, escape='literal')
169+
table = _escape_string_literal(self.get_name())
170+
# S608: db and table are escaped via _escape_string_literal
171+
result = backend.sql(
172+
f"""
173+
SELECT * FROM information_schema.table_statistics
174+
WHERE database_name = '{db}' AND table_name = '{table}'
175+
""", # noqa: S608
176+
).execute()
177+
return result.to_dict(orient='records')[0] if len(result) else {}
195178

196179
def get_column_statistics(self, column: str | None = None) -> ir.Table:
197180
"""Get column statistics (SingleStoreDB only).
@@ -201,11 +184,9 @@ def get_column_statistics(self, column: str | None = None) -> ir.Table:
201184
column
202185
Specific column name, or None for all columns.
203186
"""
204-
backend, db = _get_table_backend_and_db(self)
205-
db_name = db or backend.current_database
206-
db_quoted = _quote_identifier(db_name)
187+
backend, db = _get_table_backend_and_db(self, escape='identifier')
207188
table = _quote_identifier(self.get_name())
208-
query = f'SHOW COLUMNAR_SEGMENT_INDEX ON {db_quoted}.{table}'
189+
query = f'SHOW COLUMNAR_SEGMENT_INDEX ON {db}.{table}'
209190
if column:
210191
query += f' COLUMNS ({_quote_identifier(column)})'
211192
return backend.sql(query)

0 commit comments

Comments
 (0)