Skip to content

Commit 2e5d719

Browse files
Merge pull request #579 from nklisch/required-properties
feat: add required properties array
2 parents 752c0cf + 07b640a commit 2e5d719

File tree

5 files changed

+123
-2
lines changed

5 files changed

+123
-2
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,17 @@ generator jsonSchema {
4949
provider = "prisma-json-schema-generator"
5050
keepRelationScalarFields = "true"
5151
schemaId = "some-schema-id"
52+
includeRequiredFields = "true"
5253
}
5354
```
5455

55-
The generator currently supports a single option
56+
The generator currently supports a few options
5657

5758
| Key | Default Value | Description |
5859
| ------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
5960
| keepRelationScalarFields | "false" | By default, the JSON Schema that's generated will output only objects for related model records. If set to "true", this will cause the generator to also output foreign key fields for related records |
6061
| schemaId | undefined | Add an id to the generated schema. All references will include the schema id |
62+
| includeRequiredFields | "false" | If this flag is ```"true"``` all required scalar prisma fields that do not have a default value, will be added to the ```required``` properties field for that schema definition.
6163

6264
**3. Run generation**
6365

src/generator/model.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,22 @@ export function getJSONSchemaModel(
3636
type: 'object',
3737
properties,
3838
}
39-
39+
if (transformOptions.includeRequiredFields) {
40+
const required = definitionPropsMap.reduce(
41+
(filtered: string[], [name, , fieldMetaData]) => {
42+
if (
43+
fieldMetaData.required &&
44+
fieldMetaData.isScalar &&
45+
!fieldMetaData.hasDefaultValue
46+
) {
47+
filtered.push(name)
48+
}
49+
return filtered
50+
},
51+
[],
52+
)
53+
definition.required = required
54+
}
4055
return [model.name, definition]
4156
}
4257
}

src/generator/properties.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ export function getJSONSchemaProperty(
183183
return (field: DMMF.Field): PropertyMap => {
184184
const propertyMetaData: PropertyMetaData = {
185185
required: field.isRequired,
186+
hasDefaultValue: field.hasDefaultValue,
187+
isScalar: isScalarType(field) || isEnumType(field),
186188
}
187189

188190
const property = isSingleReference(field)

src/generator/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { JSONSchema7Definition } from 'json-schema'
33

44
export interface PropertyMetaData {
55
required: boolean
6+
hasDefaultValue: boolean
7+
isScalar: boolean
68
}
79

810
export interface ModelMetaData {
@@ -15,4 +17,5 @@ export type PropertyMap = [...DefinitionMap, PropertyMetaData]
1517
export interface TransformOptions {
1618
keepRelationScalarFields?: 'true' | 'false'
1719
schemaId?: string
20+
includeRequiredFields?: 'true' | 'false'
1821
}

src/tests/generator.test.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,105 @@ describe('JSON Schema Generator', () => {
261261
})
262262
})
263263

264+
it('adds required field if requested', async () => {
265+
const dmmf = await getDMMF({ datamodel: datamodelPostGresQL })
266+
expect(
267+
transformDMMF(dmmf, { includeRequiredFields: 'true' }),
268+
).toEqual({
269+
$schema: 'http://json-schema.org/draft-07/schema#',
270+
definitions: {
271+
Post: {
272+
properties: {
273+
id: { type: 'integer' },
274+
user: {
275+
anyOf: [
276+
{ $ref: '#/definitions/User' },
277+
{ type: 'null' },
278+
],
279+
},
280+
},
281+
type: 'object',
282+
required: [],
283+
},
284+
User: {
285+
properties: {
286+
biography: {
287+
type: [
288+
'number',
289+
'string',
290+
'boolean',
291+
'object',
292+
'array',
293+
'null',
294+
],
295+
},
296+
createdAt: { format: 'date-time', type: 'string' },
297+
email: {
298+
description:
299+
'Triple Slash Comment: Will show up in JSON schema [EMAIL]',
300+
type: 'string',
301+
},
302+
number: {
303+
type: 'integer',
304+
default: '34534535435353',
305+
},
306+
bytes: {
307+
description:
308+
'Triple Slash Inline Comment: Will show up in JSON schema [BYTES]',
309+
type: 'string',
310+
},
311+
favouriteDecimal: {
312+
default: 22.222222,
313+
type: 'number',
314+
},
315+
id: { type: 'integer' },
316+
is18: { default: false, type: ['boolean', 'null'] },
317+
keywords: {
318+
items: { type: 'string' },
319+
type: 'array',
320+
},
321+
name: {
322+
default: 'Bela B',
323+
type: ['string', 'null'],
324+
},
325+
posts: {
326+
items: { $ref: '#/definitions/Post' },
327+
type: 'array',
328+
},
329+
predecessor: {
330+
anyOf: [
331+
{ $ref: '#/definitions/User' },
332+
{ type: 'null' },
333+
],
334+
},
335+
role: {
336+
default: 'USER',
337+
enum: ['USER', 'ADMIN'],
338+
type: 'string',
339+
},
340+
successor: {
341+
anyOf: [
342+
{ $ref: '#/definitions/User' },
343+
{ type: 'null' },
344+
],
345+
},
346+
weight: {
347+
default: 333.33,
348+
type: ['number', 'null'],
349+
},
350+
},
351+
type: 'object',
352+
required: ['email', 'bytes', 'keywords', 'biography'],
353+
},
354+
},
355+
properties: {
356+
post: { $ref: '#/definitions/Post' },
357+
user: { $ref: '#/definitions/User' },
358+
},
359+
type: 'object',
360+
})
361+
})
362+
264363
it('adds schema id', async () => {
265364
const dmmf = await getDMMF({ datamodel: datamodelPostGresQL })
266365
expect(

0 commit comments

Comments
 (0)