Skip to content

Commit 2855647

Browse files
authored
fix: open-api issues (#446)
1 parent 4a382ae commit 2855647

File tree

22 files changed

+410
-93
lines changed

22 files changed

+410
-93
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "zenstack-monorepo",
3-
"version": "1.0.0-alpha.121",
3+
"version": "1.0.0-alpha.122",
44
"description": "",
55
"scripts": {
66
"build": "pnpm -r build",

packages/language/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/language",
3-
"version": "1.0.0-alpha.121",
3+
"version": "1.0.0-alpha.122",
44
"displayName": "ZenStack modeling language compiler",
55
"description": "ZenStack modeling language compiler",
66
"homepage": "https://zenstack.dev",

packages/next/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/next",
3-
"version": "1.0.0-alpha.121",
3+
"version": "1.0.0-alpha.122",
44
"displayName": "ZenStack Next.js integration",
55
"description": "ZenStack Next.js integration",
66
"homepage": "https://zenstack.dev",

packages/plugins/openapi/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/openapi",
33
"displayName": "ZenStack Plugin and Runtime for OpenAPI",
4-
"version": "1.0.0-alpha.121",
4+
"version": "1.0.0-alpha.122",
55
"description": "ZenStack plugin and runtime supporting OpenAPI",
66
"main": "index.js",
77
"repository": {

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

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase {
533533
_jsonapi: {
534534
type: 'object',
535535
description: 'An object describing the server’s implementation',
536+
required: ['version'],
536537
properties: {
537538
version: { type: 'string' },
538539
meta: this.ref('_meta'),
@@ -548,44 +549,50 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase {
548549
description: 'Identifier for a resource',
549550
required: ['type', 'id'],
550551
properties: {
551-
type: { type: 'string' },
552-
id: { type: 'string' },
552+
type: { type: 'string', description: 'Resource type' },
553+
id: { type: 'string', description: 'Resource id' },
553554
},
554555
},
555556
_resource: this.allOf(this.ref('_resourceIdentifier'), {
556557
type: 'object',
557558
description: 'A resource with attributes and relationships',
558559
properties: {
559-
attributes: { type: 'object' },
560-
relationships: { type: 'object' },
560+
attributes: { type: 'object', description: 'Resource attributes' },
561+
relationships: { type: 'object', description: 'Resource relationships' },
561562
},
562563
}),
563564
_links: {
564565
type: 'object',
565566
required: ['self'],
566567
description: 'Links related to the resource',
567-
properties: { self: { type: 'string' } },
568+
properties: { self: { type: 'string', description: 'Link for refetching the curent results' } },
568569
},
569570
_pagination: {
570571
type: 'object',
571572
description: 'Pagination information',
573+
required: ['first', 'last', 'prev', 'next'],
572574
properties: {
573-
first: this.nullable({ type: 'string' }),
574-
last: this.nullable({ type: 'string' }),
575-
prev: this.nullable({ type: 'string' }),
576-
next: this.nullable({ type: 'string' }),
575+
first: this.nullable({ type: 'string', description: 'Link to the first page' }),
576+
last: this.nullable({ type: 'string', description: 'Link to the last page' }),
577+
prev: this.nullable({ type: 'string', description: 'Link to the previous page' }),
578+
next: this.nullable({ type: 'string', description: 'Link to the next page' }),
577579
},
578580
},
579581
_errors: {
580582
type: 'array',
581583
description: 'An array of error objects',
582584
items: {
583585
type: 'object',
586+
required: ['status', 'code'],
584587
properties: {
585-
status: { type: 'string' },
586-
code: { type: 'string' },
587-
title: { type: 'string' },
588-
detail: { type: 'string' },
588+
status: { type: 'string', description: 'HTTP status' },
589+
code: { type: 'string', description: 'Error code' },
590+
prismaCode: {
591+
type: 'string',
592+
description: 'Prisma error code if the error is thrown by Prisma',
593+
},
594+
title: { type: 'string', description: 'Error title' },
595+
detail: { type: 'string', description: 'Error detail' },
589596
},
590597
},
591598
},
@@ -603,8 +610,11 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase {
603610
required: ['self', 'related'],
604611
description: 'Links related to a relationship',
605612
properties: {
606-
self: { type: 'string' },
607-
related: { type: 'string' },
613+
self: { type: 'string', description: 'Link for fetching this relationship' },
614+
related: {
615+
type: 'string',
616+
description: 'Link for fetching the resource represented by this relationship',
617+
},
608618
},
609619
},
610620
_toOneRelationship: {

packages/plugins/openapi/tests/baseline/rest.baseline.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,8 @@ components:
12961296
_jsonapi:
12971297
type: object
12981298
description: An object describing the server’s implementation
1299+
required:
1300+
- version
12991301
properties:
13001302
version:
13011303
type: string
@@ -1314,8 +1316,10 @@ components:
13141316
properties:
13151317
type:
13161318
type: string
1319+
description: Resource type
13171320
id:
13181321
type: string
1322+
description: Resource id
13191323
_resource:
13201324
allOf:
13211325
- $ref: '#/components/schemas/_resourceIdentifier'
@@ -1324,8 +1328,10 @@ components:
13241328
properties:
13251329
attributes:
13261330
type: object
1331+
description: Resource attributes
13271332
relationships:
13281333
type: object
1334+
description: Resource relationships
13291335
_links:
13301336
type: object
13311337
required:
@@ -1334,40 +1340,60 @@ components:
13341340
properties:
13351341
self:
13361342
type: string
1343+
description: Link for refetching the curent results
13371344
_pagination:
13381345
type: object
13391346
description: Pagination information
1347+
required:
1348+
- first
1349+
- last
1350+
- prev
1351+
- next
13401352
properties:
13411353
first:
13421354
oneOf:
13431355
- type: string
1356+
description: Link to the first page
13441357
- type: 'null'
13451358
last:
13461359
oneOf:
13471360
- type: string
1361+
description: Link to the last page
13481362
- type: 'null'
13491363
prev:
13501364
oneOf:
13511365
- type: string
1366+
description: Link to the previous page
13521367
- type: 'null'
13531368
next:
13541369
oneOf:
13551370
- type: string
1371+
description: Link to the next page
13561372
- type: 'null'
13571373
_errors:
13581374
type: array
13591375
description: An array of error objects
13601376
items:
13611377
type: object
1378+
required:
1379+
- status
1380+
- code
13621381
properties:
13631382
status:
13641383
type: string
1384+
description: HTTP status
13651385
code:
13661386
type: string
1387+
description: Error code
1388+
prismaCode:
1389+
type: string
1390+
description: Prisma error code if the error is thrown by Prisma
13671391
title:
13681392
type: string
1393+
description: Error title
13691394
detail:
13701395
type: string
1396+
description: Error detail
13711397
_errorResponse:
13721398
type: object
13731399
required:
@@ -1387,8 +1413,10 @@ components:
13871413
properties:
13881414
self:
13891415
type: string
1416+
description: Link for fetching this relationship
13901417
related:
13911418
type: string
1419+
description: Link for fetching the resource represented by this relationship
13921420
_toOneRelationship:
13931421
type: object
13941422
description: A to-one relationship

packages/plugins/react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/react",
33
"displayName": "ZenStack plugin and runtime for ReactJS",
4-
"version": "1.0.0-alpha.121",
4+
"version": "1.0.0-alpha.122",
55
"description": "ZenStack plugin and runtime for ReactJS",
66
"main": "index.js",
77
"repository": {

packages/plugins/swr/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/swr",
33
"displayName": "ZenStack plugin for generating SWR hooks",
4-
"version": "1.0.0-alpha.121",
4+
"version": "1.0.0-alpha.122",
55
"description": "ZenStack plugin for generating SWR hooks",
66
"main": "index.js",
77
"repository": {

packages/plugins/tanstack-query/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/tanstack-query",
33
"displayName": "ZenStack plugin for generating tanstack-query hooks",
4-
"version": "1.0.0-alpha.121",
4+
"version": "1.0.0-alpha.122",
55
"description": "ZenStack plugin for generating tanstack-query hooks",
66
"main": "index.js",
77
"repository": {

packages/plugins/trpc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/trpc",
33
"displayName": "ZenStack plugin for tRPC",
4-
"version": "1.0.0-alpha.121",
4+
"version": "1.0.0-alpha.122",
55
"description": "ZenStack plugin for tRPC",
66
"main": "index.js",
77
"repository": {

packages/runtime/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/runtime",
33
"displayName": "ZenStack Runtime Library",
4-
"version": "1.0.0-alpha.121",
4+
"version": "1.0.0-alpha.122",
55
"description": "Runtime of ZenStack for both client-side and server-side environments.",
66
"repository": {
77
"type": "git",

packages/runtime/src/enhancements/policy/policy-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ export class PolicyUtil {
864864
* Gets "id" field for a given model.
865865
*/
866866
getIdFields(model: string) {
867-
return getIdFields(this.modelMeta, model);
867+
return getIdFields(this.modelMeta, model, true);
868868
}
869869

870870
/**

packages/runtime/src/enhancements/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ export function getModelFields(data: object) {
2424
/**
2525
* Gets id fields for the given model.
2626
*/
27-
export function getIdFields(modelMeta: ModelMeta, model: string) {
27+
export function getIdFields(modelMeta: ModelMeta, model: string, throwIfNotFound = false) {
2828
const fields = modelMeta.fields[lowerCaseFirst(model)];
2929
if (!fields) {
3030
throw new Error(`Unable to load fields for ${model}`);
3131
}
3232
const result = Object.values(fields).filter((f) => f.isId);
33-
if (result.length === 0) {
33+
if (result.length === 0 && throwIfNotFound) {
3434
throw new Error(`model ${model} does not have an id field`);
3535
}
3636
return result;

packages/schema/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"publisher": "zenstack",
44
"displayName": "ZenStack Language Tools",
55
"description": "A toolkit for building secure CRUD apps with Next.js + Typescript",
6-
"version": "1.0.0-alpha.121",
6+
"version": "1.0.0-alpha.122",
77
"author": {
88
"name": "ZenStack Team"
99
},

packages/schema/src/plugins/prisma/schema-generator.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from '@zenstackhq/language/ast';
2323
import {
2424
analyzePolicies,
25+
getDataModels,
2526
getLiteral,
2627
getLiteralArray,
2728
GUARD_FIELD_NAME,
@@ -219,9 +220,7 @@ export default class PrismaSchemaGenerator {
219220
this.generateModelField(model, field);
220221
}
221222

222-
const { allowAll, denyAll, hasFieldValidation } = analyzePolicies(decl);
223-
224-
if ((!allowAll && !denyAll) || hasFieldValidation) {
223+
if (this.shouldGenerateAuxFields(decl)) {
225224
// generate auxiliary fields for policy check
226225

227226
// add an "zenstack_guard" field for dealing with boolean conditions
@@ -274,6 +273,40 @@ export default class PrismaSchemaGenerator {
274273
decl.comments.forEach((c) => model.addComment(c));
275274
}
276275

276+
private shouldGenerateAuxFields(decl: DataModel) {
277+
const { allowAll, denyAll, hasFieldValidation } = analyzePolicies(decl);
278+
279+
if (!allowAll && !denyAll) {
280+
// has policy conditions
281+
return true;
282+
}
283+
284+
if (hasFieldValidation) {
285+
return true;
286+
}
287+
288+
// check if the model is related by other models, if so
289+
// aux fields are needed for nested queries
290+
const root = decl.$container;
291+
for (const model of getDataModels(root)) {
292+
if (model === decl) {
293+
continue;
294+
}
295+
for (const field of model.fields) {
296+
if (field.type.reference?.ref === decl) {
297+
// found a relation with policies
298+
const otherPolicies = analyzePolicies(model);
299+
if ((!otherPolicies.allowAll && !otherPolicies.denyAll) || otherPolicies.hasFieldValidation) {
300+
// the relating side has policies
301+
return true;
302+
}
303+
}
304+
}
305+
}
306+
307+
return false;
308+
}
309+
277310
private isPrismaAttribute(attr: DataModelAttribute | DataModelFieldAttribute) {
278311
if (!attr.decl.ref) {
279312
return false;

0 commit comments

Comments
 (0)