query-key-factory icon indicating copy to clipboard operation
query-key-factory copied to clipboard

Nested keys required?

Open kimbuba opened this issue 1 year ago • 10 comments

Hello, with React query i naturally have this scenario:

-list of customers by account filtered by order by

how i map this to cache keys is:

`function customersByAccountId(accountId: number) { return ["customerListByAccountId", accountId]; }

function customersByAccountIdFiltered(accountId: number, queryFilter: QueryFilter) { return [...customersByAccountId(accountId), "list", { queryFilter }]; }`

This way, when i edit an attribute for a customer, i can: update the in memory query for customersByAccountIdFiltered (which will change the attribute on the current screen, without reload)

and invalidate customersByAccountId (with refetchActive: false,) which will invalidate all other cached filtered entries.

How do i map this with query-key-factory?

kimbuba avatar Sep 16 '22 08:09 kimbuba

@kimbuba can you share a little more context about your use case? especially about:

invalidate customersByAccountId (with refetchActive: false,) which will invalidate all other cached filtered entries.

I can see ["customerListByAccountId", accountId, 'list'] being enough to invalidate the "other cached filtered entries", so I want to understand a little more about how you use ["customerListByAccountId", accountId] connected to the ["customerListByAccountId", accountId, 'list'] queries, so that I can give you a proper solution or really understand if that's a use-case that the lib does not support yet

lukemorales avatar Sep 16 '22 12:09 lukemorales

Hello Luke! Yes sure. I need to support the following keys structure

["customerListByAccountId", accountId, 'list', {orderBy:"create_date"}] ["customerListByAccountId", accountId, 'list', {orderBy:"id"}] ["customerListByAccountId", accountId, 'list2', {orderBy:"create_date"}]

how do i clean this using your library? accountId is a variable number. Basically i need to do the following, clean: ["customerListByAccountId", accountId]

how do you translate it with createQueryKeyStore?

kimbuba avatar Sep 16 '22 13:09 kimbuba

What's the difference between list and list2? Is that also a dynamic parameter? Maybe pagination?

lukemorales avatar Sep 16 '22 13:09 lukemorales

I'm asking because it really seems to me that this structure should fit your needs:

const store = createQueryKeyStore({
  customers: {
    listByAccountId: (accountId: number, queryFilter: QueryFilter) => [accountId, 'list', queryFilter],
    // ['customers', 'listByAccountId', accountId, 'list', queryFilter]
  },
});

// then on your components
useQuery(store.customers.listByAccountId(accountId, queryFilter));

queryClient.invalidateQueries(store.customers.listByAccountId(accountId, {}), { refetchActive: false });
// to understand why invalidating ['customers', 'listByAccountId', accountId, 'list', {}] works
// see this example: https://codesandbox.io/s/react-query-object-keys-pogsr

// or if you prefer:
queryClient.invalidateQueries([...store.customers.listByAccountId._def, accountId], { refetchActive: false });
 //                                 ^? ['customers', 'listByAccountId', accountId]
queryClient.invalidateQueries(Array.prototype.concat(store.customers.listByAccountId._def, accountId), { refetchActive: false });
 //                                 ^? ['customers', 'listByAccountId', accountId]

lukemorales avatar Sep 16 '22 13:09 lukemorales

thanks, i see.

Would it be possible to go more deeper in the hierarchy?

Say: customer/10/stakeholders/213/load that would easily translate into [customer,10,stakeholders,213,load] so i could easily invalidate customerId 10 and everything under it with this key [customer,10]

kimbuba avatar Sep 16 '22 13:09 kimbuba

@kimbuba oh, that's definitely a use case not supported yet. Do you have more examples of similar use cases?

lukemorales avatar Sep 16 '22 14:09 lukemorales

that would be to support a hierarchy structure. But i'm trying to adapt my current structure to your library.

Btw is this

queryClient.invalidateQueries([...store.customers.accountId._def, accountId], { refetchActive: false });

actually

queryClient.invalidateQueries([...store.customers. listByAccountId._def, accountId], { refetchActive: false });

or am i missing something?

kimbuba avatar Sep 16 '22 14:09 kimbuba

that would be to support a hierarchy structure.

Basically scoping some keys to an entity ID, or any other use cases? I remember thinking something like this when designing this first api but couldn't think about any examples at the time. So, as much information for use cases like these as I can get will help me think about how to support it

Btw is this

queryClient.invalidateQueries([...store.customers.accountId._def, accountId], { refetchActive: false });

actually

queryClient.invalidateQueries([...store.customers. listByAccountId._def, accountId], { refetchActive: false });

Yes you're correct, I totally miswrote that 😓

lukemorales avatar Sep 16 '22 14:09 lukemorales

np,

here is another example: I have a list of accounts and each account has customers i want to do different lists per customers, as they are calling different endpoints. I could put everything as in a filter for this simple example but i may not want to.

API:

- customersListByAccountInvited(1, "desc");
- customersListByAccountNotInvited(2, "asc");

The first gives the list of all customers non invited ordered by desc. The second gives the list of all customers non invited ordered by asc.

This would naturally map as: ["customers",1,"invited", {sort:"desc"}] And: ["customers",1,"non_invited", {sort:"asc"}]

With 1, the accountId

Now say i'm adding a customer to the first cache. I would setQuery on["customers",1,"invited", {sort:"desc"}]and add a user "John" I now need to invalidate the following queryClient.invalidateQueries(["customers",1], { refetchActive: false }); This way:

  • The current list has updated data without refetching
  • The second list is invalidated and will be reloaded

Is there a way to map this?

Something like this would not give me what i want to accomplish:

customers: {
    listInvited: (accountId: number, sort: {"asc"|"desc"}) => [accountId, { sort }],
    listNonInvited: (accountId: number, sort: {"asc"|"desc"}) => [accountId, { sort }],
  },

As there would be no way to invalidate

queryClient.invalidateQueries(["customers",1], { refetchActive: false });

kimbuba avatar Sep 16 '22 15:09 kimbuba

Thanks for the information @kimbuba, I'll start some exploration towards that use case

lukemorales avatar Sep 17 '22 03:09 lukemorales

@kimbuba just letting you know, v1.0 has been released with support for nested keys: https://github.com/lukemorales/query-key-factory/releases/tag/v1.0.0

lukemorales avatar Oct 25 '22 03:10 lukemorales