Skip to content

feat(schema): remove duplicated field_map on strawchemy types#200

Open
gazorby wants to merge 3 commits into
mainfrom
worktree-centralize-factory-field-map
Open

feat(schema): remove duplicated field_map on strawchemy types#200
gazorby wants to merge 3 commits into
mainfrom
worktree-centralize-factory-field-map

Conversation

@gazorby

@gazorby gazorby commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Bug Fixes
    • Resolved an issue where ordering by aliased aggregated fields could fail during schema/query generation.
  • Refactor
    • Streamlined internal GraphQL DTO field-definition resolution by removing the previous key/map-based plumbing and switching to direct per-field-name lookups.
    • Simplified schema/factory aggregation and order-by generation to build required field metadata up-front.
  • Tests
    • Added a regression test for aliased aggregation order-by.
    • Removed SQLAlchemy-specific DTO tests that no longer apply.
  • Chores
    • Reformatted tool configuration in pyproject.toml without changing values.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR removes the DTOKey/field_map/populate_fields indirect field-definition lookup from the DTO layer and all factory/repository consumers, replacing it with a new __dto_field_definitions__: dict[str, GraphQLFieldDefinition] class variable on StrawchemyObject that is accessed directly by field name. A regression fix for KeyError when building order-by schemas with aliased aggregatable columns is included. pyproject.toml receives multi-line TOML formatting changes and removes two ruff exclude glob entries.

Changes

DTOKey / field_map removal and aliased-column regression fix

Layer / File(s) Summary
DTO contract: remove DTOKey, add __dto_field_definitions__
src/strawchemy/dto/strawberry.py
StrawchemyDefinition loses field_map and all related methods; DTOKey/_Key classes are deleted; StrawchemyObject gains __dto_field_definitions__: ClassVar[dict[str, GraphQLFieldDefinition]]; OrderByDTO.tree() and BooleanFilterDTO.filters_tree() switch to direct __dto_field_definitions__[name] lookup.
Factory base and ForwardedFactoryKwargs: remove field_map plumbing
src/strawchemy/schema/factories/base.py, src/strawchemy/schema/factories/_kwargs.py
GraphQLFactory.iter_field_definitions drops the field_map accumulator; GraphQLFactory.factory removes field_map initialization and post-call DTO population; ForwardedFactoryKwargs removes the field_map TypedDict key.
Factory implementations: remove field_map from types, inputs, aggregations
src/strawchemy/schema/factories/types.py, src/strawchemy/schema/factories/inputs.py, src/strawchemy/schema/factories/aggregations.py
ObjectTypeFactory, AggregateRootTypeFactory, AggregateFieldsFactory, and MutationInputFactory drop field_map parameters and yield fields directly; _FilterFactory, AggregateFilterFactory, and OrderByFactory remove field_map arguments, populate_fields calls, and DTOKey registration; OrderByFactory._order_by_aggregation_fields adds a model_fields lookup to supply _model_field directly.
Repository: switch field-definition lookup to __dto_field_definitions__
src/strawchemy/repository/strawberry/base.py
_build removes the intermediate dto_model_from_type call and replaces DTOKey+get_field_or_none with dto.__dto_field_definitions__.get(strawberry_field.name).
Regression fix: aliased aggregatable column order-by
tests/unit/schemas/order/order_by_aliased_aggregation.py, tests/unit/mapping/test_schemas.py
New test schema with a READ-purpose aliased scorerating column on item models; Strawchemy instance and GraphQL types registered; Query root exposes containers with order-by input; new unit test asserts schema construction succeeds without KeyError and AliasedItemAggregateOrderBy appears in the SDL.
Test cleanup: remove populate_fields test
tests/unit/dto/test_dto.py
Removes test_strawchemy_definition_populate_fields, its SQLAlchemy declarative helper models, and the now-unused imports.

pyproject.toml formatting

Layer / File(s) Summary
Multi-line TOML reformatting and ruff exclude cleanup
pyproject.toml
Classifiers, dependency groups, git-cliff commit parsers/preprocessors, pytest markers, ruff exclude/ignore lists, and ty.src exclude globs reformatted to multi-line TOML arrays; two ruff exclude entries (tests/codegen/snapshots, alembic/*) removed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • gazorby/strawchemy#135: Adds constraint-aware iter_field_definitions signatures that relied on field_map/DTOKey machinery, which this PR removes.
  • gazorby/strawchemy#147: Refactors public paginate/order API and threads order/pagination through factories, directly affected by removal of DTOKey-based OrderByDTO field lookup.
  • gazorby/strawchemy#154: Adjusts typing/kwarg threading around field_map in MutationInputFactory.iter_field_definitions, which is being removed entirely in this PR.

Poem

🐇 The DTOKey hopped away one day,
No map to carry, no fields to weigh.
__dto_field_definitions__ now does the deed—
Just look up by name at lightning speed!
A bug with aliases tried to hide,
But the rabbit found it, thumped with pride. 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.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 clearly and specifically describes the main change: removing duplicated field_map from strawchemy types, which aligns with the comprehensive refactoring across multiple files to eliminate field_map plumbing.
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-centralize-factory-field-map

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 and usage tips.

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/strawchemy/schema/factories/inputs.py (1)

320-375: ⚠️ Potential issue | 🔴 Critical

This code will fail with aliased aggregatable fields.

name.field_definition.name returns the aliased name (e.g., "rating") when an alias is configured, but model_fields is keyed by the actual model field name (e.g., "score"). The lookup at line 331 will raise a KeyError when aggregatable columns have aliases. Additionally, line 328 incorrectly uses name.field_definition.name as model_field_name instead of the actual model field name.

Use name.field_definition.model_field_name instead to access the underlying model field name that matches the keys in model_fields.

🤖 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/schema/factories/inputs.py` around lines 320 - 375, In the
_order_by_aggregation_fields method, the code uses name.field_definition.name
which returns the aliased field name (e.g., "rating"), but model_fields is keyed
by the actual model field name (e.g., "score"). This causes a KeyError when
aggregatable columns have aliases. Replace both occurrences of
name.field_definition.name with name.field_definition.model_field_name: first
when assigning the model_field_name parameter in the FunctionArgFieldDefinition
constructor, and second when looking up the field from the model_fields
dictionary at the model_fields[name.field_definition.name].model_field access
point.
🤖 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 `@pyproject.toml`:
- Line 316: The glob pattern entry for alembic contains two trailing spaces
before the comma that should be removed. Locate the "alembic/*" pattern in the
pyproject.toml file and remove the trailing whitespace so the pattern reads
"alembic/*" without any spaces before the comma.

---

Outside diff comments:
In `@src/strawchemy/schema/factories/inputs.py`:
- Around line 320-375: In the _order_by_aggregation_fields method, the code uses
name.field_definition.name which returns the aliased field name (e.g.,
"rating"), but model_fields is keyed by the actual model field name (e.g.,
"score"). This causes a KeyError when aggregatable columns have aliases. Replace
both occurrences of name.field_definition.name with
name.field_definition.model_field_name: first when assigning the
model_field_name parameter in the FunctionArgFieldDefinition constructor, and
second when looking up the field from the model_fields dictionary at the
model_fields[name.field_definition.name].model_field access point.
🪄 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: 91708b44-7b89-42f7-9040-8cc0e159e88b

📥 Commits

Reviewing files that changed from the base of the PR and between ea50659 and 820f5c8.

📒 Files selected for processing (11)
  • pyproject.toml
  • src/strawchemy/dto/strawberry.py
  • src/strawchemy/repository/strawberry/base.py
  • src/strawchemy/schema/factories/_kwargs.py
  • src/strawchemy/schema/factories/aggregations.py
  • src/strawchemy/schema/factories/base.py
  • src/strawchemy/schema/factories/inputs.py
  • src/strawchemy/schema/factories/types.py
  • tests/unit/dto/test_dto.py
  • tests/unit/mapping/test_schemas.py
  • tests/unit/schemas/order/order_by_aliased_aggregation.py
💤 Files with no reviewable changes (1)
  • tests/unit/dto/test_dto.py

Comment thread pyproject.toml Outdated
@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.27%. Comparing base (227bc21) to head (9c874b2).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #200   +/-   ##
=======================================
  Coverage   93.26%   93.27%           
=======================================
  Files          69       72    +3     
  Lines        6338     6391   +53     
  Branches      853      847    -6     
=======================================
+ Hits         5911     5961   +50     
- Misses        285      292    +7     
+ Partials      142      138    -4     

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

@gazorby gazorby force-pushed the worktree-centralize-factory-field-map branch from 820f5c8 to 9c874b2 Compare June 22, 2026 06:14

@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: 1

🤖 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/strawberry.py`:
- Around line 507-509: The issue is that field.model_field assignment in the
FunctionFieldDefinition handling directly mutates the shared
__dto_field_definitions__ ClassVar, causing stale model_field values to persist
across subsequent OrderByDTO instances. Instead of mutating the shared field
definition, create a copy of the field object before assigning
node.value.model_field to it. This ensures each instance has its own independent
copy of the field with the correct node-specific model context rather than
reusing a mutated shared definition.
🪄 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: fbae2cf6-f1ff-4de4-a7af-5d307cc1b2b3

📥 Commits

Reviewing files that changed from the base of the PR and between 820f5c8 and 9c874b2.

📒 Files selected for processing (11)
  • pyproject.toml
  • src/strawchemy/dto/strawberry.py
  • src/strawchemy/repository/strawberry/base.py
  • src/strawchemy/schema/factories/_kwargs.py
  • src/strawchemy/schema/factories/aggregations.py
  • src/strawchemy/schema/factories/base.py
  • src/strawchemy/schema/factories/inputs.py
  • src/strawchemy/schema/factories/types.py
  • tests/unit/dto/test_dto.py
  • tests/unit/mapping/test_schemas.py
  • tests/unit/schemas/order/order_by_aliased_aggregation.py
💤 Files with no reviewable changes (1)
  • tests/unit/dto/test_dto.py

Comment on lines +507 to 509
field = self.__dto_field_definitions__[name]
if isinstance(field, FunctionFieldDefinition) and not field.has_model_field:
field.model_field = node.value.model_field

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Copy the field before adding node-specific model context.

__dto_field_definitions__ is a ClassVar, so field.model_field = node.value.model_field mutates shared DTO metadata. After the first traversal sets it, later OrderByDTO instances can reuse a stale parent model_field and build incorrect order-by nodes.

🐛 Proposed fix
-            field = self.__dto_field_definitions__[name]
+            field = self.__dto_field_definitions__[name]
             if isinstance(field, FunctionFieldDefinition) and not field.has_model_field:
+                field = copy(field)
                 field.model_field = node.value.model_field
🤖 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/strawberry.py` around lines 507 - 509, The issue is that
field.model_field assignment in the FunctionFieldDefinition handling directly
mutates the shared __dto_field_definitions__ ClassVar, causing stale model_field
values to persist across subsequent OrderByDTO instances. Instead of mutating
the shared field definition, create a copy of the field object before assigning
node.value.model_field to it. This ensures each instance has its own independent
copy of the field with the correct node-specific model context rather than
reusing a mutated shared definition.

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