Skip to content

feat: removing dup logic in sqla/models.py and models/helpers.py - #34177

Merged
mistercrunch merged 4 commits into
masterfrom
fix_mess
Jul 15, 2025
Merged

feat: removing dup logic in sqla/models.py and models/helpers.py#34177
mistercrunch merged 4 commits into
masterfrom
fix_mess

Conversation

@mistercrunch

@mistercrunch mistercrunch commented Jul 15, 2025

Copy link
Copy Markdown
Member

Huge props to Claude Code for running this whole analysis and fixing everything here.

Remove duplicate code between SqlaTable and ExploreMixin classes

This commit eliminates 7 duplicate methods totaling ~146 lines of code that were
introduced by PR #20281 in July 2022. The duplication occurred when @hughhhh
created the ExploreMixin class to enable Query objects to be visualized in Explore,
but instead of properly refactoring shared functionality, he copy-pasted methods
from SqlaTable into the new mixin.

Root Cause Analysis

The code duplication was traced to commit e5e8867
where ExploreMixin was created with methods copied from SqlaTable:

  • 5 methods were exact duplicates with identical implementations
  • 2 methods had diverged over time with different error handling and security practices

Method Resolution Order Impact

SqlaTable inherits from (Model, BaseDatasource, ExploreMixin), meaning:

  • SqlaTable's implementations override ExploreMixin's versions
  • Query class (inheriting only from ExploreMixin) uses the ExploreMixin versions
  • Both sets of methods were being used, creating genuine duplication

Methods Removed from SqlaTable

Exact duplicates:

  • filter_values_handler (60 lines) - Static method for handling filter values
  • _apply_cte (12 lines) - Static method for appending CTEs to SQL
  • make_orderby_compatible (28 lines) - Instance method for ORDER BY compatibility
  • text (2 lines) - Instance method for creating TextClause objects
  • get_query_str (4 lines) - Instance method for generating query strings

Divergent methods consolidated:

  • _normalize_prequery_result_type (35 lines) - Improved to use ExploreMixin's
    more robust version with better error handling for missing columns
  • changed_by_name (5 lines) - Improved to use AuditMixinNullable's more secure
    version with HTML escaping instead of plain string conversion

Technical Improvements

Beyond eliminating duplication, this refactoring improves the codebase by:

  • Using safer .get() method instead of direct dict access for column lookups
  • Implementing proper HTML escaping for user-facing data (security improvement)
  • Maintaining single source of truth for shared functionality between SqlaTable and Query

Testing

All existing unit tests pass (8/8) and critical integration tests for the
normalize_prequery_result_type functionality have been verified. The inheritance
hierarchy ensures SqlaTable now properly inherits the more robust implementations
from ExploreMixin and AuditMixinNullable.

Fixes: Code duplication introduced in PR #20281 (feat: Visualize SqlLab.Query model data in Explore)

@dosubot dosubot Bot added the change:backend Requires changing the backend label Jul 15, 2025

@korbit-ai korbit-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I've completed my review and didn't find any issues.

Files scanned
File Path Reviewed
superset/connectors/sqla/models.py
superset/models/helpers.py

Explore our documentation to understand the languages and file types we support and the files we ignore.

Check out our docs on how you can make Korbit work best for you and your team.

Loving Korbit!? Share us on LinkedIn Reddit and X

Comment on lines +1897 to +1903
def get_query_str(self, query_obj: QueryObjectDict) -> str:
"""Returns a query as a string using ExploreMixin implementation"""
return ExploreMixin.get_query_str(self, query_obj)

def text(self, clause: str) -> TextClause:
"""Returns a text clause using ExploreMixin implementation"""
return ExploreMixin.text(self, clause)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@betodealmeida these two methods are a bit of a hack, where from my understanding the inheritance scheme is non linear in some specific cases, so we need to cherry pick some methods to skip a level of inheritance.

PR still achieves the goal of de-duping logic, but doesn't fully fix the inheritance scheme and related patchwork ...

)
return ob

def _normalize_prequery_result_type(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The parent method seems more complete, handling cases where column is not a dict. This is one of the major problems with code duplication, things get fixed in one place but not another. :(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Confirmed on slack, this comment vouches for deleting this method as opposed to the other one that's slightly different.

@mistercrunch
mistercrunch merged commit fe9eef9 into master Jul 15, 2025
48 checks passed
@mistercrunch
mistercrunch deleted the fix_mess branch July 15, 2025 21:02
ianngech pushed a commit to Pesapal-Ltd/superset that referenced this pull request Jul 17, 2025
dankor pushed a commit to dankor/superset that referenced this pull request Aug 18, 2025
@github-actions github-actions Bot added 🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels 🚢 6.0.0 First shipped in 6.0.0 labels Dec 18, 2025
qfcwell pushed a commit to qfcwell/superset that referenced this pull request May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels change:backend Requires changing the backend preset-io size/L 🚢 6.0.0 First shipped in 6.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants