Skip to content

Commit 0c7ac83

Browse files
authored
feat: Add Resource+Entity to legacy (#924)
1 parent ae46eba commit 0c7ac83

34 files changed

+5525
-99
lines changed

__tests__/legacy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MutateShape, Resource, schemas } from 'rest-hooks';
1+
import { MutateShape, Resource, Delete } from '@rest-hooks/legacy';
22

33
export class UserResource extends Resource {
44
readonly id: number | undefined = undefined;
@@ -66,7 +66,7 @@ export class CoolerArticleResource extends ArticleResource {
6666

6767
static deleteShape<T extends typeof Resource>(
6868
this: T,
69-
): MutateShape<schemas.Delete<T>, Readonly<object>, unknown> {
69+
): MutateShape<Delete<T>, Readonly<object>, unknown> {
7070
return super.deleteShape() as any;
7171
}
7272
}

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const baseConfig = {
88
'react-integration/hooks/useSelection',
99
'packages/test',
1010
'packages/experimental',
11+
'packages/legacy/src/resource',
1112
],
1213
testURL: 'http://localhost',
1314
};

packages/legacy/src/__tests__/useStatefulResource.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { makeRenderRestHook, makeCacheProvider } from '@rest-hooks/test';
77
import nock from 'nock';
88

99
import { payload, payload2, users, nested } from './fixtures';
10-
import { useStatefulResource } from '..';
10+
import useStatefulResource from '../useStatefulResource';
1111

1212
function onError(e: any) {
1313
e.preventDefault();

packages/legacy/src/index.ts

Lines changed: 8 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,10 @@
1-
import {
2-
useRetrieve,
3-
useError,
4-
Schema,
5-
useDenormalized,
6-
StateContext,
7-
hasUsableData,
8-
useMeta,
9-
ParamsFromShape,
1+
export * from './resource';
2+
export { default as useStatefulResource } from './useStatefulResource';
3+
export type {
4+
FetchShape,
105
ReadShape,
11-
__INTERNAL__,
12-
} from '@rest-hooks/core';
13-
import type {
14-
Denormalize,
15-
DenormalizeNullable,
16-
ErrorTypes,
6+
MutateShape,
7+
DeleteShape,
8+
SetShapeParams,
9+
ParamsFromShape,
1710
} from '@rest-hooks/core';
18-
import { denormalize } from '@rest-hooks/normalizr';
19-
import { useContext } from 'react';
20-
21-
const { inferResults } = __INTERNAL__;
22-
23-
type CondNull<P, A, B> = P extends null ? A : B;
24-
25-
type StatefulReturn<S extends Schema, P> = CondNull<
26-
P,
27-
{
28-
data: DenormalizeNullable<S>;
29-
loading: false;
30-
error: undefined;
31-
},
32-
| {
33-
data: Denormalize<S>;
34-
loading: false;
35-
error: undefined;
36-
}
37-
| { data: DenormalizeNullable<S>; loading: true; error: undefined }
38-
| { data: DenormalizeNullable<S>; loading: false; error: ErrorTypes }
39-
>;
40-
41-
/** Ensure a resource is available; loading and error returned explicitly. */
42-
export function useStatefulResource<
43-
Shape extends ReadShape<any, any>,
44-
Params extends ParamsFromShape<Shape> | null,
45-
>(fetchShape: Shape, params: Params): StatefulReturn<Shape['schema'], Params> {
46-
const state = useContext(StateContext);
47-
const [denormalized, ready, deleted, entitiesExpireAt] = useDenormalized(
48-
fetchShape,
49-
params,
50-
state,
51-
);
52-
const error = useError(fetchShape, params, ready);
53-
54-
const maybePromise: Promise<any> | undefined = useRetrieve(
55-
fetchShape,
56-
params,
57-
deleted && !error,
58-
entitiesExpireAt,
59-
);
60-
61-
if (maybePromise) {
62-
maybePromise.catch(() => {});
63-
}
64-
65-
const loading =
66-
!hasUsableData(
67-
fetchShape,
68-
ready,
69-
deleted,
70-
useMeta(fetchShape, params)?.invalidated,
71-
) && !!maybePromise;
72-
const data = loading
73-
? denormalize(
74-
inferResults(fetchShape.schema, [params], state.indexes),
75-
fetchShape.schema,
76-
{},
77-
)[0]
78-
: denormalized;
79-
80-
return {
81-
data,
82-
loading,
83-
error,
84-
} as any;
85-
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2+
import { schema, AbstractInstanceType, DELETED } from '@rest-hooks/normalizr';
3+
4+
export default class Delete<E extends schema.EntityInterface & { fromJS: any }>
5+
implements schema.SchemaClass
6+
{
7+
private declare _entity: E;
8+
9+
constructor(entity: E) {
10+
if (process.env.NODE_ENV !== 'production' && !entity) {
11+
throw new Error('Expected option "entity" not found on DeleteSchema.');
12+
}
13+
this._entity = entity;
14+
}
15+
16+
get key() {
17+
return this._entity.key;
18+
}
19+
20+
normalize(
21+
input: any,
22+
parent: any,
23+
key: string | undefined,
24+
visit: (...args: any) => any,
25+
addEntity: (...args: any) => any,
26+
visitedEntities: Record<string, any>,
27+
): string | undefined {
28+
// pass over already processed entities
29+
if (typeof input === 'string') return input;
30+
// TODO: what's store needs to be a differing type from fromJS
31+
const processedEntity = this._entity.fromJS(input, parent, key);
32+
const id = processedEntity.pk(parent, key);
33+
if (
34+
process.env.NODE_ENV !== 'production' &&
35+
(id === undefined || id === '')
36+
) {
37+
const error = new Error(
38+
`Missing usable primary key when normalizing response.
39+
40+
This is likely due to a malformed response.
41+
Try inspecting the network response or fetch() return value.
42+
Or use debugging tools: https://resthooks.io/docs/guides/debugging
43+
Learn more about schemas: https://resthooks.io/docs/api/schema
44+
45+
Delete(Entity): Delete(${(this._entity as any).name ?? this._entity})
46+
Value: ${input && JSON.stringify(input, null, 2)}
47+
`,
48+
);
49+
(error as any).status = 400;
50+
throw error;
51+
}
52+
addEntity(this, DELETED, id);
53+
return id;
54+
}
55+
56+
infer(args: any, indexes: any, recurse: any): any {
57+
return undefined;
58+
}
59+
60+
denormalize(
61+
id: string,
62+
unvisit: schema.UnvisitFunction,
63+
): [AbstractInstanceType<E>, boolean, boolean] {
64+
return unvisit(id, this._entity) as any;
65+
}
66+
67+
/* istanbul ignore next */
68+
_denormalizeNullable(): [
69+
AbstractInstanceType<E> | undefined,
70+
boolean,
71+
false,
72+
] {
73+
return [] as any;
74+
}
75+
76+
/* istanbul ignore next */
77+
_normalizeNullable(): string | undefined {
78+
return [] as any;
79+
}
80+
81+
/* istanbul ignore next */
82+
merge(existing: any, incoming: any) {
83+
return incoming;
84+
}
85+
}

0 commit comments

Comments
 (0)