lukemorales / query-key-factory

A library for creating typesafe standardized query keys, useful for cache management in @tanstack/query
https://www.npmjs.com/package/@lukemorales/query-key-factory
MIT License
1.16k stars 32 forks source link

Unable to access specific part of query key when multiple parameters are used. #92

Closed AlexShukel closed 2 months ago

AlexShukel commented 2 months ago

Issue

I have the following query keys for "trips" query:

const trips= createQueryKeys('trips', {
    page: (showCompleted: boolean, pageNumber: number) => ({
        queryKey: [showCompleted, pageNumber],
        queryFn: async () => {
            // ...
        },
    }),
});

After that, in application I need an access to several keys:

  1. All pages - ["trips", "page"]
  2. Only completed / not completed trips - ["trips", "page", boolean]
  3. Trips page - ["trips", "page", boolean, number]

However, I do not have access to ["trips", "page", boolean] query key:

type TripsKeys= {
    _def: readonly ["trips"];
    page: {
        _def: readonly ["trips", "page"];
        queryKey: readonly ["trips", "page", boolean, number];
    };
}

Workaround with contextQueries

It is possible to get those keys using contextQueries:

const trips= createQueryKeys('trips', {
    showCompleted: (showCompleted: boolean) => ({
        queryKey: [showCompleted],
        queryFn: null,
        contextQueries: {
            page: (pageNumber: number) => ({
                queryFn: async () => {
                    // ... showCompleted, pageNumber
                },
                queryKey: [pageNumber],
            }),
        },
    }),
});

But it isn't convenient to call 2 functions when accessing page's key and it looks pretty messy: trips.showCompleted(false)._ctx.page(1).queryKey

linear[bot] commented 2 months ago

OSS-13 Unable to access specific part of query key when multiple parameters are used.

lukemorales commented 2 months ago

@AlexShukel if your modeling to the query keys doesn't allow you to access the shape that you want, you can just use javascript to remove the undesired elements. The awesome thing the type-safety that the lib provides is that you know exactly the shape of the key and what indexes you want to remove:

const trips = createQueryKeys('trips', {
    page: (showCompleted: boolean, pageNumber: number) => ({
        queryKey: [showCompleted, pageNumber],
        queryFn: async () => {
            // ...
        },
    }),
});

queryClient.invalidateQueries({
  queryKey: trips.page(true, 0).toSpliced(-1) // <<<<<<<< ['trips', 'page', true]
})