Skip to content

Commit

Permalink
feat: new AbortOptimistic() -> snap.abort (#2957)
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker authored Feb 20, 2024
1 parent 10432b7 commit c129a25
Show file tree
Hide file tree
Showing 23 changed files with 818 additions and 132 deletions.
19 changes: 19 additions & 0 deletions .changeset/plenty-crews-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
"@data-client/endpoint": minor
"@data-client/rest": minor
"@data-client/graphql": minor
---

BREAKING CHANGE: Remove new AbortOptimistic() in favor of [snapshot.abort](https://dataclient.io/docs/api/Snapshot#abort)


```ts
getOptimisticResponse(snapshot, { id }) {
const { data } = snapshot.getResponse(Base.get, { id });
if (!data) throw snapshot.abort;
return {
id,
votes: data.votes + 1,
};
}
```
18 changes: 18 additions & 0 deletions .changeset/thirty-cherries-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"@data-client/normalizr": minor
"@data-client/react": minor
"@data-client/core": minor
---

Add [snapshot.abort](https://dataclient.io/docs/api/Snapshot#abort)

```ts
getOptimisticResponse(snapshot, { id }) {
const { data } = snapshot.getResponse(Base.get, { id });
if (!data) throw snapshot.abort;
return {
id,
votes: data.votes + 1,
};
}
```
5 changes: 2 additions & 3 deletions __tests__/new.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
schema,
AbortOptimistic,
Endpoint,
Index,
createResource,
Expand Down Expand Up @@ -90,7 +89,7 @@ export const VisSettingsResource = {
partialUpdate: VisSettingsResourceBase.partialUpdate.extend({
getOptimisticResponse(snap, params, body) {
const { data } = snap.getResponse(VisSettingsResourceBase.get, params);
if (!data) throw new AbortOptimistic();
if (!data) throw snap.abort;
return {
...data,
...body,
Expand Down Expand Up @@ -129,7 +128,7 @@ export const VisSettingsResourceFromMixin = {
VisSettingsResourceBaseFromMixin.get,
params,
);
if (!data) throw new AbortOptimistic();
if (!data) throw snap.abort;
return {
...data,
...body,
Expand Down
6 changes: 6 additions & 0 deletions docs/core/api/Snapshot.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface Snapshot {
getResponse(endpoint, ...args)​ => { data, expiryStatus, expiresAt };
getError(endpoint, ...args)​ => ErrorTypes | undefined;
fetchedAt: number;
abort: Error;
}
```

Expand Down Expand Up @@ -90,3 +91,8 @@ Gets the error, if any, for a given endpoint. Returns undefined for no errors.
### fetchedAt

When the fetch was called that resulted in this snapshot.

### abort

This is an Error to be thrown in [Endpoint.getOptimisticResponse()](/rest/api/RestEndpoint#getoptimisticresponse)
to cancel an optimistic update.
5 changes: 2 additions & 3 deletions docs/core/shared/_VoteDemo.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ export class Post extends Entity {
}
```

```ts title="PostResource" {16-23}
```ts title="PostResource" {15-22}
import { RestEndpoint, createResource } from '@data-client/rest';
import { AbortOptimistic } from '@data-client/rest';
import { Post } from './Post';

export { Post };
Expand All @@ -42,7 +41,7 @@ export const PostResource = createResource({
schema: Post,
getOptimisticResponse(snapshot, { id }) {
const { data } = snapshot.getResponse(Base.get, { id });
if (!data) throw new AbortOptimistic();
if (!data) throw snapshot.abort;
return {
id,
votes: data.votes + 1,
Expand Down
4 changes: 2 additions & 2 deletions docs/rest/guides/optimistic-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ function optimisticPartial(
) {
return function (snap: SnapshotInterface, params: any, body: any) {
const { data } = snap.getResponse(getEndpoint, params);
if (!data) throw new AbortOptimistic();
if (!data) throw snap.abort;
return {
...params,
...data,
Expand Down Expand Up @@ -330,7 +330,7 @@ export const increment = new RestEndpoint({
},
getOptimisticResponse(snap) {
const { data } = snap.getResponse(getCount);
if (!data) throw new AbortOptimistic();
if (!data) throw snap.abort;
return {
count: data.count + 1,
updatedAt: snap.fetchedAt,
Expand Down
2 changes: 1 addition & 1 deletion docs/rest/shared/_optimisticTransform.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const increment = new RestEndpoint({
schema: CountEntity,
getOptimisticResponse(snap) {
const { data } = snap.getResponse(getCount);
if (!data) throw new AbortOptimistic();
if (!data) throw snap.abort;
return {
count: data.count + 1,
};
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions packages/core/src/controller/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from '@data-client/normalizr';
import { inferResults, validateInference } from '@data-client/normalizr';

import AbortOptimistic from './AbortOptimistic.js';
import createExpireAll from './createExpireAll.js';
import createFetch from './createFetch.js';
import createInvalidate from './createInvalidate.js';
Expand Down Expand Up @@ -478,6 +479,7 @@ class Snapshot<T = unknown> implements SnapshotInterface {
private state: State<T>;
private controller: Controller;
readonly fetchedAt: number;
readonly abort = new AbortOptimistic();

constructor(controller: Controller, state: State<T>, fetchedAt = 0) {
this.state = state;
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/state/reducer/setReducer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { normalize } from '@data-client/normalizr';

import { OPTIMISTIC_TYPE } from '../../actionTypes.js';
import AbortOptimistic from '../../controller/AbortOptimistic.js';
import type Controller from '../../controller/Controller.js';
import type { State, SetAction, OptimisticAction } from '../../types.js';

Expand All @@ -27,7 +28,7 @@ export function setReducer(
);
} catch (e: any) {
// AbortOptimistic means 'do nothing', otherwise we count the exception as endpoint failure
if (e.constructor?.name === 'AbortOptimistic') {
if (e.constructor === AbortOptimistic) {
return state;
}
throw e;
Expand Down
1 change: 1 addition & 0 deletions packages/endpoint/src/SnapshotInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface SnapshotInterface {
) => ErrorTypes | undefined;

readonly fetchedAt: number;
readonly abort: Error;
}

// looser version to allow for cross-package version compatibility
Expand Down
1 change: 0 additions & 1 deletion packages/endpoint/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,3 @@ export { default as Endpoint, ExtendableEndpoint } from './endpoint.js';
export type { KeyofEndpointInstance } from './endpoint.js';
export * from './indexEndpoint.js';
export * from './queryEndpoint.js';
export { default as AbortOptimistic } from './AbortOptimistic.js';
1 change: 1 addition & 0 deletions packages/normalizr/src/endpoint/SnapshotInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ export interface SnapshotInterface {
) => ErrorTypes | undefined;

readonly fetchedAt: number;
readonly abort: Error;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Endpoint, Entity, AbortOptimistic } from '@data-client/endpoint';
import { Endpoint, Entity } from '@data-client/endpoint';
import { CacheProvider } from '@data-client/react';
import { CacheProvider as ExternalCacheProvider } from '@data-client/redux';
import { jest } from '@jest/globals';
Expand Down Expand Up @@ -792,7 +792,7 @@ describe.each([
sideEffect: true,
getOptimisticResponse(snap, id) {
const { data } = snap.getResponse(getbool, id);
if (!data) throw new AbortOptimistic();
if (!data) throw snap.abort;
return {
id,
visible: data.visible ? false : true,
Expand Down
8 changes: 2 additions & 6 deletions packages/rest/src/createResource.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
AbortOptimistic,
SnapshotInterface,
schema,
} from '@data-client/endpoint';
import { SnapshotInterface, schema } from '@data-client/endpoint';

import { ResourcePath } from './pathTypes.js';
import {
Expand Down Expand Up @@ -146,7 +142,7 @@ function optimisticPartial(
) {
return function (snap: SnapshotInterface, params: any, body: any) {
const { data } = snap.getResponse(getEndpoint, params) as { data: any };
if (!data) throw new AbortOptimistic();
if (!data) throw snap.abort;
return {
...params,
...data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ interface SnapshotInterface {
};
getError: <E extends Pick<EndpointInterface, 'key'>, Args extends readonly [...Parameters<E['key']>]>(endpoint: E, ...args: Args) => ErrorTypes | undefined;
readonly fetchedAt: number;
readonly abort: Error;
}

/** Defines a networking endpoint */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ interface SnapshotInterface {
};
getError: <E extends Pick<EndpointInterface, 'key'>, Args extends readonly [...Parameters<E['key']>]>(endpoint: E, ...args: Args) => ErrorTypes | undefined;
readonly fetchedAt: number;
readonly abort: Error;
}
type ExpiryStatusInterface = 1 | 2 | 3;

Expand Down Expand Up @@ -964,7 +965,4 @@ type QuerySchema<Schema, R> = Exclude<Schema, 'denormalize' | '_denormalizeNulla
denormalize(input: {}, args: readonly any[], unvisit: (input: any, schema: any) => any): R;
};

declare class AbortOptimistic extends Error {
}

export { AbortOptimistic, AbstractInstanceType, Array$1 as Array, ArrayElement, Collection, Denormalize, DenormalizeNullable, Endpoint, EndpointExtendOptions, EndpointExtraOptions, EndpointInstance, EndpointInstanceInterface, EndpointInterface, EndpointOptions, EndpointParam, EndpointToFunction, Entity, ErrorTypes, ExpiryStatusInterface, ExtendableEndpoint, FetchFunction, INVALID, Index, IndexParams, Invalidate, KeyofEndpointInstance, MutateEndpoint, NetworkError, Normalize, NormalizeNullable, PolymorphicInterface, Query, ReadEndpoint, ResolveType, Schema, SchemaClass, SchemaSimple, SchemaToArgs, SnapshotInterface, UnknownError, schema_d as schema, validateRequired };
export { AbstractInstanceType, Array$1 as Array, ArrayElement, Collection, Denormalize, DenormalizeNullable, Endpoint, EndpointExtendOptions, EndpointExtraOptions, EndpointInstance, EndpointInstanceInterface, EndpointInterface, EndpointOptions, EndpointParam, EndpointToFunction, Entity, ErrorTypes, ExpiryStatusInterface, ExtendableEndpoint, FetchFunction, INVALID, Index, IndexParams, Invalidate, KeyofEndpointInstance, MutateEndpoint, NetworkError, Normalize, NormalizeNullable, PolymorphicInterface, Query, ReadEndpoint, ResolveType, Schema, SchemaClass, SchemaSimple, SchemaToArgs, SnapshotInterface, UnknownError, schema_d as schema, validateRequired };
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ interface SnapshotInterface {
};
getError: <E extends Pick<EndpointInterface, 'key'>, Args extends readonly [...Parameters<E['key']>]>(endpoint: E, ...args: Args) => ErrorTypes | undefined;
readonly fetchedAt: number;
readonly abort: Error;
}
type ExpiryStatusInterface = 1 | 2 | 3;

Expand Down Expand Up @@ -964,9 +965,6 @@ type QuerySchema<Schema, R> = Exclude<Schema, 'denormalize' | '_denormalizeNulla
denormalize(input: {}, args: readonly any[], unvisit: (input: any, schema: any) => any): R;
};

declare class AbortOptimistic extends Error {
}

declare class GQLEntity extends Entity {
readonly id: string;
pk(): string;
Expand Down Expand Up @@ -1009,4 +1007,4 @@ interface GQLError {
path: (string | number)[];
}

export { AbortOptimistic, AbstractInstanceType, Array$1 as Array, ArrayElement, Collection, Denormalize, DenormalizeNullable, Endpoint, EndpointExtendOptions, EndpointExtraOptions, EndpointInstance, EndpointInstanceInterface, EndpointInterface, EndpointOptions, EndpointParam, EndpointToFunction, Entity, ErrorTypes, ExpiryStatusInterface, ExtendableEndpoint, FetchFunction, GQLEndpoint, GQLEntity, GQLError, GQLNetworkError, GQLOptions, INVALID, Index, IndexParams, Invalidate, KeyofEndpointInstance, MutateEndpoint, NetworkError, Normalize, NormalizeNullable, PolymorphicInterface, Query, ReadEndpoint, ResolveType, Schema, SchemaClass, SchemaSimple, SchemaToArgs, SnapshotInterface, UnknownError, schema_d as schema, validateRequired };
export { AbstractInstanceType, Array$1 as Array, ArrayElement, Collection, Denormalize, DenormalizeNullable, Endpoint, EndpointExtendOptions, EndpointExtraOptions, EndpointInstance, EndpointInstanceInterface, EndpointInterface, EndpointOptions, EndpointParam, EndpointToFunction, Entity, ErrorTypes, ExpiryStatusInterface, ExtendableEndpoint, FetchFunction, GQLEndpoint, GQLEntity, GQLError, GQLNetworkError, GQLOptions, INVALID, Index, IndexParams, Invalidate, KeyofEndpointInstance, MutateEndpoint, NetworkError, Normalize, NormalizeNullable, PolymorphicInterface, Query, ReadEndpoint, ResolveType, Schema, SchemaClass, SchemaSimple, SchemaToArgs, SnapshotInterface, UnknownError, schema_d as schema, validateRequired };
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ interface SnapshotInterface {
};
getError: <E extends Pick<EndpointInterface, 'key'>, Args extends readonly [...Parameters<E['key']>]>(endpoint: E, ...args: Args) => ErrorTypes | undefined;
readonly fetchedAt: number;
readonly abort: Error;
}

/** Defines a networking endpoint */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ interface SnapshotInterface {
};
getError: <E extends Pick<EndpointInterface, 'key'>, Args extends readonly [...Parameters<E['key']>]>(endpoint: E, ...args: Args) => ErrorTypes | undefined;
readonly fetchedAt: number;
readonly abort: Error;
}
type ExpiryStatusInterface = 1 | 2 | 3;

Expand Down Expand Up @@ -962,9 +963,6 @@ type QuerySchema<Schema, R> = Exclude<Schema, 'denormalize' | '_denormalizeNulla
denormalize(input: {}, args: readonly any[], unvisit: (input: any, schema: any) => any): R;
};

declare class AbortOptimistic extends Error {
}

type ExtractObject<S extends Record<string, any>> = {
[K in keyof S]: S[K] extends Schema ? ExtractCollection<S[K]> : never;
}[keyof S];
Expand Down Expand Up @@ -1539,4 +1537,4 @@ declare class NetworkError extends Error {
constructor(response: Response);
}

export { AbortOptimistic, AbstractInstanceType, AddEndpoint, Array$1 as Array, ArrayElement, Collection, CustomResource, Defaults, Denormalize, DenormalizeNullable, Endpoint, EndpointExtendOptions, EndpointExtraOptions, EndpointInstance, EndpointInstanceInterface, EndpointInterface, EndpointOptions, EndpointParam, EndpointToFunction, Entity, ErrorTypes, ExpiryStatusInterface, ExtendableEndpoint, ExtendedResource, FetchFunction, FetchGet, FetchMutate, FromFallBack, GetEndpoint, HookResource, HookableEndpointInterface, INVALID, Index, IndexParams, Invalidate, KeyofEndpointInstance, KeyofRestEndpoint, KeysToArgs, MethodToSide, MutateEndpoint, NetworkError, Normalize, NormalizeNullable, OptionsToFunction, PaginationEndpoint, PaginationFieldEndpoint, ParamFetchNoBody, ParamFetchWithBody, PartialRestGenerics, PathArgs, PathArgsAndSearch, PathKeys, PolymorphicInterface, Query, ReadEndpoint, ResolveType, Resource, ResourceEndpointExtensions, ResourceExtension, ResourceGenerics, ResourceOptions, RestEndpoint, RestEndpointConstructor, RestEndpointConstructorOptions, RestEndpointExtendOptions, RestEndpointOptions, RestExtendedEndpoint, RestFetch, RestGenerics, RestInstance, RestInstanceBase, RestType, RestTypeNoBody, RestTypeWithBody, Schema, SchemaClass, SchemaSimple, SchemaToArgs, ShortenPath, SnapshotInterface, UnknownError, createResource, getUrlBase, getUrlTokens, hookifyResource, schema_d as schema, validateRequired };
export { AbstractInstanceType, AddEndpoint, Array$1 as Array, ArrayElement, Collection, CustomResource, Defaults, Denormalize, DenormalizeNullable, Endpoint, EndpointExtendOptions, EndpointExtraOptions, EndpointInstance, EndpointInstanceInterface, EndpointInterface, EndpointOptions, EndpointParam, EndpointToFunction, Entity, ErrorTypes, ExpiryStatusInterface, ExtendableEndpoint, ExtendedResource, FetchFunction, FetchGet, FetchMutate, FromFallBack, GetEndpoint, HookResource, HookableEndpointInterface, INVALID, Index, IndexParams, Invalidate, KeyofEndpointInstance, KeyofRestEndpoint, KeysToArgs, MethodToSide, MutateEndpoint, NetworkError, Normalize, NormalizeNullable, OptionsToFunction, PaginationEndpoint, PaginationFieldEndpoint, ParamFetchNoBody, ParamFetchWithBody, PartialRestGenerics, PathArgs, PathArgsAndSearch, PathKeys, PolymorphicInterface, Query, ReadEndpoint, ResolveType, Resource, ResourceEndpointExtensions, ResourceExtension, ResourceGenerics, ResourceOptions, RestEndpoint, RestEndpointConstructor, RestEndpointConstructorOptions, RestEndpointExtendOptions, RestEndpointOptions, RestExtendedEndpoint, RestFetch, RestGenerics, RestInstance, RestInstanceBase, RestType, RestTypeNoBody, RestTypeWithBody, Schema, SchemaClass, SchemaSimple, SchemaToArgs, ShortenPath, SnapshotInterface, UnknownError, createResource, getUrlBase, getUrlTokens, hookifyResource, schema_d as schema, validateRequired };
Loading

0 comments on commit c129a25

Please sign in to comment.