Skip to content

fix(query-core): treat undefined object properties as missing in partialMatchKey#10795

Open
AliMahmoudDev wants to merge 1 commit into
TanStack:mainfrom
AliMahmoudDev:fix/query-key-undefined-property-matching
Open

fix(query-core): treat undefined object properties as missing in partialMatchKey#10795
AliMahmoudDev wants to merge 1 commit into
TanStack:mainfrom
AliMahmoudDev:fix/query-key-undefined-property-matching

Conversation

@AliMahmoudDev
Copy link
Copy Markdown

@AliMahmoudDev AliMahmoudDev commented May 25, 2026

Closes #3741

🎯 Changes

Query keys with object properties set to undefined were not treated as equivalent to missing properties during partial key matching (used by invalidateQueries, getQueriesData, etc.).

Before this fix:

// Query key: ["todos"]
// This invalidation would NOT match the query:
queryClient.invalidateQueries({ queryKey: ["todos", { filter: undefined }] })

After this fix:

// Query key: ["todos"]
// Now correctly matches:
queryClient.invalidateQueries({ queryKey: ["todos", { filter: undefined }] })
// Also matches ["todos", {}] and ["todos", { status: "done" }]

This aligns partialMatchKey behavior with the documented behavior that query keys are hashed deterministically, where { filter: undefined } should be equivalent to {}.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.

Will generate changeset after review feedback.

Summary by CodeRabbit

  • Tests

    • Added comprehensive test cases covering undefined value handling scenarios in partial key matching.
  • Bug Fixes

    • Improved partial key matching to treat undefined object properties as missing values. Ensures consistent comparison behavior for nested objects and filters containing undefined values.

Review Change Stack

…ialMatchKey

Closes TanStack#3741

Query keys with object properties set to undefined were not treated as
equivalent to missing properties during partial key matching (used by
invalidateQueries, getQueriesData, etc.).

For example, invalidateQueries({ queryKey: ['todos', { filter: undefined }] })
would not match a query with key ['todos'] or ['todos', {}], even though
per the docs query keys are hashed deterministically and { filter: undefined }
should be equivalent to {}.

The fix skips keys with undefined values in the filter object, and also
handles the case where the query key array is shorter than the filter array
by treating objects with all-undefined values as empty (equivalent to
no constraint).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

📝 Walkthrough

Walkthrough

The partialMatchKey utility function is updated to treat undefined object properties as equivalent to missing properties. The matching logic now explicitly handles undefined values during object-to-object comparison, and test cases are added to verify the new semantics.

Changes

partialMatchKey undefined handling

Layer / File(s) Summary
Explicit undefined handling in partialMatchKey
packages/query-core/src/utils.ts
Object-to-object matching now iterates over keys and treats b[key] === undefined as a successful match, special-cases when a[key] is undefined but b[key] is an object with all-undefined values, and otherwise only recurses when neither condition applies.
Test coverage for undefined-handling semantics
packages/query-core/src/__tests__/utils.test.tsx
New test assertions verify that undefined properties are treated as missing, {} and objects with undefined values are considered equivalent, queries with specific filters match undefined filters, and mismatches occur when both sides specify different non-undefined values.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • TkDodo

Poem

🐰 When keys hold undefined in their soul,
We treat them as absent, make matching whole—
Filter or not, the meaning's the same,
Query invalidation wins the game! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing treatment of undefined object properties in partialMatchKey to be treated as missing.
Description check ✅ Passed The description covers the changes, provides before/after examples, links to issue #3741, includes a completed checklist, and explains the rationale.
Linked Issues check ✅ Passed The PR successfully addresses issue #3741 by modifying partialMatchKey logic to treat undefined properties as missing, enabling queries with { filter: undefined } to match queries without that property.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the partialMatchKey behavior for undefined properties: test additions and implementation updates are directly related to the stated objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
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.

🧹 Nitpick comments (1)
packages/query-core/src/__tests__/utils.test.tsx (1)

168-191: 💤 Low value

Consider adding a test for empty object matching shorter arrays.

The new implementation causes ['todos', {}] (as filter) to also match ['todos'] (as query) since Object.values({}).every(v => v === undefined) is vacuously true. This is a natural consequence of the design but worth documenting with a test:

it('should match shorter array against filter with empty object', () => {
  const a = ['todos']
  const b = ['todos', {}]
  expect(partialMatchKey(a, b)).toEqual(true)
})

This would make the behavioral contract explicit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/query-core/src/__tests__/utils.test.tsx` around lines 168 - 191, Add
a unit test to document the behavior that a shorter key array matches a longer
key when the longer key's last segment is an empty object: in
packages/query-core/src/__tests__/utils.test.tsx add a test case invoking
partialMatchKey with a = ['todos'] and b = ['todos', {}] and assert
expect(partialMatchKey(a, b)).toEqual(true); reference the existing test block
near other partialMatchKey cases (the 'should treat empty object and object with
undefined values as equivalent' group) so the new test sits alongside related
scenarios.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/query-core/src/__tests__/utils.test.tsx`:
- Around line 168-191: Add a unit test to document the behavior that a shorter
key array matches a longer key when the longer key's last segment is an empty
object: in packages/query-core/src/__tests__/utils.test.tsx add a test case
invoking partialMatchKey with a = ['todos'] and b = ['todos', {}] and assert
expect(partialMatchKey(a, b)).toEqual(true); reference the existing test block
near other partialMatchKey cases (the 'should treat empty object and object with
undefined values as equivalent' group) so the new test sits alongside related
scenarios.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 398e004e-edf8-4b23-a081-c4eb25bc863a

📥 Commits

Reviewing files that changed from the base of the PR and between b110d25 and 5c799ab.

📒 Files selected for processing (2)
  • packages/query-core/src/__tests__/utils.test.tsx
  • packages/query-core/src/utils.ts

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.

Query keys with object property set to undefined are not considered equal to missing property during invalidation

1 participant