Skip to content

Commit

Permalink
[C-5826] Add combineQueryStatuses helper (#11551)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Mar 7, 2025
1 parent 5c389a4 commit 42323a7
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 83 deletions.
13 changes: 9 additions & 4 deletions packages/common/src/api/tan-query/comments/useComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const useComments = (
const queryClient = useQueryClient()
const [hasInitialized, setHasInitialized] = useState(false)

const { data: comments, ...queryResults } = useQueries({
const queryResults = useQueries({
queries: (commentIds ?? []).map((commentId) => ({
queryKey: getCommentQueryKey(commentId),
queryFn: async (): Promise<CommentOrReply | {}> => {
Expand All @@ -42,6 +42,8 @@ export const useComments = (
}
}, [commentIds?.length])

const { data: comments } = queryResults

const isPending =
!hasInitialized || commentIds?.length === 0 || queryResults.isPending

Expand All @@ -53,11 +55,14 @@ export const useComments = (
return byId
}, [comments])

return {
data: comments,
byId,
const results = {
...queryResults,
isPending,
isLoading
} as typeof queryResults

return {
byId,
...results
}
}
19 changes: 3 additions & 16 deletions packages/common/src/api/tan-query/comments/useTrackComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { toast } from '~/store/ui/toast/slice'

import { QueryOptions } from '../types'
import { useCurrentUserId } from '../useCurrentUserId'
import { combineQueryStatuses } from '../utils/combineQueryStatuses'
import { primeCommentData } from '../utils/primeCommentData'
import { primeRelatedData } from '../utils/primeRelatedData'

Expand Down Expand Up @@ -95,26 +96,12 @@ export const useTrackComments = (
const commentsQuery = useComments(commentIds)
const { data: comments } = commentsQuery

// Merge the loading states from both queries
const isLoading = queryRes.isLoading || commentsQuery.isLoading
const isPending = queryRes.isPending || commentsQuery.isPending
const isFetching = queryRes.isFetching || commentsQuery.isFetching
const isSuccess = queryRes.isSuccess && commentsQuery.isSuccess

// Determine the overall status based on both queries
let status = queryRes.status
if (queryRes.status === 'success' && commentsQuery.status !== 'success') {
status = commentsQuery.status
}
const statusResults = combineQueryStatuses([queryRes, commentsQuery])

return {
...queryRes,
data: comments,
commentIds,
isLoading,
isPending,
isFetching,
isSuccess,
status
...statusResults
}
}
19 changes: 3 additions & 16 deletions packages/common/src/api/tan-query/comments/useUserComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { toast } from '~/store/ui/toast/slice'

import { QueryOptions } from '../types'
import { useCurrentUserId } from '../useCurrentUserId'
import { combineQueryStatuses } from '../utils/combineQueryStatuses'
import { primeCommentData } from '../utils/primeCommentData'
import { primeRelatedData } from '../utils/primeRelatedData'

Expand Down Expand Up @@ -87,26 +88,12 @@ export const useUserComments = (
const commentsQuery = useComments(commentIds)
const { data: comments } = commentsQuery

// Merge the loading states from both queries
const isLoading = queryRes.isLoading || commentsQuery.isLoading
const isPending = queryRes.isPending || commentsQuery.isPending
const isFetching = queryRes.isFetching || commentsQuery.isFetching
const isSuccess = queryRes.isSuccess && commentsQuery.isSuccess

// Determine the overall status based on both queries
let status = queryRes.status
if (queryRes.status === 'success' && commentsQuery.status !== 'success') {
status = commentsQuery.status
}
const statusResults = combineQueryStatuses([queryRes, commentsQuery])

return {
...queryRes,
data: comments,
commentIds,
isLoading,
isPending,
isFetching,
isSuccess,
status
...statusResults
}
}
19 changes: 12 additions & 7 deletions packages/common/src/api/tan-query/useCollections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const useCollections = (
const queryClient = useQueryClient()
const dispatch = useDispatch()

const { data: collections, ...queryResults } = useQueries({
const queriesResults = useQueries({
queries: (collectionIds ?? []).map((collectionId) => ({
queryKey: getCollectionQueryKey(collectionId),
queryFn: async () => {
Expand All @@ -48,6 +48,8 @@ export const useCollections = (
combine: combineQueryResults<UserCollectionMetadata[]>
})

const { data: collections } = queriesResults

const byId = useMemo(() => keyBy(collections, 'playlist_id'), [collections])

const isSavedToRedux = useSelector((state: CommonState) =>
Expand All @@ -56,12 +58,15 @@ export const useCollections = (
)
)

return {
const results = {
...queriesResults,
data: isSavedToRedux ? collections : undefined,
byId,
...queryResults,
isPending: queryResults.isPending || !isSavedToRedux,
isLoading: queryResults.isLoading || !isSavedToRedux,
isSuccess: queryResults.isSuccess && isSavedToRedux
isPending: queriesResults.isPending || !isSavedToRedux,
isLoading: queriesResults.isLoading || !isSavedToRedux
} as typeof queriesResults

return {
...results,
byId
}
}
32 changes: 10 additions & 22 deletions packages/common/src/api/tan-query/useNotifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useCurrentUserId } from './useCurrentUserId'
import { useNotificationValidTypes } from './useNotificationValidTypes'
import { useTracks } from './useTracks'
import { useUsers } from './useUsers'
import { combineQueryStatuses } from './utils/combineQueryStatuses'

const DEFAULT_LIMIT = 20
const USER_INITIAL_LOAD_COUNT = 9
Expand Down Expand Up @@ -223,36 +224,23 @@ export const useNotifications = (options?: QueryOptions) => {
const tracksQuery = useTracks(Array.from(trackIds))
const collectionsQuery = useCollections(Array.from(collectionIds))

// Check if the latest page's entity data is still loading
const isLatestPagePending =
query.isPending ||
usersQuery.isPending ||
tracksQuery.isPending ||
collectionsQuery.isPending

const isLatestPageLoading =
query.isLoading ||
usersQuery.isLoading ||
tracksQuery.isLoading ||
collectionsQuery.isLoading

const isError =
query.isError ||
usersQuery.isError ||
tracksQuery.isError ||
collectionsQuery.isError
// Use combineQueryStatuses to merge the status properties from all queries
const statusResults = combineQueryStatuses([
query,
usersQuery,
tracksQuery,
collectionsQuery
])

// Return all pages except the last one if it's still loading entity data
const notifications = query.data?.pages.slice(0, -1).flat() ?? []
if (!isLatestPagePending && lastPage) {
if (!statusResults.isPending && lastPage) {
notifications.push(...lastPage)
}

return {
...query,
isPending: isLatestPagePending,
isLoading: isLatestPageLoading,
isError,
...statusResults,
notifications
}
}
17 changes: 11 additions & 6 deletions packages/common/src/api/tan-query/useTracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const useTracks = (
const queryClient = useQueryClient()
const { data: currentUserId } = useCurrentUserId()

const { data: tracks, ...queryResults } = useQueries({
const queryResults = useQueries({
queries: (trackIds ?? []).map((trackId) => ({
queryKey: getTrackQueryKey(trackId),
queryFn: async () => {
Expand All @@ -49,18 +49,23 @@ export const useTracks = (
combine: combineQueryResults<TrackMetadata[]>
})

const { data: tracks } = queryResults

const byId = useMemo(() => keyBy(tracks, 'track_id'), [tracks])

const isSavedToRedux = useSelector((state: CommonState) =>
trackIds?.every((trackId) => !!state.tracks.entries[trackId])
)

return {
data: isSavedToRedux ? tracks : undefined,
byId,
const results = {
...queryResults,
data: isSavedToRedux ? tracks : undefined,
isPending: queryResults.isPending || !isSavedToRedux,
isLoading: queryResults.isLoading || !isSavedToRedux,
isSuccess: queryResults.isSuccess && isSavedToRedux
isLoading: queryResults.isLoading || !isSavedToRedux
} as typeof queryResults

return {
...results,
byId
}
}
13 changes: 9 additions & 4 deletions packages/common/src/api/tan-query/useUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const useUsers = (
const queryClient = useQueryClient()
const { data: currentUserId } = useCurrentUserId()

const { data: users, ...queryResults } = useQueries({
const queryResults = useQueries({
queries: (userIds ?? []).map((userId) => ({
queryKey: getUserQueryKey(userId),
queryFn: async () => {
Expand All @@ -48,18 +48,23 @@ export const useUsers = (
})),
combine: combineQueryResults<UserMetadata[]>
})
const { data: users } = queryResults

const byId = useMemo(() => keyBy(users, 'user_id'), [users])

const isSavedToRedux = useSelector((state: CommonState) =>
userIds?.every((userId) => !!state.users.entries[userId])
)

return {
data: isSavedToRedux ? users : undefined,
byId,
const results = {
...queryResults,
data: isSavedToRedux ? users : undefined,
isPending: queryResults.isPending || !isSavedToRedux,
isLoading: queryResults.isLoading || !isSavedToRedux
} as typeof queryResults

return {
...results,
byId
}
}
69 changes: 69 additions & 0 deletions packages/common/src/api/tan-query/utils/combineQueryStatuses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { QueryObserverResult } from '@tanstack/react-query'
import { sumBy } from 'lodash'

/**
* Combines multiple query statuses into a single status result
* This is a lightweight version of combineQueryResults that only focuses on status properties
* and doesn't handle data types or refetch functionality
*
* @param queries Array of query results to combine
* @returns An object with combined status information
*/
export const combineQueryStatuses = (queries: QueryObserverResult[]) => {
const isPending = queries.some((query) => query.isPending)
const isError = queries.some((query) => query.isError)
const isFetching = queries.some((query) => query.isFetching)
const isLoading = queries.some((query) => query.isLoading)
const isSuccess = queries.every((query) => query.isSuccess)
const isFetched = queries.every((query) => query.isFetched)
const isFetchedAfterMount = queries.every(
(query) => query.isFetchedAfterMount
)
const isPlaceholderData = queries.some((query) => query.isPlaceholderData)

// Combine error information if any query has an error
const error = queries.find((query) => query.error)?.error ?? null
const errorUpdatedAt = queries.reduce((latest, query) => {
const currentTime = query.errorUpdatedAt
if (!currentTime) return latest
if (!latest) return currentTime
return currentTime > latest ? currentTime : latest
}, 0)

// Get the most recent fetch time
const dataUpdatedAt = queries.reduce((latest, query) => {
const currentTime = query.dataUpdatedAt
if (!currentTime) return latest
if (!latest) return currentTime
return currentTime > latest ? currentTime : latest
}, 0)

// Determine overall status
let status: 'pending' | 'error' | 'success' = 'success'
if (isPending) status = 'pending'
if (isError) status = 'error'

return {
error: error as Error,
isError,
isFetching,
isLoading,
isPending,
isSuccess,
status,
dataUpdatedAt,
errorUpdatedAt,
failureCount: sumBy(queries, (q) => q.failureCount ?? 0),
failureReason: isError ? error : null,
errorUpdateCount: sumBy(queries, (q) => q.errorUpdateCount ?? 0),
fetchStatus: isFetching ? 'fetching' : 'idle',
isLoadingError: queries.some((q) => q.isLoadingError),
isPaused: queries.some((q) => q.isPaused),
isRefetchError: queries.some((q) => q.isRefetchError),
isRefetching: queries.some((q) => q.isRefetching),
isStale: queries.some((q) => q.isStale),
isFetched,
isFetchedAfterMount,
isPlaceholderData
}
}
10 changes: 10 additions & 0 deletions packages/common/src/api/tan-query/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export { combineQueryResults } from './combineQueryResults'
export { combineQueryStatuses } from './combineQueryStatuses'
export { loadNextPage } from './infiniteQueryLoadNextPage'
export { handleStemUpdates } from './handleStemUpdates'
export { parsePurchase } from './parsePurchase'
export { primeCollectionData } from './primeCollectionData'
export { primeCommentData } from './primeCommentData'
export { primeRelatedData } from './primeRelatedData'
export { primeTrackData } from './primeTrackData'
export { primeUserData } from './primeUserData'
Loading

0 comments on commit 42323a7

Please sign in to comment.