Align GraphQL lookup types for booleans & numerics (replace FilterLookup) #11744

Open
opened 2025-12-29 21:49:22 +01:00 by adam · 1 comment
Owner

Originally created by @pheus on GitHub (Oct 17, 2025).

NetBox version

v4.4.4

Feature type

Change to existing functionality

Proposed functionality

To keep GraphQL filter inputs consistent and aligned with Strawberry‑Django, I’d like to suggest:

  • Booleans:

    Option A (preferred): use a plain bool on all boolean filter fields
    This keeps input shapes simple and ergonomic for typical use.

    # v2 boolean filters – applied consistently across all fields
    is_active: bool | None = strawberry_django.filter_field()
    

    Option B (alternative): use BaseFilterLookup[bool] on all boolean filter fields
    Choose this if we want to expose exact, isNull, and inList uniformly for tri‑state scenarios.

    from strawberry_django import BaseFilterLookup
    
    # v2 boolean filters – applied consistently across all fields
    is_active: BaseFilterLookup[bool] | None = strawberry_django.filter_field()
    

    The intent is consistency: adopt Option A (recommended) or Option B across the entire v2 schema, but don’t mix them by field.

  • Numerics (e.g., counts/lengths): adopt ComparisonFilterLookup[...] so v2 clients can use exact/gt/gte/lt/lte/range.

    from strawberry_django import ComparisonFilterLookup
    
    device_bay_count: ComparisonFilterLookup[int] | None = strawberry_django.filter_field()
    
  • Strings: continue using FilterLookup[str] where substring/regex matching is desired.

Use case

  • With Option A (preferred), boolean queries remain compact and easy to read:

    # exact match using plain bool
    query {
      device_type_list(filters: { is_full_depth: true }) { id }
    }
    
  • If Option B is selected, nullable/tri‑state patterns remain idiomatic:

    # exact true
    query {
      device_type_list(filters: { is_full_depth: { exact: true } }) { id }
    }
    
    # explicit null check
    query {
      device_type_list(filters: { is_full_depth: { is_null: true } }) { id }
    }
    
    # exclude nulls (generic builder pattern)
    query {
      device_type_list(filters: { is_full_depth: { in_list: [true, false] } }) { id }
    }
    
  • Numeric comparisons become first‑class:

    query {
      device_list(filters: { device_bay_count: { gte: 1, lte: 4 } }) { count }
    }
    

This keeps boolean filters uniform across v2 and exposes the intended comparison operators for numeric fields, aligning with Strawberry‑Django’s lookup families.

Database changes

None.

External dependencies

None.

Additional context

Originally created by @pheus on GitHub (Oct 17, 2025). ### NetBox version v4.4.4 ### Feature type Change to existing functionality ### Proposed functionality To keep GraphQL filter inputs consistent and aligned with Strawberry‑Django, I’d like to suggest: - **Booleans:** **Option A (preferred): use a plain `bool` on *all* boolean filter fields** This keeps input shapes simple and ergonomic for typical use. ```py # v2 boolean filters – applied consistently across all fields is_active: bool | None = strawberry_django.filter_field() ``` **Option B (alternative): use `BaseFilterLookup[bool]` on *all* boolean filter fields** Choose this if we want to expose `exact`, `isNull`, and `inList` uniformly for tri‑state scenarios. ```py from strawberry_django import BaseFilterLookup # v2 boolean filters – applied consistently across all fields is_active: BaseFilterLookup[bool] | None = strawberry_django.filter_field() ``` > The intent is **consistency**: adopt **Option A** (recommended) *or* **Option B** across the entire v2 schema, but don’t mix them by field. - **Numerics (e.g., counts/lengths):** adopt `ComparisonFilterLookup[...]` so v2 clients can use `exact/gt/gte/lt/lte/range`. ```py from strawberry_django import ComparisonFilterLookup device_bay_count: ComparisonFilterLookup[int] | None = strawberry_django.filter_field() ``` - **Strings:** continue using `FilterLookup[str]` where substring/regex matching is desired. ### Use case - With **Option A (preferred)**, boolean queries remain compact and easy to read: ```graphql # exact match using plain bool query { device_type_list(filters: { is_full_depth: true }) { id } } ``` - If **Option B** is selected, nullable/tri‑state patterns remain idiomatic: ```graphql # exact true query { device_type_list(filters: { is_full_depth: { exact: true } }) { id } } # explicit null check query { device_type_list(filters: { is_full_depth: { is_null: true } }) { id } } # exclude nulls (generic builder pattern) query { device_type_list(filters: { is_full_depth: { in_list: [true, false] } }) { id } } ``` - Numeric comparisons become first‑class: ```graphql query { device_list(filters: { device_bay_count: { gte: 1, lte: 4 } }) { count } } ``` This keeps boolean filters **uniform** across v2 and exposes the intended comparison operators for numeric fields, aligning with Strawberry‑Django’s lookup families. ### Database changes None. ### External dependencies None. ### Additional context - Related: #20603
Author
Owner

@arthanson commented on GitHub (Oct 23, 2025):

blocked by #20603

@arthanson commented on GitHub (Oct 23, 2025): blocked by #20603
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11744