Skip to content

Fix variable coercion for expression-based filter fields - #10126

Open
glen-84 wants to merge 2 commits into
mainfrom
gai/expression-filter-field-variable-coercion
Open

Fix variable coercion for expression-based filter fields#10126
glen-84 wants to merge 2 commits into
mainfrom
gai/expression-filter-field-variable-coercion

Conversation

@glen-84

@glen-84 glen-84 commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary

  • Expression-based filter fields (for example descriptor.Field(x => x.Bars.OrderByDescending(b => b.Id).Take(1))) registered the expression's return type as the field's input coercion runtime type. When the filter was supplied through a GraphQL variable, variable coercion tried to materialize the filter value into that type and failed for non-constructible types such as collection interfaces, rejecting the request with HC0016: Variable 'where' got an invalid value.
  • Expression-based filter fields now leave the coercion runtime type unset, so filter variable values materialize as plain dictionaries, exactly like member-bound filter fields. The expression's return type is still used to build the filter predicate, so filtering behavior is unchanged.

Test plan

  • New Create_CollectionExpression_WithVariables snapshot test: a collection-valued expression field filtered through a variable, asserting matching and non-matching results.
  • Ran the filter suites for every provider locally: Data.Filters.Tests, Data.Filters.InMemory.Tests, Data.Filters.SqlServer.Tests, MongoDb, Marten, Raven, and Spatial.

Closes #7024
Supersedes #9266

Copilot AI review requested due to automatic review settings July 21, 2026 11:47

Copilot AI 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.

Pull request overview

Fixes variable coercion failures for expression-based filter fields by avoiding registration of the expression return type as the field’s input coercion runtime type, while still preserving the expression return type for predicate construction.

Changes:

  • Stop setting FilterFieldConfiguration.RuntimeType from expression return types during filter field descriptor construction to prevent variable materialization into non-constructible interface types.
  • Ensure FilterField.RuntimeType is still derived from the expression return type during type completion so expression-based predicates continue to work.
  • Add an in-memory snapshot test covering filtering a collection-valued expression field via GraphQL variables.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/HotChocolate/Data/test/Data.Filters.InMemory.Tests/QueryableFilterVisitorExpressionTests.cs Adds a regression test for variable-based filtering against a collection-valued expression field.
src/HotChocolate/Data/test/Data.Filters.InMemory.Tests/snapshots/QueryableFilterVisitorExpressionTests.Create_CollectionExpression_WithVariables.snap Snapshot for the new regression test (match + no-match cases).
src/HotChocolate/Data/src/Data/Filters/FilterFieldDescriptor.cs Removes expression-based assignment of Configuration.RuntimeType to avoid incorrect variable coercion behavior.
src/HotChocolate/Data/src/Data/Filters/Fields/FilterField.cs Restores runtime type derivation for expression fields at completion time to keep predicate building behavior unchanged.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

Copy link
Copy Markdown
Contributor

Patch coverage

100.0% of changed lines covered (4/4)

File Covered Changed Patch %
src/HotChocolate/Data/src/Data/Filters/Fields/FilterField.cs 4 4 100.0% 🟢

Project coverage: 53.8% (231323/430064 lines)

@glen-84
glen-84 requested a review from michaelstaib July 21, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error in variable coercion when using custom filter in query

2 participants