Skip to content

Feat/rapid 7283 fix or filter audience#512

Closed
LinoGiger wants to merge 6 commits intomainfrom
feat/RAPID-7283-fix-or-filter-audience
Closed

Feat/rapid 7283 fix or filter audience#512
LinoGiger wants to merge 6 commits intomainfrom
feat/RAPID-7283-fix-or-filter-audience

Conversation

@LinoGiger
Copy link
Collaborator

image

@claude
Copy link

claude bot commented Mar 19, 2026

PR Review: Feat/RAPID-7283 Fix or Filter Audience

Overall a clean, well-scoped PR. Changes align with existing patterns (lazy init, TYPE_CHECKING imports). A few observations:

or_filter.py bug fix - The .to_dict() addition is correct. OneOf discriminated union models in Pydantic-based generated code do not recursively serialize nested instances — plain dicts are required. Real bug fix, correct approach.

Naming inconsistency: _add_rapid_example() - The method internals were updated to use IExamplePayload/IExampleTruth but the method name still says 'rapid'. Consider renaming to _add_example() for consistency with the migration.

Fragile conversion via from_dict(to_dict()) - The comment says both types are structurally identical, which is true today. But if the backend schemas ever diverge, this breaks silently at runtime with no compile-time signal. A round-trip unit test would catch future drift. Also worth guarding: IExamplePayload.from_dict() can return None — consider raising a ValueError with a helpful message if that happens.

api.mustache deep object support - The hasattr(_param_val, 'to_dict') duck-typing approach is reasonable for generated code. Worth documenting in a comment that this pattern is intentional so future template maintainers don't remove it.

find_orders() simplification - The new flat parameter interface is much cleaner than the previous 7-import nested QueryModel. FlowGetNameParameter is a slightly odd name for an order name filter, but that appears to be a backend naming decision.

Missing tests - No tests cover: OrFilter nested serialization (the bug fix), the IRapidPayload->IExamplePayload conversion in _add_rapid_example, or the new find_orders() query params. A regression test for the OrFilter fix would be especially valuable.

Minor - The preview_order_endpoint_input import line in rapidata_order.py is quite long compared to the rest of the file.

Generated with Claude Code

@claude
Copy link

claude bot commented Mar 19, 2026

PR Review: Fix OrFilter serialization

The fix is correct and well-targeted. Here's the analysis and a few points to consider.


Why this fix is correct

The root cause is a type mismatch in the generated API models:

  • IUserFilterModelOrUserFilterModel.filters and IAudienceFilterOrAudienceFilter.filters are typed as Optional[Any], and their to_dict() methods rely on plain model_dump() — which will not recursively call .to_dict() on nested Pydantic objects.
  • By contrast, IUserFilterModelAndUserFilterModel.filters and IAudienceFilterAndAudienceFilter.filters are typed as List[IUserFilterModel]/List[IAudienceFilter] respectively, and their to_dict() methods explicitly call .to_dict() on each item:
    # in IAudienceFilterAndAudienceFilter.to_dict()
    for _item_filters in self.filters:
        if _item_filters:
            _items.append(_item_filters.to_dict())

So AndFilter serializes correctly without pre-conversion, but OrFilter does not — making the fix asymmetric but correct.


Points to consider

1. Root cause is in the generated API client (not just or_filter.py)

The underlying issue is that IAudienceFilterOrAudienceFilter and IUserFilterModelOrUserFilterModel use Optional[Any] for filters instead of a strongly-typed list. This looks like an OpenAPI spec or generator issue. The workaround (pre-converting to dict) is a reasonable short-term fix, but it would be cleaner to fix the OpenAPI spec/template so that OrFilter gets the same strongly-typed treatment as AndFilter.

Per CLAUDE.md: if changes are needed in generated files, the mustache templates under openapi/templates should also be updated. This PR does not touch those templates — worth checking if this asymmetry should be addressed at the spec/template level to prevent future regressions.

2. NotFilter may have a similar issue

not_filter.py passes a single IUserFilterModel/IAudienceFilter directly (not a list), via:

filter=self.filter._to_model()

The IUserFilterModelNotUserFilterModel and IAudienceFilterNotAudienceFilter models should be checked to confirm their to_dict() handles nested objects correctly — or whether a similar .to_dict() call is also needed there.

3. No test coverage

There are no existing tests for filter serialization. A simple unit test verifying that OrFilter([LanguageFilter(...), CountryFilter(...)])._to_model().to_dict() produces the expected dict structure would prevent regressions and make the fix self-documenting.


Summary

The fix correctly resolves the serialization bug in OrFilter. Approve with the suggestion to investigate whether the same issue affects NotFilter, and whether the root cause in the generated models should be addressed at the OpenAPI template level.

@claude
Copy link

claude bot commented Mar 20, 2026

PR Review: Fix OrFilter serialization for audience filters

The fix is correct and well-targeted.

Root cause confirmed

The asymmetry between AndFilter and OrFilter stems from the generated API models:

  • IAudienceFilterAndAudienceFilter.filters typed as List[IAudienceFilter]: Pydantic serializes each item via .to_dict() explicitly
  • IAudienceFilterOrAudienceFilter.filters typed as Optional[Any]: model_dump() dumps whatever is there, losing nested structure

AndFilter worked by accident (strongly typed list), while OrFilter silently produced broken output. The pre-converting-to-dict workaround in or_filter.py is correct given the generated model constraints. NotFilter does not need the same fix since IAudienceFilterNotAudienceFilter.filter is typed as IAudienceFilter with an explicit .to_dict() call in its serializer.

Observations

  1. Inline import inconsistency in _backend_filter_mapper.py: The file already imports IAudienceFilter under TYPE_CHECKING at the top (lines 6-8), but a new runtime import was added inline inside the elif branch at line 115. Python module caching means this is not a performance issue, but a comment explaining why a separate runtime import is needed here would help future readers.

  2. Mapper fix is correctly asymmetric: The BackendAndAudienceFilter branch does not need the from_dict check because IAudienceFilterAndAudienceFilter.filters is List[IAudienceFilter] and Pydantic deserializes them as proper objects. The BackendOrAudienceFilter branch correctly adds the dict->IAudienceFilter conversion since Optional[Any] causes raw dicts to be returned.

  3. Root fix belongs in the OpenAPI spec/template: Per CLAUDE.md, changes to generated files should also update mustache templates under openapi/templates. The spec appears to declare OrFilter.filters differently from AndFilter.filters. Fixing the spec so OrAudienceFilter.filters gets a typed list would eliminate these workarounds and prevent future filter types from hitting the same issue.

  4. No test coverage: There are no tests verifying that OrFilter serialization produces the correct nested structure. A regression test would catch recurrence immediately.

Summary: The fix resolves the bug correctly. Suggestions: (1) add a comment explaining the inline import in the mapper, (2) consider fixing the OpenAPI spec so OrFilter.filters is strongly typed, (3) add a unit test for OrFilter serialization.

Generated with Claude Code

@LinoGiger LinoGiger closed this Mar 27, 2026
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