Skip to content

Commit b236b91

Browse files
authored
feat: Add Entity.validate() (#934)
1 parent e68b0f9 commit b236b91

File tree

3 files changed

+174
-154
lines changed

3 files changed

+174
-154
lines changed

packages/experimental/src/entity/Entity.ts

Lines changed: 79 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,65 @@ export default abstract class Entity {
112112
// pass over already processed entities
113113
if (typeof input === 'string') return input;
114114
const processedEntity = this.process(input, parent, key);
115+
const id = this.pk(processedEntity, parent, key);
116+
if (id === undefined || id === '') {
117+
if (process.env.NODE_ENV !== 'production') {
118+
const error = new Error(
119+
`Missing usable primary key when normalizing response.
120+
121+
This is likely due to a malformed response.
122+
Try inspecting the network response or fetch() return value.
123+
Or use debugging tools: https://resthooks.io/docs/guides/debugging
124+
Learn more about schemas: https://resthooks.io/docs/api/schema
125+
126+
Entity: ${this.name}
127+
Value (processed): ${
128+
processedEntity && JSON.stringify(processedEntity, null, 2)
129+
}
130+
`,
131+
);
132+
(error as any).status = 400;
133+
throw error;
134+
} else {
135+
// these make the keys get deleted
136+
return undefined;
137+
}
138+
}
139+
const entityType = this.key;
140+
141+
if (!(entityType in visitedEntities)) {
142+
visitedEntities[entityType] = {};
143+
}
144+
if (!(id in visitedEntities[entityType])) {
145+
visitedEntities[entityType][id] = [];
146+
}
147+
if (
148+
visitedEntities[entityType][id].some((entity: any) => entity === input)
149+
) {
150+
return id;
151+
}
152+
this.validate(processedEntity);
153+
visitedEntities[entityType][id].push(input);
154+
155+
Object.keys(this.schema).forEach(key => {
156+
if (Object.prototype.hasOwnProperty.call(processedEntity, key)) {
157+
const schema = this.schema[key];
158+
processedEntity[key] = visit(
159+
processedEntity[key],
160+
processedEntity,
161+
key,
162+
schema,
163+
addEntity,
164+
visitedEntities,
165+
);
166+
}
167+
});
168+
169+
addEntity(this, processedEntity, id);
170+
return id;
171+
}
172+
173+
protected static validate(processedEntity: any) {
115174
/* istanbul ignore else */
116175
if (
117176
process.env.NODE_ENV !== 'production' &&
@@ -207,60 +266,12 @@ First three members: ${JSON.stringify(processedEntity.slice(0, 3), null, 2)}`;
207266
}
208267
}
209268
}
210-
const id = this.pk(processedEntity, parent, key);
211-
if (id === undefined || id === '') {
212-
if (process.env.NODE_ENV !== 'production') {
213-
const error = new Error(
214-
`Missing usable primary key when normalizing response.
215-
216-
This is likely due to a malformed response.
217-
Try inspecting the network response or fetch() return value.
218-
Or use debugging tools: https://resthooks.io/docs/guides/debugging
219-
Learn more about schemas: https://resthooks.io/docs/api/schema
220-
221-
Entity: ${this.name}
222-
Value (processed): ${
223-
processedEntity && JSON.stringify(processedEntity, null, 2)
224-
}
225-
`,
226-
);
227-
(error as any).status = 400;
228-
throw error;
229-
} else {
230-
// these make the keys get deleted
231-
return undefined;
232-
}
233-
}
234-
const entityType = this.key;
235-
236-
if (!(entityType in visitedEntities)) {
237-
visitedEntities[entityType] = {};
238-
}
239-
if (!(id in visitedEntities[entityType])) {
240-
visitedEntities[entityType][id] = [];
241-
}
242-
if (
243-
visitedEntities[entityType][id].some((entity: any) => entity === input)
244-
) {
245-
return id;
246-
}
247-
visitedEntities[entityType][id].push(input);
248-
249-
Object.keys(this.schema).forEach(key => {
250-
if (Object.hasOwnProperty.call(processedEntity, key)) {
251-
const schema = this.schema[key];
252-
processedEntity[key] = visit(
253-
processedEntity[key],
254-
processedEntity,
255-
key,
256-
schema,
257-
addEntity,
258-
visitedEntities,
259-
);
260-
} else if (process.env.NODE_ENV !== 'production') {
261-
if (!Object.hasOwnProperty.call(this.defaults, key)) {
262-
const error = new Error(
263-
`Schema key is missing in Entity
269+
if (process.env.NODE_ENV !== 'production') {
270+
Object.keys(this.schema).forEach(key => {
271+
if (!Object.prototype.hasOwnProperty.call(processedEntity, key)) {
272+
if (!Object.prototype.hasOwnProperty.call(this.defaults, key)) {
273+
const error = new Error(
274+
`Schema key is missing in Entity
264275
265276
Be sure all schema members are also part of the entity
266277
Or use debugging tools: https://resthooks.io/docs/guides/debugging
@@ -269,15 +280,13 @@ First three members: ${JSON.stringify(processedEntity.slice(0, 3), null, 2)}`;
269280
Entity keys: ${Object.keys(this.defaults)}
270281
Schema key(missing): ${key}
271282
`,
272-
);
273-
(error as any).status = 400;
274-
throw error;
283+
);
284+
(error as any).status = 400;
285+
throw error;
286+
}
275287
}
276-
}
277-
});
278-
279-
addEntity(this, processedEntity, id);
280-
return id;
288+
});
289+
}
281290
}
282291

283292
static infer(args: any[], indexes: NormalizedIndex, recurse: any): any {
@@ -299,10 +308,10 @@ First three members: ${JSON.stringify(processedEntity.slice(0, 3), null, 2)}`;
299308
}
300309

301310
static expiresAt(
302-
{ expiresAt }: { expiresAt: number; date: number },
311+
meta: { expiresAt: number; date: number },
303312
input: any,
304313
): number {
305-
return expiresAt;
314+
return meta.expiresAt;
306315
}
307316

308317
static denormalize<T extends typeof Entity>(
@@ -331,19 +340,22 @@ First three members: ${JSON.stringify(processedEntity.slice(0, 3), null, 2)}`;
331340
// note: iteration order must be stable
332341
Object.keys(this.schema).forEach(key => {
333342
const schema = this.schema[key];
334-
const nextInput = Object.hasOwnProperty.call(input, key)
343+
const nextInput = Object.prototype.hasOwnProperty.call(input, key)
335344
? (input as any)[key]
336345
: undefined;
337346
const [value, , deletedItem] = unvisit(nextInput, schema);
338347

339348
if (
340349
deletedItem &&
341-
!(Object.hasOwnProperty.call(input, key) && !this.defaults[key])
350+
!(
351+
Object.prototype.hasOwnProperty.call(input, key) &&
352+
!this.defaults[key]
353+
)
342354
) {
343355
deleted = true;
344356
}
345357
if (
346-
Object.hasOwnProperty.call(input, key) &&
358+
Object.prototype.hasOwnProperty.call(input, key) &&
347359
(input as any)[key] !== value
348360
) {
349361
this.set(entityCopy, key, value);

packages/experimental/src/entity/__tests__/__snapshots__/NewEntity.test.ts.snap

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -817,18 +817,16 @@ exports[`Entity normalization should throw a custom error if data loads with hal
817817
`;
818818

819819
exports[`Entity normalization should throw a custom error if data loads with no matching props 1`] = `
820-
"Attempted to initialize MyEntity with no matching keys found
820+
"Missing usable primary key when normalizing response.
821821
822822
This is likely due to a malformed response.
823823
Try inspecting the network response or fetch() return value.
824824
Or use debugging tools: https://resthooks.io/docs/guides/debugging
825825
Learn more about schemas: https://resthooks.io/docs/api/schema
826-
If this is a mistake, you can disable this check by setting static automaticValidation = 'silent'
827826
828-
Expected keys:
829-
Found:
830-
Missing: name,secondthing
831-
Value (processed): {}"
827+
Entity: MyEntity
828+
Value (processed): {}
829+
"
832830
`;
833831

834832
exports[`Entity normalization should throw a custom error if data loads with string 1`] = `
@@ -855,16 +853,15 @@ exports[`Entity normalization should throw a custom error if schema key is missi
855853
`;
856854

857855
exports[`Entity normalization should throw a custom error loads with array 1`] = `
858-
"Attempted to initialize MyEntity with an array, but named members were expected
856+
"Missing usable primary key when normalizing response.
859857
860-
This is likely due to a malformed response.
861-
Try inspecting the network response or fetch() return value.
862-
Or use debugging tools: https://resthooks.io/docs/guides/debugging
863-
Learn more about schemas: https://resthooks.io/docs/api/schema
864-
If this is a mistake, you can disable this check by setting static automaticValidation = 'silent'
858+
This is likely due to a malformed response.
859+
Try inspecting the network response or fetch() return value.
860+
Or use debugging tools: https://resthooks.io/docs/guides/debugging
861+
Learn more about schemas: https://resthooks.io/docs/api/schema
865862
866-
Missing: name,secondthing
867-
First three members: [
863+
Entity: MyEntity
864+
Value (processed): [
868865
{
869866
\\"name\\": \\"hi\\",
870867
\\"secondthing\\": \\"ho\\"
@@ -877,7 +874,8 @@ First three members: [
877874
\\"name\\": \\"hi\\",
878875
\\"secondthing\\": \\"ho\\"
879876
}
880-
]"
877+
]
878+
"
881879
`;
882880

883881
exports[`Entity normalization should warn when automaticValidation === "warn" 1`] = `

0 commit comments

Comments
 (0)