Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No longer works #1

Open
TSMMark opened this issue Oct 22, 2019 · 6 comments
Open

No longer works #1

TSMMark opened this issue Oct 22, 2019 · 6 comments

Comments

@TSMMark
Copy link

TSMMark commented Oct 22, 2019

queryManager.queryIdsByName now returns undefined and I think the internal data structure has changed significantly since my original post in Aug 2018 apollographql/apollo-client#3540 (comment)

I'm not sure what version of apollo client broke this implementation but we're looking into a fix for our codebase. I'll try to remember to post it here if we get something working.

@TSMMark
Copy link
Author

TSMMark commented Oct 23, 2019

AFAICT queryIdsByName is no longer exposed by Apollo. So I reimplemented queryIdsByName as a function. This fixes the internals of this library's refetchQueries functions, while reducing the amount of code changes necessary in the other internal functions of the library.

At @Vydia, we never actually looped back and migrated our application code to use this package, so I'm working from my original issue comment code, but this is working for us now:

export const getObservableQueriesByName = (client: ApolloClient, queryName: string): Array<Object> => {
  const queryIdsByName = getQueryIdsByName(client)
  const { queryManager: { queries } } = client
  const queryIds = queryIdsByName[queryName] || []
  return map(queryIds, (queryId: string) => queries.get(queryId).observableQuery)
}

export const getAllObservableQueries = (client: ApolloClient): Array<Object> => {
  const queryIdsByName = getQueryIdsByName(client)
  const { queryManager: { queries } } = client
  const queryIds = flatten(values(queryIdsByName))
  return map(queryIds, (queryId: string) => queries.get(queryId).observableQuery)
}

export const getQueryIdsByName = (client: ApolloClient): $Shape<{| [string]: string[] |}> => {
  const { queryManager: { queries } } = client
  const queryIdsByName = {}

  // `queries` contains a Map instance. I'm not sure the best way to transform a Map - is there a better way to do this loop?
  queries.forEach((value, key) => {
    (queryIdsByName[value.observableQuery.queryName] = (queryIdsByName[value.observableQuery.queryName] || [])).push(key)
  })

  return queryIdsByName
}

I'll try to find some time to submit a PR to this package, and to migrate our application codebase at @Vydia to use this package.

@asselstine
Copy link
Member

Thanks @TSMMark!

It's funny, I think we actually patched this in our application too. Hopefully one of us can get around to this soon :)

@adamtysonsmith
Copy link

adamtysonsmith commented Oct 29, 2019

Not sure if this helps but I hacked together a hook pretty quickly, it does not handle variables yet though

export const useRefetchByQueryNames = () => {
  const client = useApolloClient()
  const queries: Map<string, any> | undefined = R.path(
    ['queryManager', 'queries'],
    client
  )

  return (queryNames: string[]) => {
    if (queries) {
      let refetchFns = []

      queries.forEach(q => {
        const name = R.path(['observableQuery', 'queryName'], q)
        if (name && queryNames.includes(name as string)) {
          // @ts-ignore
          refetchFns.push(q.observableQuery.refetch.bind(q.observableQuery))
        }
      })

      refetchFns.forEach((fn: Function) => {
        fn()
      })
    }
  }
}

@amannn
Copy link

amannn commented Nov 15, 2019

@adamtysonsmith If I'm not mistaken, it does handle variables.

Previous variables are reused if you don't provide new ones:

https://github.com/apollographql/apollo-client/blob/d5d313846308b3c97330a6b1bd4e06aed73fd894/packages/apollo-client/src/core/ObservableQuery.ts#L315-L321

I made a function that invalidates all currently active queries:

const client = useApolloClient();

function invalidateCache() {
  client.queryManager.queries.forEach(query => {
    if (!query.observableQuery) return;
    query.observableQuery.refetch();
  });
}

@TSMMark
Copy link
Author

TSMMark commented Nov 15, 2019

@amannn That looks cool but that could be a very expensive operation as it looks like it actually refetches all the queries, not only invalidating them right? Do you know of a way to ONLY invalidate without refetching? And let queries hit the network later, on demand, as needed?

@amannn
Copy link

amannn commented Nov 15, 2019

Yep, that's true, but it's the wanted behaviour in my case.

If you're looking for only invalidation without refetching, you could try this:

const client = useApolloClient();

function invalidateCache() {
  client.queryManager.queries.forEach((query, queryId) => {
    client.queryManager.invalidate(queryId);
  });
}

No idea if that works properly, but it uses some things I found in the QueryManager class. Maybe it's helpful to you!

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

No branches or pull requests

4 participants