Skip to content

Commit

Permalink
fix(packages/react): Stop auto refetch on render when maxRetries is…
Browse files Browse the repository at this point in the history
… reached. (#1742)
  • Loading branch information
vicary authored May 4, 2024
1 parent ba288fd commit 2e274f1
Show file tree
Hide file tree
Showing 22 changed files with 413 additions and 959 deletions.
5 changes: 5 additions & 0 deletions .changeset/big-tigers-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@gqty/react': patch
---

Stop auto refetch on render when `maxRetries` is reached.
2 changes: 1 addition & 1 deletion .changeset/clever-plums-shout.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'gqty': minor
---

feat: batching by microtask
Batching by microtask
2 changes: 1 addition & 1 deletion .changeset/curvy-dragons-smell.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@gqty/cli': minor
---

feat: Support "endpoint" in configuration
Support "endpoint" in configuration
2 changes: 1 addition & 1 deletion .changeset/fluffy-colts-confess.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@gqty/cli': major
---

feat(package/cli): upgrade @graphql-codegen/typescript to v4
Upgrade @graphql-codegen/typescript to v4
2 changes: 1 addition & 1 deletion .changeset/lemon-bags-behave.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@gqty/cli': minor
---

feat: interactive mode
Interactive mode for generating queries and mutations
5 changes: 5 additions & 0 deletions .changeset/polite-insects-protect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'gqty': minor
---

Added `batchWindow` option in `ClientOptions`
2 changes: 1 addition & 1 deletion .changeset/real-camels-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@gqty/react': minor
---

feat: Added onComplete for useMutation
Added `onComplete` in `useMutation`
2 changes: 1 addition & 1 deletion .changeset/silly-foxes-hug.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'gqty': patch
---

fix(packages/gqty): default return type for `resolve`
Added default return type for `resolve`
2 changes: 1 addition & 1 deletion .changeset/small-fishes-dress.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@gqty/cli': major
---

generated query fetcher now takes a single QueryPayload parameter
Generated query fetcher now takes a single `QueryPayload` parameter
2 changes: 1 addition & 1 deletion .changeset/weak-cougars-compare.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
'gqty': minor
---

feat: added extensions option
Added `extensions` option for passing arbitraty data to the query fetcher.
43 changes: 33 additions & 10 deletions examples/gnt/app/components/CscCharactersSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
'use client';

import type { Variables } from 'gqty';
import { useState, type FunctionComponent } from 'react';
import Button from '~/components/tailwindui/Button';
import type { Query } from '~/gqty';
import type { Character, Characters, Maybe } from '~/gqty';
import { useQuery } from '~/gqty/react';
import Avatar from './Avatar';
import Card from './Card';
Expand All @@ -15,10 +14,36 @@ export type Props = {};
const Component: FunctionComponent<Props> = () => {
const [searchValue, setSearchValue] = useState<string>();

const query = useQuery({
// cachePolicy: 'no-cache',
});

const error = query.$state.error;

return (
<>
<SearchBox onChange={setSearchValue} />
<Characters filter={{ name: searchValue }} />
<SearchBox
onChange={(v) => {
setSearchValue(v);
query.$refetch(false);
}}
/>

{error && (
<Card>
{error.name ?? 'Error'}: {error.message}
</Card>
)}

{!error && (
<Characters
characters={
query.characters(
searchValue ? { filter: { name: searchValue } } : undefined
)?.results ?? undefined
}
/>
)}
</>
);
};
Expand All @@ -41,14 +66,12 @@ const SearchBox: FunctionComponent<{
);
};

const Characters: FunctionComponent<Variables<Query['characters']>> = (
props
) => {
const query = useQuery();

const Characters: FunctionComponent<{ characters?: Maybe<Character>[] }> = ({
characters,
}) => {
return (
<>
{query.characters(props)?.results?.map((character) => (
{characters?.map((character) => (
<Card key={character?.id ?? '0'}>
<Avatar character={character} />

Expand Down
2 changes: 0 additions & 2 deletions examples/gnt/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ export default function Home() {
return (
<main className="p-5 min-h-screen">
{/* CSR test */}

<Suspense fallback={<div>Loading...</div>}>
<CharactersSearch />
</Suspense>

{/* RSC test */}

<Character id="1" />
<Character id="2" />
<Character id="3" />
Expand Down
11 changes: 6 additions & 5 deletions internal/test-utils/test/_generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export interface SubscriptionSubscriberObject<
TKey extends string,
TParent,
TContext,
TArgs
TArgs,
> {
subscribe: SubscriptionSubscribeFn<
{ [key in TKey]: TResult },
Expand All @@ -87,7 +87,7 @@ export type SubscriptionObject<
TKey extends string,
TParent,
TContext,
TArgs
TArgs,
> =
| SubscriptionSubscriberObject<TResult, TKey, TParent, TContext, TArgs>
| SubscriptionResolverObject<TResult, TParent, TContext, TArgs>;
Expand All @@ -97,7 +97,7 @@ export type SubscriptionResolver<
TKey extends string,
TParent = {},
TContext = {},
TArgs = {}
TArgs = {},
> =
| ((
...args: any[]
Expand All @@ -122,7 +122,7 @@ export type DirectiveResolverFn<
TResult = {},
TParent = {},
TContext = {},
TArgs = {}
TArgs = {},
> = (
next: NextResolverFn<TResult>,
parent: TParent,
Expand All @@ -147,7 +147,8 @@ export type ResolversParentTypes = {

export type QueryResolvers<
ContextType = EZContext,
ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']
ParentType extends
ResolversParentTypes['Query'] = ResolversParentTypes['Query'],
> = {
hello?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
};
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.7",
"@types/node": "^20.12.8",
"@types/prettier": "^2.7.3",
"bob-tsm": "^1.1.2",
"esbuild": "^0.20.2",
"open-cli": "^8.0.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/gqty/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@
"just-safe-set": "^4.2.1",
"multidict": "^1.0.8",
"object-hash": "^3.0.0",
"p-defer": "^3.0.0",
"p-lazy": "^3.1.0"
"p-defer": "^3.0.0"
},
"devDependencies": {
"@size-limit/preset-small-lib": "^11.1.2",
Expand All @@ -74,6 +73,7 @@
"jest": "^29.5.0",
"just-memoize": "^2.2.0",
"open-cli": "^8.0.0",
"p-lazy": "^3.0.0",
"rimraf": "^5.0.5",
"serve": "^14.2.3",
"size-limit": "^11.1.2",
Expand Down
22 changes: 21 additions & 1 deletion packages/gqty/src/Client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,31 @@ export type ClientOptions = {
*/
aliasLength?: number;

/**
* Milliseconds to wait before pending queries are batched up for fetching.
*/
batchWindow?: number;

/**
* The cache to be used by the accessors and fetches.
*/
cache: Cache;

/**
* Options related to fetching.
*/
fetchOptions: FetchOptions;

scalars: ScalarsEnumsHash;

/**
* The generated schema object.
*/
schema: Readonly<Schema>;

/**
* Maximum accessor depth, prevents infinite recursions.
* Maximum accessor depth before an error is thrown, prevents infinite
* recursions.
*
* @default 15
*/
Expand Down Expand Up @@ -145,6 +163,7 @@ export const createClient = <
_ObjectTypes extends SchemaObjects<TSchema> = never
>({
aliasLength = 6,
batchWindow,
// This default cache on a required option is for legacy clients, which does
// not provide a `cache` option.
// TODO: compat: remove in v4
Expand Down Expand Up @@ -197,6 +216,7 @@ export const createClient = <

const resolvers = createResolvers<TSchema>({
aliasLength,
batchWindow,
scalars,
schema,
cache,
Expand Down
17 changes: 13 additions & 4 deletions packages/gqty/src/Client/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { updateCaches } from './updateCaches';

export type CreateResolversOptions = {
aliasLength?: number;
batchWindow?: number;
cache: Cache;
debugger?: Debugger;
depthLimit: number;
Expand Down Expand Up @@ -99,7 +100,7 @@ export type SubscribeFn<TSchema extends BaseGeneratedSchema> = <

export type DataFn<TSchema, TResult = unknown> = (schema: TSchema) => TResult;

export type CreateResolverOptions = {
export type ResolverOptions = {
/**
* Defines how a query should fetch from the cache and network.
*
Expand Down Expand Up @@ -132,7 +133,7 @@ export type CreateResolverOptions = {
operationName?: string;
};

export type ResolveOptions = CreateResolverOptions & {
export type ResolveOptions = ResolverOptions & {
/**
* Awaits resolution it the query results in a fetch. Specify `false` to
* immediately return the current cache, placeholder data will be returned on
Expand All @@ -145,7 +146,7 @@ export type ResolveOptions = CreateResolverOptions & {
onFetch?: (fetchPromise: Promise<unknown>) => void;
};

export type SubscribeOptions = CreateResolverOptions & {
export type SubscribeOptions = ResolverOptions & {
/**
* Intercept errors thrown from the underlying subscription client or query
* fetcher.
Expand All @@ -171,6 +172,7 @@ const pendingQueries = new WeakMap<Set<Set<Selection>>, Promise<unknown>>();

export const createResolvers = <TSchema extends BaseGeneratedSchema>({
aliasLength,
batchWindow,
cache: clientCache,
debugger: debug,
depthLimit,
Expand Down Expand Up @@ -235,7 +237,7 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
}

// Batch selections up at client level, fetch all of them "next tick".
const selectionsCacheKey = `${cachePolicy}/${operationName ?? ''}`;
const selectionsCacheKey = operationName ?? '';

const pendingSelections = addSelections(
clientCache,
Expand All @@ -248,6 +250,13 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
pendingSelections,
// Batching happens at the end of microtask queue
Promise.resolve().then(async () => {
// Have to skip this because a 0 timeout still pushes it at least
// one more mictotask to the future. Also setTimeout() has no real
// time guarantee.
if (batchWindow) {
await new Promise((resolve) => setTimeout(resolve, batchWindow));
}

const uniqueSelections = new Set<Selection>();

getSelectionsSet(clientCache, selectionsCacheKey)?.forEach(
Expand Down
34 changes: 2 additions & 32 deletions packages/gqty/src/Utils/deferred.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,4 @@
export type DeferredState = 'pending' | 'resolved' | 'rejected';

export type Deferred<T> = {
promise: Promise<T>;
resolve: (value: T) => void;
reject: (error: unknown) => void;
state: DeferredState;
};

export const createDeferred = <T>(): Deferred<T> => {
let resolve!: (value: T) => void;
let reject!: (error: unknown) => void;
let state: DeferredState = 'pending';
const promise = new Promise<T>((res, rej) => {
resolve = (value: T) => {
state = 'resolved';
res(value);
};
reject = (error: unknown) => {
state = 'rejected';
rej(error);
};
});

return {
promise,
resolve,
reject,
state,
};
};
import createDeferred, { type DeferredPromise } from 'p-defer';

const asyncItDoneMessage = { done: true } as IteratorResult<never>;

Expand All @@ -38,7 +8,7 @@ export type DeferredIterator<T> = AsyncGenerator<T, void, unknown> & {
};

export const createDeferredIterator = <T>(): DeferredIterator<T> => {
let deferred: Deferred<void> | undefined = createDeferred<void>();
let deferred: DeferredPromise<void> | undefined = createDeferred<void>();
const events: T[] = [];

const next = async (): Promise<IteratorResult<T>> => {
Expand Down
Loading

0 comments on commit 2e274f1

Please sign in to comment.