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

feat: expose querykey getter and fix some querykey stuff #3302

Merged
merged 51 commits into from Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5392463
1
juliusmarminge Nov 27, 2022
8638767
Merge branch 'main' into julius/querykeys
juliusmarminge Nov 27, 2022
bc702cc
2
juliusmarminge Nov 27, 2022
5b55386
add some tests
juliusmarminge Nov 27, 2022
2711978
failing test
juliusmarminge Nov 27, 2022
30dcc40
simplify
juliusmarminge Nov 27, 2022
d77f3c8
going places
juliusmarminge Nov 27, 2022
36ffd96
docs
juliusmarminge Nov 27, 2022
0a97a6b
more docs
juliusmarminge Nov 27, 2022
217db37
revert example
juliusmarminge Nov 27, 2022
964da9c
docs 3
juliusmarminge Nov 27, 2022
90a9173
add test
juliusmarminge Nov 27, 2022
dc92dcf
fix test
juliusmarminge Nov 27, 2022
5813e19
restructure
juliusmarminge Nov 27, 2022
366107d
revert lock
juliusmarminge Nov 27, 2022
c1d4497
better brackets
juliusmarminge Nov 27, 2022
c909673
better docs
juliusmarminge Nov 27, 2022
4efa3a8
fixy
juliusmarminge Nov 27, 2022
778859d
please not now docu
juliusmarminge Nov 27, 2022
7770be8
imports
juliusmarminge Nov 27, 2022
e9f03e1
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 4, 2022
cca2d30
move it to trpc object instead
juliusmarminge Dec 5, 2022
8b937df
docs
juliusmarminge Dec 5, 2022
c9b59bd
simplify test setup
juliusmarminge Dec 5, 2022
44179fd
make optional
juliusmarminge Dec 5, 2022
2d25187
add test outside react
juliusmarminge Dec 5, 2022
d06701a
add example
juliusmarminge Dec 5, 2022
4b4e12f
fix
juliusmarminge Dec 5, 2022
377e271
fix2
juliusmarminge Dec 5, 2022
c8b8ee8
docs and remove example
juliusmarminge Dec 16, 2022
cdc5808
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 16, 2022
dd8062e
revert downgrade of docusaurus
juliusmarminge Dec 16, 2022
04d5333
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 16, 2022
c92eb39
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 16, 2022
c1b162e
qc -> queryClient
juliusmarminge Dec 16, 2022
c8e3ed7
mby???
juliusmarminge Dec 16, 2022
0e519e2
patch querykey
juliusmarminge Dec 22, 2022
60afce2
fix invalidate
juliusmarminge Dec 22, 2022
72b5ab6
fix old
juliusmarminge Dec 22, 2022
6f195da
regression tests
juliusmarminge Dec 22, 2022
d60dea3
testid
juliusmarminge Dec 22, 2022
f566339
Merge remote-tracking branch 'origin/main' into julius/querykeys
juliusmarminge Dec 22, 2022
5adc7ec
fix
juliusmarminge Dec 22, 2022
957a78c
interop
juliusmarminge Dec 22, 2022
f025343
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 22, 2022
3ceba17
disable interop
juliusmarminge Dec 22, 2022
05f5c8d
comment
juliusmarminge Dec 22, 2022
88b8052
1 more test
juliusmarminge Dec 22, 2022
943fdeb
fix the interop stuff
juliusmarminge Dec 22, 2022
bb26bc1
eeh
juliusmarminge Dec 22, 2022
1396478
Merge branch 'main' into julius/querykeys
kodiakhq[bot] Dec 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/minimal-react/client/package.json
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@tanstack/react-query": "^4.3.8",
"@tanstack/react-query-devtools": "^4.3.8",
"@trpc/client": "^10.4.0",
"@trpc/react-query": "^10.4.0",
"@trpc/server": "^10.4.0",
Expand Down
2 changes: 2 additions & 0 deletions examples/minimal-react/client/src/App.tsx
@@ -1,4 +1,5 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { httpBatchLink } from '@trpc/client';
import { useState } from 'react';
import { Greeting } from './Greeting';
Expand All @@ -19,6 +20,7 @@ export function App() {
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
<Greeting />
<ReactQueryDevtools />
</QueryClientProvider>
</trpc.Provider>
);
Expand Down
20 changes: 18 additions & 2 deletions examples/minimal-react/client/src/Greeting.tsx
@@ -1,7 +1,23 @@
import { useQueryClient } from '@tanstack/react-query';
import { trpc } from './utils/trpc';

export function Greeting() {
const greeting = trpc.greeting.useQuery({ name: 'tRPC user' });
const qc = useQueryClient();
const utils = trpc.useContext();

return <div>{greeting.data?.text}</div>;
const greeting = trpc.greeting.useQuery();
const qKey = utils.greeting.getQueryKey();

const isFetching = qc.isFetching({ queryKey: qKey });

console.log('qKey', qKey);
console.log('isFetching', isFetching);

return (
<div>
{greeting.data?.text ?? 'Loading...'}
{!!isFetching && ' (fetching)'}
<button onClick={() => greeting.refetch()}></button>
</div>
);
}
5 changes: 3 additions & 2 deletions examples/minimal-react/server/index.ts
Expand Up @@ -19,12 +19,13 @@ const appRouter = router({
.input(
z
.object({
name: z.string().nullish(),
name: z.string(),
})
.nullish(),
)
.query(({ input }) => {
.query(async ({ input }) => {
// This is what you're returning to your client
await new Promise((resolve) => setTimeout(resolve, 1000));
return {
text: `hello ${input?.name ?? 'world'}`,
// 💡 Tip: Try adding a new property here and see it propagate to the client straight-away
Expand Down
6 changes: 5 additions & 1 deletion packages/react-query/src/internals/getArrayQueryKey.ts
@@ -1,5 +1,9 @@
export type QueryType = 'query' | 'infinite' | 'any';

export type QueryKey = [
string[],
{ input?: unknown; type?: Exclude<QueryType, 'any'> },
];
/**
* To allow easy interactions with groups of related queries, such as
* invalidating all queries of a router, we use an array as the path when
Expand All @@ -10,7 +14,7 @@ export type QueryType = 'query' | 'infinite' | 'any';
export function getArrayQueryKey(
queryKey: string | [string] | [string, ...unknown[]] | unknown[],
type: QueryType,
): [string[], { input?: unknown; type?: Exclude<QueryType, 'any'> }] {
): QueryKey {
const queryKeyArrayed = Array.isArray(queryKey) ? queryKey : [queryKey];
const [path, input] = queryKeyArrayed;

Expand Down
21 changes: 21 additions & 0 deletions packages/react-query/src/shared/proxy/utilsProxy.ts
Expand Up @@ -29,6 +29,7 @@ import {
TRPCFetchQueryOptions,
contextProps,
} from '../../internals/context';
import { QueryKey, getArrayQueryKey } from '../../internals/getArrayQueryKey';
import { getQueryKey } from '../../internals/getQueryKey';

type DecorateProcedure<
Expand Down Expand Up @@ -158,6 +159,18 @@ type DecorateProcedure<
getInfiniteData(
input?: inferProcedureInput<TProcedure>,
): InfiniteData<inferTransformedProcedureOutput<TProcedure>> | undefined;

/**
* Method to extract the query key for a given procedure
* @link https://trpc.io/docs/queries#query-key
*/
getQueryKey(input: inferProcedureInput<TProcedure>): QueryKey;

/**
* Method to extract the query key for a given procedure
* @link https://trpc.io/docs/queries#query-key
*/
getInfiniteQueryKey(input: inferProcedureInput<TProcedure>): QueryKey;
};

/**
Expand All @@ -174,6 +187,12 @@ type DecorateRouter = {
filters?: InvalidateQueryFilters,
options?: InvalidateOptions,
): Promise<void>;

/**
* Method to extract the query key for a given procedure
* @link https://trpc.io/docs/queries#query-key
*/
getQueryKey(): QueryKey;
};

/**
Expand Down Expand Up @@ -265,6 +284,8 @@ export function createReactQueryUtilsProxy<
context.setInfiniteQueryData(queryKey, updater, ...rest),
getData: () => context.getQueryData(queryKey),
getInfiniteData: () => context.getInfiniteQueryData(queryKey),
getQueryKey: () => getArrayQueryKey(queryKey, 'query'),
getInfiniteQueryKey: () => getArrayQueryKey(queryKey, 'infinite'),
};

return contextMap[utilName]();
Expand Down
116 changes: 116 additions & 0 deletions packages/tests/server/react/useContext.test.tsx
@@ -1,5 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { getServerAndReactClient } from './__reactHelpers';
import { useQueryClient } from '@tanstack/react-query';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { initTRPC } from '@trpc/server/src/core';
Expand Down Expand Up @@ -798,4 +799,119 @@ describe('query keys are stored separtely', () => {
`);
expect(data.infinite).toBeUndefined();
});

describe('getQueryKeys', () => {
test('no input', async () => {
const { proxy, App } = ctx;

function MyComponent() {
const utils = proxy.useContext();
const happy = utils.post.all.getQueryKey();

// @ts-expect-error - post.all has no input
const sad = utils.post.all.getQueryKey('foo');

return <pre data-testid="qKey">{JSON.stringify(happy)}</pre>;
}

const utils = render(
<App>
<MyComponent />
</App>,
);

await waitFor(() => {
expect(utils.getByTestId('qKey')).toHaveTextContent(
JSON.stringify([['post', 'all'], { type: 'query' }]),
);
});
});

test('with input', async () => {
const { proxy, App } = ctx;

function MyComponent() {
const utils = proxy.useContext();
const happy = utils.post.byId.getQueryKey({ id: 1 });

// @ts-expect-error - post.byId has required input
const sad1 = utils.post.byId.getQueryKey();
// @ts-expect-error - id should be a number
const sad2 = utils.post.byId.getQueryKey({ id: '1' });

return <pre data-testid="qKey">{JSON.stringify(happy)}</pre>;
}

const utils = render(
<App>
<MyComponent />
</App>,
);

await waitFor(() => {
expect(utils.getByTestId('qKey')).toHaveTextContent(
JSON.stringify([
['post', 'byId'],
{ input: { id: 1 }, type: 'query' },
]),
);
});
});

test('on router', async () => {
const { proxy, App } = ctx;

function MyComponent() {
const utils = proxy.useContext();
const happy = utils.post.getQueryKey();

// @ts-expect-error - router has no input
const sad = utils.post.getQueryKey('foo');

return (
<div>
<pre data-testid="qKey">{JSON.stringify(happy)}</pre>
</div>
);
}

const utils = render(
<App>
<MyComponent />
</App>,
);

await waitFor(() => {
expect(utils.getByTestId('qKey')).toHaveTextContent(
JSON.stringify([['post']]),
);
});
});

test('forwarded to a real method', async () => {
const { proxy, App } = ctx;

function MyComponent() {
const utils = proxy.useContext();
const qc = useQueryClient();

const key = utils.post.all.getQueryKey();
const isFetching = qc.isFetching({ queryKey: key });

return <pre data-testid="isFetching">{isFetching}</pre>;
}

const utils = render(
<App>
<MyComponent />
</App>,
);

// should be fetching initially, and then not
expect(utils.container).toHaveTextContent('1');
await waitFor(() => {
expect(utils.container).toHaveTextContent('0');
});
juliusmarminge marked this conversation as resolved.
Show resolved Hide resolved
});
});
});