Skip to content

Commit a61b8cf

Browse files
OliverJAshpaularmstrong
andcommittedJan 23, 2020
Add ability to dynamically set nested schema type (paularmstrong#415)
* Add ability to dynamically set nested schema type * Re-use type * Use blocks * Add response type * Update types, add tests Co-authored-by: Paul Armstrong <[email protected]>
1 parent 3246f91 commit a61b8cf

File tree

6 files changed

+127
-11
lines changed

6 files changed

+127
-11
lines changed
 

‎index.d.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ declare namespace schema {
2323
}
2424

2525
export class Object<T = any> {
26-
constructor(definition: {[key: string]: Schema<T>})
26+
constructor(definition: SchemaObject<T>)
2727
define(definition: Schema): void
2828
}
2929

@@ -46,8 +46,11 @@ export type Schema<T = any> =
4646
| SchemaObject<T>
4747
| SchemaArray<T>;
4848

49+
export type SchemaValueFunction<T> = (t: T) => Schema<T>;
50+
export type SchemaValue<T> = Schema<T> | SchemaValueFunction<T>;
51+
4952
export interface SchemaObject<T> {
50-
[key: string]: Schema<T>
53+
[key: string]: SchemaValue<T>
5154
}
5255

5356
export interface SchemaArray<T> extends Array<Schema<T>> {}

‎src/__tests__/__snapshots__/index.test.js.snap

+41
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,47 @@ Object {
6464
}
6565
`;
6666

67+
exports[`normalize can normalize entity nested inside entity using property from parent 1`] = `
68+
Object {
69+
"entities": Object {
70+
"linkables": Object {
71+
"1": Object {
72+
"data": 2,
73+
"id": 1,
74+
"module_type": "article",
75+
"schema_type": "media",
76+
},
77+
},
78+
"media": Object {
79+
"2": Object {
80+
"id": 2,
81+
"url": "catimage.jpg",
82+
},
83+
},
84+
},
85+
"result": 1,
86+
}
87+
`;
88+
89+
exports[`normalize can normalize entity nested inside object using property from parent 1`] = `
90+
Object {
91+
"entities": Object {
92+
"media": Object {
93+
"2": Object {
94+
"id": 2,
95+
"url": "catimage.jpg",
96+
},
97+
},
98+
},
99+
"result": Object {
100+
"data": 2,
101+
"id": 1,
102+
"module_type": "article",
103+
"schema_type": "media",
104+
},
105+
}
106+
`;
107+
67108
exports[`normalize can use fully custom entity classes 1`] = `
68109
Object {
69110
"entities": Object {

‎src/__tests__/index.test.js

+53
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,59 @@ describe('normalize', () => {
162162

163163
expect(() => normalize(test, testEntity)).not.toThrow();
164164
});
165+
166+
test('can normalize entity nested inside entity using property from parent', () => {
167+
const linkablesSchema = new schema.Entity('linkables');
168+
const mediaSchema = new schema.Entity('media');
169+
const listsSchema = new schema.Entity('lists');
170+
171+
const schemaMap = {
172+
media: mediaSchema,
173+
lists: listsSchema
174+
};
175+
176+
linkablesSchema.define({
177+
data: (parent) => schemaMap[parent.schema_type]
178+
});
179+
180+
const input = {
181+
id: 1,
182+
module_type: 'article',
183+
schema_type: 'media',
184+
data: {
185+
id: 2,
186+
url: 'catimage.jpg'
187+
}
188+
};
189+
190+
expect(normalize(input, linkablesSchema)).toMatchSnapshot();
191+
});
192+
193+
test('can normalize entity nested inside object using property from parent', () => {
194+
const mediaSchema = new schema.Entity('media');
195+
const listsSchema = new schema.Entity('lists');
196+
197+
const schemaMap = {
198+
media: mediaSchema,
199+
lists: listsSchema
200+
};
201+
202+
const linkablesSchema = {
203+
data: (parent) => schemaMap[parent.schema_type]
204+
};
205+
206+
const input = {
207+
id: 1,
208+
module_type: 'article',
209+
schema_type: 'media',
210+
data: {
211+
id: 2,
212+
url: 'catimage.jpg'
213+
}
214+
};
215+
216+
expect(normalize(input, linkablesSchema)).toMatchSnapshot();
217+
});
165218
});
166219

167220
describe('denormalize', () => {

‎src/schemas/Entity.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,15 @@ export default class EntitySchema {
6767
Object.keys(this.schema).forEach((key) => {
6868
if (processedEntity.hasOwnProperty(key) && typeof processedEntity[key] === 'object') {
6969
const schema = this.schema[key];
70-
processedEntity[key] = visit(processedEntity[key], processedEntity, key, schema, addEntity, visitedEntities);
70+
const resolvedSchema = typeof schema === 'function' ? schema(input) : schema;
71+
processedEntity[key] = visit(
72+
processedEntity[key],
73+
processedEntity,
74+
key,
75+
resolvedSchema,
76+
addEntity,
77+
visitedEntities
78+
);
7179
}
7280
});
7381

‎src/schemas/Object.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ export const normalize = (schema, input, parent, key, visit, addEntity, visitedE
44
const object = { ...input };
55
Object.keys(schema).forEach((key) => {
66
const localSchema = schema[key];
7-
const value = visit(input[key], input, key, localSchema, addEntity, visitedEntities);
7+
const resolvedLocalSchema = typeof localSchema === 'function' ? localSchema(input) : localSchema;
8+
const value = visit(input[key], input, key, resolvedLocalSchema, addEntity, visitedEntities);
89
if (value === undefined || value === null) {
910
delete object[key];
1011
} else {

‎typescript-tests/object.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import { normalize, schema } from '../index'
22

3-
const data = {
4-
/* ...*/
5-
};
3+
type Response = {
4+
users: Array<{ id: string }>
5+
}
6+
const data: Response = { users: [ { id: 'foo' } ] };
67
const user = new schema.Entity('users');
78

8-
const responseSchema = new schema.Object({ users: new schema.Array(user) });
9-
const normalizedData = normalize(data, responseSchema);
9+
{
10+
const responseSchema = new schema.Object({ users: new schema.Array(user) });
11+
const normalizedData = normalize(data, responseSchema);
12+
}
1013

11-
const responseSchemaAlt = { users: new schema.Array(user) };
12-
const normalizedDataAlt = normalize(data, responseSchemaAlt);
14+
{
15+
const responseSchema = new schema.Object<Response>({ users: (response: Response) => new schema.Array(user) });
16+
const normalizedData = normalize(data, responseSchema);
17+
}
18+
19+
{
20+
const responseSchema = { users: new schema.Array(user) };
21+
const normalizedData = normalize(data, responseSchema);
22+
}

0 commit comments

Comments
 (0)
Please sign in to comment.