Claude/optimize playlist queries n1nt b#908
Conversation
…hunking Replace unbounded single-request pattern with incremental fetch + chunking to fix server validation failures and eliminate wasteful refetching: - Create generic useIncrementalQuery hook that tracks fetched UUIDs, only fetches new ones, chunks requests >500 into parallel batches, and accumulates results in a stable cache key with optimistic update support - Refactor useClimbActionsData to use useIncrementalQuery for both favorites and playlist membership queries - Add server-side validation for favorites climbUuids (max 500, matching existing playlistsForClimbs limit) - Update tests with incremental fetch and reorder-stability scenarios https://claude.ai/code/session_0146aSM1evtmv8pnVAazL6FP
Claude Review✅ Ready to merge - Minor issues noted below, but nothing blocking. Issues
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 064c0e941f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const newUuids = useMemo( | ||
| () => (enabled ? uuids.filter((uuid) => !fetchedUuidsRef.current.has(uuid)) : []), | ||
| [uuids, enabled, invalidationCount], |
There was a problem hiding this comment.
Reset fetched UUID tracking when query identity changes
Track key changes (accumulatedKey/fetchKeyPrefix) as part of the incremental state reset, because newUuids currently depends only on uuids, enabled, and invalidationCount. When callers change context (e.g., boardName or angle in useClimbActionsData) but pass the same UUID list, those UUIDs stay marked as fetched and no new request is issued, so stale accumulated results from the previous context are reused.
Useful? React with 👍 / 👎.
| await queryClient.cancelQueries({ queryKey: favoritesQueryKey }); | ||
| const previousFavorites = queryClient.getQueryData<Set<string>>(favoritesQueryKey); | ||
| queryClient.setQueryData<Set<string>>(favoritesQueryKey, (old) => { | ||
| await queryClient.cancelQueries({ queryKey: favAccKey }); |
There was a problem hiding this comment.
Cancel in-flight favorites fetches before optimistic toggle
Canceling only favAccKey in onMutate does not stop active incremental fetch queries (['favorites', ..., 'fetch', ...]), so a stale response started before the toggle can still merge afterward and overwrite the optimistic removal/addition. This race is user-visible when toggling while favorites are loading, because the UI can revert to the pre-toggle state until a later manual refresh.
Useful? React with 👍 / 👎.
…lQuery tests - Add lastCacheWriteRef guard to skip self-triggered cache subscription events, preventing redundant setAccumulated calls from the merge effect's own write - Restore try-catch error logging in fetchChunk callbacks for both favorites and playlist memberships to aid debugging - Add comprehensive useIncrementalQuery unit tests covering chunking, chunk failure, cache invalidation, optimistic updates, auth reset, and incremental fetch behavior https://claude.ai/code/session_0146aSM1evtmv8pnVAazL6FP
Claude Review✅ Ready to merge - Well-structured optimization with good test coverage. No significant issues found. Minor observations (non-blocking)
Tests are comprehensive - covering incremental fetching, chunking, error handling, cache invalidation, and optimistic updates. |
P1 fixes: - Reset fetchedUuidsRef when accumulatedKey identity changes (e.g., user switches board or angle). Previously, same UUID list with a different context would reuse stale accumulated results from the old context. - Cancel in-flight fetch queries in onMutate (not just accumulated key) to prevent a completing fetch from overwriting the optimistic update. Expose cancelFetches() from useIncrementalQuery for this purpose. Minor: - Rename hasSetChanged/hasMapChanged to hasSetSizeChanged/hasMapSizeChanged with comments clarifying the size-only comparison is intentional for performance (merge always grows, so size change is a reliable signal). - Add test for context switch reset behavior. https://claude.ai/code/session_0146aSM1evtmv8pnVAazL6FP
Claude Review✅ Ready to merge - Well-implemented optimization with comprehensive tests. Minor observations noted below. Minor Observations (non-blocking)
Positive Notes
|
- Replace render-time ref mutation with effect-based keyChangeCount for React concurrent mode safety (discarded renders won't leave stale refs) - Cancel in-flight fetches in addToPlaylist/removeFromPlaylist (consistent with toggleFavorite) to prevent stale responses overwriting cache - Document shallow merge assumption on mergeMapFn - Remove duplicate prevAccKeyRef effect (consolidated into key-change effect) - Fix implicit any parameters in cache subscription - Fix test TypeScript: type mockFetchChunk, widen literal types for context switch test rerender https://claude.ai/code/session_0146aSM1evtmv8pnVAazL6FP
Claude Review✅ Ready to merge - Well-designed incremental query pattern with solid test coverage. Minor observations below, but nothing blocking. Minor Notes
|
- Document primitive-only constraint on accumulatedKey/fetchKeyPrefix - Note reference equality usage in cache subscription key comparison - Explain why MoonBoard is excluded from playlist memberships query https://claude.ai/code/session_0146aSM1evtmv8pnVAazL6FP
Claude Review✅ Ready to merge - Well-designed incremental query pattern with comprehensive tests. No significant issues found. Minor observations (non-blocking):
Verified:
|
No description provided.