Skip to content

ref: small refactors#138

Merged
gazorby merged 5 commits intomainfrom
small-refactors
Dec 18, 2025
Merged

ref: small refactors#138
gazorby merged 5 commits intomainfrom
small-refactors

Conversation

@gazorby
Copy link
Owner

@gazorby gazorby commented Dec 18, 2025

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

  • Refactor

    • Centralized factory/container and unified mutation-field builder for consistent DTO and mutation creation.
    • Consolidated aggregation type-filtering into a single configurable system.
    • Mapper simplified to use the new container and builder.
  • Chores

    • Added a new slotscheck tool and task; task dependencies reorganized to use a unified install target.
    • CI lint job now installs dependencies before linting.
    • Tooling configs updated.
  • Tests

    • Removed a few type-check suppression comments in unit tests.
  • Style

    • Added a new VCS ignore rule.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 18, 2025

Walkthrough

Introduces StrawchemyFactories and MutationFieldBuilder, refactors mapper and aggregation factories to use centralized factories and type-filter configs, adds slotscheck tooling and task, updates lint/ruff/unasyncd config, CI install step, minor task/docs edits, removes two pyright-ignore comments, and adds .serena to .gitignore.

Changes

Cohort / File(s) Summary
Repo config & CI
\.gitignore, pyproject.toml, .github/workflows/ci.yaml, tasks.md, mise.toml
Adds .serena to .gitignore; adds [tool.slotscheck] config and slotscheck dependency; removes fix = true from Ruff; extends unasyncd options; replaces _install with uv:install across tasks; adds CI step mise run uv:install; formatting and placeholder edits in tasks docs.
Factory container
src/strawchemy/factories.py
New StrawchemyFactories dataclass with create() and create_public_api() to centralize instantiation and wiring of DTO factories, backends, and a public API mapping.
Mapper refactor
src/strawchemy/mapper.py
Mapper now uses StrawchemyFactories for factory wiring and a MutationFieldBuilder for mutation fields; removes many direct factory instantiations and derives public API from the container.
Mutation field builder
src/strawchemy/strawberry/mutation/builder.py
Adds MutationFieldBuilder with build() to unify creation of create/update/upsert/delete mutation fields, handling repo resolution, type annotations, resolver binding, and shared params.
Aggregations refactor
src/strawchemy/strawberry/factories/aggregations.py
Replaces numerous specialized aggregation DTO factories with _TypeFilteredFunctionArgDTOFactory driven by _TypeFilterConfig; AggregationInspector now uses a per-aggregation factory map and updated signatures (use type[DeclarativeBase]).
Inputs type hint update
src/strawchemy/strawberry/factories/inputs.py
Updated _order_by_aggregation() parameter type to type[DeclarativeBase].
Tests cleanup
tests/unit/mapping/test_schemas.py, tests/unit/test_mutation_input.py
Removed inline Pyright ignore comments; runtime tests unchanged.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus review on factory wiring in StrawchemyFactories.create() for correct backend/config propagation and any lazy-import effects.
  • Validate MutationFieldBuilder.build() for complete coverage of mutation field variants and preservation of resolver/type semantics.
  • Review AggregationInspector’s _TypeFilterConfig mapping to ensure aggregation-specific behavior and naming/suffixes are preserved.
  • Confirm mapper public API surface and any partial-bound call semantics remain compatible with callers.
  • Check CI/task changes and pyproject.toml tooling entries (slotscheck, ruff/unasyncd) for consistency.

Possibly related PRs

Poem

🐇 I stitched the factories into one tidy den,

Builders ready, bindings snug as a pen.
Slotscheck hops in, CI hums a song,
Aggregates dance and fields get strong.
Hooray — little rabbit hops along.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.26% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title "ref: small refactors" is vague and generic, using non-descriptive language that does not convey meaningful information about the actual changes in the changeset. Clarify the title to specifically describe the main refactoring changes, such as "refactor: centralize DTO factory initialization with StrawchemyFactories container" or reference the most significant change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch small-refactors

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af15c83 and 685c085.

📒 Files selected for processing (3)
  • .github/workflows/ci.yaml (5 hunks)
  • mise.toml (4 hunks)
  • tasks.md (26 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Run `mise run install` to install all dependencies and pre-commit hooks

Applied to files:

  • .github/workflows/ci.yaml
  • tasks.md
  • mise.toml
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Run `mise run lint` to execute linters and formatters (optional to run manually; will run via pre-commit)

Applied to files:

  • .github/workflows/ci.yaml
  • tasks.md
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Use mise to manage build and test tasks for the project

Applied to files:

  • .github/workflows/ci.yaml
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Install mise globally or via the local bootstrap script (`./tools/mise`) which installs into `.mise`

Applied to files:

  • .github/workflows/ci.yaml
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Consult the tasks documentation at tasks.md for available tasks

Applied to files:

  • tasks.md
  • mise.toml
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Alternatively, run `mise run auto-bump` to bump the version locally and push changes

Applied to files:

  • tasks.md
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Use the GitHub bump workflow to bump version and create a tag; optionally use `auto` or choose `major|minor|patch`

Applied to files:

  • tasks.md
🪛 YAMLlint (1.37.1)
.github/workflows/ci.yaml

[error] 9-9: too many spaces inside brackets

(brackets)


[error] 9-9: too many spaces inside brackets

(brackets)


[error] 13-13: too many spaces inside brackets

(brackets)


[error] 13-13: too many spaces inside brackets

(brackets)


[error] 60-60: too many spaces inside brackets

(brackets)


[error] 60-60: too many spaces inside brackets

(brackets)


[error] 124-124: too many spaces inside brackets

(brackets)


[error] 124-124: too many spaces inside brackets

(brackets)


[error] 158-158: too many spaces inside brackets

(brackets)


[error] 158-158: too many spaces inside brackets

(brackets)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 💻 Generate test matrix
  • GitHub Check: ✨ Lint
  • GitHub Check: Optimize new code in this PR
🔇 Additional comments (5)
.github/workflows/ci.yaml (1)

199-201: Good addition to ensure dependencies are installed before linting.

The new install step correctly aligns with the task refactoring in mise.toml where _install was renamed to uv:install. Explicitly installing dependencies before running linters ensures the CI environment is properly configured.

tasks.md (1)

1-396: Auto-generated documentation correctly reflects task configuration changes.

This file is automatically generated from mise.toml (via the render:usage task), and all changes consistently reflect the refactoring in the task configuration:

  • Dependency updates from _install to uv:install
  • Addition of the slotscheck task
  • Addition of the public uv:install task
mise.toml (3)

228-231: Good addition: slotscheck improves code quality checks.

Adding the slotscheck task and integrating it into the lint task dependencies is a valuable enhancement. Slotscheck verifies correct __slots__ usage, which helps catch memory and performance issues early in development.

Also applies to: 217-217


247-255: LGTM: formatting changes have no functional impact.

The spacing adjustments to the clean task's run commands are purely cosmetic and maintain the same functionality.


44-46: Excellent refactoring: task rename improves clarity and accessibility.

Renaming _install to uv:install and updating all dependencies is a well-executed refactor:

  • Removes the implicit "hidden" convention (underscore prefix)
  • Makes dependency installation a first-class public task
  • The uv: namespace logically groups UV-related tasks
  • All dependency references are consistently updated across the configuration

Also applies to: 52-52, 64-64, 71-71, 78-78, 85-85, 91-91, 98-98, 104-104, 110-110, 116-116, 122-122, 129-129, 136-136, 143-143, 239-239

⛔ Skipped due to learnings
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Run `mise run install` to install all dependencies and pre-commit hooks
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Consult the tasks documentation at tasks.md for available tasks

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/strawchemy/strawberry/factories/aggregations.py (1)

240-336: Functional but repetitive pattern.

The method works correctly, routing through the new arguments_type method with the appropriate aggregation keys. However, the repetitive structure for each datetime/date/time/string variant could be consolidated using a data-driven approach similar to _aggregation_type_filters. This is optional since the current implementation is clear and explicit.

🔎 Example consolidation approach
_MIN_MAX_FILTER_CONFIGS = [
    ("min_max_numeric", float, None, None),  # (key, comparison_type, min_suffix, max_suffix)
    ("min_max_datetime", datetime, "min_datetime", "max_datetime"),
    ("min_max_date", date, "min_date", "max_date"),
    ("min_max_time", time, "min_time", "max_time"),
    ("min_max_string", str, "min_string", "max_string"),
]

def _min_max_filters(self, model: type[DeclarativeBase], dto_config: DTOConfig) -> list[FilterFunctionInfo]:
    aggregations: list[FilterFunctionInfo] = []
    for key, comparison_type, min_name, max_name in self._MIN_MAX_FILTER_CONFIGS:
        if fields := self.arguments_type(model, dto_config, key):
            for func, name in [("min", min_name), ("max", max_name)]:
                kwargs = {"field_name_": name} if name else {}
                aggregations.append(
                    FilterFunctionInfo(
                        enum_fields=fields,
                        function=func,
                        aggregation_type=key if name else "numeric",
                        comparison_type=self._inspector.get_type_comparison(comparison_type),
                        **kwargs,
                    )
                )
    return aggregations
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7ac6df and f2db5ce.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • .gitignore (1 hunks)
  • mise.toml (3 hunks)
  • pyproject.toml (2 hunks)
  • src/strawchemy/factories.py (1 hunks)
  • src/strawchemy/mapper.py (8 hunks)
  • src/strawchemy/strawberry/factories/aggregations.py (11 hunks)
  • src/strawchemy/strawberry/factories/inputs.py (1 hunks)
  • src/strawchemy/strawberry/mutation/builder.py (1 hunks)
  • tasks.md (14 hunks)
  • tests/unit/mapping/test_schemas.py (1 hunks)
  • tests/unit/test_mutation_input.py (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Consult the tasks documentation at tasks.md for available tasks

Applied to files:

  • tasks.md
  • mise.toml
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Run `mise run lint` to execute linters and formatters (optional to run manually; will run via pre-commit)

Applied to files:

  • tasks.md
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Run `mise run install` to install all dependencies and pre-commit hooks

Applied to files:

  • mise.toml
🧬 Code graph analysis (5)
tests/unit/test_mutation_input.py (2)
tests/unit/schemas/mutation_and_query.py (1)
  • ColorInput (23-23)
src/strawchemy/strawberry/mutation/input.py (1)
  • Input (276-385)
tests/unit/mapping/test_schemas.py (4)
tests/integration/models.py (1)
  • id (61-67)
src/strawchemy/dto/base.py (1)
  • name (347-348)
src/strawchemy/sqlalchemy/_query.py (2)
  • name (112-114)
  • name (781-787)
src/strawchemy/sqlalchemy/_scope.py (1)
  • name (369-383)
src/strawchemy/mapper.py (2)
src/strawchemy/factories.py (3)
  • StrawchemyFactories (24-135)
  • create (54-114)
  • create_public_api (116-135)
src/strawchemy/strawberry/mutation/builder.py (2)
  • MutationFieldBuilder (28-109)
  • build (39-109)
src/strawchemy/strawberry/mutation/builder.py (2)
src/strawchemy/config/base.py (1)
  • StrawchemyConfig (21-62)
src/strawchemy/strawberry/_field.py (3)
  • StrawchemyCreateMutationField (507-530)
  • StrawchemyUpdateMutationField (598-653)
  • StrawchemyUpsertMutationField (533-595)
src/strawchemy/strawberry/factories/aggregations.py (7)
src/strawchemy/strawberry/factories/inputs.py (3)
  • iter_field_definitions (130-162)
  • factory (171-198)
  • factory (451-480)
src/strawchemy/strawberry/factories/types.py (7)
  • iter_field_definitions (166-188)
  • iter_field_definitions (269-303)
  • iter_field_definitions (423-448)
  • iter_field_definitions (630-647)
  • factory (191-242)
  • factory (306-335)
  • factory (650-679)
src/strawchemy/strawberry/factories/enum.py (1)
  • iter_field_definitions (125-136)
src/strawchemy/strawberry/factories/base.py (3)
  • iter_field_definitions (329-346)
  • factory (349-398)
  • factory (517-546)
src/strawchemy/strawberry/dto.py (9)
  • FunctionArgFieldDefinition (328-331)
  • from_field (249-257)
  • from_field (309-316)
  • function (264-264)
  • function (267-267)
  • function (270-270)
  • function (272-278)
  • FilterFunctionInfo (212-225)
  • OutputFunctionInfo (204-208)
src/strawchemy/dto/types.py (1)
  • DTOConfig (105-257)
src/strawchemy/dto/exceptions.py (1)
  • DTOError (6-6)
🪛 Ruff (0.14.8)
src/strawchemy/strawberry/mutation/builder.py

47-47: Dynamically typed expressions (typing.Any) are disallowed in resolver

(ANN401)


50-50: Dynamically typed expressions (typing.Any) are disallowed in graphql_type

(ANN401)


55-55: Dynamically typed expressions (typing.Any) are disallowed in default

(ANN401)


60-60: Dynamically typed expressions (typing.Any) are disallowed in **field_specific_kwargs

(ANN401)


61-61: Dynamically typed expressions (typing.Any) are disallowed in build

(ANN401)

src/strawchemy/factories.py

64-64: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


65-65: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


66-66: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


67-67: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


71-71: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


75-75: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: 🔬 integration-sqlite on 3.13
  • GitHub Check: 🔬 integration-sqlite on 3.14
  • GitHub Check: 🔬 integration-mysql on 3.14
  • GitHub Check: 🔬 unit-no-extras on 3.12
  • GitHub Check: 🔬 unit on 3.13
  • GitHub Check: 🔬 unit on 3.10
  • GitHub Check: 🔬 integration-postgres on 3.12
  • GitHub Check: 🔬 integration-mysql on 3.13
  • GitHub Check: 🔬 integration-postgres on 3.13
  • GitHub Check: 🔬 integration-sqlite on 3.12
  • GitHub Check: 🔬 integration-postgres on 3.14
  • GitHub Check: 🔬 unit on 3.11
  • GitHub Check: 🔬 integration-mysql on 3.11
  • GitHub Check: 🔬 unit-no-extras on 3.14
  • GitHub Check: 🔬 unit-no-extras on 3.13
  • GitHub Check: 🔬 unit on 3.12
  • GitHub Check: 🔬 integration-postgres on 3.11
  • GitHub Check: 🔬 unit-no-extras on 3.11
  • GitHub Check: 🔬 unit on 3.14
  • GitHub Check: Optimize new code in this PR
🔇 Additional comments (29)
.gitignore (1)

195-196: LGTM!

Adding .serena to the gitignore is appropriate for excluding tool-specific configuration from version control.

tests/unit/test_mutation_input.py (1)

22-25: LGTM!

Removing the Pyright type-ignore comments is a positive cleanup, indicating that the type system now correctly infers these types after the refactoring work in this PR.

tests/unit/mapping/test_schemas.py (1)

65-67: LGTM!

Consistent with the cleanup in test_mutation_input.py, removing type-ignore comments here indicates improved type inference for dynamically generated input types.

src/strawchemy/strawberry/factories/inputs.py (1)

397-397: LGTM!

Narrowing the type hint from type[Any] to type[DeclarativeBase] is a good refinement that accurately reflects the expected SQLAlchemy model type and improves type safety.

pyproject.toml (3)

380-396: LGTM!

The slotscheck configuration is well-structured with appropriate exclusions for test files and external modules. The comment referencing slotscheck/issues/178 for the SQLAlchemy mypy exclusion is helpful documentation.


398-403: LGTM!

The additional unasyncd options are sensible defaults that improve the quality of generated synchronous code by automatically applying formatting and updating docstrings.


66-66: LGTM!

Adding slotscheck to the lint dependencies is a good addition for verifying proper __slots__ usage in the codebase. Version 0.16.5 and later are available on PyPI.

mise.toml (2)

218-218: LGTM! Slotscheck task addition is well-structured.

The new slotscheck task is properly defined with a clear description and command, and correctly wired as a dependency of the lint task. This enhances runtime memory efficiency checks for class definitions.

Also applies to: 229-231


247-255: Formatting-only changes to clean task.

These are cosmetic indentation adjustments with no semantic impact.

tasks.md (2)

73-73: LGTM! Documentation correctly reflects slotscheck task addition.

The generated documentation is consistent with the mise.toml changes.

Also applies to: 132-136


151-152: Auto-generated default placeholders are correct.

The empty **Default:** `` entries throughout the file correctly represent optional arguments with empty string defaults, matching the arg(..., default="")specifications inmise.toml`.

src/strawchemy/factories.py (3)

23-51: Well-designed factory container with clear responsibilities.

The StrawchemyFactories dataclass provides a clean centralized container for all DTO factories with comprehensive docstrings. The # type: ignore[type-arg] comments on lines 46-48 are acceptable for complex generic factory types where full type parameters would add noise without practical benefit.


53-114: Factory wiring logic is clean and well-documented.

The create() classmethod properly initializes all backends and factories with their dependencies. The dependency injection pattern here supports easier testing and better separation of concerns.


116-135: Public API mapping is clear and consistent.

The create_public_api() method provides a clean mapping of user-facing API names to internal factory methods, using partial() appropriately to bind mode parameters.

src/strawchemy/mapper.py (5)

93-123: Excellent refactor to centralized factory management.

The initialization now cleanly delegates to StrawchemyFactories.create(self), storing private factory references for internal use while exposing the public API through create_public_api(). This significantly improves testability and maintainability.


364-380: Clean delegation to MutationFieldBuilder.

The create() method now delegates to _mutation_builder.build(), eliminating boilerplate while maintaining the same functionality. The input_type and validation are correctly passed as field-specific kwargs.


440-458: Upsert method correctly passes enum kwargs.

The update_fields_enum and conflict_fields_enum are properly forwarded to the builder as field-specific kwargs, matching the StrawchemyUpsertMutationField constructor expectations.


516-533: Update method correctly forwards filter_type.

The filter_input is passed as filter_type to the builder, consistent with the field class's expected parameter naming.


660-675: Delete method correctly handles optional filter_input.

The filter_input is passed as input_type to the builder. StrawchemyDeleteMutationField handles None gracefully—its auto_arguments() method checks if self._input_type: before creating filter arguments, returning an empty list when None.

src/strawchemy/strawberry/mutation/builder.py (3)

27-37: Well-structured builder dataclass.

The MutationFieldBuilder cleanly encapsulates the configuration and namespace getter needed for mutation field construction. Using a dataclass provides immutability for the configuration while supporting the builder pattern.


39-61: Any types are appropriate for this dynamic builder interface.

The static analysis flags ANN401 for several Any usages, but these are justified:

  • resolver: Accepts any callable signature
  • graphql_type: Strawberry types are dynamically resolved
  • default: Mirrors dataclasses.MISSING pattern
  • **field_specific_kwargs: Must accept various field-specific parameters
  • Return type: Returns different mutation field types

This is a valid use of Any for a generic factory/builder pattern.


87-109: Build logic correctly delegates to field constructors.

The method properly:

  1. Resolves the namespace from the getter
  2. Creates StrawberryAnnotation only when graphql_type is provided
  3. Falls back to config.repository_type when repository_type is None
  4. Passes all common and field-specific kwargs to the field constructor
  5. Wraps with resolver if provided

This eliminates significant duplication across mutation methods in the mapper.

src/strawchemy/strawberry/factories/aggregations.py (7)

41-52: Well-designed configuration dataclass.

The _TypeFilterConfig dataclass is appropriately frozen and slotted for immutability and memory efficiency. Using frozenset for the types collection is a good choice since these shouldn't be mutated after creation.


105-112: LGTM!

The variable rename from field to field_def improves clarity and avoids shadowing the built-in. The conditional wrapping with FunctionArgFieldDefinition.from_field when a function is provided aligns with the from_field signature in the relevant code snippets.


208-228: Clean configuration-driven factory initialization.

The centralized _aggregation_type_filters class variable provides a clear, maintainable way to define aggregation type configurations. The instance-level _type_filtered_factories dictionary is appropriately created per inspector since factories hold mapper references. This pattern makes adding new aggregation types straightforward.


338-348: LGTM!

The method properly handles missing aggregation keys with a safe .get() lookup and returns None for both unknown keys and when no matching fields exist (via DTOError handling).


350-378: Verify direct dictionary access is intentional.

These methods use direct dictionary access (_type_filtered_factories["key"]) while arguments_type uses .get(). The direct access is safe since the keys are hardcoded and guaranteed to exist in _aggregation_type_filters. However, if you prefer consistency with arguments_type, consider using .get() with a fallback. The current approach is valid as it will fail fast if configuration is inadvertently broken.


380-412: LGTM!

The method signature is updated to use type[DeclarativeBase] consistently with the rest of the refactor. The aggregation logic remains sound and properly integrates with the updated factory methods.


414-457: LGTM!

The method properly uses the new arguments_type method for factory lookup and maintains the existing aggregation filter logic. The type hint update is consistent with the broader refactor.

Comment on lines +64 to +82
from strawchemy.dto.backend.strawberry import StrawberrryDTOBackend # noqa: PLC0415
from strawchemy.strawberry.dto import MappedStrawberryGraphQLDTO # noqa: PLC0415
from strawchemy.strawberry.factories.aggregations import EnumDTOFactory # noqa: PLC0415
from strawchemy.strawberry.factories.enum import ( # noqa: PLC0415
EnumDTOBackend,
UpsertConflictFieldsEnumDTOBackend,
)
from strawchemy.strawberry.factories.inputs import ( # noqa: PLC0415
AggregateFilterDTOFactory,
BooleanFilterDTOFactory,
)
from strawchemy.strawberry.factories.types import ( # noqa: PLC0415
DistinctOnFieldsDTOFactory,
InputFactory,
OrderByDTOFactory,
RootAggregateTypeDTOFactory,
TypeDTOFactory,
UpsertConflictFieldsDTOFactory,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove unused noqa directives.

Static analysis indicates that PLC0415 is not enabled in your ruff configuration, making these noqa comments unnecessary. The internal imports are still valid and intentional for avoiding circular dependencies.

🔎 Proposed fix
-        from strawchemy.dto.backend.strawberry import StrawberrryDTOBackend  # noqa: PLC0415
-        from strawchemy.strawberry.dto import MappedStrawberryGraphQLDTO  # noqa: PLC0415
-        from strawchemy.strawberry.factories.aggregations import EnumDTOFactory  # noqa: PLC0415
-        from strawchemy.strawberry.factories.enum import (  # noqa: PLC0415
+        from strawchemy.dto.backend.strawberry import StrawberrryDTOBackend
+        from strawchemy.strawberry.dto import MappedStrawberryGraphQLDTO
+        from strawchemy.strawberry.factories.aggregations import EnumDTOFactory
+        from strawchemy.strawberry.factories.enum import (
             EnumDTOBackend,
             UpsertConflictFieldsEnumDTOBackend,
         )
-        from strawchemy.strawberry.factories.inputs import (  # noqa: PLC0415
+        from strawchemy.strawberry.factories.inputs import (
             AggregateFilterDTOFactory,
             BooleanFilterDTOFactory,
         )
-        from strawchemy.strawberry.factories.types import (  # noqa: PLC0415
+        from strawchemy.strawberry.factories.types import (
             DistinctOnFieldsDTOFactory,
             InputFactory,
             OrderByDTOFactory,
             RootAggregateTypeDTOFactory,
             TypeDTOFactory,
             UpsertConflictFieldsDTOFactory,
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from strawchemy.dto.backend.strawberry import StrawberrryDTOBackend # noqa: PLC0415
from strawchemy.strawberry.dto import MappedStrawberryGraphQLDTO # noqa: PLC0415
from strawchemy.strawberry.factories.aggregations import EnumDTOFactory # noqa: PLC0415
from strawchemy.strawberry.factories.enum import ( # noqa: PLC0415
EnumDTOBackend,
UpsertConflictFieldsEnumDTOBackend,
)
from strawchemy.strawberry.factories.inputs import ( # noqa: PLC0415
AggregateFilterDTOFactory,
BooleanFilterDTOFactory,
)
from strawchemy.strawberry.factories.types import ( # noqa: PLC0415
DistinctOnFieldsDTOFactory,
InputFactory,
OrderByDTOFactory,
RootAggregateTypeDTOFactory,
TypeDTOFactory,
UpsertConflictFieldsDTOFactory,
)
from strawchemy.dto.backend.strawberry import StrawberrryDTOBackend
from strawchemy.strawberry.dto import MappedStrawberryGraphQLDTO
from strawchemy.strawberry.factories.aggregations import EnumDTOFactory
from strawchemy.strawberry.factories.enum import (
EnumDTOBackend,
UpsertConflictFieldsEnumDTOBackend,
)
from strawchemy.strawberry.factories.inputs import (
AggregateFilterDTOFactory,
BooleanFilterDTOFactory,
)
from strawchemy.strawberry.factories.types import (
DistinctOnFieldsDTOFactory,
InputFactory,
OrderByDTOFactory,
RootAggregateTypeDTOFactory,
TypeDTOFactory,
UpsertConflictFieldsDTOFactory,
)
🧰 Tools
🪛 Ruff (0.14.8)

64-64: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


65-65: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


66-66: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


67-67: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


71-71: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


75-75: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

🤖 Prompt for AI Agents
In src/strawchemy/factories.py around lines 64 to 82, multiple import lines
include unnecessary "# noqa: PLC0415" directives; remove these unused noqa
comments from each import (e.g., after StrawberrryDTOBackend,
MappedStrawberryGraphQLDTO, EnumDTOFactory, EnumDTOBackend,
UpsertConflictFieldsEnumDTOBackend, AggregateFilterDTOFactory,
BooleanFilterDTOFactory, DistinctOnFieldsDTOFactory, InputFactory,
OrderByDTOFactory, RootAggregateTypeDTOFactory, TypeDTOFactory,
UpsertConflictFieldsDTOFactory) so the imports remain but the redundant noqa
annotations are deleted.

Comment on lines +174 to +182
def __init__(
self,
base_name: str,
dto_config: DTOConfig,
node: Node[Relation[Any, UnmappedStrawberryGraphQLDTO[ModelT]], None] | None = None,
) -> str:
return f"{base_name}MinMaxStringFields"


class _MinMaxTimeFieldsDTOFactory(_FunctionArgDTOFactory):
types: ClassVar[set[type[Any]]] = {time}
mapper: Strawchemy,
filter_config: _TypeFilterConfig,
backend: DTOBackend[UnmappedStrawberryGraphQLDTO[DeclarativeBase]] | None = None,
) -> None:
super().__init__(mapper, backend)
self._filter_types = set(filter_config.types)
self._suffix = filter_config.suffix
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider keeping _filter_types as frozenset instead of converting to set.

Since _filter_types is only used for membership testing (not in self._filter_types), there's no need to convert the immutable frozenset to a mutable set. Keeping it as frozenset maintains consistency with the source config and prevents accidental mutation.

🔎 Proposed fix
     def __init__(
         self,
         mapper: Strawchemy,
         filter_config: _TypeFilterConfig,
         backend: DTOBackend[UnmappedStrawberryGraphQLDTO[DeclarativeBase]] | None = None,
     ) -> None:
         super().__init__(mapper, backend)
-        self._filter_types = set(filter_config.types)
+        self._filter_types = filter_config.types
         self._suffix = filter_config.suffix
🤖 Prompt for AI Agents
In src/strawchemy/strawberry/factories/aggregations.py around lines 174 to 182,
the constructor converts filter_config.types into a mutable set even though only
membership checks are performed; change self._filter_types to hold the original
frozenset (or cast to frozenset) instead of set to avoid unnecessary mutability
and preserve the config's immutability — replace the set(...) conversion with
using filter_config.types directly (or wrap with frozenset(...) if type
assurance is needed).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2db5ce and af15c83.

📒 Files selected for processing (1)
  • .github/workflows/ci.yaml (5 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Run `mise run lint` to execute linters and formatters (optional to run manually; will run via pre-commit)

Applied to files:

  • .github/workflows/ci.yaml
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Run `mise run install` to install all dependencies and pre-commit hooks

Applied to files:

  • .github/workflows/ci.yaml
📚 Learning: 2025-09-14T11:55:31.395Z
Learnt from: CR
Repo: gazorby/strawchemy PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-09-14T11:55:31.395Z
Learning: Use mise to manage build and test tasks for the project

Applied to files:

  • .github/workflows/ci.yaml
🪛 YAMLlint (1.37.1)
.github/workflows/ci.yaml

[error] 9-9: too many spaces inside brackets

(brackets)


[error] 9-9: too many spaces inside brackets

(brackets)


[error] 13-13: too many spaces inside brackets

(brackets)


[error] 13-13: too many spaces inside brackets

(brackets)


[error] 60-60: too many spaces inside brackets

(brackets)


[error] 60-60: too many spaces inside brackets

(brackets)


[error] 124-124: too many spaces inside brackets

(brackets)


[error] 124-124: too many spaces inside brackets

(brackets)


[error] 158-158: too many spaces inside brackets

(brackets)


[error] 158-158: too many spaces inside brackets

(brackets)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: 🔬 integration-sqlite on 3.10
  • GitHub Check: 🔬 unit-no-extras on 3.13
  • GitHub Check: 🔬 integration-postgres on 3.13
  • GitHub Check: 🔬 unit-no-extras on 3.12
  • GitHub Check: 🔬 unit-no-extras on 3.14
  • GitHub Check: ✨ Lint
  • GitHub Check: Optimize new code in this PR
🔇 Additional comments (1)
.github/workflows/ci.yaml (1)

199-201: Good addition to ensure dependencies are installed before linting.

This step properly prepares the lint environment by installing dependencies (including the newly added slotscheck tooling). This aligns well with the project's use of mise for task management.

on:
push:
branches: [main, ci/*, dependabot/*, renovate/*]
branches: [ main, ci/*, dependabot/*, renovate/* ]
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove extra spaces inside brackets to comply with YAML style guidelines.

YAMLlint flags "too many spaces inside brackets" on these lines. The standard YAML convention is to write arrays without spaces after [ and before ].

🔎 Proposed fix
-    branches: [ main, ci/*, dependabot/*, renovate/* ]
+    branches: [main, ci/*, dependabot/*, renovate/*]
-    branches: [ main ]
+    branches: [main]
-    needs: [ pre, generate-jobs-tests ]
+    needs: [pre, generate-jobs-tests]
-    needs: [ tests, generate-jobs-tests ]
+    needs: [tests, generate-jobs-tests]
-    needs: [ tests, generate-jobs-tests ]
+    needs: [tests, generate-jobs-tests]

Also applies to: 13-13, 60-60, 124-124, 158-158

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 9-9: too many spaces inside brackets

(brackets)


[error] 9-9: too many spaces inside brackets

(brackets)

🤖 Prompt for AI Agents
.github/workflows/ci.yaml lines 9, 13, 60, 124 and 158: the array entries use
spaces inside square brackets (e.g. "[ main, ci/*, ... ]") which violates YAML
lint rules; remove the extra spaces immediately after '[' and before ']' so
arrays read like "[main, ci/*, dependabot/*, renovate/*]" (and similarly for the
other lines) to comply with YAML style guidelines.

@codecov
Copy link

codecov bot commented Dec 18, 2025

Codecov Report

❌ Patch coverage is 98.30508% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.29%. Comparing base (2113d64) to head (685c085).
⚠️ Report is 5 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...rc/strawchemy/strawberry/factories/aggregations.py 93.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #138      +/-   ##
==========================================
- Coverage   94.37%   94.29%   -0.09%     
==========================================
  Files          63       65       +2     
  Lines        5833     5832       -1     
  Branches      775      770       -5     
==========================================
- Hits         5505     5499       -6     
- Misses        186      191       +5     
  Partials      142      142              

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

@gazorby gazorby merged commit 0be5a15 into main Dec 18, 2025
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