Skip to content

Commit 3134f0d

Browse files
authored
feat(openapi): add plugin option to omit generating input object details for RPC flavor (#1852)
1 parent 0cd51aa commit 3134f0d

File tree

5 files changed

+6158
-82
lines changed

5 files changed

+6158
-82
lines changed

packages/plugins/openapi/src/rest-generator.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@ import {
77
isForeignKeyField,
88
isIdField,
99
isRelationshipField,
10+
PluginError,
11+
PluginOptions,
1012
requireOption,
1113
resolvePath,
1214
} from '@zenstackhq/sdk';
13-
import { DataModel, DataModelField, DataModelFieldType, Enum, isDataModel, isEnum } from '@zenstackhq/sdk/ast';
15+
import { DataModel, DataModelField, DataModelFieldType, Enum, isDataModel, isEnum, Model } from '@zenstackhq/sdk/ast';
1416
import type { DMMF } from '@zenstackhq/sdk/prisma';
1517
import fs from 'fs';
1618
import { lowerCaseFirst } from 'lower-case-first';
1719
import type { OpenAPIV3_1 as OAPI } from 'openapi-types';
1820
import path from 'path';
1921
import pluralize from 'pluralize';
2022
import invariant from 'tiny-invariant';
21-
import { P, match } from 'ts-pattern';
23+
import { match, P } from 'ts-pattern';
2224
import YAML from 'yaml';
2325
import { name } from '.';
2426
import { OpenAPIGeneratorBase } from './generator-base';
@@ -32,6 +34,14 @@ type Policies = ReturnType<typeof analyzePolicies>;
3234
export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase {
3335
private warnings: string[] = [];
3436

37+
constructor(protected model: Model, protected options: PluginOptions, protected dmmf: DMMF.Document) {
38+
super(model, options, dmmf);
39+
40+
if (this.options.omitInputDetails !== undefined) {
41+
throw new PluginError(name, '"omitInputDetails" option is not supported for "rest" flavor');
42+
}
43+
}
44+
3545
generate() {
3646
let output = requireOption<string>(this.options, 'output', name);
3747
output = resolvePath(output, this.options);

packages/plugins/openapi/src/rpc-generator.ts

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Inspired by: https://github.com/omar-dulaimi/prisma-trpc-generator
22

3-
import { PluginError, analyzePolicies, requireOption, resolvePath } from '@zenstackhq/sdk';
4-
import { DataModel, isDataModel } from '@zenstackhq/sdk/ast';
3+
import { PluginError, PluginOptions, analyzePolicies, requireOption, resolvePath } from '@zenstackhq/sdk';
4+
import { DataModel, Model, isDataModel } from '@zenstackhq/sdk/ast';
55
import {
66
AggregateOperationSupport,
77
addMissingInputObjectTypesForAggregate,
@@ -23,6 +23,8 @@ import { name } from '.';
2323
import { OpenAPIGeneratorBase } from './generator-base';
2424
import { getModelResourceMeta } from './meta';
2525

26+
const ANY_OBJECT = '_AnyObject';
27+
2628
/**
2729
* Generates OpenAPI specification.
2830
*/
@@ -32,6 +34,16 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
3234
private usedComponents: Set<string> = new Set<string>();
3335
private aggregateOperationSupport: AggregateOperationSupport;
3436
private warnings: string[] = [];
37+
private omitInputDetails: boolean;
38+
39+
constructor(protected model: Model, protected options: PluginOptions, protected dmmf: DMMF.Document) {
40+
super(model, options, dmmf);
41+
42+
this.omitInputDetails = this.getOption<boolean>('omitInputDetails', false);
43+
if (this.omitInputDetails !== undefined && typeof this.omitInputDetails !== 'boolean') {
44+
throw new PluginError(name, `Invalid option value for "omitInputDetails", boolean expected`);
45+
}
46+
}
3547

3648
generate() {
3749
let output = requireOption<string>(this.options, 'output', name);
@@ -151,9 +163,9 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
151163
type: 'object',
152164
required: ['data'],
153165
properties: {
154-
select: this.ref(`${modelName}Select`),
155-
include: hasRelation ? this.ref(`${modelName}Include`) : undefined,
156-
data: this.ref(`${modelName}CreateInput`),
166+
select: this.omittableRef(`${modelName}Select`),
167+
include: hasRelation ? this.omittableRef(`${modelName}Include`) : undefined,
168+
data: this.omittableRef(`${modelName}CreateInput`),
157169
meta: this.ref('_Meta'),
158170
},
159171
},
@@ -177,8 +189,8 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
177189
required: ['data'],
178190
properties: {
179191
data: this.oneOf(
180-
this.ref(`${modelName}CreateManyInput`),
181-
this.array(this.ref(`${modelName}CreateManyInput`))
192+
this.omittableRef(`${modelName}CreateManyInput`),
193+
this.array(this.omittableRef(`${modelName}CreateManyInput`))
182194
),
183195
skipDuplicates: {
184196
type: 'boolean',
@@ -207,9 +219,9 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
207219
type: 'object',
208220
required: ['where'],
209221
properties: {
210-
select: this.ref(`${modelName}Select`),
211-
include: hasRelation ? this.ref(`${modelName}Include`) : undefined,
212-
where: this.ref(`${modelName}WhereUniqueInput`),
222+
select: this.omittableRef(`${modelName}Select`),
223+
include: hasRelation ? this.omittableRef(`${modelName}Include`) : undefined,
224+
where: this.omittableRef(`${modelName}WhereUniqueInput`),
213225
meta: this.ref('_Meta'),
214226
},
215227
},
@@ -230,9 +242,9 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
230242
{
231243
type: 'object',
232244
properties: {
233-
select: this.ref(`${modelName}Select`),
234-
include: hasRelation ? this.ref(`${modelName}Include`) : undefined,
235-
where: this.ref(`${modelName}WhereInput`),
245+
select: this.omittableRef(`${modelName}Select`),
246+
include: hasRelation ? this.omittableRef(`${modelName}Include`) : undefined,
247+
where: this.omittableRef(`${modelName}WhereInput`),
236248
meta: this.ref('_Meta'),
237249
},
238250
},
@@ -253,9 +265,9 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
253265
{
254266
type: 'object',
255267
properties: {
256-
select: this.ref(`${modelName}Select`),
257-
include: hasRelation ? this.ref(`${modelName}Include`) : undefined,
258-
where: this.ref(`${modelName}WhereInput`),
268+
select: this.omittableRef(`${modelName}Select`),
269+
include: hasRelation ? this.omittableRef(`${modelName}Include`) : undefined,
270+
where: this.omittableRef(`${modelName}WhereInput`),
259271
meta: this.ref('_Meta'),
260272
},
261273
},
@@ -277,10 +289,10 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
277289
type: 'object',
278290
required: ['where', 'data'],
279291
properties: {
280-
select: this.ref(`${modelName}Select`),
281-
include: hasRelation ? this.ref(`${modelName}Include`) : undefined,
282-
where: this.ref(`${modelName}WhereUniqueInput`),
283-
data: this.ref(`${modelName}UpdateInput`),
292+
select: this.omittableRef(`${modelName}Select`),
293+
include: hasRelation ? this.omittableRef(`${modelName}Include`) : undefined,
294+
where: this.omittableRef(`${modelName}WhereUniqueInput`),
295+
data: this.omittableRef(`${modelName}UpdateInput`),
284296
meta: this.ref('_Meta'),
285297
},
286298
},
@@ -302,8 +314,8 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
302314
type: 'object',
303315
required: ['data'],
304316
properties: {
305-
where: this.ref(`${modelName}WhereInput`),
306-
data: this.ref(`${modelName}UpdateManyMutationInput`),
317+
where: this.omittableRef(`${modelName}WhereInput`),
318+
data: this.omittableRef(`${modelName}UpdateManyMutationInput`),
307319
meta: this.ref('_Meta'),
308320
},
309321
},
@@ -325,11 +337,11 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
325337
type: 'object',
326338
required: ['create', 'update', 'where'],
327339
properties: {
328-
select: this.ref(`${modelName}Select`),
329-
include: hasRelation ? this.ref(`${modelName}Include`) : undefined,
330-
where: this.ref(`${modelName}WhereUniqueInput`),
331-
create: this.ref(`${modelName}CreateInput`),
332-
update: this.ref(`${modelName}UpdateInput`),
340+
select: this.omittableRef(`${modelName}Select`),
341+
include: hasRelation ? this.omittableRef(`${modelName}Include`) : undefined,
342+
where: this.omittableRef(`${modelName}WhereUniqueInput`),
343+
create: this.omittableRef(`${modelName}CreateInput`),
344+
update: this.omittableRef(`${modelName}UpdateInput`),
333345
meta: this.ref('_Meta'),
334346
},
335347
},
@@ -351,9 +363,9 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
351363
type: 'object',
352364
required: ['where'],
353365
properties: {
354-
select: this.ref(`${modelName}Select`),
355-
include: hasRelation ? this.ref(`${modelName}Include`) : undefined,
356-
where: this.ref(`${modelName}WhereUniqueInput`),
366+
select: this.omittableRef(`${modelName}Select`),
367+
include: hasRelation ? this.omittableRef(`${modelName}Include`) : undefined,
368+
where: this.omittableRef(`${modelName}WhereUniqueInput`),
357369
meta: this.ref('_Meta'),
358370
},
359371
},
@@ -374,7 +386,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
374386
{
375387
type: 'object',
376388
properties: {
377-
where: this.ref(`${modelName}WhereInput`),
389+
where: this.omittableRef(`${modelName}WhereInput`),
378390
meta: this.ref('_Meta'),
379391
},
380392
},
@@ -395,8 +407,8 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
395407
{
396408
type: 'object',
397409
properties: {
398-
select: this.ref(`${modelName}Select`),
399-
where: this.ref(`${modelName}WhereInput`),
410+
select: this.omittableRef(`${modelName}Select`),
411+
where: this.omittableRef(`${modelName}WhereInput`),
400412
meta: this.ref('_Meta'),
401413
},
402414
},
@@ -425,9 +437,9 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
425437
{
426438
type: 'object',
427439
properties: {
428-
where: this.ref(`${modelName}WhereInput`),
429-
orderBy: this.ref(orderByWithRelationInput),
430-
cursor: this.ref(`${modelName}WhereUniqueInput`),
440+
where: this.omittableRef(`${modelName}WhereInput`),
441+
orderBy: this.omittableRef(orderByWithRelationInput),
442+
cursor: this.omittableRef(`${modelName}WhereUniqueInput`),
431443
take: { type: 'integer' },
432444
skip: { type: 'integer' },
433445
...this.aggregateFields(model),
@@ -451,10 +463,10 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
451463
{
452464
type: 'object',
453465
properties: {
454-
where: this.ref(`${modelName}WhereInput`),
455-
orderBy: this.ref(orderByWithRelationInput),
456-
by: this.ref(`${modelName}ScalarFieldEnum`),
457-
having: this.ref(`${modelName}ScalarWhereWithAggregatesInput`),
466+
where: this.omittableRef(`${modelName}WhereInput`),
467+
orderBy: this.omittableRef(orderByWithRelationInput),
468+
by: this.omittableRef(`${modelName}ScalarFieldEnum`),
469+
having: this.omittableRef(`${modelName}ScalarWhereWithAggregatesInput`),
458470
take: { type: 'integer' },
459471
skip: { type: 'integer' },
460472
...this.aggregateFields(model),
@@ -587,19 +599,19 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
587599
const modelName = upperCaseFirst(model.name);
588600
if (supportedOps) {
589601
if (supportedOps.count) {
590-
result._count = this.oneOf({ type: 'boolean' }, this.ref(`${modelName}CountAggregateInput`));
602+
result._count = this.oneOf({ type: 'boolean' }, this.omittableRef(`${modelName}CountAggregateInput`));
591603
}
592604
if (supportedOps.min) {
593-
result._min = this.ref(`${modelName}MinAggregateInput`);
605+
result._min = this.omittableRef(`${modelName}MinAggregateInput`);
594606
}
595607
if (supportedOps.max) {
596-
result._max = this.ref(`${modelName}MaxAggregateInput`);
608+
result._max = this.omittableRef(`${modelName}MaxAggregateInput`);
597609
}
598610
if (supportedOps.sum) {
599-
result._sum = this.ref(`${modelName}SumAggregateInput`);
611+
result._sum = this.omittableRef(`${modelName}SumAggregateInput`);
600612
}
601613
if (supportedOps.avg) {
602-
result._avg = this.ref(`${modelName}AvgAggregateInput`);
614+
result._avg = this.omittableRef(`${modelName}AvgAggregateInput`);
603615
}
604616
}
605617
return result;
@@ -617,6 +629,14 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
617629
schemas,
618630
};
619631

632+
if (this.omitInputDetails) {
633+
// generate a catch-all object type
634+
schemas[ANY_OBJECT] = {
635+
type: 'object',
636+
additionalProperties: true,
637+
};
638+
}
639+
620640
// user-defined and built-in enums
621641
for (const _enum of [...(this.dmmf.schema.enumTypes.model ?? []), ...this.dmmf.schema.enumTypes.prisma]) {
622642
schemas[upperCaseFirst(_enum.name)] = this.generateEnumComponent(_enum);
@@ -824,6 +844,14 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
824844
return { $ref: `#/components/schemas/${upperCaseFirst(type)}`, description };
825845
}
826846

847+
private omittableRef(type: string, rooted = true, description?: string): OAPI.ReferenceObject {
848+
if (this.omitInputDetails) {
849+
return this.ref(ANY_OBJECT);
850+
} else {
851+
return this.ref(type, rooted, description);
852+
}
853+
}
854+
827855
private response(schema: OAPI.SchemaObject): OAPI.SchemaObject {
828856
return {
829857
type: 'object',

0 commit comments

Comments
 (0)