Skip to content

refactor(inspector): remove sqla private usages - #203

Merged
gazorby merged 1 commit into
mainfrom
worktree-remove-sqla-private-usages
Jun 22, 2026
Merged

refactor(inspector): remove sqla private usages#203
gazorby merged 1 commit into
mainfrom
worktree-remove-sqla-private-usages

Conversation

@gazorby

@gazorby gazorby commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Description

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Documentation

Issues Fixed or Closed by This PR

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

Summary by CodeRabbit

  • Bug Fixes

    • Improved SQLAlchemy relationship resolution for enhanced compatibility and stability.
  • Tests

    • Added validation tests for relationship detection logic.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

SQLAlchemyInspector gains a new _reverse_relationships() classmethod that reconstructs reverse relationship properties using public SQLAlchemy ORM attributes (entity.mapper, back_populates, backref) instead of the internal ._reverse_property. Call sites in relation_cycle and reverse_relation_required are updated accordingly. Column nullability in required() switches from columns_to_assign to columns. A parametrized unit test validates the helper against several ORM relationship patterns.

Changes

Public reverse-relationship resolution in SQLAlchemyInspector

Layer / File(s) Summary
New _reverse_relationships() classmethod and caller updates
src/strawchemy/dto/inspectors/sqlalchemy.py
Adds _reverse_relationships() that iterates prop.entity.mapper.relationships and filters candidates by back_populates/backref key matching. Updates relation_cycle and reverse_relation_required to call this helper instead of ._reverse_property. Switches required() column-branch nullability from columns_to_assign to columns.
ORM test models and parametrized reverse-relationship test
tests/unit/test_inspector.py
Defines _Base, Department, Group, User, Tag, Author, Book with colliding back_populates, self-referential, one-sided back_populates, and backref patterns. Parametrizes test_reverse_relationships_matches_private over all collected relationship properties, asserting parity with SQLAlchemy's private _reverse_property.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hopping past the private lane,
No more internal hacks remain!
back_populates and backref too,
The mapper's paths I trace anew.
With public APIs, my burrow's bright —
Every reverse found just right! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the changeset: refactoring the inspector module to eliminate private SQLAlchemy API dependencies.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-remove-sqla-private-usages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.33333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.26%. Comparing base (227bc21) to head (016128a).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/strawchemy/dto/inspectors/sqlalchemy.py 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #203      +/-   ##
==========================================
- Coverage   93.26%   93.26%   -0.01%     
==========================================
  Files          69       72       +3     
  Lines        6338     6486     +148     
  Branches      853      853              
==========================================
+ Hits         5911     6049     +138     
- Misses        285      296      +11     
+ Partials      142      141       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@gazorby
gazorby force-pushed the worktree-remove-sqla-private-usages branch from 410e2e4 to 016128a Compare June 22, 2026 22:30

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/strawchemy/dto/inspectors/sqlalchemy.py`:
- Around line 529-532: The code comment in the required method indicates that
the column property branch (returning any not column.nullable for column in
model_field.property.columns) is never executed in production since the caller
only invokes required() for relationships. Evaluate whether this dead code
should be removed entirely to maintain code cleanliness, or if it should be
explicitly documented with a comment explaining why it is being retained for
future-proofing purposes. If keeping it, add clarity to the existing comment to
justify its presence despite being unreachable in the current codebase.

In `@tests/unit/test_inspector.py`:
- Around line 79-81: Add a sanity check assertion immediately after the
`_ALL_RELATIONSHIPS` list comprehension to verify the expected number of
relationships are present. This assertion should check that the length of
`_ALL_RELATIONSHIPS` equals the expected count (10) and fail with a descriptive
message if the count is incorrect, catching any accidental model removals or
broken relationship definitions that would otherwise cause silent test failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: be5c0f4c-ad50-4b6d-a1c7-d7dddb03d53b

📥 Commits

Reviewing files that changed from the base of the PR and between 410e2e4 and 016128a.

📒 Files selected for processing (2)
  • src/strawchemy/dto/inspectors/sqlalchemy.py
  • tests/unit/test_inspector.py

Comment on lines +529 to +532
# NOTE: reached only for column properties; the sole caller invokes
# required() exclusively for relationships, so this branch is
# currently unexercised in production.
return any(not column.nullable for column in model_field.property.columns)

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The change from columns_to_assign to columns is semantically correct.

The columns attribute is the public API for accessing the underlying column collection. The comment accurately notes this branch is not exercised in production (only relationships call required()), which matches the downstream usage in types.py where self.inspector.required(field.model_field) is called within a field.is_relation context block.

However, the comment could lead to dead-code removal assumptions. If this branch is truly unreachable, consider whether it should remain for future-proofing or be removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/strawchemy/dto/inspectors/sqlalchemy.py` around lines 529 - 532, The code
comment in the required method indicates that the column property branch
(returning any not column.nullable for column in model_field.property.columns)
is never executed in production since the caller only invokes required() for
relationships. Evaluate whether this dead code should be removed entirely to
maintain code cleanliness, or if it should be explicitly documented with a
comment explaining why it is being retained for future-proofing purposes. If
keeping it, add clarity to the existing comment to justify its presence despite
being unreachable in the current codebase.

Comment on lines +79 to +81
_ALL_RELATIONSHIPS = [
rel for model in (Department, Group, User, Tag, Author, Book) for rel in inspect(model).relationships
]

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding a sanity check for relationship count.

The _ALL_RELATIONSHIPS collection is built dynamically. If a model is accidentally removed or a relationship definition is broken, the test would silently run with fewer cases. Consider adding a brief assertion on the expected count.

_ALL_RELATIONSHIPS = [
    rel for model in (Department, Group, User, Tag, Author, Book) for rel in inspect(model).relationships
]
# Sanity check: ensure we're testing all expected relationships
assert len(_ALL_RELATIONSHIPS) == 10, f"Expected 10 relationships, got {len(_ALL_RELATIONSHIPS)}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/test_inspector.py` around lines 79 - 81, Add a sanity check
assertion immediately after the `_ALL_RELATIONSHIPS` list comprehension to
verify the expected number of relationships are present. This assertion should
check that the length of `_ALL_RELATIONSHIPS` equals the expected count (10) and
fail with a descriptive message if the count is incorrect, catching any
accidental model removals or broken relationship definitions that would
otherwise cause silent test failures.

@gazorby
gazorby merged commit 6ca2f19 into main Jun 22, 2026
95 of 96 checks passed
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.

1 participant