Skip to content

Commit 1695dfd

Browse files
committed
Add enum values to table_summary and truncate long column values
1 parent 27a4985 commit 1695dfd

11 files changed

Lines changed: 90 additions & 14 deletions

File tree

TODO.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,3 @@
99
- changing DB port
1010
- search
1111
- table_summary
12-
13-
14-
## schema include/exclude list in config
15-
16-
## Add enum values to table_summary
17-
## Truncate sampled columns in table_summary

config_example.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,4 @@ databases:
7474
settings:
7575
max_query_timeout: 30
7676
max_rows_per_query: 500
77-
sample_size: 10
7877
enable_write_operations: false

src/meeseeql/main.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,18 @@ async def table_summary(
103103
database: str,
104104
table_name: str,
105105
db_schema: str | None = None,
106-
limit: int = 250,
106+
limit: int = 100,
107107
page: int = 1,
108108
) -> ToolResult:
109-
"""Get table structure including columns and foreign keys with pagination"""
109+
"""Get table structure including columns and foreign keys with pagination
110+
111+
Args:
112+
database: Database name to query
113+
table_name: Name of the table to summarize
114+
db_schema: Optional schema name (uses default schema if not provided)
115+
limit: Maximum items per page (default: 100)
116+
page: Page number (default: 1)
117+
"""
110118
result = await tools.table_summary(
111119
get_or_init_db_manager(), database, table_name, db_schema, limit, page
112120
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SELECT
2+
NULL as column_name,
3+
NULL as enum_values
4+
LIMIT 0
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
SELECT
2+
c.column_name,
3+
CASE
4+
WHEN c.data_type = 'enum' THEN
5+
REPLACE(REPLACE(SUBSTRING(c.column_type, 6, CHAR_LENGTH(c.column_type) - 6), '''', ''), ')', '')
6+
ELSE NULL
7+
END as enum_values
8+
FROM information_schema.columns c
9+
WHERE c.table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
10+
AND LOWER(c.table_name) = LOWER('{{table_name}}')
11+
AND LOWER(c.table_schema) = LOWER('{{schema_name}}')
12+
AND c.data_type = 'enum'
13+
ORDER BY c.ordinal_position

src/meeseeql/tools/sql/postgresql/columns.sql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
SELECT
22
c.column_name,
3-
c.data_type,
3+
CASE
4+
WHEN c.data_type = 'USER-DEFINED' THEN c.udt_name
5+
ELSE c.data_type
6+
END as data_type,
47
c.is_nullable,
58
c.column_default
69
FROM information_schema.columns c
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
SELECT
2+
c.column_name,
3+
string_agg(e.enumlabel, ', ' ORDER BY e.enumsortorder) as enum_values
4+
FROM information_schema.columns c
5+
JOIN pg_type t ON t.typname = c.udt_name
6+
JOIN pg_enum e ON e.enumtypid = t.oid
7+
WHERE c.table_schema NOT IN ('information_schema', 'pg_catalog')
8+
AND LOWER(c.table_name) = LOWER('{{table_name}}')
9+
AND LOWER(c.table_schema) = LOWER('{{schema_name}}')
10+
AND t.typtype = 'e'
11+
GROUP BY c.column_name, c.ordinal_position
12+
ORDER BY c.ordinal_position
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SELECT
2+
NULL as column_name,
3+
NULL as enum_values
4+
LIMIT 0
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SELECT
2+
NULL as column_name,
3+
NULL as enum_values
4+
LIMIT 0

src/meeseeql/tools/table_summary.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class ColumnInfo(BaseModel):
2222
nullable: bool
2323
default: Any = None
2424
primary_key: bool = False
25+
enum_values: str | None = None
2526

2627

2728
class ForeignKey(BaseModel):
@@ -54,6 +55,8 @@ def __str__(self) -> str:
5455
parts.insert(-1, "PRIMARY KEY")
5556
if col.default is not None:
5657
parts.append(f"default: {col.default}")
58+
if col.enum_values:
59+
parts.append(f"values: {col.enum_values}")
5760
result += f" {col.name}: {', '.join(parts)}\n"
5861

5962
if self.sample_rows:
@@ -64,7 +67,13 @@ def __str__(self) -> str:
6467
result += f" {'-' * (len(' | '.join(column_names)))}\n"
6568
for row in self.sample_rows:
6669
row_str = " | ".join(
67-
str(val) if val is not None else "NULL" for val in row
70+
(
71+
# Truncate column values to 50 chars to prevent massive overflow
72+
str(val)[:50] + ("..." if len(str(val)) > 50 else "")
73+
if val is not None
74+
else "NULL"
75+
)
76+
for val in row
6877
)
6978
result += f" {row_str}\n"
7079

@@ -86,6 +95,29 @@ def __str__(self) -> str:
8695
return result
8796

8897

98+
async def _get_enum_values(
99+
db_manager: DatabaseManager,
100+
database: str,
101+
table_name: str,
102+
db_schema: str,
103+
) -> dict[str, str]:
104+
try:
105+
dialect = db_manager.get_dialect_name(database)
106+
enum_query_template = load_sql_query(dialect, "enum_values")
107+
enum_query = enum_query_template.replace("{{table_name}}", table_name).replace(
108+
"{{schema_name}}", db_schema
109+
)
110+
111+
transformer = SqlQueryTransformer(enum_query, dialect)
112+
transformer.validate_read_only()
113+
114+
result = await db_manager.execute_query(database, enum_query)
115+
rows = result.fetchall()
116+
return {row[0]: row[1] for row in rows if row[0] and row[1]}
117+
except Exception:
118+
return {}
119+
120+
89121
async def _get_primary_keys(
90122
db_manager: DatabaseManager,
91123
database: str,
@@ -117,6 +149,7 @@ async def _get_columns(
117149
table_name: str,
118150
db_schema: str,
119151
primary_keys: set,
152+
enum_values: dict[str, str],
120153
limit: int,
121154
offset: int,
122155
) -> List[ColumnInfo]:
@@ -152,6 +185,7 @@ async def _get_columns(
152185
nullable=nullable,
153186
default=column_default,
154187
primary_key=is_primary_key,
188+
enum_values=enum_values.get(column_name),
155189
)
156190
)
157191
return columns
@@ -365,12 +399,13 @@ async def table_summary(
365399
db_manager, database, table_name, schema_value
366400
)
367401

368-
sample_size = db_manager.config.settings.get("sample_size", 5)
402+
enum_values = await _get_enum_values(db_manager, database, table_name, schema_value)
403+
369404
sample_response = await execute_query(
370405
db_manager,
371406
database,
372407
f"SELECT * FROM {schema_value}.{table_name}",
373-
limit=sample_size,
408+
limit=5,
374409
page=1,
375410
)
376411
sample_rows = [list(row.values()) for row in sample_response.rows]
@@ -386,6 +421,7 @@ async def table_summary(
386421
table_name,
387422
schema_value,
388423
primary_keys,
424+
enum_values,
389425
num_columns_to_fetch,
390426
current_offset,
391427
)

0 commit comments

Comments
 (0)