Skip to content

fix: Bool/ID/Int/Float/Decimal filter lookups without type parameter - #933

Open
skocks wants to merge 1 commit into
strawberry-graphql:mainfrom
EONIQ-AI:concrete-numeric-filter-lookups
Open

fix: Bool/ID/Int/Float/Decimal filter lookups without type parameter#933
skocks wants to merge 1 commit into
strawberry-graphql:mainfrom
EONIQ-AI:concrete-numeric-filter-lookups

Conversation

@skocks

@skocks skocks commented Jul 6, 2026

Copy link
Copy Markdown

Related to #519.

BoolFilterLookup, IDFilterLookup, IntFilterLookup, FloatFilterLookup and DecimalFilterLookup were resolved via the generic BaseFilterLookup/ComparisonFilterLookup, re-specializing the generic at every usage site — once per filterable bool/ID/int/float/Decimal field, per model. For schemas with many models this adds up (#519's report: startup time scaling ~linearly with filter field count).

Made them concrete, mirroring the StrFilterLookup/DateFilterLookup/TimeFilterLookup/DatetimeFilterLookup fix from #891/#910 — this completes that same treatment for every remaining generic entry in type_filter_map. No changes needed to resolve_model_field_type's auto-resolution path; the __parameters__ guard added in #910 already skips subscripting any concrete lookup generically.

@strawberry_django.filter_type(models.Project)
class ProjectFilter:
    is_active: strawberry_django.BoolFilterLookup | None
    priority: strawberry_django.IntFilterLookup | None
    budget: strawberry_django.DecimalFilterLookup | None

Breaking change

Generated GraphQL input names lose their type prefix: IntComparisonFilterLookup becomes IntFilterLookup, BoolBaseFilterLookup becomes BoolFilterLookup, IDBaseFilterLookup becomes IDFilterLookup. Clients referencing these inputs by name need to update. Bumping as minor, matching #910's precedent.

Measured impact

Benchmarked cold schema builds on a real-world downstream schema (~180 models, 2 distinct exposure shapes), 3 runs each, before/after:

shape A shape B
baseline (0.82.1, fully generic) 3.235s 3.244s
after #910 alone (0.86.4) 3.057s (−5.5%) 3.093s (−4.7%)
after this PR on top of #910 3.026s (−6.5%) 3.037s (−6.4%)

The marginal win on top of #910 alone is modest for this particular schema (datetime fields dominated its filter-lookup redundancy, and #910 already covers those) — but schemas with a larger share of bool/int/float/Decimal filterable fields relative to datetime fields should see comparatively more benefit, since this closes the same gap for those types.

Test plan

  • Added regression tests mirroring fix: Date/Time/Datetime filter lookups without type parameter #910's test_{str,date,time,datetime}_filter_lookup_without_type_parameter for the 5 new concrete lookups
  • Updated test_filter_type (auto-resolved id/sweetness fields now report IDFilterLookup/IntFilterLookup instead of BaseFilterLookup/ComparisonFilterLookup)
  • Full suite passes, ruff check/format clean, pyright clean
  • RELEASE.md added

Summary by Sourcery

Make scalar filter lookup inputs concrete for bool, ID, int, float, and Decimal fields to avoid per-field generic specialization and improve schema build performance.

New Features:

  • Expose concrete BoolFilterLookup, IDFilterLookup, IntFilterLookup, FloatFilterLookup, and DecimalFilterLookup types for use in filter definitions.

Bug Fixes:

  • Ensure filter lookups for bool, ID, int, float, and Decimal fields work without requiring an explicit type parameter, aligning behavior with other scalar lookups.

Enhancements:

  • Update type_filter_map to use the new concrete scalar filter lookup types for common field types, reducing redundant generic specialization during schema construction.

Documentation:

  • Add RELEASE.md documenting the new concrete filter lookup types, migration steps for existing filter usages, and the breaking changes to generated GraphQL input names.

Tests:

  • Add regression tests covering Bool/ID/Int/Float/DecimalFilterLookup usage without type parameters and update existing filter type tests to expect the new concrete lookup names.

BoolFilterLookup, IDFilterLookup, IntFilterLookup, FloatFilterLookup and
DecimalFilterLookup were resolved via the generic BaseFilterLookup/
ComparisonFilterLookup, re-specializing the generic per usage site for
every filterable bool/ID/int/float/Decimal field across every model.
For large schemas this is a meaningful share of build time (strawberry-graphql#519).

Made them concrete, mirroring the StrFilterLookup/DateFilterLookup/
TimeFilterLookup/DatetimeFilterLookup fix from strawberry-graphql#891/strawberry-graphql#910 - completing
that pattern for every remaining generic entry in type_filter_map.

Breaking change: generated GraphQL input names lose their type prefix
(e.g. IntComparisonFilterLookup becomes IntFilterLookup). Bumping as
minor for this reason, matching strawberry-graphql#910's precedent.
@skocks
skocks marked this pull request as draft July 6, 2026 12:21
@botberry

botberry commented Jul 6, 2026

Copy link
Copy Markdown
Member

Thanks for adding the RELEASE.md file!

Below is the changelog that will be used for the release.


BoolFilterLookup, IDFilterLookup, IntFilterLookup, FloatFilterLookup and
DecimalFilterLookup no longer require a type parameter, matching
StrFilterLookup/DateFilterLookup/TimeFilterLookup/DatetimeFilterLookup
(#891, #910). This completes the same fix for every remaining entry in
type_filter_map that was still generic.

@strawberry_django.filter_type(models.Project)
class ProjectFilter:
    is_active: strawberry_django.BoolFilterLookup | None
    id: strawberry_django.IDFilterLookup | None
    priority: strawberry_django.IntFilterLookup | None
    weight: strawberry_django.FloatFilterLookup | None
    budget: strawberry_django.DecimalFilterLookup | None

Migrating:

  • Drop the type argument from BaseFilterLookup[bool], ComparisonFilterLookup[int],
    etc. when referencing the now-concrete classes directly. The bare lookup now works;
    the bracket form still resolves to the same class but emits a DeprecationWarning.
  • Generated GraphQL input names lose their type prefix, e.g. IntComparisonFilterLookup
    becomes IntFilterLookup, BoolBaseFilterLookup becomes BoolFilterLookup, and
    IDBaseFilterLookup becomes IDFilterLookup. Clients referencing these inputs by
    name need to update.

Building on many models with many filterable fields previously re-specialized these
generic lookups independently at every usage site, which is a meaningful share of
schema build time for large schemas (see #519). Making them concrete removes that
redundant generic re-specialization for the most common filter field types.

This release was contributed by @skocks in #933

@sourcery-ai sourcery-ai 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.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@skocks
skocks marked this pull request as ready for review August 3, 2026 05:39
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.

2 participants