Skip to content

refactor: extract shared SQL wrapper helper for repeated tool flow#1084

Merged
muddlebee merged 7 commits intoTracer-Cloud:mainfrom
Ryjen1:fix/extract-sql-wrapper-helper
Apr 29, 2026
Merged

refactor: extract shared SQL wrapper helper for repeated tool flow#1084
muddlebee merged 7 commits intoTracer-Cloud:mainfrom
Ryjen1:fix/extract-sql-wrapper-helper

Conversation

@Ryjen1
Copy link
Copy Markdown
Contributor

@Ryjen1 Ryjen1 commented Apr 29, 2026

Summary

This PR resolves #894 by extracting the repeated SQL-tool wrapper pattern into a single, reusable helper function. The change centralizes the common flow of resolving database config, calling vendor-specific functions, and optionally injecting warnings when a database parameter defaults.

Changes

New Helper

  • app/tools/utils/sql_wrapper.py: Introduces call_db_tool_with_default_db_warning() to handle the orchestration pattern consistently across all SQL tools

Migrated Tools (No Behavior Change)

  1. AzureSQLCurrentQueriesTool
  2. AzureSQLSlowQueriesTool
  3. PostgreSQLCurrentQueriesTool
  4. PostgreSQLSlowQueriesTool
  5. MySQLCurrentProcessesTool
  6. MariaDBProcessListTool

All tool names, schemas, and output keys remain unchanged. Vendor-specific config builders and query functions remain in their original locations under app/integrations/.

Test Coverage

  • 6 new wrapper tests in tests/tools/test_sql_wrapper.py:
    • Dict preservation from wrapped calls
    • Warning injection when database defaults to None
    • No warning when database explicitly provided
    • Correct default database names applied
    • Resolver kwargs passed correctly
  • 29 existing tool tests continue to pass with zero regressions

Code Reduction

  • 246 lines added (wrapper + tests)
  • 60 lines removed (reduced duplication in migrated tools)
  • ~19% reduction in migrated tool files

Verification

✅ All 35 tests passing (29 existing + 6 new)
✅ All acceptance criteria from #894 met
✅ Scope strictly limited to six specified tools
✅ No behavioral changes to tool APIs

- Add call_db_tool_with_default_db_warning helper in app/tools/utils/sql_wrapper.py
  to centralize the repeated pattern of resolving config, calling DB function,
  and optionally injecting warnings when database defaults

- Migrate six SQL tools to use the wrapper, reducing code duplication:
  - AzureSQLCurrentQueriesTool
  - AzureSQLSlowQueriesTool
  - PostgreSQLCurrentQueriesTool
  - PostgreSQLSlowQueriesTool
  - MySQLCurrentProcessesTool
  - MariaDBProcessListTool

- Add comprehensive tests for wrapper behavior:
  - Verify dict preservation
  - Verify warning injection on database defaulting
  - Verify no warning when database explicitly provided
  - Verify correct default database names used

All existing tool tests continue to pass with no behavior change.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 29, 2026

Greptile Summary

This PR extracts a repeated six-step SQL-tool pattern (detect default → set default → resolve config → call vendor fn → inject warning → return) into a single helper call_db_tool_with_default_db_warning and migrates six tools to use it. All tool names, schemas, and output keys are unchanged; the refactor is purely structural with a small net line reduction.

Confidence Score: 5/5

Safe to merge — all remaining findings are P2 style suggestions with no impact on runtime behaviour.

Both findings are P2: one is a defensive-copy best practice (the dict mutation has no effect on current callers, which all pass fresh literals), and the other is a stale comment in a test. No logic changes, no schema changes, and 35 tests pass.

app/tools/utils/sql_wrapper.py — consider making a copy of resolver_kwargs before mutating it.

Important Files Changed

Filename Overview
app/tools/utils/sql_wrapper.py New shared helper that centralises the resolve→call→warn flow; well-typed and documented, but mutates the caller-supplied resolver_kwargs dict in-place (line 43).
tests/tools/test_sql_wrapper.py Six focused unit tests covering all branches of the wrapper; minor leftover self-contradicting comment in test_wrapper_handles_empty_string_database that should be cleaned up.
app/tools/AzureSQLCurrentQueriesTool/init.py Migrated cleanly to call_db_tool_with_default_db_warning; behaviour is equivalent to before with no regressions.
app/tools/AzureSQLSlowQueriesTool/init.py Migrated cleanly; equivalent behaviour preserved.
app/tools/MariaDBProcessListTool/init.py Uses a local closure (mariadb_config_builder) to adapt MariaDB's constructor-based config to the wrapper interface; correctly passes resolver_kwargs={} with the database injected by the helper.
app/tools/MySQLCurrentProcessesTool/init.py Migrated cleanly; equivalent behaviour preserved.
app/tools/PostgreSQLCurrentQueriesTool/init.py Migrated cleanly; equivalent behaviour preserved.
app/tools/PostgreSQLSlowQueriesTool/init.py Migrated cleanly; equivalent behaviour preserved.

Sequence Diagram

sequenceDiagram
    participant Tool as SQL Tool (e.g. AzureSQLCurrentQueriesTool)
    participant Wrapper as call_db_tool_with_default_db_warning
    participant Resolver as config_resolver (e.g. resolve_azure_sql_config)
    participant Caller as db_caller (e.g. get_current_queries)
    participant Warnings as default_db_warning

    Tool->>Wrapper: database, default_db_name, config_resolver, resolver_kwargs, db_caller
    alt database is None
        Wrapper->>Wrapper: database = default_db_name, _db_defaulted = True
    end
    Wrapper->>Wrapper: resolver_kwargs[database] = database
    Wrapper->>Resolver: **resolver_kwargs
    Resolver-->>Wrapper: config
    Wrapper->>Caller: config
    Caller-->>Wrapper: result dict
    alt _db_defaulted
        Wrapper->>Warnings: default_db_warning(default_db_name)
        Warnings-->>Wrapper: warning string
        Wrapper->>Wrapper: result[default_db_warning] = warning
    end
    Wrapper-->>Tool: result dict
Loading

Reviews (1): Last reviewed commit: "refactor: extract shared SQL wrapper hel..." | Re-trigger Greptile

Comment thread app/tools/utils/sql_wrapper.py Outdated
Comment on lines +43 to +46
resolver_kwargs["database"] = database

# Resolve config using the vendor-specific resolver
config = config_resolver(**resolver_kwargs)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Caller's dict is mutated in-place

Line 43 writes directly into the resolver_kwargs dict the caller passed in. Every current call site happens to pass a fresh dict literal ({"server": server, "port": port}), so there's no visible bug today, but it breaks the least-surprise contract: a caller that stores its kwargs dict externally (or passes the same dict twice) will find an unexpected "database" key after the first call. Use a shallow copy to avoid the side-effect:

Suggested change
resolver_kwargs["database"] = database
# Resolve config using the vendor-specific resolver
config = config_resolver(**resolver_kwargs)
kwargs = {**resolver_kwargs, "database": database}
config = config_resolver(**kwargs)

(And remove the separate resolver_kwargs["database"] = database line above.)

Comment thread tests/tools/test_sql_wrapper.py Outdated
Comment on lines +123 to +126
# Empty string is falsy but was explicitly provided, so no warning
# Actually, the wrapper treats None as "not provided", so "" would trigger warning
# Let me verify the actual behavior: the condition is "if database is None"
# So "" is NOT None and should not trigger warning
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Self-contradicting comment should be cleaned up

Lines 123–126 contain draft reasoning that contradicts itself ("Actually, the wrapper treats None …") and was clearly left over from the authoring process. It hurts readability and could confuse future maintainers. The assertion on line 128 is the ground truth; the comment above should either be replaced with a single clear statement or removed entirely.

Suggested change
# Empty string is falsy but was explicitly provided, so no warning
# Actually, the wrapper treats None as "not provided", so "" would trigger warning
# Let me verify the actual behavior: the condition is "if database is None"
# So "" is NOT None and should not trigger warning
# Empty string is explicitly provided (not None), so no default warning is injected.

Ryjen1 added 2 commits April 29, 2026 19:10
- Use shallow copy for resolver_kwargs to avoid mutating caller's dict
  (all current call sites pass fresh dicts, but this prevents surprises
  for future callers who may store or reuse their kwargs dict)

- Clean up self-contradicting comment in test_wrapper_handles_empty_string_database
  - Remove draft reasoning that contradicts itself
  - Replace with single clear statement explaining the behavior

All 35 tests continue to pass (29 existing + 6 new wrapper tests).
- UP035: Import Callable from collections.abc instead of typing
  (Python 3.9+ prefers collections.abc for standard library collections)

- UP047: Add Generic import to enable proper type parameter handling
  (required for TypeVar usage with generic function signatures)

All tests continue to pass.
Comment thread app/tools/utils/sql_wrapper.py Fixed
Ryjen1 added 3 commits April 29, 2026 19:27
- F401: Removed unused Generic import
  (only TypeVar is needed, Generic is not used)

- UP047: Add noqa comment to suppress false positive
  (UP047 requires PEP 695 syntax which isn't available in Python 3.10;
  function is already properly generic with TypeVar[T] usage)

All tests passing.
- Wrap long description strings in tool decorators
- Wrap long use_case strings in lists
- Wrap long lambda function calls
- Format test dict to multiple lines for readability

All tests continue to pass.
- Keep long lambda expressions on single line (ruff preference)
- Remove multi-line wrapping of lambdas

All tests continue to pass.
@muddlebee
Copy link
Copy Markdown
Collaborator

@Ryjen1 LMK once review comments adressed

@Ryjen1
Copy link
Copy Markdown
Contributor Author

Ryjen1 commented Apr 29, 2026

Hi @muddlebee All review comments have been addressed!

Changes made:

  • Fixed resolver_kwargs mutation by using shallow copy
  • Cleaned up self-contradicting comment in test
  • Resolved all ruff linting issues (UP035, UP047, F401)
  • Applied ruff formatting to all modified files

-All 35 tests passing (6 wrapper + 29 existing tools)
-Now ready for re-review

Comment thread app/tools/utils/sql_wrapper.py Outdated
database = default_db_name

# Resolve config using the vendor-specific resolver
# Use shallow copy to avoid mutating caller's dict
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is inaccurate: {**resolver_kwargs, "database": database} creates a brand-new merged dict — it does not shallow-copy resolver_kwargs. Drop the comment; the spread syntax is self-explanatory.

"Identifying slow queries that may be causing performance degradation",
"Analyzing query execution patterns during incident timeframes",
"Finding poorly optimized queries with high execution times or low cache hit rates",
("Finding poorly optimized queries with high execution times or low cache hit rates"),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapping a single string in parentheses without a trailing comma is a no-op — it does not create a tuple. Remove the parens to stay consistent with the other two list entries above it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the brackets "( )" seems uncessary 🤔 ??

@muddlebee
Copy link
Copy Markdown
Collaborator

@Ryjen1 just small nits above, otherwise good to go 👍

- Remove inaccurate comment about 'shallow copy' in sql_wrapper.py
  ({**resolver_kwargs, 'database': database} creates a brand-new merged dict,
  not a shallow copy. The spread syntax is self-explanatory.)

- Remove unnecessary parentheses from PostgreSQL use_case string
  (Wrapping single string in parens is a no-op; keep consistent with other entries)

All tests continue to pass.
@Ryjen1
Copy link
Copy Markdown
Contributor Author

Ryjen1 commented Apr 29, 2026

Hi @muddlebee kindly take a look again

@muddlebee muddlebee merged commit ac348be into Tracer-Cloud:main Apr 29, 2026
7 checks passed
@muddlebee
Copy link
Copy Markdown
Collaborator

Goood work 🎉🍺

@github-actions
Copy link
Copy Markdown
Contributor

🎯 Bullseye. @Ryjen1 opened a PR, kept the vibes clean, and got it merged. Absolute cinema. 🎬


👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extract one shared wrapper helper for the repeated SQL-tool flow

3 participants